Compare commits
254 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6dbb61dc12 | ||
|
|
f1d3b68308 | ||
|
|
cec61fc225 | ||
|
|
caf31517ca | ||
|
|
22edebbf9b | ||
|
|
806f17f6ea | ||
|
|
77a5896997 | ||
|
|
cc754342c8 | ||
|
|
eeb700c75d | ||
|
|
9bb83d4574 | ||
|
|
8023b2ea29 | ||
|
|
3e1244a27a | ||
|
|
51e610830f | ||
|
|
a2877f6b5f | ||
|
|
acf6b3dffd | ||
|
|
b6a1c4b308 | ||
|
|
e29ab817af | ||
|
|
86576581cd | ||
|
|
50bd46015b | ||
|
|
aa2ffaf1ea | ||
|
|
5cc6b6c69c | ||
|
|
0365f71c00 | ||
|
|
4d666907c9 | ||
|
|
0466678176 | ||
|
|
c1e239b9b3 | ||
|
|
26aaeabd7f | ||
|
|
0e0bc9dfd2 | ||
|
|
8990cbfd6a | ||
|
|
8f34c03289 | ||
|
|
c1322a3566 | ||
|
|
5101e2851a | ||
|
|
7b7f67ad2e | ||
|
|
dbdc566ae4 | ||
|
|
f4fd991907 | ||
|
|
42ad74158b | ||
|
|
c99afa79e1 | ||
|
|
789c3b869a | ||
|
|
7d8d87662b | ||
|
|
645a5ced14 | ||
|
|
5ed98e8fed | ||
|
|
f12370389c | ||
|
|
fc35d7bb26 | ||
|
|
95c1f7bde0 | ||
|
|
d52c249921 | ||
|
|
0b9a50cd8d | ||
|
|
25bbfec318 | ||
|
|
1192c26b8f | ||
|
|
4a3201ffd4 | ||
|
|
406a22100d | ||
|
|
2547cf70c2 | ||
|
|
e83fa4d40b | ||
|
|
c552cb5e40 | ||
|
|
363904411d | ||
|
|
49bc9f50bc | ||
|
|
30501feb99 | ||
|
|
efc07e1553 | ||
|
|
9bbeec523e | ||
|
|
943ee517f4 | ||
|
|
18bb3bf246 | ||
|
|
117d51caab | ||
|
|
a3e411f225 | ||
|
|
083af3ebc7 | ||
|
|
3fd4d106d9 | ||
|
|
7c376c93a2 | ||
|
|
4ef7b645a8 | ||
|
|
cccc7ff2d0 | ||
|
|
b7c45f4c6e | ||
|
|
3964658d9a | ||
|
|
03212be54a | ||
|
|
46098f2127 | ||
|
|
2005d0b0b9 | ||
|
|
3293380515 | ||
|
|
68e5b22fe2 | ||
|
|
0f7dd7cc0c | ||
|
|
0713251685 | ||
|
|
3fda62e320 | ||
|
|
5f1c2d6676 | ||
|
|
c0ba559ca6 | ||
|
|
164720db3d | ||
|
|
bd90ec4bf0 | ||
|
|
d7e24dfa8f | ||
|
|
2f1ad21392 | ||
|
|
687d539534 | ||
|
|
bd6793bc19 | ||
|
|
6dd6452c11 | ||
|
|
e59a1cd27b | ||
|
|
24d14d5e19 | ||
|
|
e0584367c5 | ||
|
|
a2f48e8944 | ||
|
|
95ba18f8a9 | ||
|
|
122d8ef367 | ||
|
|
281d2ed1f4 | ||
|
|
48924774f9 | ||
|
|
ee00914a2b | ||
|
|
48d90c1eca | ||
|
|
415b3db809 | ||
|
|
53451dfaf6 | ||
|
|
49181dce2b | ||
|
|
199763bcca | ||
|
|
033647da61 | ||
|
|
00e8e9d84a | ||
|
|
96b701687b | ||
|
|
e1e90cc23e | ||
|
|
f41ecae8c8 | ||
|
|
65ec8cf4ee | ||
|
|
4fc93f7089 | ||
|
|
3ec01a20c2 | ||
|
|
8a10f0a766 | ||
|
|
0db125177f | ||
|
|
a3f532f62f | ||
|
|
234f36c8c0 | ||
|
|
2c3957b2db | ||
|
|
79deca41c1 | ||
|
|
570df7f645 | ||
|
|
8153b80d05 | ||
|
|
b74654a5b3 | ||
|
|
4c6f68b07e | ||
|
|
9839efc2dc | ||
|
|
9d379d966c | ||
|
|
61086989dc | ||
|
|
023ea43611 | ||
|
|
044e032ab3 | ||
|
|
da7b95041d | ||
|
|
f52f39984f | ||
|
|
1513b07071 | ||
|
|
be19b7414a | ||
|
|
75f9a0252a | ||
|
|
5169c35d5c | ||
|
|
bbdf1ee6cc | ||
|
|
6c6e8a9972 | ||
|
|
97742b08c8 | ||
|
|
8ef4c61fc3 | ||
|
|
ff607e4b03 | ||
|
|
30c1ab125c | ||
|
|
8276746dad | ||
|
|
5560ef4d34 | ||
|
|
fac31f7254 | ||
|
|
1efcc8d3ef | ||
|
|
03c2088e6b | ||
|
|
5c20ee7ade | ||
|
|
04c62aabea | ||
|
|
0994158abd | ||
|
|
77a66a66ea | ||
|
|
0b615b578a | ||
|
|
53f07db5fe | ||
|
|
4d4815d6af | ||
|
|
b296e0709c | ||
|
|
373e0a390b | ||
|
|
222037ff40 | ||
|
|
4fac10ccb7 | ||
|
|
7956ca0409 | ||
|
|
5b27d0559f | ||
|
|
85157fdf85 | ||
|
|
caf8e7f2d6 | ||
|
|
124bb027ab | ||
|
|
d5ca14ca52 | ||
|
|
99982aa547 | ||
|
|
3f4493c0ea | ||
|
|
cdb604b29f | ||
|
|
d3b8cebc8a | ||
|
|
7d245660bc | ||
|
|
b1e40427a3 | ||
|
|
73925df24b | ||
|
|
04fbd3b548 | ||
|
|
d9dd94d6c3 | ||
|
|
963353a1dc | ||
|
|
3411dcfd91 | ||
|
|
ae6434affb | ||
|
|
f773e0a935 | ||
|
|
7ab3ad9e08 | ||
|
|
3f3a82ca6c | ||
|
|
e902cc5780 | ||
|
|
fcb6952119 | ||
|
|
3eecd57979 | ||
|
|
6e73b9fefd | ||
|
|
f0b0285f77 | ||
|
|
e706a015b3 | ||
|
|
a804f9a1ad | ||
|
|
9e1b7dbb87 | ||
|
|
551ffe9ed3 | ||
|
|
cbe1ce5bcd | ||
|
|
917afd5067 | ||
|
|
c3fb9231a4 | ||
|
|
2ed2f8e262 | ||
|
|
390d90ac47 | ||
|
|
4c877e7a5a | ||
|
|
972fe433f7 | ||
|
|
ecaf6f96a9 | ||
|
|
8541e2a869 | ||
|
|
48a2963472 | ||
|
|
f245a02372 | ||
|
|
1c16343b46 | ||
|
|
d0f66f2d16 | ||
|
|
df0c6ed269 | ||
|
|
9a4e26a5be | ||
|
|
2b87f91279 | ||
|
|
9b48b61b9b | ||
|
|
57e67b3699 | ||
|
|
15e60c3d24 | ||
|
|
ebf07db6c6 | ||
|
|
1559767201 | ||
|
|
6e5e52df37 | ||
|
|
e9289c102b | ||
|
|
81d61d7e29 | ||
|
|
9ab4ec2d4f | ||
|
|
565332dfcd | ||
|
|
f94fbd740a | ||
|
|
a2719ec2f7 | ||
|
|
1da12cb18e | ||
|
|
e0cddcd061 | ||
|
|
78f632a4f6 | ||
|
|
52754535a0 | ||
|
|
a9db667c9c | ||
|
|
f442632fbc | ||
|
|
362086cc83 | ||
|
|
73d59569ff | ||
|
|
cb4fadf84c | ||
|
|
e85d144928 | ||
|
|
07099f4057 | ||
|
|
96c13c344a | ||
|
|
8f42822d9e | ||
|
|
c5ba79cfbb | ||
|
|
f69f76856a | ||
|
|
3a23d820cc | ||
|
|
c917d22db5 | ||
|
|
c3f8b102fa | ||
|
|
5e566db47d | ||
|
|
5b2c5907ed | ||
|
|
dd78a41171 | ||
|
|
201fb4e241 | ||
|
|
8abd25fe40 | ||
|
|
d59c897921 | ||
|
|
cb89d13d9f | ||
|
|
a1aa78adc0 | ||
|
|
4bbbd33917 | ||
|
|
42ccc53166 | ||
|
|
35ad21da38 | ||
|
|
bd0fcbef3a | ||
|
|
c5c673e360 | ||
|
|
5cd21da7b1 | ||
|
|
fe1c4cc4d4 | ||
|
|
ed649dd4c7 | ||
|
|
33eccaa374 | ||
|
|
7b0f672f04 | ||
|
|
33bf5234d0 | ||
|
|
cb392e7e5f | ||
|
|
dfba033190 | ||
|
|
5fbe623ae6 | ||
|
|
e025bff99b | ||
|
|
e77dddc15b | ||
|
|
eea8019593 | ||
|
|
c7360c8cc3 | ||
|
|
2376148380 | ||
|
|
9e8166c13d |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -120,3 +120,5 @@ eos.iml
|
||||
gitversion
|
||||
.version
|
||||
/.version
|
||||
*.swp
|
||||
|
||||
|
||||
@@ -15,12 +15,8 @@ The latest version along with release notes can always be found on the project's
|
||||
Windows and OS X users are supplied self-contained builds of pyfa on the [latest releases](https://github.com/pyfa-org/Pyfa/releases/latest) page. An `.exe` installer is also available for Windows builds. Linux users can run pyfa using their distribution's Python interpreter. There is no official self-contained package for Linux, however, there are a number of third-party packages available through distribution-specific repositories.
|
||||
|
||||
#### OS X
|
||||
There are two different distributives for OS X: `-mac` and `-mac-deprecated`.
|
||||
|
||||
* `-mac`: based on wxPython 3.0.2.0 and has updated libraries. This is the recommended build.
|
||||
* `-mac-deprecated`: utilizes older binaries running on wxPython 2.8; because of this, some features are not available (currently CREST support and Attribute Overrides). Additionally, as development happens primarily on wxPython 3.0, a few GUI bugs may pop up as `-mac-deprecated` is not actively tested. However, due to some general issues with wxPython 3.0, especially on some newer OS X versions, `-mac-deprecated` is still offered for those that need it.
|
||||
|
||||
There is also a [Homebrew](http://brew.sh) option for installing pyfa on OS X. Please note this is maintained by a third-party and is not tested by pyfa developers. Simply fire up in terminal:
|
||||
Apart from the official release, there is also a [Homebrew](http://brew.sh) option for installing pyfa on OS X. Please note this is maintained by a third-party and is not tested by pyfa developers. Simply fire up in terminal:
|
||||
```
|
||||
$ brew install Caskroom/cask/pyfa
|
||||
```
|
||||
|
||||
36
config.py
36
config.py
@@ -3,6 +3,9 @@ import sys
|
||||
|
||||
from logbook import CRITICAL, DEBUG, ERROR, FingersCrossedHandler, INFO, Logger, NestedSetup, NullHandler, \
|
||||
StreamHandler, TimedRotatingFileHandler, WARNING
|
||||
import hashlib
|
||||
|
||||
from cryptography.fernet import Fernet
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
@@ -20,12 +23,15 @@ debug = False
|
||||
saveInRoot = False
|
||||
|
||||
# Version data
|
||||
version = "2.0.0b3"
|
||||
tag = "git"
|
||||
expansionName = "YC120.2"
|
||||
expansionVersion = "1.2"
|
||||
|
||||
version = "2.0.2"
|
||||
tag = "Stable"
|
||||
expansionName = "YC120.3"
|
||||
expansionVersion = "1.8"
|
||||
evemonMinVersion = "4081"
|
||||
|
||||
minItemSearchLength = 3
|
||||
|
||||
pyfaPath = None
|
||||
savePath = None
|
||||
saveDB = None
|
||||
@@ -33,6 +39,10 @@ gameDB = None
|
||||
logPath = None
|
||||
loggingLevel = None
|
||||
logging_setup = None
|
||||
cipher = None
|
||||
clientHash = None
|
||||
|
||||
ESI_CACHE = 'esi_cache'
|
||||
|
||||
LOGLEVEL_MAP = {
|
||||
"critical": CRITICAL,
|
||||
@@ -43,6 +53,10 @@ LOGLEVEL_MAP = {
|
||||
}
|
||||
|
||||
|
||||
def getClientSecret():
|
||||
return clientHash
|
||||
|
||||
|
||||
def isFrozen():
|
||||
if hasattr(sys, 'frozen'):
|
||||
return True
|
||||
@@ -85,6 +99,8 @@ def defPaths(customSavePath=None):
|
||||
global gameDB
|
||||
global saveInRoot
|
||||
global logPath
|
||||
global cipher
|
||||
global clientHash
|
||||
|
||||
pyfalog.debug("Configuring Pyfa")
|
||||
|
||||
@@ -109,12 +125,22 @@ def defPaths(customSavePath=None):
|
||||
|
||||
__createDirs(savePath)
|
||||
|
||||
secret_file = os.path.join(savePath, ".secret")
|
||||
if not os.path.exists(secret_file):
|
||||
with open(secret_file, "wb") as _file:
|
||||
_file.write(Fernet.generate_key())
|
||||
|
||||
with open(secret_file, 'rb') as fp:
|
||||
key = fp.read()
|
||||
clientHash = hashlib.sha3_256(key).hexdigest()
|
||||
cipher = Fernet(key)
|
||||
|
||||
# if isFrozen():
|
||||
# os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(pyfaPath, "cacert.pem")
|
||||
# os.environ["SSL_CERT_FILE"] = os.path.join(pyfaPath, "cacert.pem")
|
||||
|
||||
# The database where we store all the fits etc
|
||||
saveDB = os.path.join(savePath, "saveddata-py3-dev.db")
|
||||
saveDB = os.path.join(savePath, "saveddata.db")
|
||||
|
||||
# The database where the static EVE data from the datadump is kept.
|
||||
# This is not the standard sqlite datadump but a modified version created by eos
|
||||
|
||||
@@ -19,6 +19,7 @@ added_files = [
|
||||
('../../imgs/icons/*.png', 'imgs/icons'),
|
||||
('../../imgs/renders/*.png', 'imgs/renders'),
|
||||
('../../dist_assets/win/pyfa.ico', '.'),
|
||||
('../../service/jargon/*.yaml', 'service/jargon'),
|
||||
(requests.certs.where(), '.'), # is this needed anymore?
|
||||
('../../eve.db', '.'),
|
||||
('../../README.md', '.'),
|
||||
@@ -29,6 +30,8 @@ added_files = [
|
||||
|
||||
import_these = []
|
||||
|
||||
icon = os.path.join(os.getcwd(), "dist_assets", "mac", "pyfa.icns")
|
||||
|
||||
# Walk directories that do dynamic importing
|
||||
paths = ('eos/effects', 'eos/db/migrations', 'service/conversions')
|
||||
for root, folders, files in chain.from_iterable(os.walk(path) for path in paths):
|
||||
@@ -64,10 +67,10 @@ exe = EXE(pyz,
|
||||
upx=True,
|
||||
runtime_tmpdir=None,
|
||||
console=False ,
|
||||
icon='dist_assets/mac/pyfa.icns',
|
||||
icon=icon,
|
||||
)
|
||||
|
||||
app = BUNDLE(exe,
|
||||
name='pyfa.app',
|
||||
icon=None,
|
||||
icon=icon,
|
||||
bundle_identifier=None)
|
||||
46
dist_assets/win/dist.py
Normal file
46
dist_assets/win/dist.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# helper script to zip up pyinstaller distribution and create installer file
|
||||
|
||||
import os.path
|
||||
from subprocess import call
|
||||
import zipfile
|
||||
|
||||
|
||||
def zipdir(path, zip):
|
||||
for root, dirs, files in os.walk(path):
|
||||
for file in files:
|
||||
zip.write(os.path.join(root, file))
|
||||
|
||||
config = {}
|
||||
|
||||
exec(compile(open("config.py").read(), "config.py", 'exec'), config)
|
||||
|
||||
iscc = "C:\Program Files (x86)\Inno Setup 5\ISCC.exe" # inno script location via wine
|
||||
|
||||
print("Creating archive")
|
||||
|
||||
source = os.path.join(os.getcwd(), "dist", "pyfa")
|
||||
|
||||
fileName = "pyfa-{}-{}-{}-win".format(
|
||||
config['version'],
|
||||
config['expansionName'].lower(),
|
||||
config['expansionVersion']
|
||||
)
|
||||
|
||||
archive = zipfile.ZipFile(os.path.join(os.getcwd(), "dist", fileName + ".zip"), 'w', compression=zipfile.ZIP_DEFLATED)
|
||||
zipdir(source, archive)
|
||||
archive.close()
|
||||
|
||||
print("Compiling EXE")
|
||||
|
||||
expansion = "%s %s" % (config['expansionName'], config['expansionVersion']),
|
||||
|
||||
call([
|
||||
iscc,
|
||||
os.path.join(os.getcwd(), "dist_assets", "win", "pyfa-setup.iss"),
|
||||
"/dMyAppVersion=%s" % (config['version']),
|
||||
"/dMyAppExpansion=%s" % (expansion),
|
||||
"/dMyAppDir=%s" % source,
|
||||
"/dMyOutputDir=%s" % os.path.join(os.getcwd(), "dist"),
|
||||
"/dMyOutputFile=%s" % fileName]) # stdout=devnull, stderr=devnull
|
||||
|
||||
print("Done")
|
||||
@@ -19,7 +19,8 @@
|
||||
#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
|
||||
#define VersionFlag 16
|
||||
#define MajorVersionFlag 2
|
||||
#define MinorVersionFlag 0
|
||||
|
||||
#ifndef MyOutputFile
|
||||
#define MyOutputFile LowerCase(StringChange(MyAppName+'-'+MyAppVersion+'-'+MyAppExpansion+'-win-wx3', " ", "-"))
|
||||
@@ -138,15 +139,19 @@ var
|
||||
V: Integer;
|
||||
iResultCode: Integer;
|
||||
sUnInstallString: string;
|
||||
iOldVersion: Cardinal;
|
||||
iOldVersionMajor: Cardinal;
|
||||
iOldVersionMinor: Cardinal;
|
||||
begin
|
||||
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
|
||||
begin
|
||||
RegQueryDWordValue(HKEY_LOCAL_MACHINE,
|
||||
'Software\Microsoft\Windows\CurrentVersion\Uninstall\{3DA39096-C08D-49CD-90E0-1D177F32C8AA}_is1',
|
||||
'MinorVersion', iOldVersion);
|
||||
if iOldVersion < {#VersionFlag} then // If old version with old structure is installed.
|
||||
'MajorVersion', iOldVersionMajor);
|
||||
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
|
||||
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
|
||||
@@ -18,6 +18,7 @@ added_files = [
|
||||
('../../imgs/gui/*.gif', 'imgs/gui'),
|
||||
('../../imgs/icons/*.png', 'imgs/icons'),
|
||||
('../../imgs/renders/*.png', 'imgs/renders'),
|
||||
('../../service/jargon/*.yaml', 'service/jargon'),
|
||||
('../../dist_assets/win/pyfa.ico', '.'),
|
||||
(requests.certs.where(), '.'), # is this needed anymore?
|
||||
('../../eve.db', '.'),
|
||||
@@ -78,4 +79,5 @@ coll = COLLECT(
|
||||
upx=True,
|
||||
name='pyfa',
|
||||
icon='dist_assets/win/pyfa.ico',
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
45
dist_assets/win/version_resource.py
Normal file
45
dist_assets/win/version_resource.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# UTF-8
|
||||
#
|
||||
# For more details about fixed file info 'ffi' see:
|
||||
# http://msdn.microsoft.com/en-us/library/ms646997.aspx
|
||||
VSVersionInfo(
|
||||
ffi=FixedFileInfo(
|
||||
# filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4)
|
||||
# Set not needed items to zero 0.
|
||||
filevers=(1, 15, 1, 0),
|
||||
prodvers=(1, 15, 1, 0),
|
||||
# Contains a bitmask that specifies the valid bits 'flags'r
|
||||
mask=0x3f,
|
||||
# Contains a bitmask that specifies the Boolean attributes of the file.
|
||||
flags=0x0,
|
||||
# The operating system for which this file was designed.
|
||||
# 0x4 - NT and there is no need to change it.
|
||||
OS=0x40004,
|
||||
# The general type of file.
|
||||
# 0x1 - the file is an application.
|
||||
fileType=0x1,
|
||||
# The function of the file.
|
||||
# 0x0 - the function is not defined for this fileType
|
||||
subtype=0x0,
|
||||
# Creation date and time stamp.
|
||||
date=(0, 0)
|
||||
),
|
||||
kids=[
|
||||
StringFileInfo(
|
||||
[
|
||||
StringTable(
|
||||
u'040904E4',
|
||||
[StringStruct(u'LegalCopyright', u''),
|
||||
StringStruct(u'InternalName', u'pyfa.exe'),
|
||||
StringStruct(u'FileVersion', u'1.15.1.0'),
|
||||
StringStruct(u'CompanyName', u''),
|
||||
StringStruct(u'OriginalFilename', u'pyfa.exe'),
|
||||
StringStruct(u'ProductVersion', u'1.15.1.0'),
|
||||
StringStruct(u'FileDescription', u'Python fitting assistant'),
|
||||
StringStruct(u'LegalTrademarks', u''),
|
||||
StringStruct(u'Comments', u''),
|
||||
StringStruct(u'ProductName', u'pyfa')])
|
||||
]),
|
||||
VarFileInfo([VarStruct(u'Translation', [1033, 1252])])
|
||||
]
|
||||
)
|
||||
@@ -72,7 +72,7 @@ class CapSimulator(object):
|
||||
disable_period = False
|
||||
|
||||
# Loop over modules, clearing clipSize if applicable, and group modules based on attributes
|
||||
for (duration, capNeed, clipSize, disableStagger) in self.modules:
|
||||
for (duration, capNeed, clipSize, disableStagger, reloadTime) in self.modules:
|
||||
if self.scale:
|
||||
duration, capNeed = self.scale_activation(duration, capNeed)
|
||||
|
||||
@@ -80,24 +80,25 @@ class CapSimulator(object):
|
||||
# a cap booster module.
|
||||
if not self.reload and capNeed > 0:
|
||||
clipSize = 0
|
||||
reloadTime = 0
|
||||
|
||||
# Group modules based on their properties
|
||||
if (duration, capNeed, clipSize, disableStagger) in mods:
|
||||
mods[(duration, capNeed, clipSize, disableStagger)] += 1
|
||||
if (duration, capNeed, clipSize, disableStagger, reloadTime) in mods:
|
||||
mods[(duration, capNeed, clipSize, disableStagger, reloadTime)] += 1
|
||||
else:
|
||||
mods[(duration, capNeed, clipSize, disableStagger)] = 1
|
||||
mods[(duration, capNeed, clipSize, disableStagger, reloadTime)] = 1
|
||||
|
||||
# Loop over grouped modules, configure staggering and push to the simulation state
|
||||
for (duration, capNeed, clipSize, disableStagger), amount in mods.items():
|
||||
for (duration, capNeed, clipSize, disableStagger, reloadTime), amount in mods.items():
|
||||
if self.stagger and not disableStagger:
|
||||
if clipSize == 0:
|
||||
duration = int(duration / amount)
|
||||
else:
|
||||
stagger_amount = (duration * clipSize + 10000) / (amount * clipSize)
|
||||
stagger_amount = (duration * clipSize + reloadTime) / (amount * clipSize)
|
||||
for i in range(1, amount):
|
||||
heapq.heappush(self.state,
|
||||
[i * stagger_amount, duration,
|
||||
capNeed, 0, clipSize])
|
||||
capNeed, 0, clipSize, reloadTime])
|
||||
else:
|
||||
capNeed *= amount
|
||||
|
||||
@@ -107,7 +108,7 @@ class CapSimulator(object):
|
||||
if clipSize:
|
||||
disable_period = True
|
||||
|
||||
heapq.heappush(self.state, [0, duration, capNeed, 0, clipSize])
|
||||
heapq.heappush(self.state, [0, duration, capNeed, 0, clipSize, reloadTime])
|
||||
|
||||
if disable_period:
|
||||
self.period = self.t_max
|
||||
@@ -144,7 +145,7 @@ class CapSimulator(object):
|
||||
|
||||
while 1:
|
||||
activation = pop(state)
|
||||
t_now, duration, capNeed, shot, clipSize = activation
|
||||
t_now, duration, capNeed, shot, clipSize, reloadTime = activation
|
||||
if t_now >= t_max:
|
||||
break
|
||||
|
||||
@@ -180,7 +181,7 @@ class CapSimulator(object):
|
||||
if clipSize:
|
||||
if shot % clipSize == 0:
|
||||
shot = 0
|
||||
t_now += 10000 # include reload time
|
||||
t_now += reloadTime # include reload time
|
||||
activation[0] = t_now
|
||||
activation[3] = shot
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ sd_lock = threading.RLock()
|
||||
# noinspection PyPep8
|
||||
from eos.db.gamedata import alphaClones, attribute, category, effect, group, icon, item, marketGroup, metaData, metaGroup, queries, traits, unit
|
||||
# noinspection PyPep8
|
||||
from eos.db.saveddata import booster, cargo, character, crest, damagePattern, databaseRepair, drone, fighter, fit, implant, implantSet, loadDefaultDatabaseValues, \
|
||||
from eos.db.saveddata import booster, cargo, character, damagePattern, databaseRepair, drone, fighter, fit, implant, implantSet, loadDefaultDatabaseValues, \
|
||||
miscData, module, override, price, queries, skill, targetResists, user
|
||||
|
||||
# Import queries
|
||||
|
||||
@@ -12,7 +12,6 @@ __all__ = [
|
||||
"miscData",
|
||||
"targetResists",
|
||||
"override",
|
||||
"crest",
|
||||
"implantSet",
|
||||
"loadDefaultDatabaseValues"
|
||||
]
|
||||
|
||||
@@ -17,24 +17,21 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
from sqlalchemy import Table, Column, Integer, ForeignKey, String, DateTime, Float
|
||||
from sqlalchemy import Table, Column, Integer, ForeignKey, String, DateTime, Float, UniqueConstraint
|
||||
from sqlalchemy.orm import relation, mapper
|
||||
import datetime
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.db.saveddata.implant import charImplants_table
|
||||
from eos.effectHandlerHelpers import HandledImplantBoosterList
|
||||
from eos.effectHandlerHelpers import HandledImplantBoosterList, HandledSsoCharacterList
|
||||
from eos.saveddata.implant import Implant
|
||||
from eos.saveddata.user import User
|
||||
from eos.saveddata.character import Character, Skill
|
||||
from eos.saveddata.ssocharacter import SsoCharacter
|
||||
|
||||
characters_table = Table("characters", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
Column("name", String, nullable=False),
|
||||
Column("apiID", Integer),
|
||||
Column("apiKey", String),
|
||||
Column("defaultChar", Integer),
|
||||
Column("chars", String, nullable=True),
|
||||
Column("defaultLevel", Integer, nullable=True),
|
||||
Column("alphaCloneID", Integer, nullable=True),
|
||||
Column("ownerID", ForeignKey("users.ID"), nullable=True),
|
||||
@@ -42,6 +39,28 @@ characters_table = Table("characters", saveddata_meta,
|
||||
Column("created", DateTime, nullable=True, default=datetime.datetime.now),
|
||||
Column("modified", DateTime, nullable=True, onupdate=datetime.datetime.now))
|
||||
|
||||
sso_table = Table("ssoCharacter", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
Column("client", String, nullable=False),
|
||||
Column("characterID", Integer, nullable=False),
|
||||
Column("characterName", String, nullable=False),
|
||||
Column("refreshToken", String, nullable=False),
|
||||
Column("accessToken", String, nullable=False),
|
||||
Column("accessTokenExpires", DateTime, nullable=False),
|
||||
Column("created", DateTime, nullable=True, default=datetime.datetime.now),
|
||||
Column("modified", DateTime, nullable=True, onupdate=datetime.datetime.now),
|
||||
UniqueConstraint('client', 'characterID', name='uix_client_characterID'),
|
||||
UniqueConstraint('client', 'characterName', name='uix_client_characterName')
|
||||
)
|
||||
|
||||
sso_character_map_table = Table("ssoCharacterMap", saveddata_meta,
|
||||
Column("characterID", ForeignKey("characters.ID"), primary_key=True),
|
||||
Column("ssoCharacterID", ForeignKey("ssoCharacter.ID"), primary_key=True),
|
||||
)
|
||||
|
||||
|
||||
mapper(SsoCharacter, sso_table)
|
||||
|
||||
mapper(Character, characters_table,
|
||||
properties={
|
||||
"_Character__alphaCloneID": characters_table.c.alphaCloneID,
|
||||
@@ -63,5 +82,10 @@ mapper(Character, characters_table,
|
||||
primaryjoin=charImplants_table.c.charID == characters_table.c.ID,
|
||||
secondaryjoin=charImplants_table.c.implantID == Implant.ID,
|
||||
secondary=charImplants_table),
|
||||
"_Character__ssoCharacters" : relation(
|
||||
SsoCharacter,
|
||||
collection_class=HandledSsoCharacterList,
|
||||
backref='characters',
|
||||
secondary=sso_character_map_table)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,34 +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 Table, Column, Integer, String, DateTime
|
||||
from sqlalchemy.orm import mapper
|
||||
import datetime
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.saveddata.crestchar import CrestChar
|
||||
|
||||
crest_table = Table("crest", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
Column("name", String, nullable=False, unique=True),
|
||||
Column("refresh_token", String, nullable=False),
|
||||
# These records aren't updated. Instead, they are dropped and created, hence we don't have a modified field
|
||||
Column("created", DateTime, nullable=True, default=datetime.datetime.now))
|
||||
|
||||
mapper(CrestChar, crest_table)
|
||||
@@ -68,7 +68,7 @@ class DefaultDatabaseValues(object):
|
||||
["[Hybrid Charges]Uranium", "0", "38.4", "57.6", "0"],
|
||||
["[Missiles]Mjolnir", "100", "0", "0", "0"], ["[Missiles]Inferno", "0", "100", "0", "0"],
|
||||
["[Missiles]Scourge", "0", "0", "100", "0"], ["[Missiles]Nova", "0", "0", "0", "100"],
|
||||
["[Missiles][Structure) Standup Missile", "100", "100", "100", "100"],
|
||||
["[Missiles][Structure] Standup Missile", "100", "100", "100", "100"],
|
||||
["[Projectile Ammo][T2] Tremor", "0", "0", "24", "40"],
|
||||
["[Projectile Ammo][T2] Quake", "0", "0", "40", "72"],
|
||||
["[Projectile Ammo][T2] Hail", "0", "0", "26.4", "96.8"],
|
||||
|
||||
@@ -27,7 +27,7 @@ from eos.db.saveddata.fit import projectedFits_table
|
||||
from eos.db.util import processEager, processWhere
|
||||
from eos.saveddata.price import Price
|
||||
from eos.saveddata.user import User
|
||||
from eos.saveddata.crestchar import CrestChar
|
||||
from eos.saveddata.ssocharacter import SsoCharacter
|
||||
from eos.saveddata.damagePattern import DamagePattern
|
||||
from eos.saveddata.targetResists import TargetResists
|
||||
from eos.saveddata.character import Character
|
||||
@@ -467,29 +467,28 @@ def getProjectedFits(fitID):
|
||||
raise TypeError("Need integer as argument")
|
||||
|
||||
|
||||
def getCrestCharacters(eager=None):
|
||||
def getSsoCharacters(clientHash, eager=None):
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
characters = saveddata_session.query(CrestChar).options(*eager).all()
|
||||
characters = saveddata_session.query(SsoCharacter).filter(SsoCharacter.client == clientHash).options(*eager).all()
|
||||
return characters
|
||||
|
||||
|
||||
@cachedQuery(CrestChar, 1, "lookfor")
|
||||
def getCrestCharacter(lookfor, eager=None):
|
||||
@cachedQuery(SsoCharacter, 1, "lookfor", "clientHash")
|
||||
def getSsoCharacter(lookfor, clientHash, eager=None):
|
||||
filter = SsoCharacter.client == clientHash
|
||||
|
||||
if isinstance(lookfor, int):
|
||||
if eager is None:
|
||||
with sd_lock:
|
||||
character = saveddata_session.query(CrestChar).get(lookfor)
|
||||
else:
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
character = saveddata_session.query(CrestChar).options(*eager).filter(CrestChar.ID == lookfor).first()
|
||||
filter = and_(filter, SsoCharacter.ID == lookfor)
|
||||
elif isinstance(lookfor, str):
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
character = saveddata_session.query(CrestChar).options(*eager).filter(CrestChar.name == lookfor).first()
|
||||
filter = and_(filter, SsoCharacter.characterName == lookfor)
|
||||
else:
|
||||
raise TypeError("Need integer or string as argument")
|
||||
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
character = saveddata_session.query(SsoCharacter).options(*eager).filter(filter).first()
|
||||
|
||||
return character
|
||||
|
||||
|
||||
@@ -544,7 +543,7 @@ def commit():
|
||||
try:
|
||||
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])
|
||||
|
||||
@@ -205,6 +205,16 @@ class HandledImplantBoosterList(HandledList):
|
||||
HandledList.append(self, thing)
|
||||
|
||||
|
||||
class HandledSsoCharacterList(list):
|
||||
def append(self, character):
|
||||
old = next((x for x in self if x.client == character.client), None)
|
||||
if old is not None:
|
||||
pyfalog.warning("Removing SSO Character with same hash: {}".format(repr(old)))
|
||||
list.remove(self, old)
|
||||
|
||||
list.append(self, character)
|
||||
|
||||
|
||||
class HandledProjectedModList(HandledList):
|
||||
def append(self, proj):
|
||||
if proj.isInvalid:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# ammoInfluenceCapNeed
|
||||
#
|
||||
# Used by:
|
||||
# Items from category: Charge (478 of 925)
|
||||
# Items from category: Charge (478 of 928)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# ammoInfluenceRange
|
||||
#
|
||||
# Used by:
|
||||
# Items from category: Charge (572 of 925)
|
||||
# Items from category: Charge (572 of 928)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Used by:
|
||||
# Charges from group: Festival Charges (23 of 23)
|
||||
# Charges from group: Interdiction Probe (2 of 2)
|
||||
# Charges from group: Structure Festival Charges (3 of 3)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# boosterArmorHpPenalty
|
||||
#
|
||||
# Used by:
|
||||
# Implants from group: Booster (12 of 54)
|
||||
# Implants from group: Booster (12 of 62)
|
||||
type = "boosterSideEffect"
|
||||
|
||||
# User-friendly name for the side effect
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# boosterMaxVelocityPenalty
|
||||
#
|
||||
# Used by:
|
||||
# Implants from group: Booster (12 of 54)
|
||||
# Implants from group: Booster (12 of 62)
|
||||
type = "boosterSideEffect"
|
||||
|
||||
# User-friendly name for the side effect
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# boosterShieldCapacityPenalty
|
||||
#
|
||||
# Used by:
|
||||
# Implants from group: Booster (12 of 54)
|
||||
# Implants from group: Booster (12 of 62)
|
||||
type = "boosterSideEffect"
|
||||
|
||||
# User-friendly name for the side effect
|
||||
|
||||
9
eos/effects/doomsdayaoebubble.py
Normal file
9
eos/effects/doomsdayaoebubble.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# doomsdayAOEBubble
|
||||
#
|
||||
# Used by:
|
||||
# Module: Warp Disruption Burst Projector
|
||||
type = "projected", "active"
|
||||
|
||||
|
||||
def handler(fit, module, context):
|
||||
return
|
||||
9
eos/effects/doomsdaybeamdot.py
Normal file
9
eos/effects/doomsdaybeamdot.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# doomsdayBeamDOT
|
||||
#
|
||||
# Used by:
|
||||
# Modules named like: Lance (4 of 4)
|
||||
type = "active"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
pass
|
||||
9
eos/effects/doomsdayconedot.py
Normal file
9
eos/effects/doomsdayconedot.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# doomsdayConeDOT
|
||||
#
|
||||
# Used by:
|
||||
# Module: Bosonic Field Generator
|
||||
type = "active"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
pass
|
||||
9
eos/effects/doomsdayhog.py
Normal file
9
eos/effects/doomsdayhog.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# doomsdayHOG
|
||||
#
|
||||
# Used by:
|
||||
# Module: Gravitational Transportation Field Oscillator
|
||||
type = "active"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
pass
|
||||
9
eos/effects/doomsdayslash.py
Normal file
9
eos/effects/doomsdayslash.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# doomsdaySlash
|
||||
#
|
||||
# Used by:
|
||||
# Modules named like: Reaper (4 of 4)
|
||||
type = "active"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
pass
|
||||
20
eos/effects/elitebonusflagcruiserallresistances1.py
Normal file
20
eos/effects/elitebonusflagcruiserallresistances1.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# eliteBonusFlagCruiserAllResistances1
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Monitor
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.ship.boostItemAttr("explosiveDamageResonance", src.getModifiedItemAttr("eliteBonusFlagCruisers1"), skill="Flag Cruisers")
|
||||
fit.ship.boostItemAttr("shieldKineticDamageResonance", src.getModifiedItemAttr("eliteBonusFlagCruisers1"), skill="Flag Cruisers")
|
||||
fit.ship.boostItemAttr("shieldExplosiveDamageResonance", src.getModifiedItemAttr("eliteBonusFlagCruisers1"), skill="Flag Cruisers")
|
||||
fit.ship.boostItemAttr("armorThermalDamageResonance", src.getModifiedItemAttr("eliteBonusFlagCruisers1"), skill="Flag Cruisers")
|
||||
fit.ship.boostItemAttr("thermalDamageResonance", src.getModifiedItemAttr("eliteBonusFlagCruisers1"), skill="Flag Cruisers")
|
||||
fit.ship.boostItemAttr("shieldEmDamageResonance", src.getModifiedItemAttr("eliteBonusFlagCruisers1"), skill="Flag Cruisers")
|
||||
fit.ship.boostItemAttr("armorExplosiveDamageResonance", src.getModifiedItemAttr("eliteBonusFlagCruisers1"), skill="Flag Cruisers")
|
||||
fit.ship.boostItemAttr("armorEmDamageResonance", src.getModifiedItemAttr("eliteBonusFlagCruisers1"), skill="Flag Cruisers")
|
||||
fit.ship.boostItemAttr("shieldThermalDamageResonance", src.getModifiedItemAttr("eliteBonusFlagCruisers1"), skill="Flag Cruisers")
|
||||
fit.ship.boostItemAttr("kineticDamageResonance", src.getModifiedItemAttr("eliteBonusFlagCruisers1"), skill="Flag Cruisers")
|
||||
fit.ship.boostItemAttr("armorKineticDamageResonance", src.getModifiedItemAttr("eliteBonusFlagCruisers1"), skill="Flag Cruisers")
|
||||
fit.ship.boostItemAttr("emDamageResonance", src.getModifiedItemAttr("eliteBonusFlagCruisers1"), skill="Flag Cruisers")
|
||||
@@ -9,4 +9,4 @@ type = "passive"
|
||||
def handler(fit, container, context):
|
||||
level = container.level if "skill" in context else 1
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("High Speed Maneuvering"),
|
||||
"capacitorNeed", container.getModifiedItemAttr("capacitorNeedMultiplier") * level)
|
||||
"capacitorNeed", container.getModifiedItemAttr("capNeedBonus") * level)
|
||||
|
||||
9
eos/effects/microjumpportaldrive.py
Normal file
9
eos/effects/microjumpportaldrive.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# microJumpPortalDrive
|
||||
#
|
||||
# Used by:
|
||||
# Module: Micro Jump Field Generator
|
||||
type = "active"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
pass
|
||||
@@ -1,7 +1,7 @@
|
||||
# missileDMGBonus
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Ballistic Control system (18 of 18)
|
||||
# Modules from group: Ballistic Control system (20 of 20)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# missileLauncherSpeedMultiplier
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Ballistic Control system (18 of 18)
|
||||
# Modules from group: Ballistic Control system (20 of 20)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Drone Damage Modules (11 of 11)
|
||||
# Modules named like: C3 'Hivaa Saitsuo' Ballistic Control System (2 of 2)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Missile Launcher Torpedo (22 of 22)
|
||||
# Items from market group: Ship Equipment > Turrets & Bays (429 of 861)
|
||||
# Items from market group: Ship Equipment > Turrets & Bays (429 of 863)
|
||||
# Module: Interdiction Sphere Launcher I
|
||||
type = "overheat"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# overloadSelfDamageBonus
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Energy Weapon (101 of 213)
|
||||
# Modules from group: Energy Weapon (101 of 214)
|
||||
# Modules from group: Hybrid Weapon (105 of 221)
|
||||
# Modules from group: Projectile Weapon (99 of 165)
|
||||
type = "overheat"
|
||||
|
||||
17
eos/effects/rolebonusflagcruisermodulefittingreduction.py
Normal file
17
eos/effects/rolebonusflagcruisermodulefittingreduction.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# roleBonusFlagCruiserModuleFittingReduction
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Monitor
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in ("Propulsion Module", "Micro Jump Drive"),
|
||||
"power", src.getModifiedItemAttr("flagCruiserFittingBonusPropMods"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in ("Propulsion Module", "Micro Jump Drive"),
|
||||
"cpu", src.getModifiedItemAttr("flagCruiserFittingBonusPropMods"))
|
||||
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in ("Target Painter", "Scan Probe Launcher"),
|
||||
"cpu", src.getModifiedItemAttr("flagCruiserFittingBonusPainterProbes"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in ("Target Painter", "Scan Probe Launcher"),
|
||||
"power", src.getModifiedItemAttr("flagCruiserFittingBonusPainterProbes"))
|
||||
@@ -0,0 +1,12 @@
|
||||
# roleBonusFlagCruiserTargetPainterModifications
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Monitor
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Target Painter", "signatureRadiusBonus",
|
||||
src.getModifiedItemAttr("targetPainterStrengthModifierFlagCruisers"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Target Painter", "maxRange",
|
||||
src.getModifiedItemAttr("targetPainterRangeModifierFlagCruisers"))
|
||||
@@ -4,4 +4,4 @@ runTime = "early"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.ship.multiplyItemAttr("structureFullPowerStateHitpointMultiplier", src.getModifiedItemAttr("serviceModuleFullPowerStateHitpointMultiplier"))
|
||||
fit.ship.forceItemAttr("structureFullPowerStateHitpointMultiplier", src.getModifiedItemAttr("serviceModuleFullPowerStateHitpointMultiplier"))
|
||||
|
||||
9
eos/effects/shipagilitybonusgc1.py
Normal file
9
eos/effects/shipagilitybonusgc1.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# shipAgilityBonusGC1
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Monitor
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.ship.boostItemAttr("agility", src.getModifiedItemAttr("shipBonusGC"), skill="Gallente Cruiser")
|
||||
9
eos/effects/shiparmorhitpointsac1.py
Normal file
9
eos/effects/shiparmorhitpointsac1.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# shipArmorHitPointsAC1
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Monitor
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.ship.boostItemAttr("armorHP", src.getModifiedItemAttr("shipBonusAC"), skill="Amarr Cruiser")
|
||||
@@ -2,6 +2,7 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Gnosis
|
||||
# Ship: Praxis
|
||||
# Ship: Sunesis
|
||||
# Ship: Taipan
|
||||
# Ship: Velator
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Used by:
|
||||
# Variations of ship: Procurer (2 of 2)
|
||||
# Ship: Gnosis
|
||||
# Ship: Praxis
|
||||
# Ship: Sunesis
|
||||
# Ship: Taipan
|
||||
# Ship: Velator
|
||||
|
||||
10
eos/effects/shipbonusheavyassaultmissileemdamagecbc2.py
Normal file
10
eos/effects/shipbonusheavyassaultmissileemdamagecbc2.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# shipBonusHeavyAssaultMissileEMDamageCBC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drake Navy Issue
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Assault Missiles"), "emDamage",
|
||||
src.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")
|
||||
@@ -0,0 +1,10 @@
|
||||
# shipBonusHeavyAssaultMissileExplosiveDamageCBC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drake Navy Issue
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Assault Missiles"), "explosiveDamage",
|
||||
src.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")
|
||||
10
eos/effects/shipbonusheavyassaultmissilekineticdamagecbc2.py
Normal file
10
eos/effects/shipbonusheavyassaultmissilekineticdamagecbc2.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# shipBonusHeavyAssaultMissileKineticDamageCBC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drake Navy Issue
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Assault Missiles"),
|
||||
"kineticDamage", src.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")
|
||||
10
eos/effects/shipbonusheavyassaultmissilethermaldamagecbc2.py
Normal file
10
eos/effects/shipbonusheavyassaultmissilethermaldamagecbc2.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# shipBonusHeavyAssaultMissileThermalDamageCBC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drake Navy Issue
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Assault Missiles"),
|
||||
"thermalDamage", src.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")
|
||||
10
eos/effects/shipbonusheavymissileemdamagecbc2.py
Normal file
10
eos/effects/shipbonusheavymissileemdamagecbc2.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# shipBonusHeavyMissileEMDamageCBC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drake Navy Issue
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Missiles"),
|
||||
"emDamage", src.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")
|
||||
10
eos/effects/shipbonusheavymissileexplosivedamagecbc2.py
Normal file
10
eos/effects/shipbonusheavymissileexplosivedamagecbc2.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# shipBonusHeavyMissileExplosiveDamageCBC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drake Navy Issue
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Missiles"), "explosiveDamage",
|
||||
src.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")
|
||||
10
eos/effects/shipbonusheavymissilekineticdamagecbc2.py
Normal file
10
eos/effects/shipbonusheavymissilekineticdamagecbc2.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# shipBonusHeavyMissileKineticDamageCBC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drake Navy Issue
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Missiles"), "kineticDamage",
|
||||
src.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")
|
||||
10
eos/effects/shipbonusheavymissilethermaldamagecbc2.py
Normal file
10
eos/effects/shipbonusheavymissilethermaldamagecbc2.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# shipBonusHeavyMissileThermalDamageCBC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Drake Navy Issue
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Missiles"), "thermalDamage",
|
||||
src.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")
|
||||
@@ -2,6 +2,7 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Gnosis
|
||||
# Ship: Praxis
|
||||
# Ship: Taipan
|
||||
# Ship: Velator
|
||||
type = "passive"
|
||||
|
||||
@@ -9,4 +9,4 @@ type = "passive"
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"),
|
||||
"explosionDelay", ship.getModifiedItemAttr("shipBonusPirateFaction2"))
|
||||
"explosionDelay", ship.getModifiedItemAttr("shipBonusRole8"))
|
||||
|
||||
@@ -7,6 +7,6 @@ type = "passive"
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"),
|
||||
"maxRange", ship.getModifiedItemAttr("shipBonusPirateFaction2"))
|
||||
"maxRange", ship.getModifiedItemAttr("shipBonusRole8"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"),
|
||||
"falloffEffectiveness", ship.getModifiedItemAttr("shipBonusPirateFaction2"))
|
||||
"falloffEffectiveness", ship.getModifiedItemAttr("shipBonusRole8"))
|
||||
|
||||
38
eos/effects/shiplargeweaponsdamagebonus.py
Normal file
38
eos/effects/shiplargeweaponsdamagebonus.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# shipLargeWeaponsDamageBonus
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Praxis
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Large Hybrid Turret"), "damageMultiplier",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Large Projectile Turret"), "damageMultiplier",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Large Energy Turret"), "damageMultiplier",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Missiles"), "thermalDamage",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Missiles"), "emDamage",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Missiles"), "kineticDamage",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Missiles"), "explosiveDamage",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Torpedoes"), "emDamage",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Torpedoes"), "kineticDamage",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Torpedoes"), "explosiveDamage",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Torpedoes"), "thermalDamage",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Cruise Missiles"), "thermalDamage",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Cruise Missiles"), "explosiveDamage",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Cruise Missiles"), "kineticDamage",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Cruise Missiles"), "emDamage",
|
||||
src.getModifiedItemAttr("shipBonusRole7"))
|
||||
@@ -4,10 +4,11 @@
|
||||
# Ships named like: Stratios (2 of 2)
|
||||
# Ship: Astero
|
||||
# Ship: Gnosis
|
||||
# Ship: Praxis
|
||||
# Ship: Sunesis
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, container, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Astrometrics"),
|
||||
"baseSensorStrength", container.getModifiedItemAttr("shipBonusPirateFaction2"))
|
||||
"baseSensorStrength", container.getModifiedItemAttr("shipBonusRole8"))
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# shipShieldEmResistance1CBC2
|
||||
#
|
||||
# Used by:
|
||||
# Variations of ship: Drake (3 of 3)
|
||||
# Ship: Drake
|
||||
# Ship: Nighthawk
|
||||
# Ship: Vulture
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# shipShieldExplosiveResistance1CBC2
|
||||
#
|
||||
# Used by:
|
||||
# Variations of ship: Drake (3 of 3)
|
||||
# Ship: Drake
|
||||
# Ship: Nighthawk
|
||||
# Ship: Vulture
|
||||
type = "passive"
|
||||
|
||||
|
||||
9
eos/effects/shipshieldhitpointscc1.py
Normal file
9
eos/effects/shipshieldhitpointscc1.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# shipShieldHitpointsCC1
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Monitor
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.ship.boostItemAttr("shieldCapacity", src.getModifiedItemAttr("shipBonusCC"), skill="Caldari Cruiser")
|
||||
@@ -1,7 +1,8 @@
|
||||
# shipShieldKineticResistance1CBC2
|
||||
#
|
||||
# Used by:
|
||||
# Variations of ship: Drake (3 of 3)
|
||||
# Ship: Drake
|
||||
# Ship: Nighthawk
|
||||
# Ship: Vulture
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# shipShieldThermalResistance1CBC2
|
||||
#
|
||||
# Used by:
|
||||
# Variations of ship: Drake (3 of 3)
|
||||
# Ship: Drake
|
||||
# Ship: Nighthawk
|
||||
# Ship: Vulture
|
||||
type = "passive"
|
||||
|
||||
|
||||
9
eos/effects/shipsignatureradiusmc1.py
Normal file
9
eos/effects/shipsignatureradiusmc1.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# shipSignatureRadiusMC1
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Monitor
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.ship.boostItemAttr("signatureRadius", src.getModifiedItemAttr("shipBonusMC"), skill="Minmatar Cruiser")
|
||||
@@ -1,14 +1,15 @@
|
||||
# Not used by any item
|
||||
type = "active"
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, container, context):
|
||||
missileGroups = ("Structure Anti-Capital Missile", "Structure Anti-Subcapital Missile")
|
||||
for srcAttr, tgtAttr in (
|
||||
("aoeCloudSizeBonus", "aoeCloudSize"),
|
||||
("aoeVelocityBonus", "aoeVelocity"),
|
||||
("missileVelocityBonus", "maxVelocity"),
|
||||
("explosionDelayBonus", "explosionDelay"),
|
||||
):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"),
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.group.name in missileGroups,
|
||||
tgtAttr, container.getModifiedItemAttr(srcAttr),
|
||||
stackingPenalties=True)
|
||||
|
||||
@@ -7,12 +7,11 @@ type = "projected", "active"
|
||||
|
||||
|
||||
def handler(fit, module, context):
|
||||
if "projected" not in context:
|
||||
return
|
||||
|
||||
fit.ship.increaseItemAttr("warpScrambleStatus", module.getModifiedItemAttr("warpScrambleStrength"))
|
||||
|
||||
# this is such a dirty hack
|
||||
for mod in fit.modules:
|
||||
if not mod.isEmpty and mod.item.requiresSkill("High Speed Maneuvering") and mod.state > State.ONLINE:
|
||||
mod.state = State.ONLINE
|
||||
if "projected" in context:
|
||||
fit.ship.increaseItemAttr("warpScrambleStatus", module.getModifiedItemAttr("warpScrambleStrength"))
|
||||
if module.charge is not None and module.charge.ID == 47336:
|
||||
for mod in fit.modules:
|
||||
if not mod.isEmpty and mod.item.requiresSkill("High Speed Maneuvering") and mod.state > State.ONLINE:
|
||||
mod.state = State.ONLINE
|
||||
if not mod.isEmpty and mod.item.requiresSkill("Micro Jump Drive Operation") and mod.state > State.ONLINE:
|
||||
mod.state = State.ONLINE
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Used by:
|
||||
# Drones from group: Combat Drone (74 of 74)
|
||||
# Modules from group: Energy Weapon (212 of 213)
|
||||
# Modules from group: Energy Weapon (212 of 214)
|
||||
type = 'active'
|
||||
|
||||
|
||||
|
||||
@@ -15,12 +15,13 @@ def handler(fit, src, context):
|
||||
if src.item.group.name == 'Missile Launcher Bomb':
|
||||
# Bomb Launcher Cooldown Timer
|
||||
moduleReactivationDelay = src.getModifiedItemAttr("moduleReactivationDelay")
|
||||
speed = src.getModifiedItemAttr("speed")
|
||||
|
||||
# Void and Focused Void Bombs
|
||||
neutAmount = src.getModifiedChargeAttr("energyNeutralizerAmount")
|
||||
|
||||
if moduleReactivationDelay and neutAmount:
|
||||
fit.addDrain(src, moduleReactivationDelay, neutAmount, 0)
|
||||
if moduleReactivationDelay and neutAmount and speed:
|
||||
fit.addDrain(src, speed + moduleReactivationDelay, neutAmount, 0)
|
||||
|
||||
# Lockbreaker Bombs
|
||||
ecmStrengthBonus = src.getModifiedChargeAttr("scan{0}StrengthBonus".format(fit.scanType))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# warpDisruptSphere
|
||||
#
|
||||
# Used by:
|
||||
@@ -9,18 +10,22 @@ runTime = "early"
|
||||
|
||||
|
||||
def handler(fit, module, context):
|
||||
fit.ship.boostItemAttr("mass", module.getModifiedItemAttr("massBonusPercentage"))
|
||||
fit.ship.boostItemAttr("signatureRadius", module.getModifiedItemAttr("signatureRadiusBonus"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Propulsion Module",
|
||||
"speedBoostFactor", module.getModifiedItemAttr("speedBoostFactorBonus"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Propulsion Module",
|
||||
"speedFactor", module.getModifiedItemAttr("speedFactorBonus"))
|
||||
fit.ship.forceItemAttr("disallowAssistance", 1)
|
||||
|
||||
if "projected" in context:
|
||||
fit.ship.increaseItemAttr("warpScrambleStatus", module.getModifiedItemAttr("warpScrambleStrength"))
|
||||
|
||||
if module.charge is not None and module.charge.ID == 45010:
|
||||
for mod in fit.modules:
|
||||
if not mod.isEmpty and mod.item.requiresSkill("High Speed Maneuvering") and mod.state > State.ONLINE:
|
||||
mod.state = State.ONLINE
|
||||
if not mod.isEmpty and mod.item.requiresSkill("Micro Jump Drive Operation") and mod.state > State.ONLINE:
|
||||
mod.state = State.ONLINE
|
||||
else:
|
||||
if module.charge is None:
|
||||
fit.ship.boostItemAttr("mass", module.getModifiedItemAttr("massBonusPercentage"))
|
||||
fit.ship.boostItemAttr("signatureRadius", module.getModifiedItemAttr("signatureRadiusBonus"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Propulsion Module",
|
||||
"speedBoostFactor", module.getModifiedItemAttr("speedBoostFactorBonus"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Propulsion Module",
|
||||
"speedFactor", module.getModifiedItemAttr("speedFactorBonus"))
|
||||
|
||||
fit.ship.forceItemAttr("disallowAssistance", 1)
|
||||
|
||||
@@ -16,5 +16,10 @@ def handler(fit, module, context):
|
||||
|
||||
# this is such a dirty hack
|
||||
for mod in fit.modules:
|
||||
if not mod.isEmpty and mod.item.requiresSkill("High Speed Maneuvering") and mod.state > State.ONLINE:
|
||||
if not mod.isEmpty and mod.state > State.ONLINE and (
|
||||
mod.item.requiresSkill("Micro Jump Drive Operation") or
|
||||
mod.item.requiresSkill("High Speed Maneuvering")
|
||||
):
|
||||
mod.state = State.ONLINE
|
||||
if not mod.isEmpty and mod.item.requiresSkill("Micro Jump Drive Operation") and mod.state > State.ONLINE:
|
||||
mod.state = State.ONLINE
|
||||
|
||||
@@ -81,7 +81,7 @@ class FitDpsGraph(Graph):
|
||||
total += dps * self.calculateTurretMultiplier(mod, data)
|
||||
|
||||
elif mod.hardpoint == Hardpoint.MISSILE:
|
||||
if mod.state >= State.ACTIVE and mod.maxRange >= distance:
|
||||
if mod.state >= State.ACTIVE and mod.maxRange is not None and mod.maxRange >= distance:
|
||||
total += dps * self.calculateMissileMultiplier(mod, data)
|
||||
|
||||
if distance <= fit.extraAttributes["droneControlRange"]:
|
||||
|
||||
@@ -52,7 +52,6 @@ class Character(object):
|
||||
self.addSkill(Skill(self, item.ID, self.defaultLevel))
|
||||
|
||||
self.__implants = HandledImplantBoosterList()
|
||||
self.apiKey = None
|
||||
|
||||
@reconstructor
|
||||
def init(self):
|
||||
@@ -119,12 +118,9 @@ class Character(object):
|
||||
|
||||
return all0
|
||||
|
||||
def apiUpdateCharSheet(self, skills, secStatus=0):
|
||||
def clearSkills(self):
|
||||
del self.__skills[:]
|
||||
self.__skillIdMap.clear()
|
||||
for skillRow in skills:
|
||||
self.addSkill(Skill(self, skillRow["typeID"], skillRow["level"]))
|
||||
self.secStatus = secStatus
|
||||
|
||||
@property
|
||||
def ro(self):
|
||||
@@ -166,6 +162,17 @@ class Character(object):
|
||||
def name(self, name):
|
||||
self.savedName = name
|
||||
|
||||
def setSsoCharacter(self, character, clientHash):
|
||||
if character is not None:
|
||||
self.__ssoCharacters.append(character)
|
||||
else:
|
||||
for x in self.__ssoCharacters:
|
||||
if x.client == clientHash:
|
||||
self.__ssoCharacters.remove(x)
|
||||
|
||||
def getSsoCharacter(self, clientHash):
|
||||
return next((x for x in self.__ssoCharacters if x.client == clientHash), None)
|
||||
|
||||
@property
|
||||
def alphaCloneID(self):
|
||||
return self.__alphaCloneID
|
||||
@@ -265,20 +272,17 @@ class Character(object):
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
copy = Character("%s copy" % self.name, initSkills=False)
|
||||
copy.apiKey = self.apiKey
|
||||
copy.apiID = self.apiID
|
||||
|
||||
for skill in self.skills:
|
||||
copy.addSkill(Skill(copy, skill.itemID, skill.level, False, skill.learned))
|
||||
|
||||
return copy
|
||||
|
||||
@validates("ID", "name", "apiKey", "ownerID")
|
||||
@validates("ID", "name", "ownerID")
|
||||
def validator(self, key, val):
|
||||
map = {
|
||||
"ID" : lambda _val: isinstance(_val, int),
|
||||
"name" : lambda _val: True,
|
||||
"apiKey" : lambda _val: _val is None or (isinstance(_val, str) and len(_val) > 0),
|
||||
"ownerID": lambda _val: isinstance(_val, int) or _val is None
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,16 @@
|
||||
# ===============================================================================
|
||||
|
||||
import re
|
||||
import eos.db
|
||||
|
||||
|
||||
class DamagePattern(object):
|
||||
DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive")
|
||||
|
||||
def __init__(self, emAmount=25, thermalAmount=25, kineticAmount=25, explosiveAmount=25):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.update(*args, **kwargs)
|
||||
|
||||
def update(self, emAmount=25, thermalAmount=25, kineticAmount=25, explosiveAmount=25):
|
||||
self.emAmount = emAmount
|
||||
self.thermalAmount = thermalAmount
|
||||
self.kineticAmount = kineticAmount
|
||||
@@ -74,6 +78,14 @@ class DamagePattern(object):
|
||||
lines = re.split('[\n\r]+', text)
|
||||
patterns = []
|
||||
numPatterns = 0
|
||||
|
||||
# When we import damage profiles, we create new ones and update old ones. To do this, get a list of current
|
||||
# patterns to allow lookup
|
||||
lookup = {}
|
||||
current = eos.db.getDamagePatternList()
|
||||
for pattern in current:
|
||||
lookup[pattern.name] = pattern
|
||||
|
||||
for line in lines:
|
||||
try:
|
||||
if line.strip()[0] == "#": # comments
|
||||
@@ -99,10 +111,18 @@ class DamagePattern(object):
|
||||
continue
|
||||
|
||||
if len(fields) == 4: # Avoid possible blank lines
|
||||
pattern = DamagePattern(**fields)
|
||||
pattern.name = name.strip()
|
||||
if name.strip() in lookup:
|
||||
pattern = lookup[name.strip()]
|
||||
pattern.update(**fields)
|
||||
eos.db.save(pattern)
|
||||
else:
|
||||
pattern = DamagePattern(**fields)
|
||||
pattern.name = name.strip()
|
||||
eos.db.save(pattern)
|
||||
patterns.append(pattern)
|
||||
|
||||
eos.db.commit()
|
||||
|
||||
return patterns, numPatterns
|
||||
|
||||
EXPORT_FORMAT = "DamageProfile = %s,%d,%d,%d,%d\n"
|
||||
|
||||
@@ -1084,7 +1084,7 @@ class Fit(object):
|
||||
|
||||
def calculateSustainableTank(self, effective=True):
|
||||
if self.__sustainableTank is None:
|
||||
if self.capStable:
|
||||
if self.capStable and not self.factorReload:
|
||||
sustainable = {
|
||||
"armorRepair" : self.extraAttributes["armorRepair"],
|
||||
"shieldRepair": self.extraAttributes["shieldRepair"],
|
||||
@@ -1142,16 +1142,38 @@ class Fit(object):
|
||||
usesCap = False
|
||||
except AttributeError:
|
||||
usesCap = False
|
||||
# Modules which do not use cap are not penalized based on cap use
|
||||
if usesCap:
|
||||
cycleTime = mod.getModifiedItemAttr("duration")
|
||||
|
||||
# Normal Repairers
|
||||
if usesCap and not mod.charge:
|
||||
cycleTime = mod.rawCycleTime
|
||||
amount = mod.getModifiedItemAttr(groupAttrMap[mod.item.group.name])
|
||||
sustainable[attr] -= amount / (cycleTime / 1000.0)
|
||||
repairers.append(mod)
|
||||
# Ancillary Armor reps etc
|
||||
elif usesCap and mod.charge:
|
||||
cycleTime = mod.rawCycleTime
|
||||
amount = mod.getModifiedItemAttr(groupAttrMap[mod.item.group.name])
|
||||
if mod.charge.name == "Nanite Repair Paste":
|
||||
multiplier = mod.getModifiedItemAttr("chargedArmorDamageMultiplier") or 1
|
||||
else:
|
||||
multiplier = 1
|
||||
sustainable[attr] -= amount * multiplier / (cycleTime / 1000.0)
|
||||
repairers.append(mod)
|
||||
# Ancillary Shield boosters etc
|
||||
elif not usesCap and mod.item.group.name in ("Ancillary Shield Booster", "Ancillary Remote Shield Booster"):
|
||||
cycleTime = mod.rawCycleTime
|
||||
amount = mod.getModifiedItemAttr(groupAttrMap[mod.item.group.name])
|
||||
if self.factorReload and mod.charge:
|
||||
reloadtime = mod.reloadTime
|
||||
else:
|
||||
reloadtime = 0.0
|
||||
offdutycycle = reloadtime / ((max(mod.numShots, 1) * cycleTime) + reloadtime)
|
||||
sustainable[attr] -= amount * offdutycycle / (cycleTime / 1000.0)
|
||||
|
||||
# Sort repairers by efficiency. We want to use the most efficient repairers first
|
||||
repairers.sort(key=lambda _mod: _mod.getModifiedItemAttr(
|
||||
groupAttrMap[_mod.item.group.name]) / _mod.getModifiedItemAttr("capacitorNeed"), reverse=True)
|
||||
groupAttrMap[_mod.item.group.name]) * (_mod.getModifiedItemAttr(
|
||||
"chargedArmorDamageMultiplier") or 1) / _mod.getModifiedItemAttr("capacitorNeed"), reverse=True)
|
||||
|
||||
# Loop through every module until we're above peak recharge
|
||||
# Most efficient first, as we sorted earlier.
|
||||
@@ -1160,15 +1182,35 @@ class Fit(object):
|
||||
for mod in repairers:
|
||||
if capUsed > totalPeakRecharge:
|
||||
break
|
||||
cycleTime = mod.cycleTime
|
||||
|
||||
if self.factorReload and mod.charge:
|
||||
reloadtime = mod.reloadTime
|
||||
else:
|
||||
reloadtime = 0.0
|
||||
|
||||
cycleTime = mod.rawCycleTime
|
||||
capPerSec = mod.capUse
|
||||
|
||||
if capPerSec is not None and cycleTime is not None:
|
||||
# Check how much this repper can work
|
||||
sustainability = min(1, (totalPeakRecharge - capUsed) / capPerSec)
|
||||
|
||||
# Add the sustainable amount
|
||||
amount = mod.getModifiedItemAttr(groupAttrMap[mod.item.group.name])
|
||||
sustainable[groupStoreMap[mod.item.group.name]] += sustainability * (amount / (cycleTime / 1000.0))
|
||||
# Add the sustainable amount
|
||||
|
||||
if not mod.charge:
|
||||
sustainable[groupStoreMap[mod.item.group.name]] += sustainability * amount / (
|
||||
cycleTime / 1000.0)
|
||||
else:
|
||||
if mod.charge.name == "Nanite Repair Paste":
|
||||
multiplier = mod.getModifiedItemAttr("chargedArmorDamageMultiplier") or 1
|
||||
else:
|
||||
multiplier = 1
|
||||
ondutycycle = (max(mod.numShots, 1) * cycleTime) / (
|
||||
(max(mod.numShots, 1) * cycleTime) + reloadtime)
|
||||
sustainable[groupStoreMap[
|
||||
mod.item.group.name]] += sustainability * amount * ondutycycle * multiplier / (
|
||||
cycleTime / 1000.0)
|
||||
|
||||
capUsed += capPerSec
|
||||
|
||||
sustainable["passiveShield"] = self.calculateShieldRecharge()
|
||||
@@ -1186,7 +1228,7 @@ class Fit(object):
|
||||
rechargeRate = self.ship.getModifiedItemAttr("shieldRechargeRate") / 1000.0
|
||||
return 10 / rechargeRate * sqrt(percent) * (1 - sqrt(percent)) * capacity
|
||||
|
||||
def addDrain(self, src, cycleTime, capNeed, clipSize=0):
|
||||
def addDrain(self, src, cycleTime, capNeed, clipSize=0, reloadTime=0):
|
||||
""" Used for both cap drains and cap fills (fills have negative capNeed) """
|
||||
|
||||
energyNeutralizerSignatureResolution = src.getModifiedItemAttr("energyNeutralizerSignatureResolution")
|
||||
@@ -1196,7 +1238,7 @@ class Fit(object):
|
||||
if energyNeutralizerSignatureResolution:
|
||||
capNeed = capNeed * min(1, signatureRadius / energyNeutralizerSignatureResolution)
|
||||
|
||||
self.__extraDrains.append((cycleTime, capNeed, clipSize))
|
||||
self.__extraDrains.append((cycleTime, capNeed, clipSize, reloadTime))
|
||||
|
||||
def removeDrain(self, i):
|
||||
del self.__extraDrains[i]
|
||||
@@ -1214,6 +1256,7 @@ class Fit(object):
|
||||
cycleTime = mod.rawCycleTime or 0
|
||||
reactivationTime = mod.getModifiedItemAttr("moduleReactivationDelay") or 0
|
||||
fullCycleTime = cycleTime + reactivationTime
|
||||
reloadTime = mod.reloadTime
|
||||
if fullCycleTime > 0:
|
||||
capNeed = mod.capUse
|
||||
if capNeed > 0:
|
||||
@@ -1225,11 +1268,11 @@ class Fit(object):
|
||||
disableStagger = mod.hardpoint == Hardpoint.TURRET
|
||||
|
||||
drains.append((int(fullCycleTime), mod.getModifiedItemAttr("capacitorNeed") or 0,
|
||||
mod.numShots or 0, disableStagger))
|
||||
mod.numShots or 0, disableStagger, reloadTime))
|
||||
|
||||
for fullCycleTime, capNeed, clipSize in self.iterDrains():
|
||||
for fullCycleTime, capNeed, clipSize, reloadTime in self.iterDrains():
|
||||
# Stagger incoming effects for cap simulation
|
||||
drains.append((int(fullCycleTime), capNeed, clipSize, False))
|
||||
drains.append((int(fullCycleTime), capNeed, clipSize, False, reloadTime))
|
||||
if capNeed > 0:
|
||||
capUsed += capNeed / (fullCycleTime / 1000.0)
|
||||
else:
|
||||
|
||||
@@ -182,7 +182,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
@property
|
||||
def numShots(self):
|
||||
if self.charge is None:
|
||||
return -1
|
||||
return 0
|
||||
if self.__chargeCycles is None and self.charge:
|
||||
numCharges = self.numCharges
|
||||
# Usual ammo like projectiles and missiles
|
||||
@@ -337,8 +337,15 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
volley *= self.getModifiedItemAttr("damageMultiplier") or 1
|
||||
if volley:
|
||||
cycleTime = self.cycleTime
|
||||
# Some weapons repeat multiple times in one cycle (think doomsdays)
|
||||
# Get the number of times it fires off
|
||||
weaponDoT = max(
|
||||
self.getModifiedItemAttr("doomsdayDamageDuration", 1) / self.getModifiedItemAttr("doomsdayDamageCycleTime", 1),
|
||||
1
|
||||
)
|
||||
|
||||
self.__volley = volley
|
||||
self.__dps = volley / (cycleTime / 1000.0)
|
||||
self.__dps = (volley * weaponDoT) / (cycleTime / 1000.0)
|
||||
|
||||
return self.__dps, self.__volley
|
||||
|
||||
@@ -710,7 +717,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
|
||||
# Module can only fire one shot at a time, think bomb launchers or defender launchers
|
||||
if self.disallowRepeatingAction:
|
||||
if numShots > 1:
|
||||
if numShots > 0:
|
||||
"""
|
||||
The actual mechanics behind this is complex. Behavior will be (for 3 ammo):
|
||||
fire, reactivation delay, fire, reactivation delay, fire, max(reactivation delay, reload)
|
||||
@@ -720,12 +727,13 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
|
||||
Currently would apply to bomb launchers and defender missiles
|
||||
"""
|
||||
effective_reload_time = ((self.reactivationDelay * (numShots - 1)) + max(raw_reload_time, self.reactivationDelay, 0)) / numShots
|
||||
effective_reload_time = ((self.reactivationDelay * (numShots - 1)) + max(raw_reload_time, self.reactivationDelay, 0))
|
||||
else:
|
||||
"""
|
||||
Applies to MJD/MJFG
|
||||
"""
|
||||
effective_reload_time = max(raw_reload_time, self.reactivationDelay, 0)
|
||||
speed = speed + effective_reload_time
|
||||
else:
|
||||
"""
|
||||
Currently no other modules would have a reactivation delay, so for sanities sake don't try and account for it.
|
||||
@@ -752,7 +760,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
|
||||
@property
|
||||
def disallowRepeatingAction(self):
|
||||
return self.getModifiedItemAttr("disallowRepeatingAction", 0)
|
||||
return self.getModifiedItemAttr("disallowRepeatingActivation", 0)
|
||||
|
||||
@property
|
||||
def reactivationDelay(self):
|
||||
|
||||
@@ -18,17 +18,31 @@
|
||||
# ===============================================================================
|
||||
|
||||
from sqlalchemy.orm import reconstructor
|
||||
|
||||
import datetime
|
||||
import time
|
||||
|
||||
# from tomorrow import threads
|
||||
|
||||
|
||||
class CrestChar(object):
|
||||
def __init__(self, id, name, refresh_token=None):
|
||||
self.ID = id
|
||||
self.name = name
|
||||
self.refresh_token = refresh_token
|
||||
class SsoCharacter(object):
|
||||
def __init__(self, charID, name, client, accessToken=None, refreshToken=None):
|
||||
self.characterID = charID
|
||||
self.characterName = name
|
||||
self.client = client
|
||||
self.accessToken = accessToken
|
||||
self.refreshToken = refreshToken
|
||||
self.accessTokenExpires = None
|
||||
|
||||
@reconstructor
|
||||
def init(self):
|
||||
pass
|
||||
|
||||
def is_token_expired(self):
|
||||
if self.accessTokenExpires is None:
|
||||
return True
|
||||
return datetime.datetime.now() >= self.accessTokenExpires
|
||||
|
||||
def __repr__(self):
|
||||
return "SsoCharacter(ID={}, name={}, client={}) at {}".format(
|
||||
self.ID, self.characterName, self.client, hex(id(self))
|
||||
)
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
import re
|
||||
from logbook import Logger
|
||||
import eos.db
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
@@ -27,7 +28,10 @@ class TargetResists(object):
|
||||
# also determined import/export order - VERY IMPORTANT
|
||||
DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive")
|
||||
|
||||
def __init__(self, emAmount=0, thermalAmount=0, kineticAmount=0, explosiveAmount=0):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.update(*args, **kwargs)
|
||||
|
||||
def update(self, emAmount=0, thermalAmount=0, kineticAmount=0, explosiveAmount=0):
|
||||
self.emAmount = emAmount
|
||||
self.thermalAmount = thermalAmount
|
||||
self.kineticAmount = kineticAmount
|
||||
@@ -38,6 +42,14 @@ class TargetResists(object):
|
||||
lines = re.split('[\n\r]+', text)
|
||||
patterns = []
|
||||
numPatterns = 0
|
||||
|
||||
# When we import damage profiles, we create new ones and update old ones. To do this, get a list of current
|
||||
# patterns to allow lookup
|
||||
lookup = {}
|
||||
current = eos.db.getTargetResistsList()
|
||||
for pattern in current:
|
||||
lookup[pattern.name] = pattern
|
||||
|
||||
for line in lines:
|
||||
try:
|
||||
if line.strip()[0] == "#": # comments
|
||||
@@ -66,10 +78,18 @@ class TargetResists(object):
|
||||
continue
|
||||
|
||||
if len(fields) == 4: # Avoid possible blank lines
|
||||
pattern = TargetResists(**fields)
|
||||
pattern.name = name.strip()
|
||||
if name.strip() in lookup:
|
||||
pattern = lookup[name.strip()]
|
||||
pattern.update(**fields)
|
||||
eos.db.save(pattern)
|
||||
else:
|
||||
pattern = TargetResists(**fields)
|
||||
pattern.name = name.strip()
|
||||
eos.db.save(pattern)
|
||||
patterns.append(pattern)
|
||||
|
||||
eos.db.commit()
|
||||
|
||||
return patterns, numPatterns
|
||||
|
||||
EXPORT_FORMAT = "TargetResists = %s,%.1f,%.1f,%.1f,%.1f\n"
|
||||
|
||||
@@ -135,7 +135,7 @@ class CargoView(d.Display):
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(event.fitID)
|
||||
|
||||
self.Parent.Parent.DisablePage(self, not fit or fit.isStructure)
|
||||
# self.Parent.Parent.DisablePage(self, not fit or fit.isStructure)
|
||||
|
||||
# Clear list and get out if current fitId is None
|
||||
if event.fitID is None and self.lastFitId is not None:
|
||||
|
||||
@@ -99,15 +99,22 @@ class ProjectedView(d.Display):
|
||||
data[0] is hard-coded str of originating source
|
||||
data[1] is typeID or index of data we want to manipulate
|
||||
"""
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(self.mainFrame.getActiveFit())
|
||||
|
||||
if data[0] == "projected":
|
||||
# if source is coming from projected, we are trying to combine drones.
|
||||
self.mergeDrones(x, y, int(data[1]))
|
||||
elif data[0] == "fitting":
|
||||
dstRow, _ = self.HitTest((x, y))
|
||||
# Gather module information to get position
|
||||
module = fit.modules[int(data[1])]
|
||||
sFit.project(fit.ID, module.item.ID)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fit.ID))
|
||||
elif data[0] == "market":
|
||||
sFit = Fit.getInstance()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
sFit.project(fitID, int(data[1]))
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit()))
|
||||
sFit.project(fit.ID, int(data[1]))
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fit.ID))
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
|
||||
@@ -26,57 +26,71 @@ class ChangeAmount(ContextMenu):
|
||||
return u"Change {0} Quantity".format(itmContext)
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
srcContext = fullContext[0]
|
||||
dlg = AmountChanger(self.mainFrame, selection[0], srcContext)
|
||||
dlg.ShowModal()
|
||||
thing = selection[0]
|
||||
mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
fitID = mainFrame.getActiveFit()
|
||||
|
||||
if isinstance(thing, es_Fit):
|
||||
value = thing.getProjectionInfo(fitID).amount
|
||||
else:
|
||||
value = thing.amount
|
||||
|
||||
dlg = AmountChanger(self.mainFrame, value)
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
|
||||
if dlg.input.GetLineText(0).strip() == '':
|
||||
return
|
||||
|
||||
sFit = Fit.getInstance()
|
||||
cleanInput = re.sub(r'[^0-9.]', '', dlg.input.GetLineText(0).strip())
|
||||
|
||||
if isinstance(thing, es_Cargo):
|
||||
sFit.addCargo(fitID, thing.item.ID, int(float(cleanInput)), replace=True)
|
||||
elif isinstance(thing, es_Fit):
|
||||
sFit.changeAmount(fitID, thing, int(float(cleanInput)))
|
||||
elif isinstance(thing, es_Fighter):
|
||||
sFit.changeActiveFighters(fitID, thing, int(float(cleanInput)))
|
||||
|
||||
wx.PostEvent(mainFrame, GE.FitChanged(fitID=fitID))
|
||||
|
||||
|
||||
ChangeAmount.register()
|
||||
|
||||
|
||||
class AmountChanger(wx.Dialog):
|
||||
def __init__(self, parent, thing, context):
|
||||
wx.Dialog.__init__(self, parent, title="Select Amount", size=wx.Size(220, 60))
|
||||
self.thing = thing
|
||||
self.context = context
|
||||
def __init__(self, parent, value):
|
||||
wx.Dialog.__init__(self, parent, title="Change Amount")
|
||||
self.SetMinSize((346, 156))
|
||||
|
||||
bSizer1 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
bSizer1 = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
bSizer2 = wx.BoxSizer(wx.VERTICAL)
|
||||
text = wx.StaticText(self, wx.ID_ANY, "New Amount:")
|
||||
bSizer2.Add(text, 0)
|
||||
|
||||
bSizer1.Add(bSizer2, 0, wx.ALL, 10)
|
||||
|
||||
self.input = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_PROCESS_ENTER)
|
||||
self.input.SetValue(str(value))
|
||||
self.input.SelectAll()
|
||||
|
||||
bSizer1.Add(self.input, 1, wx.ALL, 5)
|
||||
bSizer1.Add(self.input, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 15)
|
||||
|
||||
bSizer3 = wx.BoxSizer(wx.VERTICAL)
|
||||
bSizer3.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.BOTTOM | wx.EXPAND, 15)
|
||||
|
||||
bSizer3.Add(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL), 0, wx.EXPAND)
|
||||
bSizer1.Add(bSizer3, 0, wx.ALL | wx.EXPAND, 10)
|
||||
|
||||
self.input.SetFocus()
|
||||
self.input.Bind(wx.EVT_CHAR, self.onChar)
|
||||
self.input.Bind(wx.EVT_TEXT_ENTER, self.change)
|
||||
self.button = wx.Button(self, wx.ID_OK, "Done")
|
||||
bSizer1.Add(self.button, 0, wx.ALL, 5)
|
||||
|
||||
self.input.Bind(wx.EVT_TEXT_ENTER, self.processEnter)
|
||||
self.SetSizer(bSizer1)
|
||||
self.Layout()
|
||||
self.Centre(wx.BOTH)
|
||||
self.button.Bind(wx.EVT_BUTTON, self.change)
|
||||
self.CenterOnParent()
|
||||
self.Fit()
|
||||
|
||||
def change(self, event):
|
||||
if self.input.GetLineText(0).strip() == '':
|
||||
event.Skip()
|
||||
self.Close()
|
||||
return
|
||||
|
||||
sFit = Fit.getInstance()
|
||||
cleanInput = re.sub(r'[^0-9.]', '', self.input.GetLineText(0).strip())
|
||||
mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
fitID = mainFrame.getActiveFit()
|
||||
|
||||
if isinstance(self.thing, es_Cargo):
|
||||
sFit.addCargo(fitID, self.thing.item.ID, int(float(cleanInput)), replace=True)
|
||||
elif isinstance(self.thing, es_Fit):
|
||||
sFit.changeAmount(fitID, self.thing, int(float(cleanInput)))
|
||||
elif isinstance(self.thing, es_Fighter):
|
||||
sFit.changeActiveFighters(fitID, self.thing, int(float(cleanInput)))
|
||||
|
||||
wx.PostEvent(mainFrame, GE.FitChanged(fitID=fitID))
|
||||
|
||||
event.Skip()
|
||||
self.Close()
|
||||
def processEnter(self, evt):
|
||||
self.EndModal(wx.ID_OK)
|
||||
|
||||
# checks to make sure it's valid number
|
||||
@staticmethod
|
||||
|
||||
@@ -31,9 +31,7 @@ class FactorReload(ContextMenu):
|
||||
|
||||
def getBitmap(self, context, selection):
|
||||
sFit = Fit.getInstance()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = sFit.getFit(fitID)
|
||||
if fit.factorReload:
|
||||
if sFit.serviceFittingOptions["useGlobalForceReload"]:
|
||||
return BitmapLoader.getBitmap("state_active_small", "gui")
|
||||
else:
|
||||
return None
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
import csv
|
||||
import config
|
||||
|
||||
@@ -203,7 +202,7 @@ class ItemParams(wx.Panel):
|
||||
else:
|
||||
attrIcon = self.imageList.Add(BitmapLoader.getBitmap("7_15", "icons"))
|
||||
|
||||
index = self.paramList.InsertItem(sys.maxsize, attrName, attrIcon)
|
||||
index = self.paramList.InsertItem(self.paramList.GetItemCount(), attrName, attrIcon)
|
||||
idNameMap[idCount] = attrName
|
||||
self.paramList.SetItemData(index, idCount)
|
||||
idCount += 1
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import sys
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
@@ -147,7 +145,7 @@ class ItemCompare(wx.Panel):
|
||||
self.paramList.SetColumnWidth(len(self.attrs) + 1, 60)
|
||||
|
||||
for item in self.items:
|
||||
i = self.paramList.InsertItem(sys.maxsize, item.name)
|
||||
i = self.paramList.InsertItem(self.paramList.GetItemCount(), item.name)
|
||||
for x, attr in enumerate(self.attrs.keys()):
|
||||
if attr in item.attributes:
|
||||
info = self.attrs[attr]
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import config
|
||||
@@ -51,7 +50,7 @@ class ItemEffects(wx.Panel):
|
||||
names.sort()
|
||||
|
||||
for name in names:
|
||||
index = self.effectList.InsertItem(sys.maxsize, name)
|
||||
index = self.effectList.InsertItem(self.effectList.GetItemCount(), name)
|
||||
|
||||
if effects[name].isImplemented:
|
||||
if effects[name].activeByDefault:
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import sys
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
@@ -79,7 +77,7 @@ class ItemProperties(wx.Panel):
|
||||
attrName = name.title()
|
||||
value = getattr(self.item, name)
|
||||
|
||||
index = self.paramList.InsertItem(sys.maxsize, attrName)
|
||||
index = self.paramList.InsertItem(self.paramList.GetItemCount(), attrName)
|
||||
# index = self.paramList.InsertImageStringItem(sys.maxint, attrName)
|
||||
idNameMap[idCount] = attrName
|
||||
self.paramList.SetItemData(index, idCount)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import wx
|
||||
|
||||
import config
|
||||
import gui.builtinMarketBrowser.pfSearchBox as SBox
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.display import Display
|
||||
@@ -170,10 +171,6 @@ class ItemView(Display):
|
||||
if len(realsearch) == 0:
|
||||
self.selectionMade()
|
||||
return
|
||||
# Show nothing if query is too short
|
||||
elif len(realsearch) < 3:
|
||||
self.clearSearch()
|
||||
return
|
||||
|
||||
self.marketBrowser.searchMode = True
|
||||
self.sMkt.searchItems(search, self.populateSearch)
|
||||
|
||||
@@ -6,7 +6,6 @@ __all__ = [
|
||||
"pyfaDatabasePreferences",
|
||||
"pyfaLoggingPreferences",
|
||||
"pyfaEnginePreferences",
|
||||
"pyfaStatViewPreferences",
|
||||
"pyfaCrestPreferences"
|
||||
]
|
||||
"pyfaEsiPreferences",
|
||||
"pyfaStatViewPreferences"]
|
||||
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
from gui.preferenceView import PreferenceView
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
|
||||
import gui.mainFrame
|
||||
|
||||
from service.settings import CRESTSettings
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
from wx.lib.intctrl import IntCtrl
|
||||
|
||||
from service.crest import Crest
|
||||
|
||||
|
||||
class PFCrestPref(PreferenceView):
|
||||
title = "CREST"
|
||||
|
||||
def populatePanel(self, panel):
|
||||
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = CRESTSettings.getInstance()
|
||||
self.dirtySettings = False
|
||||
dlgWidth = panel.GetParent().GetParent().ClientSize.width
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.stTitle = wx.StaticText(panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stTitle.Wrap(-1)
|
||||
self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString))
|
||||
|
||||
mainSizer.Add(self.stTitle, 0, wx.ALL, 5)
|
||||
|
||||
self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
|
||||
mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
|
||||
|
||||
self.stInfo = wx.StaticText(panel, wx.ID_ANY,
|
||||
"Please see the pyfa wiki on GitHub for information regarding these options.",
|
||||
wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stInfo.Wrap(dlgWidth - 50)
|
||||
mainSizer.Add(self.stInfo, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
|
||||
|
||||
rbSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
self.rbMode = wx.RadioBox(panel, -1, "Mode", wx.DefaultPosition, wx.DefaultSize,
|
||||
['Implicit', 'User-supplied details'], 1, wx.RA_SPECIFY_COLS)
|
||||
self.rbServer = wx.RadioBox(panel, -1, "Server", wx.DefaultPosition, wx.DefaultSize,
|
||||
['Tranquility', 'Singularity'], 1, wx.RA_SPECIFY_COLS)
|
||||
|
||||
self.rbMode.SetSelection(self.settings.get('mode'))
|
||||
self.rbServer.SetSelection(self.settings.get('server'))
|
||||
|
||||
rbSizer.Add(self.rbMode, 1, wx.TOP | wx.RIGHT, 5)
|
||||
rbSizer.Add(self.rbServer, 1, wx.ALL, 5)
|
||||
|
||||
self.rbMode.Bind(wx.EVT_RADIOBOX, self.OnModeChange)
|
||||
self.rbServer.Bind(wx.EVT_RADIOBOX, self.OnServerChange)
|
||||
|
||||
mainSizer.Add(rbSizer, 1, wx.ALL | wx.EXPAND, 0)
|
||||
|
||||
timeoutSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.stTimout = wx.StaticText(panel, wx.ID_ANY, "Timeout (seconds):", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stTimout.Wrap(-1)
|
||||
|
||||
timeoutSizer.Add(self.stTimout, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.intTimeout = IntCtrl(panel, max=300000, limited=True, value=self.settings.get('timeout'))
|
||||
timeoutSizer.Add(self.intTimeout, 0, wx.ALL, 5)
|
||||
self.intTimeout.Bind(wx.lib.intctrl.EVT_INT, self.OnTimeoutChange)
|
||||
|
||||
mainSizer.Add(timeoutSizer, 0, wx.ALL | wx.EXPAND, 0)
|
||||
|
||||
detailsTitle = wx.StaticText(panel, wx.ID_ANY, "CREST client details", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
detailsTitle.Wrap(-1)
|
||||
detailsTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString))
|
||||
|
||||
mainSizer.Add(detailsTitle, 0, wx.ALL, 5)
|
||||
mainSizer.Add(wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0,
|
||||
wx.EXPAND, 5)
|
||||
|
||||
fgAddrSizer = wx.FlexGridSizer(2, 2, 0, 0)
|
||||
fgAddrSizer.AddGrowableCol(1)
|
||||
fgAddrSizer.SetFlexibleDirection(wx.BOTH)
|
||||
fgAddrSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
|
||||
|
||||
self.stSetID = wx.StaticText(panel, wx.ID_ANY, "Client ID:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stSetID.Wrap(-1)
|
||||
fgAddrSizer.Add(self.stSetID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.inputClientID = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientID'), wx.DefaultPosition,
|
||||
wx.DefaultSize, 0)
|
||||
|
||||
fgAddrSizer.Add(self.inputClientID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
|
||||
|
||||
self.stSetSecret = wx.StaticText(panel, wx.ID_ANY, "Client Secret:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stSetSecret.Wrap(-1)
|
||||
|
||||
fgAddrSizer.Add(self.stSetSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.inputClientSecret = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientSecret'), wx.DefaultPosition,
|
||||
wx.DefaultSize, 0)
|
||||
|
||||
fgAddrSizer.Add(self.inputClientSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
|
||||
|
||||
self.btnApply = wx.Button(panel, wx.ID_ANY, "Save Client Settings", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.btnApply.Bind(wx.EVT_BUTTON, self.OnBtnApply)
|
||||
|
||||
mainSizer.Add(fgAddrSizer, 0, wx.EXPAND, 5)
|
||||
mainSizer.Add(self.btnApply, 0, wx.ALIGN_RIGHT, 5)
|
||||
|
||||
self.ToggleProxySettings(self.settings.get('mode'))
|
||||
|
||||
panel.SetSizer(mainSizer)
|
||||
panel.Layout()
|
||||
|
||||
def OnTimeoutChange(self, event):
|
||||
self.settings.set('timeout', event.GetEventObject().GetValue())
|
||||
|
||||
def OnModeChange(self, event):
|
||||
self.settings.set('mode', event.GetInt())
|
||||
self.ToggleProxySettings(self.settings.get('mode'))
|
||||
Crest.restartService()
|
||||
|
||||
def OnServerChange(self, event):
|
||||
self.settings.set('server', event.GetInt())
|
||||
Crest.restartService()
|
||||
|
||||
def OnBtnApply(self, event):
|
||||
self.settings.set('clientID', self.inputClientID.GetValue().strip())
|
||||
self.settings.set('clientSecret', self.inputClientSecret.GetValue().strip())
|
||||
sCrest = Crest.getInstance()
|
||||
sCrest.delAllCharacters()
|
||||
|
||||
def ToggleProxySettings(self, mode):
|
||||
if mode:
|
||||
self.stSetID.Enable()
|
||||
self.inputClientID.Enable()
|
||||
self.stSetSecret.Enable()
|
||||
self.inputClientSecret.Enable()
|
||||
else:
|
||||
self.stSetID.Disable()
|
||||
self.inputClientID.Disable()
|
||||
self.stSetSecret.Disable()
|
||||
self.inputClientSecret.Disable()
|
||||
|
||||
def getImage(self):
|
||||
return BitmapLoader.getBitmap("eve", "gui")
|
||||
|
||||
|
||||
PFCrestPref.register()
|
||||
197
gui/builtinPreferenceViews/pyfaEsiPreferences.py
Normal file
197
gui/builtinPreferenceViews/pyfaEsiPreferences.py
Normal file
@@ -0,0 +1,197 @@
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
from gui.preferenceView import PreferenceView
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
|
||||
import gui.mainFrame
|
||||
|
||||
from service.settings import EsiSettings
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
from wx.lib.intctrl import IntCtrl
|
||||
|
||||
from service.esi import Esi
|
||||
|
||||
|
||||
class PFEsiPref(PreferenceView):
|
||||
title = "EVE SSO"
|
||||
|
||||
def populatePanel(self, panel):
|
||||
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = EsiSettings.getInstance()
|
||||
self.dirtySettings = False
|
||||
dlgWidth = panel.GetParent().GetParent().ClientSize.width
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.stTitle = wx.StaticText(panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stTitle.Wrap(-1)
|
||||
self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString))
|
||||
|
||||
mainSizer.Add(self.stTitle, 0, wx.ALL, 5)
|
||||
|
||||
self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
|
||||
mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
|
||||
|
||||
self.stInfo = wx.StaticText(panel, wx.ID_ANY,
|
||||
"Please see the pyfa wiki on GitHub for information regarding these options.",
|
||||
wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stInfo.Wrap(dlgWidth - 50)
|
||||
mainSizer.Add(self.stInfo, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
|
||||
|
||||
rbSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
self.rbMode = wx.RadioBox(panel, -1, "Login Authentication Method", wx.DefaultPosition, wx.DefaultSize,
|
||||
['Local Server', 'Manual'], 1, wx.RA_SPECIFY_COLS)
|
||||
self.rbMode.SetItemToolTip(0, "This options starts a local webserver that the web application will call back to"
|
||||
" with information about the character login.")
|
||||
self.rbMode.SetItemToolTip(1, "This option prompts users to copy and paste information from the web application "
|
||||
"to allow for character login. Use this if having issues with the local server.")
|
||||
|
||||
self.rbSsoMode = wx.RadioBox(panel, -1, "SSO Mode", wx.DefaultPosition, wx.DefaultSize,
|
||||
['pyfa.io', 'Custom application'], 1, wx.RA_SPECIFY_COLS)
|
||||
self.rbSsoMode.SetItemToolTip(0, "This options routes SSO Logins through pyfa.io, allowing you to easily login "
|
||||
"without any configuration. When in doubt, use this option.")
|
||||
self.rbSsoMode.SetItemToolTip(1, "This option goes through EVE SSO directly, but requires more configuration. Use "
|
||||
"this is pyfa.io is blocked for some reason, or if you do not wish to route data throguh pyfa.io.")
|
||||
|
||||
self.rbMode.SetSelection(self.settings.get('loginMode'))
|
||||
self.rbSsoMode.SetSelection(self.settings.get('ssoMode'))
|
||||
|
||||
rbSizer.Add(self.rbSsoMode, 1, wx.ALL, 5)
|
||||
rbSizer.Add(self.rbMode, 1, wx.TOP | wx.RIGHT, 5)
|
||||
|
||||
self.rbMode.Bind(wx.EVT_RADIOBOX, self.OnModeChange)
|
||||
self.rbSsoMode.Bind(wx.EVT_RADIOBOX, self.OnSSOChange)
|
||||
|
||||
mainSizer.Add(rbSizer, 1, wx.ALL | wx.EXPAND, 0)
|
||||
|
||||
detailsTitle = wx.StaticText(panel, wx.ID_ANY, "Custom Application", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
detailsTitle.Wrap(-1)
|
||||
detailsTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString))
|
||||
|
||||
mainSizer.Add(detailsTitle, 0, wx.ALL, 5)
|
||||
mainSizer.Add(wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0,
|
||||
wx.EXPAND, 5)
|
||||
|
||||
fgAddrSizer = wx.FlexGridSizer(2, 2, 0, 0)
|
||||
fgAddrSizer.AddGrowableCol(1)
|
||||
fgAddrSizer.SetFlexibleDirection(wx.BOTH)
|
||||
fgAddrSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
|
||||
|
||||
self.stSetID = wx.StaticText(panel, wx.ID_ANY, u"Client ID:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stSetID.Wrap(-1)
|
||||
fgAddrSizer.Add(self.stSetID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.inputClientID = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientID'), wx.DefaultPosition,
|
||||
wx.DefaultSize, 0)
|
||||
|
||||
fgAddrSizer.Add(self.inputClientID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
|
||||
|
||||
self.stSetSecret = wx.StaticText(panel, wx.ID_ANY, u"Client Secret:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stSetSecret.Wrap(-1)
|
||||
|
||||
fgAddrSizer.Add(self.stSetSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.inputClientSecret = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientSecret'), wx.DefaultPosition,
|
||||
wx.DefaultSize, 0)
|
||||
|
||||
fgAddrSizer.Add(self.inputClientSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
|
||||
|
||||
self.inputClientID.Bind(wx.EVT_TEXT, self.OnClientDetailChange)
|
||||
self.inputClientSecret.Bind(wx.EVT_TEXT, self.OnClientDetailChange)
|
||||
|
||||
mainSizer.Add(fgAddrSizer, 0, wx.EXPAND, 5)
|
||||
|
||||
# self.stTimout = wx.StaticText(panel, wx.ID_ANY, "Timeout (seconds):", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
# self.stTimout.Wrap(-1)
|
||||
#
|
||||
# timeoutSizer.Add(self.stTimout, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
# self.intTimeout = IntCtrl(panel, max=300000, limited=True, value=self.settings.get('timeout'))
|
||||
# timeoutSizer.Add(self.intTimeout, 0, wx.ALL, 5)
|
||||
# self.intTimeout.Bind(wx.lib.intctrl.EVT_INT, self.OnTimeoutChange)
|
||||
#
|
||||
# mainSizer.Add(timeoutSizer, 0, wx.ALL | wx.EXPAND, 0)
|
||||
|
||||
# detailsTitle = wx.StaticText(panel, wx.ID_ANY, "CREST client details", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
# detailsTitle.Wrap(-1)
|
||||
# detailsTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString))
|
||||
#
|
||||
# mainSizer.Add(detailsTitle, 0, wx.ALL, 5)
|
||||
# mainSizer.Add(wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0,
|
||||
# wx.EXPAND, 5)
|
||||
|
||||
# fgAddrSizer = wx.FlexGridSizer(2, 2, 0, 0)
|
||||
# fgAddrSizer.AddGrowableCol(1)
|
||||
# fgAddrSizer.SetFlexibleDirection(wx.BOTH)
|
||||
# fgAddrSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
|
||||
#
|
||||
# self.stSetID = wx.StaticText(panel, wx.ID_ANY, "Client ID:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
# self.stSetID.Wrap(-1)
|
||||
# fgAddrSizer.Add(self.stSetID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
#
|
||||
# self.inputClientID = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientID'), wx.DefaultPosition,
|
||||
# wx.DefaultSize, 0)
|
||||
#
|
||||
# fgAddrSizer.Add(self.inputClientID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
|
||||
#
|
||||
# self.stSetSecret = wx.StaticText(panel, wx.ID_ANY, "Client Secret:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
# self.stSetSecret.Wrap(-1)
|
||||
#
|
||||
# fgAddrSizer.Add(self.stSetSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
#
|
||||
# self.inputClientSecret = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientSecret'), wx.DefaultPosition,
|
||||
# wx.DefaultSize, 0)
|
||||
#
|
||||
# fgAddrSizer.Add(self.inputClientSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
|
||||
#
|
||||
# self.btnApply = wx.Button(panel, wx.ID_ANY, "Save Client Settings", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
# self.btnApply.Bind(wx.EVT_BUTTON, self.OnBtnApply)
|
||||
#
|
||||
# mainSizer.Add(fgAddrSizer, 0, wx.EXPAND, 5)
|
||||
# mainSizer.Add(self.btnApply, 0, wx.ALIGN_RIGHT, 5)
|
||||
|
||||
# self.ToggleProxySettings(self.settings.get('loginMode'))
|
||||
|
||||
self.ToggleSSOMode(self.settings.get('ssoMode'))
|
||||
panel.SetSizer(mainSizer)
|
||||
panel.Layout()
|
||||
|
||||
def OnTimeoutChange(self, event):
|
||||
self.settings.set('timeout', event.GetEventObject().GetValue())
|
||||
|
||||
def OnModeChange(self, event):
|
||||
self.settings.set('loginMode', event.GetInt())
|
||||
|
||||
def OnSSOChange(self, event):
|
||||
self.settings.set('ssoMode', event.GetInt())
|
||||
self.ToggleSSOMode(event.GetInt())
|
||||
|
||||
def ToggleSSOMode(self, mode):
|
||||
if mode:
|
||||
self.stSetID.Enable()
|
||||
self.inputClientID.Enable()
|
||||
self.stSetSecret.Enable()
|
||||
self.inputClientSecret.Enable()
|
||||
self.rbMode.Disable()
|
||||
else:
|
||||
self.stSetID.Disable()
|
||||
self.inputClientID.Disable()
|
||||
self.stSetSecret.Disable()
|
||||
self.inputClientSecret.Disable()
|
||||
self.rbMode.Enable()
|
||||
|
||||
def OnClientDetailChange(self, evt):
|
||||
self.settings.set('clientID', self.inputClientID.GetValue().strip())
|
||||
self.settings.set('clientSecret', self.inputClientSecret.GetValue().strip())
|
||||
|
||||
# sEsi = Esi.getInstance()
|
||||
# sEsi.delAllCharacters()
|
||||
#
|
||||
|
||||
def getImage(self):
|
||||
return BitmapLoader.getBitmap("eve", "gui")
|
||||
|
||||
|
||||
PFEsiPref.register()
|
||||
@@ -42,6 +42,15 @@ class PFGeneralPref(PreferenceView):
|
||||
self.inputLogPath.SetBackgroundColour((200, 200, 200))
|
||||
mainSizer.Add(self.inputLogPath, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
|
||||
|
||||
import requests
|
||||
self.certPath = wx.StaticText(panel, wx.ID_ANY, "Cert Path:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.certPath .Wrap(-1)
|
||||
mainSizer.Add(self.certPath, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
self.certPathCtrl = wx.TextCtrl(panel, wx.ID_ANY, requests.certs.where(), wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.certPathCtrl.SetEditable(False)
|
||||
self.certPathCtrl.SetBackgroundColour((200, 200, 200))
|
||||
mainSizer.Add(self.certPathCtrl, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
|
||||
|
||||
# Debug Logging
|
||||
self.cbdebugLogging = wx.CheckBox(panel, wx.ID_ANY, "Debug Logging Enabled", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
mainSizer.Add(self.cbdebugLogging, 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
@@ -121,11 +121,11 @@ class PFNetworkPref(PreferenceView):
|
||||
self.stPSetLogin = wx.StaticText(panel, wx.ID_ANY, "Username:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stPSetLogin.Wrap(-1)
|
||||
self.editProxySettingsLogin = wx.TextCtrl(panel, wx.ID_ANY, self.nAuth[0], wx.DefaultPosition, wx.DefaultSize,
|
||||
0)
|
||||
0)
|
||||
self.stPSetPassword = wx.StaticText(panel, wx.ID_ANY, "Password:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stPSetPassword.Wrap(-1)
|
||||
self.editProxySettingsPassword = wx.TextCtrl(panel, wx.ID_ANY, self.nAuth[1], wx.DefaultPosition,
|
||||
wx.DefaultSize, wx.TE_PASSWORD)
|
||||
wx.DefaultSize, wx.TE_PASSWORD)
|
||||
pAuthSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
pAuthSizer.Add(self.stPSetLogin, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
pAuthSizer.Add(self.editProxySettingsLogin, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
@@ -134,7 +134,7 @@ class PFNetworkPref(PreferenceView):
|
||||
mainSizer.Add(pAuthSizer, 0, wx.EXPAND, 5)
|
||||
|
||||
self.stPSAutoDetected = wx.StaticText(panel, wx.ID_ANY, "Auto-detected: ", wx.DefaultPosition, wx.DefaultSize,
|
||||
0)
|
||||
0)
|
||||
self.stPSAutoDetected.Wrap(-1)
|
||||
mainSizer.Add(self.stPSAutoDetected, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
|
||||
@@ -289,6 +289,7 @@ class FitItem(SFItem.SFBrowserItem):
|
||||
def editLostFocus(self, event):
|
||||
self.RestoreEditButton()
|
||||
self.Refresh()
|
||||
event.Skip()
|
||||
|
||||
def editCheckEsc(self, event):
|
||||
if event.GetKeyCode() == wx.WXK_ESCAPE:
|
||||
|
||||
@@ -51,9 +51,13 @@ class PFBitmapFrame(wx.Frame):
|
||||
pass
|
||||
|
||||
def OnWindowPaint(self, event):
|
||||
# todo: evaluate wx.DragImage, might make this class obsolete, however might also lose our customizations
|
||||
# (like the sexy fade-in animation)
|
||||
rect = self.GetRect()
|
||||
canvas = wx.Bitmap(rect.width, rect.height)
|
||||
mdc = wx.AutoBufferedPaintDC(self)
|
||||
# todo: convert to context manager after updating to wxPython >v4.0.1 (4.0.1 has a bug, see #1421)
|
||||
# See #1418 for discussion
|
||||
mdc = wx.BufferedPaintDC(self)
|
||||
mdc.SelectObject(canvas)
|
||||
mdc.DrawBitmap(self.bitmap, 0, 0)
|
||||
mdc.SetPen(wx.Pen("#000000", width=1))
|
||||
|
||||
@@ -129,7 +129,7 @@ class FirepowerViewFull(StatsView):
|
||||
# Remove effective label
|
||||
hsizer = self.headerPanel.GetSizer()
|
||||
hsizer.Hide(self.stEff)
|
||||
#self.stEff.Destroy()
|
||||
# self.stEff.Destroy()
|
||||
|
||||
# Get the new view
|
||||
view = StatsView.getView("miningyieldViewFull")(self.parent)
|
||||
|
||||
@@ -76,6 +76,31 @@ class Miscellanea(ViewColumn):
|
||||
stuff.getModifiedItemAttr("boosterDuration")
|
||||
text = "{0} min".format(formatAmount(stuff.getModifiedItemAttr("boosterDuration") / 1000 / 60, 3, 0, 3))
|
||||
return text, "Booster Duration"
|
||||
elif itemGroup in ("Super Weapon", "Structure Doomsday Weapon"):
|
||||
doomsday_duration = stuff.getModifiedItemAttr("doomsdayDamageDuration", 1)
|
||||
doomsday_dottime = stuff.getModifiedItemAttr("doomsdayDamageCycleTime", 1)
|
||||
func = stuff.getModifiedItemAttr
|
||||
|
||||
volley = sum(
|
||||
map(
|
||||
lambda attr: (func("%sDamage" % attr) or 0),
|
||||
("em", "thermal", "kinetic", "explosive")
|
||||
)
|
||||
)
|
||||
volley *= stuff.getModifiedItemAttr("damageMultiplier") or 1
|
||||
|
||||
if volley <= 0:
|
||||
text = ""
|
||||
tooltip = ""
|
||||
elif max(doomsday_duration / doomsday_dottime, 1) > 1:
|
||||
text = "{0} dmg over {1} s".format(formatAmount(volley * (doomsday_duration / doomsday_dottime), 3, 0, 3), doomsday_duration / 1000)
|
||||
tooltip = "Raw damage done over time"
|
||||
else:
|
||||
text = "{0} dmg".format(formatAmount(volley * (doomsday_duration / doomsday_dottime), 3, 0, 3))
|
||||
tooltip = "Raw damage done"
|
||||
return text, tooltip
|
||||
|
||||
pass
|
||||
elif itemGroup in ("Energy Weapon", "Hybrid Weapon", "Projectile Weapon", "Combat Drone", "Fighter Drone"):
|
||||
trackingSpeed = stuff.getModifiedItemAttr("trackingSpeed")
|
||||
if not trackingSpeed:
|
||||
|
||||
@@ -69,11 +69,12 @@ class FitSpawner(gui.multiSwitch.TabSpawner):
|
||||
pyfalog.critical(e)
|
||||
if count < 0:
|
||||
startup = getattr(event, "startup", False) # see OpenFitsThread in gui.mainFrame
|
||||
from_import = getattr(event, "from_import", False) # always open imported into a new tab
|
||||
sFit = Fit.getInstance()
|
||||
openFitInNew = sFit.serviceFittingOptions["openFitInNew"]
|
||||
mstate = wx.GetMouseState()
|
||||
|
||||
if (not openFitInNew and mstate.CmdDown()) or startup or (openFitInNew and not mstate.CmdDown()):
|
||||
if from_import or (not openFitInNew and mstate.CmdDown()) or startup or (openFitInNew and not mstate.CmdDown()):
|
||||
self.multiSwitch.AddPage()
|
||||
|
||||
view = self.multiSwitch.GetSelectedPage()
|
||||
@@ -87,7 +88,7 @@ class FitSpawner(gui.multiSwitch.TabSpawner):
|
||||
|
||||
def handleDrag(self, type, fitID):
|
||||
if type == "fit":
|
||||
for page in self.multiSwitch.pages:
|
||||
for page in self.multiSwitch._pages:
|
||||
if isinstance(page, FittingView) and page.activeFitID == fitID:
|
||||
index = self.multiSwitch.GetPageIndex(page)
|
||||
self.multiSwitch.SetSelection(index)
|
||||
@@ -221,12 +222,15 @@ class FittingView(d.Display):
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID))
|
||||
|
||||
def Destroy(self):
|
||||
# @todo: when wxPython 4.0.2 is release, https://github.com/pyfa-org/Pyfa/issues/1586#issuecomment-390074915
|
||||
# Make sure to remove the shitty checks that I have to put in place for these handlers to ignore when self is None
|
||||
print("+++++ Destroy " + repr(self))
|
||||
print(self.parent.Unbind(EVT_NOTEBOOK_PAGE_CHANGED))
|
||||
print(self.mainFrame.Unbind(GE.FIT_CHANGED))
|
||||
print(self.mainFrame.Unbind(EVT_FIT_RENAMED))
|
||||
print(self.mainFrame.Unbind(EVT_FIT_REMOVED))
|
||||
print(self.mainFrame.Unbind(ITEM_SELECTED))
|
||||
|
||||
# print(self.parent.Unbind(EVT_NOTEBOOK_PAGE_CHANGED))
|
||||
# print(self.mainFrame.Unbind(GE.FIT_CHANGED, handler=self.fitChanged))
|
||||
# print(self.mainFrame.Unbind(EVT_FIT_RENAMED, handler=self.fitRenamed ))
|
||||
# print(self.mainFrame.Unbind(EVT_FIT_REMOVED, handler=self.fitRemoved))
|
||||
# print(self.mainFrame.Unbind(ITEM_SELECTED, handler=self.appendItem))
|
||||
|
||||
d.Display.Destroy(self)
|
||||
|
||||
@@ -290,6 +294,9 @@ class FittingView(d.Display):
|
||||
"""
|
||||
print('_+_+_+_+_+_ Fit Removed: {} {} activeFitID: {}, eventFitID: {}'.format(repr(self), str(bool(self)), self.activeFitID, event.fitID))
|
||||
pyfalog.debug("FittingView::fitRemoved")
|
||||
if not self:
|
||||
event.Skip()
|
||||
return
|
||||
if event.fitID == self.getActiveFit():
|
||||
pyfalog.debug(" Deleted fit is currently active")
|
||||
self.parent.DeletePage(self.parent.GetPageIndex(self))
|
||||
@@ -297,8 +304,12 @@ class FittingView(d.Display):
|
||||
try:
|
||||
# Sometimes there is no active page after deletion, hence the try block
|
||||
sFit = Fit.getInstance()
|
||||
sFit.refreshFit(self.getActiveFit())
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.activeFitID))
|
||||
|
||||
# stopgap for #1384
|
||||
fit = sFit.getFit(self.getActiveFit())
|
||||
if fit:
|
||||
sFit.refreshFit(self.getActiveFit())
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.activeFitID))
|
||||
except RuntimeError:
|
||||
pyfalog.warning("Caught dead object")
|
||||
pass
|
||||
@@ -306,6 +317,9 @@ class FittingView(d.Display):
|
||||
event.Skip()
|
||||
|
||||
def fitRenamed(self, event):
|
||||
if not self:
|
||||
event.Skip()
|
||||
return
|
||||
fitID = event.fitID
|
||||
if fitID == self.getActiveFit():
|
||||
self.updateTab()
|
||||
@@ -342,6 +356,9 @@ class FittingView(d.Display):
|
||||
self.parent.SetPageTextIcon(pageIndex, text, bitmap)
|
||||
|
||||
def appendItem(self, event):
|
||||
if not self:
|
||||
event.Skip()
|
||||
return
|
||||
if self.parent.IsActive(self):
|
||||
itemID = event.itemID
|
||||
fitID = self.activeFitID
|
||||
@@ -523,7 +540,9 @@ class FittingView(d.Display):
|
||||
|
||||
def fitChanged(self, event):
|
||||
print('====== Fit Changed: {} {} activeFitID: {}, eventFitID: {}'.format(repr(self), str(bool(self)), self.activeFitID, event.fitID))
|
||||
|
||||
if not self:
|
||||
event.Skip()
|
||||
return
|
||||
try:
|
||||
if self.activeFitID is not None and self.activeFitID == event.fitID:
|
||||
self.generateMods()
|
||||
@@ -693,28 +712,26 @@ class FittingView(d.Display):
|
||||
# pyfalog.critical(e)
|
||||
|
||||
def OnShow(self, event):
|
||||
pass
|
||||
# if event.Show():
|
||||
# try:
|
||||
# self.MakeSnapshot()
|
||||
# except Exception as e:
|
||||
# pyfalog.critical("Failed to make snapshot")
|
||||
# pyfalog.critical(e)
|
||||
# event.Skip()
|
||||
if self and not self.IsShown():
|
||||
try:
|
||||
self.MakeSnapshot()
|
||||
except Exception as e:
|
||||
pyfalog.critical("Failed to make snapshot")
|
||||
pyfalog.critical(e)
|
||||
event.Skip()
|
||||
|
||||
def Snapshot(self):
|
||||
return self.FVsnapshot
|
||||
|
||||
# noinspection PyPropertyAccess
|
||||
def MakeSnapshot(self, maxColumns=1337):
|
||||
|
||||
if self.FVsnapshot:
|
||||
del self.FVsnapshot
|
||||
|
||||
tbmp = wx.Bitmap(16, 16)
|
||||
tdc = wx.MemoryDC()
|
||||
tdc.SelectObject(tbmp)
|
||||
font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
|
||||
font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
|
||||
tdc.SetFont(font)
|
||||
|
||||
columnsWidths = []
|
||||
@@ -727,6 +744,7 @@ class FittingView(d.Display):
|
||||
except Exception as e:
|
||||
pyfalog.critical("Failed to get fit")
|
||||
pyfalog.critical(e)
|
||||
return
|
||||
|
||||
if fit is None:
|
||||
return
|
||||
|
||||
@@ -30,9 +30,10 @@ from gui.bitmap_loader import BitmapLoader
|
||||
from gui.contextMenu import ContextMenu
|
||||
import gui.globalEvents as GE
|
||||
from gui.builtinViews.implantEditor import BaseImplantEditorView
|
||||
from gui.builtinViews.entityEditor import EntityEditor, BaseValidator
|
||||
from gui.builtinViews.entityEditor import EntityEditor, BaseValidator, TextEntryValidatedDialog
|
||||
from service.fit import Fit
|
||||
from service.character import Character
|
||||
from service.esi import Esi
|
||||
from service.network import AuthenticationError, TimeoutError
|
||||
from service.market import Market
|
||||
from logbook import Logger
|
||||
@@ -42,9 +43,22 @@ from wx.lib.agw.floatspin import FloatSpin
|
||||
|
||||
from gui.utils.clipboard import toClipboard, fromClipboard
|
||||
|
||||
import roman
|
||||
import re
|
||||
import webbrowser
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
def arabicOrRomanToInt(s):
|
||||
m = re.match(r'\d+$', s)
|
||||
if m:
|
||||
i = int(s)
|
||||
else:
|
||||
i = roman.fromRoman(s)
|
||||
return i
|
||||
|
||||
|
||||
class CharacterTextValidor(BaseValidator):
|
||||
def __init__(self):
|
||||
BaseValidator.__init__(self)
|
||||
@@ -53,14 +67,14 @@ class CharacterTextValidor(BaseValidator):
|
||||
return CharacterTextValidor()
|
||||
|
||||
def Validate(self, win):
|
||||
entityEditor = win.parent
|
||||
textCtrl = self.GetWindow()
|
||||
text = textCtrl.GetValue().strip()
|
||||
sChar = Character.getInstance()
|
||||
|
||||
try:
|
||||
if len(text) == 0:
|
||||
raise ValueError("You must supply a name for the Character!")
|
||||
elif text in [x.name for x in entityEditor.choices]:
|
||||
elif text in [x.name for x in sChar.getCharacterList()]:
|
||||
raise ValueError("Character name already in use, please choose another.")
|
||||
|
||||
return True
|
||||
@@ -162,7 +176,7 @@ class CharacterEditor(wx.Frame):
|
||||
|
||||
self.viewsNBContainer.AddPage(self.sview, "Skills")
|
||||
self.viewsNBContainer.AddPage(self.iview, "Implants")
|
||||
self.viewsNBContainer.AddPage(self.aview, "API")
|
||||
self.viewsNBContainer.AddPage(self.aview, "EVE SSO")
|
||||
|
||||
mainSizer.Add(self.viewsNBContainer, 1, wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
@@ -230,8 +244,8 @@ class CharacterEditor(wx.Frame):
|
||||
|
||||
def saveCharAs(self, event):
|
||||
char = self.entityEditor.getActiveEntity()
|
||||
dlg = SaveCharacterAs(self, char.ID)
|
||||
dlg.ShowModal()
|
||||
self.SaveCharacterAs(self, char.ID)
|
||||
wx.PostEvent(self, GE.CharListUpdated())
|
||||
|
||||
def revertChar(self, event):
|
||||
sChr = Character.getInstance()
|
||||
@@ -273,6 +287,22 @@ class CharacterEditor(wx.Frame):
|
||||
|
||||
wx.Frame.Destroy(self)
|
||||
|
||||
@staticmethod
|
||||
def SaveCharacterAs(parent, charID):
|
||||
sChar = Character.getInstance()
|
||||
name = sChar.getCharName(charID)
|
||||
|
||||
dlg = TextEntryValidatedDialog(parent, CharacterTextValidor,
|
||||
"Enter a name for your new Character:",
|
||||
"Save Character As...")
|
||||
dlg.SetValue("{} Copy".format(name))
|
||||
dlg.txtctrl.SetInsertionPointEnd()
|
||||
dlg.CenterOnParent()
|
||||
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
sChar = Character.getInstance()
|
||||
return sChar.saveCharacterAs(charID, dlg.txtctrl.GetValue().strip())
|
||||
|
||||
|
||||
class SkillTreeView(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
@@ -414,7 +444,8 @@ class SkillTreeView(wx.Panel):
|
||||
lines = text.splitlines()
|
||||
|
||||
for l in lines:
|
||||
skill, level = l.strip()[:-1].strip(), int(l.strip()[-1])
|
||||
s = l.strip()
|
||||
skill, level = s.rsplit(None, 1)[0], arabicOrRomanToInt(s.rsplit(None, 1)[1])
|
||||
skill = char.getSkill(skill)
|
||||
if skill:
|
||||
skill.setLevel(level, ignoreRestrict=True)
|
||||
@@ -693,118 +724,132 @@ class APIView(wx.Panel):
|
||||
self.charEditor = self.Parent.Parent # first parent is Notebook, second is Character Editor
|
||||
self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW))
|
||||
|
||||
self.apiUrlCreatePredefined = "https://community.eveonline.com/support/api-key/CreatePredefined?accessMask=8"
|
||||
self.apiUrlKeyList = "https://community.eveonline.com/support/api-key/"
|
||||
|
||||
pmainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
hintSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
hintSizer.AddStretchSpacer()
|
||||
self.stDisabledTip = wx.StaticText(self, wx.ID_ANY,
|
||||
"You cannot add API Details for All 0 and All 5 characters.\n"
|
||||
"You cannot link All 0 or All 5 characters to an EVE character.\n"
|
||||
"Please select another character or make a new one.", style=wx.ALIGN_CENTER)
|
||||
self.stDisabledTip.Wrap(-1)
|
||||
hintSizer.Add(self.stDisabledTip, 0, wx.TOP | wx.BOTTOM, 10)
|
||||
|
||||
|
||||
|
||||
|
||||
self.stDisabledTip.Hide()
|
||||
hintSizer.AddStretchSpacer()
|
||||
pmainSizer.Add(hintSizer, 0, wx.EXPAND, 5)
|
||||
|
||||
fgSizerInput = wx.FlexGridSizer(3, 2, 0, 0)
|
||||
fgSizerInput = wx.FlexGridSizer(1, 3, 0, 0)
|
||||
fgSizerInput.AddGrowableCol(1)
|
||||
fgSizerInput.SetFlexibleDirection(wx.BOTH)
|
||||
fgSizerInput.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
|
||||
|
||||
self.m_staticIDText = wx.StaticText(self, wx.ID_ANY, "keyID:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.m_staticIDText.Wrap(-1)
|
||||
fgSizerInput.Add(self.m_staticIDText, 0, wx.ALL | wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.inputID = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
fgSizerInput.Add(self.inputID, 1, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
self.m_staticKeyText = wx.StaticText(self, wx.ID_ANY, "vCode:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.m_staticKeyText.Wrap(-1)
|
||||
fgSizerInput.Add(self.m_staticKeyText, 0, wx.ALL | wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.inputKey = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
fgSizerInput.Add(self.inputKey, 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
self.m_staticCharText = wx.StaticText(self, wx.ID_ANY, "Character:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.m_staticCharText.Wrap(-1)
|
||||
fgSizerInput.Add(self.m_staticCharText, 0, wx.ALL | wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
fgSizerInput.Add(self.m_staticCharText, 0, wx.ALL | wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, 10)
|
||||
|
||||
self.charChoice = wx.Choice(self, wx.ID_ANY, style=0)
|
||||
self.charChoice.Append("No Selection", 0)
|
||||
fgSizerInput.Add(self.charChoice, 1, wx.ALL | wx.EXPAND, 5)
|
||||
fgSizerInput.Add(self.charChoice, 1, wx.TOP | wx.BOTTOM | wx.EXPAND, 10)
|
||||
|
||||
self.charChoice.Enable(False)
|
||||
self.fetchButton = wx.Button(self, wx.ID_ANY, "Get Skills", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.fetchButton.Bind(wx.EVT_BUTTON, self.fetchSkills)
|
||||
fgSizerInput.Add(self.fetchButton, 0, wx.ALL | wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, 10)
|
||||
|
||||
pmainSizer.Add(fgSizerInput, 0, wx.EXPAND, 5)
|
||||
|
||||
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
btnSizer.AddStretchSpacer()
|
||||
|
||||
self.btnFetchCharList = wx.Button(self, wx.ID_ANY, "Get Characters")
|
||||
btnSizer.Add(self.btnFetchCharList, 0, wx.ALL, 2)
|
||||
self.btnFetchCharList.Bind(wx.EVT_BUTTON, self.fetchCharList)
|
||||
|
||||
self.btnFetchSkills = wx.Button(self, wx.ID_ANY, "Fetch Skills")
|
||||
btnSizer.Add(self.btnFetchSkills, 0, wx.ALL, 2)
|
||||
self.btnFetchSkills.Bind(wx.EVT_BUTTON, self.fetchSkills)
|
||||
self.btnFetchSkills.Enable(False)
|
||||
|
||||
btnSizer.AddStretchSpacer()
|
||||
pmainSizer.Add(btnSizer, 0, wx.EXPAND, 5)
|
||||
|
||||
self.stStatus = wx.StaticText(self, wx.ID_ANY, wx.EmptyString)
|
||||
pmainSizer.Add(self.stStatus, 0, wx.ALL, 5)
|
||||
|
||||
pmainSizer.AddStretchSpacer()
|
||||
self.stAPITip = wx.StaticText(self, wx.ID_ANY,
|
||||
"You can create a pre-defined key here (only CharacterSheet is required):",
|
||||
wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stAPITip.Wrap(-1)
|
||||
|
||||
pmainSizer.Add(self.stAPITip, 0, wx.ALL, 2)
|
||||
self.m_staticline1 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
|
||||
pmainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.ALL, 10)
|
||||
|
||||
self.hlEveAPI = wx.lib.agw.hyperlink.HyperLinkCtrl(self, wx.ID_ANY, label=self.apiUrlCreatePredefined)
|
||||
pmainSizer.Add(self.hlEveAPI, 0, wx.ALL, 2)
|
||||
self.noCharactersTip = wx.StaticText(self, wx.ID_ANY, "Don't see your EVE character in the list?", style=wx.ALIGN_CENTER)
|
||||
|
||||
self.stAPITip2 = wx.StaticText(self, wx.ID_ANY, "Or, you can choose an existing key from:", wx.DefaultPosition,
|
||||
wx.DefaultSize, 0)
|
||||
self.stAPITip2.Wrap(-1)
|
||||
pmainSizer.Add(self.stAPITip2, 0, wx.ALL, 2)
|
||||
self.noCharactersTip.Wrap(-1)
|
||||
pmainSizer.Add(self.noCharactersTip, 0, wx.CENTER | wx.TOP | wx.BOTTOM, 0)
|
||||
|
||||
self.hlEveAPI2 = wx.lib.agw.hyperlink.HyperLinkCtrl(self, wx.ID_ANY, label=self.apiUrlKeyList)
|
||||
pmainSizer.Add(self.hlEveAPI2, 0, wx.ALL, 2)
|
||||
self.addButton = wx.Button(self, wx.ID_ANY, "Log In with EVE SSO", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.addButton.Bind(wx.EVT_BUTTON, self.addCharacter)
|
||||
pmainSizer.Add(self.addButton, 0, wx.ALL | wx.ALIGN_CENTER, 10)
|
||||
|
||||
self.charEditor.mainFrame.Bind(GE.EVT_SSO_LOGOUT, self.ssoListChanged)
|
||||
self.charEditor.mainFrame.Bind(GE.EVT_SSO_LOGIN, self.ssoListChanged)
|
||||
self.charEditor.entityEditor.Bind(wx.EVT_CHOICE, self.charChanged)
|
||||
|
||||
self.charChoice.Bind(wx.EVT_CHOICE, self.ssoCharChanged)
|
||||
|
||||
self.SetSizer(pmainSizer)
|
||||
self.Layout()
|
||||
self.charChanged(None)
|
||||
self.ssoListChanged(None)
|
||||
|
||||
def ssoCharChanged(self, event):
|
||||
sChar = Character.getInstance()
|
||||
activeChar = self.charEditor.entityEditor.getActiveEntity()
|
||||
ssoChar = self.getActiveCharacter()
|
||||
sChar.setSsoCharacter(activeChar.ID, ssoChar)
|
||||
|
||||
self.fetchButton.Enable(ssoChar is not None)
|
||||
|
||||
event.Skip()
|
||||
|
||||
def fetchSkills(self, evt):
|
||||
sChar = Character.getInstance()
|
||||
char = self.charEditor.entityEditor.getActiveEntity()
|
||||
sChar.apiFetch(char.ID, self.__fetchCallback)
|
||||
|
||||
def addCharacter(self, event):
|
||||
sEsi = Esi.getInstance()
|
||||
sEsi.login()
|
||||
|
||||
def getActiveCharacter(self):
|
||||
selection = self.charChoice.GetCurrentSelection()
|
||||
return self.charChoice.GetClientData(selection) if selection is not -1 else None
|
||||
|
||||
def ssoListChanged(self, event):
|
||||
if not self: # todo: fix event not unbinding properly
|
||||
return
|
||||
|
||||
self.charChanged(event)
|
||||
|
||||
def charChanged(self, event):
|
||||
sChar = Character.getInstance()
|
||||
sEsi = Esi.getInstance()
|
||||
|
||||
activeChar = self.charEditor.entityEditor.getActiveEntity()
|
||||
|
||||
ID, key, char, chars = sChar.getApiDetails(activeChar.ID)
|
||||
self.inputID.SetValue(str(ID))
|
||||
self.inputKey.SetValue(key)
|
||||
if event and event.EventType == GE.EVT_SSO_LOGIN.typeId and hasattr(event, 'character'):
|
||||
# Automatically assign the character that was just logged into
|
||||
sChar.setSsoCharacter(activeChar.ID, event.character.ID)
|
||||
|
||||
sso = sChar.getSsoCharacter(activeChar.ID)
|
||||
|
||||
self.fetchButton.Enable(sso is not None)
|
||||
|
||||
ssoChars = sEsi.getSsoCharacters()
|
||||
|
||||
self.charChoice.Clear()
|
||||
|
||||
if chars:
|
||||
for charName in chars:
|
||||
self.charChoice.Append(charName)
|
||||
self.charChoice.SetStringSelection(char)
|
||||
self.charChoice.Enable(True)
|
||||
self.btnFetchSkills.Enable(True)
|
||||
else:
|
||||
self.charChoice.Append("No characters...", 0)
|
||||
self.charChoice.SetSelection(0)
|
||||
self.charChoice.Enable(False)
|
||||
self.btnFetchSkills.Enable(False)
|
||||
noneID = self.charChoice.Append("None", None)
|
||||
|
||||
for char in ssoChars:
|
||||
currId = self.charChoice.Append(char.characterName, char.ID)
|
||||
|
||||
if sso is not None and char.ID == sso.ID:
|
||||
self.charChoice.SetSelection(currId)
|
||||
|
||||
if sso is None:
|
||||
self.charChoice.SetSelection(noneID)
|
||||
|
||||
#
|
||||
# if chars:
|
||||
# for charName in chars:
|
||||
# self.charChoice.Append(charName)
|
||||
# self.charChoice.SetStringSelection(char)
|
||||
# else:
|
||||
# self.charChoice.Append("No characters...", 0)
|
||||
# self.charChoice.SetSelection(0)
|
||||
#
|
||||
if activeChar.name in ("All 0", "All 5"):
|
||||
self.Enable(False)
|
||||
self.stDisabledTip.Show()
|
||||
@@ -817,85 +862,18 @@ class APIView(wx.Panel):
|
||||
if event is not None:
|
||||
event.Skip()
|
||||
|
||||
def fetchCharList(self, event):
|
||||
self.stStatus.SetLabel("")
|
||||
if self.inputID.GetLineText(0) == "" or self.inputKey.GetLineText(0) == "":
|
||||
self.stStatus.SetLabel("Invalid keyID or vCode!")
|
||||
return
|
||||
|
||||
sChar = Character.getInstance()
|
||||
try:
|
||||
activeChar = self.charEditor.entityEditor.getActiveEntity()
|
||||
list = sChar.apiCharList(activeChar.ID, self.inputID.GetLineText(0), self.inputKey.GetLineText(0))
|
||||
except AuthenticationError as e:
|
||||
msg = "Authentication failure. Please check keyID and vCode combination."
|
||||
pyfalog.info(msg)
|
||||
self.stStatus.SetLabel(msg)
|
||||
except TimeoutError as e:
|
||||
msg = "Request timed out. Please check network connectivity and/or proxy settings."
|
||||
pyfalog.info(msg)
|
||||
self.stStatus.SetLabel(msg)
|
||||
except Exception as e:
|
||||
pyfalog.error(e)
|
||||
self.stStatus.SetLabel("Error:\n%s" % e)
|
||||
else:
|
||||
self.charChoice.Clear()
|
||||
for charName in list:
|
||||
self.charChoice.Append(charName)
|
||||
|
||||
self.btnFetchSkills.Enable(True)
|
||||
self.charChoice.Enable(True)
|
||||
|
||||
self.Layout()
|
||||
|
||||
self.charChoice.SetSelection(0)
|
||||
|
||||
def fetchSkills(self, event):
|
||||
charName = self.charChoice.GetString(self.charChoice.GetSelection())
|
||||
if charName:
|
||||
sChar = Character.getInstance()
|
||||
activeChar = self.charEditor.entityEditor.getActiveEntity()
|
||||
sChar.apiFetch(activeChar.ID, charName, self.__fetchCallback)
|
||||
self.stStatus.SetLabel("Getting skills for {}".format(charName))
|
||||
|
||||
def __fetchCallback(self, e=None):
|
||||
charName = self.charChoice.GetString(self.charChoice.GetSelection())
|
||||
if e is None:
|
||||
self.stStatus.SetLabel("Successfully fetched {}\'s skills from EVE API.".format(charName))
|
||||
else:
|
||||
if e:
|
||||
exc_type, exc_obj, exc_trace = e
|
||||
pyfalog.error("Unable to retrieve {0}\'s skills. Error message:\n{1}".format(charName, exc_obj))
|
||||
self.stStatus.SetLabel("Unable to retrieve {}\'s skills. Error message:\n{}".format(charName, exc_obj))
|
||||
pyfalog.warn("Error fetching skill information for character")
|
||||
pyfalog.warn(exc_obj)
|
||||
|
||||
|
||||
class SaveCharacterAs(wx.Dialog):
|
||||
def __init__(self, parent, charID):
|
||||
wx.Dialog.__init__(self, parent, title="Save Character As...", size=wx.Size(300, 60))
|
||||
self.charID = charID
|
||||
self.parent = parent
|
||||
sChar = Character.getInstance()
|
||||
name = sChar.getCharName(charID)
|
||||
bSizer1 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.input = wx.TextCtrl(self, wx.ID_ANY, name, style=wx.TE_PROCESS_ENTER)
|
||||
|
||||
bSizer1.Add(self.input, 1, wx.ALL, 5)
|
||||
self.input.Bind(wx.EVT_TEXT_ENTER, self.change)
|
||||
self.button = wx.Button(self, wx.ID_OK, "Save")
|
||||
bSizer1.Add(self.button, 0, wx.ALL, 5)
|
||||
|
||||
self.SetSizer(bSizer1)
|
||||
self.Layout()
|
||||
self.Centre(wx.BOTH)
|
||||
self.button.Bind(wx.EVT_BUTTON, self.change)
|
||||
|
||||
def change(self, event):
|
||||
sChar = Character.getInstance()
|
||||
sChar.saveCharacterAs(self.charID, self.input.GetLineText(0))
|
||||
wx.PostEvent(self.parent, GE.CharListUpdated())
|
||||
|
||||
event.Skip()
|
||||
self.Close()
|
||||
wx.MessageBox(
|
||||
"Error fetching skill information",
|
||||
"Error", wx.ICON_ERROR | wx.STAY_ON_TOP)
|
||||
else:
|
||||
wx.MessageBox(
|
||||
"Successfully fetched skills", "Success", wx.ICON_INFORMATION | wx.STAY_ON_TOP)
|
||||
|
||||
|
||||
class SecStatusDialog(wx.Dialog):
|
||||
|
||||
@@ -79,6 +79,7 @@ class CharacterSelection(wx.Panel):
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
|
||||
|
||||
self.SetMinSize(wx.Size(25, -1))
|
||||
self.toggleRefreshButton()
|
||||
|
||||
self.charChoice.Enable(False)
|
||||
|
||||
@@ -97,7 +98,7 @@ class CharacterSelection(wx.Panel):
|
||||
grantItem = menu.Append(wx.ID_ANY, "Grant Missing Skills")
|
||||
self.Bind(wx.EVT_MENU, self.grantMissingSkills, grantItem)
|
||||
|
||||
exportItem = menu.Append(wx.ID_ANY, "Export Missing Skills")
|
||||
exportItem = menu.Append(wx.ID_ANY, "Copy Missing Skills")
|
||||
self.Bind(wx.EVT_MENU, self.exportSkills, exportItem)
|
||||
|
||||
self.PopupMenu(menu, pos)
|
||||
@@ -151,9 +152,7 @@ class CharacterSelection(wx.Panel):
|
||||
def refreshApi(self, event):
|
||||
self.btnRefresh.Enable(False)
|
||||
sChar = Character.getInstance()
|
||||
ID, key, charName, chars = sChar.getApiDetails(self.getActiveCharacter())
|
||||
if charName:
|
||||
sChar.apiFetch(self.getActiveCharacter(), charName, self.refreshAPICallback)
|
||||
sChar.apiFetch(self.getActiveCharacter(), self.refreshAPICallback)
|
||||
|
||||
def refreshAPICallback(self, e=None):
|
||||
self.btnRefresh.Enable(True)
|
||||
@@ -161,33 +160,39 @@ class CharacterSelection(wx.Panel):
|
||||
self.refreshCharacterList()
|
||||
else:
|
||||
exc_type, exc_obj, exc_trace = e
|
||||
pyfalog.warn("Error fetching API information for character")
|
||||
pyfalog.warn("Error fetching skill information for character")
|
||||
pyfalog.warn(exc_obj)
|
||||
|
||||
wx.MessageBox(
|
||||
"Error fetching API information, please check your API details in the character editor and try again later",
|
||||
"Error fetching skill information",
|
||||
"Error", wx.ICON_ERROR | wx.STAY_ON_TOP)
|
||||
|
||||
def charChanged(self, event):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
charID = self.getActiveCharacter()
|
||||
sChar = Character.getInstance()
|
||||
|
||||
if charID == -1:
|
||||
# revert to previous character
|
||||
self.charChoice.SetSelection(self.charCache)
|
||||
self.mainFrame.showCharacterEditor(event)
|
||||
return
|
||||
if sChar.getCharName(charID) not in ("All 0", "All 5") and sChar.apiEnabled(charID):
|
||||
self.btnRefresh.Enable(True)
|
||||
else:
|
||||
self.btnRefresh.Enable(False)
|
||||
|
||||
self.toggleRefreshButton()
|
||||
|
||||
sFit = Fit.getInstance()
|
||||
sFit.changeChar(fitID, charID)
|
||||
self.charCache = self.charChoice.GetCurrentSelection()
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
|
||||
|
||||
def toggleRefreshButton(self):
|
||||
charID = self.getActiveCharacter()
|
||||
sChar = Character.getInstance()
|
||||
char = sChar.getCharacter(charID)
|
||||
if sChar.getCharName(charID) not in ("All 0", "All 5") and sChar.getSsoCharacter(char.ID) is not None:
|
||||
self.btnRefresh.Enable(True)
|
||||
else:
|
||||
self.btnRefresh.Enable(False)
|
||||
|
||||
def selectChar(self, charID):
|
||||
choice = self.charChoice
|
||||
numItems = len(choice.GetItems())
|
||||
@@ -244,6 +249,8 @@ class CharacterSelection(wx.Panel):
|
||||
if not fit.calculated:
|
||||
self.charChanged(None)
|
||||
|
||||
self.toggleRefreshButton()
|
||||
|
||||
event.Skip()
|
||||
|
||||
def exportSkills(self, evt):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#===============================================================================
|
||||
# ===============================================================================
|
||||
#
|
||||
# ToDo: Bug - when selecting close on a tab, sometimes the tab to the right is
|
||||
# selected, most likely due to determination of mouse position
|
||||
@@ -11,7 +11,7 @@
|
||||
# tab index?). This will also help with finding close buttons.
|
||||
# ToDo: Fix page preview code (PFNotebookPagePreview)
|
||||
#
|
||||
#= ==============================================================================
|
||||
# ===============================================================================
|
||||
|
||||
import wx
|
||||
import wx.lib.newevent
|
||||
@@ -19,7 +19,7 @@ import wx.lib.newevent
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.utils import draw
|
||||
from gui.utils import color as color_utils
|
||||
|
||||
from service.fit import Fit
|
||||
|
||||
_PageChanging, EVT_NOTEBOOK_PAGE_CHANGING = wx.lib.newevent.NewEvent()
|
||||
_PageChanged, EVT_NOTEBOOK_PAGE_CHANGED = wx.lib.newevent.NewEvent()
|
||||
@@ -413,7 +413,7 @@ class _TabRenderer:
|
||||
mdc.SelectObject(ebmp)
|
||||
mdc.SetFont(self.font)
|
||||
textSizeX, textSizeY = mdc.GetTextExtent(self.text)
|
||||
totalSize = self.left_width + self.right_width + textSizeX + self.close_btn_width / 2 + 16 + self.padding* 2
|
||||
totalSize = self.left_width + self.right_width + textSizeX + self.close_btn_width / 2 + 16 + self.padding * 2
|
||||
mdc.SelectObject(wx.NullBitmap)
|
||||
return totalSize, self.tab_height
|
||||
|
||||
@@ -1057,6 +1057,10 @@ class _TabsContainer(wx.Panel):
|
||||
Checks to see if we have a tab preview and sets up the timer for it
|
||||
to display
|
||||
"""
|
||||
sFit = Fit.getInstance()
|
||||
if not sFit.serviceFittingOptions["showTooltip"] or False:
|
||||
return
|
||||
|
||||
if self.preview_timer:
|
||||
if self.preview_timer.IsRunning():
|
||||
if self.preview_wnd:
|
||||
@@ -1286,6 +1290,7 @@ class _TabsContainer(wx.Panel):
|
||||
if not self.preview_tab.GetSelected():
|
||||
page = self.Parent.GetPage(self.GetTabIndex(self.preview_tab))
|
||||
if page.Snapshot():
|
||||
|
||||
self.preview_wnd = PFNotebookPagePreview(
|
||||
self,
|
||||
(mposx + 3, mposy + 3),
|
||||
@@ -1373,7 +1378,7 @@ class PFNotebookPagePreview(wx.Frame):
|
||||
def OnWindowPaint(self, event):
|
||||
rect = self.GetRect()
|
||||
canvas = wx.Bitmap(rect.width, rect.height)
|
||||
mdc = wx.AudoBufferedPaintDC(self)
|
||||
mdc = wx.BufferedPaintDC(self)
|
||||
mdc.SelectObject(canvas)
|
||||
color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)
|
||||
mdc.SetBackground(wx.Brush(color))
|
||||
@@ -1473,4 +1478,3 @@ if __name__ == "__main__":
|
||||
top = Frame("Test Chrome Tabs")
|
||||
top.Show()
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class CopySelectDialog(wx.Dialog):
|
||||
copyFormatEftImps = 1
|
||||
copyFormatXml = 2
|
||||
copyFormatDna = 3
|
||||
copyFormatCrest = 4
|
||||
copyFormatEsi = 4
|
||||
copyFormatMultiBuy = 5
|
||||
|
||||
def __init__(self, parent):
|
||||
@@ -40,7 +40,7 @@ class CopySelectDialog(wx.Dialog):
|
||||
CopySelectDialog.copyFormatEftImps: "EFT text format",
|
||||
CopySelectDialog.copyFormatXml: "EVE native XML format",
|
||||
CopySelectDialog.copyFormatDna: "A one-line text format",
|
||||
CopySelectDialog.copyFormatCrest: "A JSON format used for EVE CREST",
|
||||
CopySelectDialog.copyFormatEsi: "A JSON format used for EVE CREST",
|
||||
CopySelectDialog.copyFormatMultiBuy: "MultiBuy text format"}
|
||||
selector = wx.RadioBox(self, wx.ID_ANY, label="Copy to the clipboard using:", choices=copyFormats,
|
||||
style=wx.RA_SPECIFY_ROWS)
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
import sys
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
import gui.mainFrame
|
||||
@@ -182,13 +181,13 @@ class Display(wx.ListCtrl):
|
||||
|
||||
if listItemCount < stuffItemCount:
|
||||
for i in range(stuffItemCount - listItemCount):
|
||||
self.InsertItem(sys.maxsize, "")
|
||||
self.InsertItem(self.GetItemCount(), "")
|
||||
|
||||
if listItemCount > stuffItemCount:
|
||||
if listItemCount - stuffItemCount > 20 > stuffItemCount:
|
||||
self.DeleteAllItems()
|
||||
for i in range(stuffItemCount):
|
||||
self.InsertItem(sys.maxsize, "")
|
||||
self.InsertItem(self.GetItemCount(), "")
|
||||
else:
|
||||
for i in range(listItemCount - stuffItemCount):
|
||||
self.DeleteItem(self.getLastItem())
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user