Merge branch 'pyfa-org:master' into master
102
.appveyor.yml
@@ -1,71 +1,48 @@
|
||||
image:
|
||||
- Visual Studio 2019
|
||||
- Ubuntu
|
||||
- macos
|
||||
clone_depth: 1
|
||||
- Ubuntu2204
|
||||
- Visual Studio 2022
|
||||
- macos-catalina
|
||||
for:
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: Ubuntu
|
||||
- image: Ubuntu2204
|
||||
environment:
|
||||
APPVEYOR_SSH_KEY: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDJDW/+oYNGOiPvwuwAL9tc/LQgg58aosIVpMYfepQZ20V+VZnHpZh8IRDA8Jo5xht19p2PksA+hFgqA0kpKtrSkuiWdE8rATQItfk4gf7yB0yGasJGGQZYazy9k/9XtmYkq2HHOOeEqdxvrICddJQ88MLCLT9lJENSUP/YS/yGcjZFXVxE11pTeIcqlCRU+3eYa1v7BeNvXIKNhZoK5orXWrtuH3cy8jrSns/u70aYfJ6B2jA8CnWnDbuvpeQtEY61SQqlKUsSArNa8NAsXj41wr3Ar9gAG9330w7EMTqlutk8HZO35uHI0q5qinUhaQYufPPrVkb2L/N+ZCfu0fnh appveyor"
|
||||
APPIMAGE_TOOL: appimagetool-x86_64.AppImage
|
||||
PYTHON_APPIMAGE: python3.7.13-cp37-cp37m-manylinux2014_x86_64.AppImage
|
||||
APPVEYOR_SSH_KEY: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDhb96UEXy8yOy/f+riX/8kKbNx/lOfIZ4pP4Cw3Gj3DmnTwEnxtRtyc+xtaxOsKbt+7+EAXFpCzYX+jHMhtd0QtWB7dbey8DBg31g0f8C5EPquqROibVbhzr/F3f6/d52FFfq6Y/CWaAvLjezvipr+zOOsIFcVusqtXdPJQ/LtUJ0LS5d4lFiw5ELHSxHIpqwGwyb7PbR3ufEFoqbr8eYiCH+vlBob72ArPfo2f3u0sMvpGYmjVVu2jj4FEY2h89sLrGyFdNWBoyumRhkb38+WSAuyPa/Y21+g+S8sRzIlkwbxicGNMtrMIi6zHEIGAgA06Sw2psP807h730PPOVaWjUcU3ojNW8hH3nPizF74pT82+iP7/fFC4PXLP+tBa+8OoHC5yiO7QKUKprMSqVa1qOm8fHbrzglplKJXfzSfUtSE+AQ+HtHhuUWKI+0LBLDrsOJwI5hbsPOAuiZ5I3VfqfAOck6SH9TcmlapVmQEypc7d7oeeUtZSOuIWKXp068= dfx@aw"
|
||||
APPIMAGE_TOOL: appimage-builder-x86_64.AppImage
|
||||
DEPLOY_DIR: AppDir/opt/pyfa
|
||||
# APPVEYOR_SSH_BLOCK: true
|
||||
# APPVEYOR_SSH_BLOCK: true
|
||||
cache:
|
||||
- /home/appveyor/.cache/pip -> requirements.txt
|
||||
init:
|
||||
- sh: curl -sflL 'https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-ssh.sh' | bash -e -
|
||||
# init:
|
||||
# - sh: curl -sflL 'https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-ssh.sh' | bash -e -
|
||||
install:
|
||||
- sh: git fetch --prune --unshallow # to fix the version dump issues
|
||||
- sh: sudo DEBIAN_FRONTEND=noninteractive apt-get -y update
|
||||
- sh: sudo DEBIAN_FRONTEND=noninteractive apt-get -y install python3.7-dev libgtk-3-dev python3-pip libwebkit2gtk-4.0-dev
|
||||
# AppImage dependencies
|
||||
- sh: sudo DEBIAN_FRONTEND=noninteractive apt-get -y install libfuse2
|
||||
# Preparation script dependencies
|
||||
- sh: sudo DEBIAN_FRONTEND=noninteractive apt-get -y install python3-wxgtk4.0 python3-sqlalchemy python3-logbook
|
||||
before_build:
|
||||
- sh: mkdir build && cd build
|
||||
- sh: curl -LO https://github.com/AppImage/AppImageKit/releases/download/13/$APPIMAGE_TOOL && chmod +x $APPIMAGE_TOOL
|
||||
- sh: curl -LO https://github.com/niess/python-appimage/releases/download/python3.7/$PYTHON_APPIMAGE && chmod +x $PYTHON_APPIMAGE
|
||||
build_script:
|
||||
# Prepare Python base AppImage, stripping Python metadata
|
||||
- sh: ./$PYTHON_APPIMAGE --appimage-extract
|
||||
- sh: mv squashfs-root AppDir
|
||||
- sh: rm AppDir/python*.desktop
|
||||
- sh: rm AppDir/usr/share/applications/*.desktop
|
||||
- sh: rm AppDir/usr/share/metainfo/*.appdata.xml
|
||||
- sh: mkdir -p $DEPLOY_DIR
|
||||
# run install pyfa packages and any other requirements
|
||||
|
||||
- sh: AppDir/usr/bin/python -s -m pip install -U pip setuptools==41.6.0 wheel pathlib2
|
||||
- sh: AppDir/usr/bin/python -s -m pip install -r ../requirements.txt
|
||||
|
||||
# Run scripts to prep pyfa data and build database
|
||||
- sh: cd ../
|
||||
# Prepare pyfa data
|
||||
- sh: find locale/ -type f -name "*.po" -exec msgen "{}" -o "{}" \;
|
||||
- sh: build/AppDir/usr/bin/python scripts/compile_lang.py
|
||||
- sh: build/AppDir/usr/bin/python scripts/dump_crowdin_progress.py
|
||||
- sh: build/AppDir/usr/bin/python db_update.py
|
||||
- sh: export PYFA_VERSION="$(python3.7 scripts/dump_version.py)"
|
||||
|
||||
# Copy pyfa files to host
|
||||
- sh: cp -r eos graphs gui imgs locale service utils eve.db config.py pyfa.py db_update.py README.md LICENSE version.yml ./build/$DEPLOY_DIR
|
||||
- sh: find ./build/$DEPLOY_DIR | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf
|
||||
|
||||
# Copy static AppImage files
|
||||
- sh: cd dist_assets/linux
|
||||
- sh: cp AppRun pyfa.desktop ../../build/AppDir/
|
||||
- sh: cp pyfa.desktop ../../build/AppDir/usr/share/applications/
|
||||
- sh: cp org.pyfa.pyfa.appdata.xml ../../build/AppDir/usr/share/metainfo/
|
||||
- sh: chmod +x pyfa && cp pyfa ../../build/AppDir/usr/bin
|
||||
- sh: cd ../../
|
||||
|
||||
# Package it all up
|
||||
- sh: mkdir dist
|
||||
- sh: ./build/$APPIMAGE_TOOL build/AppDir dist/pyfa-$PYFA_VERSION-linux.AppImage
|
||||
- sh: python3 -B scripts/compile_lang.py
|
||||
- sh: python3 -B scripts/dump_crowdin_progress.py
|
||||
- sh: python3 -B db_update.py
|
||||
- sh: export PYFA_VERSION="$(python3 -B scripts/dump_version.py)"
|
||||
- sh: mkdir build
|
||||
# Download packaging tool
|
||||
- sh: curl -o $APPIMAGE_TOOL -L https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-x86_64.AppImage
|
||||
- sh: chmod +x $APPIMAGE_TOOL
|
||||
build_script:
|
||||
- sh: mkdir -p AppDir/opt/pyfa
|
||||
- sh: cp -r eos graphs gui imgs locale service utils eve.db config.py pyfa.py db_update.py README.md LICENSE version.yml AppDir/opt/pyfa/
|
||||
- sh: mkdir -p AppDir/usr/share/icons/hicolor/64x64/apps/
|
||||
- sh: cp imgs/gui/pyfa64.png AppDir/usr/share/icons/hicolor/64x64/apps/pyfa.png
|
||||
- sh: ./$APPIMAGE_TOOL --recipe dist_assets/linux/AppImageBuilder.yml
|
||||
after_build:
|
||||
- sh: ls -la build
|
||||
- sh: ls -la
|
||||
artifacts:
|
||||
- path: dist/pyfa-$PYFA_VERSION-linux.AppImage
|
||||
- path: pyfa-$PYFA_VERSION-linux.AppImage
|
||||
deploy:
|
||||
tag: $PYFA_VERSION
|
||||
release: pyfa $PYFA_VERSION
|
||||
@@ -81,17 +58,15 @@ for:
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: Visual Studio 2019
|
||||
- image: Visual Studio 2022
|
||||
environment:
|
||||
PYTHON: "C:\\Python37-x64"
|
||||
PYTHON: "C:\\Python311-x64"
|
||||
# Should be enabled only for build process debugging
|
||||
# init:
|
||||
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
cache:
|
||||
- C:\users\appveyor\appdata\local\pip\cache\ -> requirements.txt
|
||||
install:
|
||||
- cmd: git fetch --prune --unshallow # to fix the version dump issues
|
||||
|
||||
- ps: echo("OS version:")
|
||||
- ps: "[System.Environment]::OSVersion.Version"
|
||||
|
||||
@@ -127,10 +102,8 @@ for:
|
||||
# pip will build them from source using the MSVC compiler matching the
|
||||
# target Python version and architecture
|
||||
- ps: echo("Install pip requirements:")
|
||||
# This one is needed to build wxpython 4.0.6 on windows
|
||||
- cmd: "python -m pip install pathlib2"
|
||||
- cmd: "python -m pip install -r requirements.txt"
|
||||
- cmd: "python -m pip install PyInstaller==3.6"
|
||||
- cmd: "python -m pip install PyInstaller==6.0.0"
|
||||
before_build:
|
||||
# directory that will contain the built files
|
||||
- ps: $env:PYFA_DIST_DIR = "c:\projects\$env:APPVEYOR_PROJECT_SLUG\dist"
|
||||
@@ -146,7 +119,7 @@ for:
|
||||
# Build gamedata DB
|
||||
- cmd: "python db_update.py"
|
||||
# Build command for PyInstaller
|
||||
- cmd: "python -m PyInstaller --noupx --clean --windowed --noconsole -y pyfa.spec"
|
||||
- cmd: "python -m PyInstaller --clean -y pyfa.spec"
|
||||
# Copy over manifest (See pyfa-org/pyfa#1622)
|
||||
- ps: xcopy /y dist_assets\win\pyfa.exe.manifest $env:PYFA_DIST_DIR\pyfa\
|
||||
# InnoScript EXE building. This is in a separate script because I don't feel like copying over the logic to AppVeyor script right now...
|
||||
@@ -173,16 +146,15 @@ for:
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: macos
|
||||
- image: macos-catalina
|
||||
environment:
|
||||
APPVEYOR_SSH_KEY: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDJDW/+oYNGOiPvwuwAL9tc/LQgg58aosIVpMYfepQZ20V+VZnHpZh8IRDA8Jo5xht19p2PksA+hFgqA0kpKtrSkuiWdE8rATQItfk4gf7yB0yGasJGGQZYazy9k/9XtmYkq2HHOOeEqdxvrICddJQ88MLCLT9lJENSUP/YS/yGcjZFXVxE11pTeIcqlCRU+3eYa1v7BeNvXIKNhZoK5orXWrtuH3cy8jrSns/u70aYfJ6B2jA8CnWnDbuvpeQtEY61SQqlKUsSArNa8NAsXj41wr3Ar9gAG9330w7EMTqlutk8HZO35uHI0q5qinUhaQYufPPrVkb2L/N+ZCfu0fnh appveyor"
|
||||
cache:
|
||||
- /Users/appveyor/Library/Caches/pip/ -> requirements.txt
|
||||
init:
|
||||
# - sh: curl -sflL 'https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-ssh.sh' | bash -e -
|
||||
- sh: source ~/venv3.7/bin/activate
|
||||
- sh: source ~/venv3.11/bin/activate
|
||||
install:
|
||||
- sh: git fetch --prune --unshallow # to fix the version dump issues
|
||||
- sh: bash scripts/osx-setup.sh
|
||||
build_script:
|
||||
- sh: bash scripts/osx-translations.sh
|
||||
@@ -211,4 +183,4 @@ for:
|
||||
force_update: false
|
||||
# deploy on tag push only
|
||||
on:
|
||||
APPVEYOR_REPO_TAG: true
|
||||
APPVEYOR_REPO_TAG: true
|
||||
|
||||
4
.gitignore
vendored
@@ -90,6 +90,7 @@ target/
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
PyfaEnv/
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
@@ -123,3 +124,6 @@ gitversion
|
||||
|
||||
*.fsdbinary
|
||||
/locale/progress.json
|
||||
|
||||
# vscode settings
|
||||
.vscode
|
||||
@@ -1,6 +1,6 @@
|
||||
# pyfa
|
||||
|
||||
[](https://pyfainvite.azurewebsites.net/) [](https://travis-ci.org/pyfa-org/Pyfa)
|
||||
[]([https://travis-ci.org/pyfa-org/Pyfa](https://ci.appveyor.com/project/pyfa-org/pyfa))
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ saveInRoot = False
|
||||
evemonMinVersion = "4081"
|
||||
|
||||
minItemSearchLength = 3
|
||||
minItemSearchLengthCjk = 1
|
||||
|
||||
pyfaPath = None
|
||||
savePath = None
|
||||
|
||||
175
db_update.py
@@ -117,8 +117,7 @@ def update_db():
|
||||
for k, v in compiled_data.items():
|
||||
row = {}
|
||||
row.update(v)
|
||||
if keyIdName not in row:
|
||||
row[keyIdName] = int(k)
|
||||
row[keyIdName] = int(k)
|
||||
data.append(row)
|
||||
return data
|
||||
|
||||
@@ -139,16 +138,18 @@ def update_db():
|
||||
for row in data:
|
||||
if (
|
||||
# Apparently people really want Civilian modules available
|
||||
(row['typeName_en-us'].startswith('Civilian') and "Shuttle" not in row['typeName_en-us']) or
|
||||
row['typeName_en-us'] == 'Capsule' or
|
||||
row['groupID'] == 4033 # destructible effect beacons
|
||||
(row['typeName_en-us'].startswith('Civilian') and "Shuttle" not in row['typeName_en-us'])
|
||||
or row['typeName_en-us'] == 'Capsule'
|
||||
or row['groupID'] == 4033 # destructible effect beacons
|
||||
or re.match('AIR .+Booster.*', row['typeName_en-us'])
|
||||
):
|
||||
row['published'] = True
|
||||
# Nearly useless and clutter search results too much
|
||||
elif (
|
||||
row['typeName_en-us'].startswith('Limited Synth ') or
|
||||
row['typeName_en-us'].startswith('Expired ') or
|
||||
row['typeName_en-us'].endswith(' Filament') and (
|
||||
row['typeName_en-us'].startswith('Limited Synth ')
|
||||
or row['typeName_en-us'].startswith('Expired ')
|
||||
or re.match('Mining Blitz .+ Booster Dose .+', row['typeName_en-us'])
|
||||
or row['typeName_en-us'].endswith(' Filament') and (
|
||||
"'Needlejack'" not in row['typeName_en-us'] and
|
||||
"'Devana'" not in row['typeName_en-us'] and
|
||||
"'Pochven'" not in row['typeName_en-us'] and
|
||||
@@ -616,6 +617,16 @@ def update_db():
|
||||
eos.db.gamedata_session.delete(cat)
|
||||
|
||||
# Unused normally, can be useful for customizing items
|
||||
def _copyItem(srcName, tgtTypeID, tgtName):
|
||||
eveType = eos.db.gamedata_session.query(eos.gamedata.Item).filter(eos.gamedata.Item.name == srcName).one()
|
||||
eos.db.gamedata_session.expunge(eveType)
|
||||
sqlalchemy.orm.make_transient(eveType)
|
||||
eveType.ID = tgtTypeID
|
||||
for suffix in eos.config.translation_mapping.values():
|
||||
setattr(eveType, f'typeName{suffix}', tgtName)
|
||||
eos.db.gamedata_session.add(eveType)
|
||||
eos.db.gamedata_session.flush()
|
||||
|
||||
def _hardcodeAttribs(typeID, attrMap):
|
||||
for attrName, value in attrMap.items():
|
||||
try:
|
||||
@@ -624,7 +635,7 @@ def update_db():
|
||||
except sqlalchemy.orm.exc.NoResultFound:
|
||||
attrInfo = eos.db.gamedata_session.query(eos.gamedata.AttributeInfo).filter(eos.gamedata.AttributeInfo.name == attrName).one()
|
||||
attr = eos.gamedata.Attribute()
|
||||
attr.ID = attrInfo.ID
|
||||
attr.attributeID = attrInfo.ID
|
||||
attr.typeID = typeID
|
||||
attr.value = value
|
||||
eos.db.gamedata_session.add(attr)
|
||||
@@ -640,6 +651,152 @@ def update_db():
|
||||
effect.effectName = effectName
|
||||
item.effects[effectName] = effect
|
||||
|
||||
def hardcodeShapash():
|
||||
shapashTypeID = 1000000
|
||||
_copyItem(srcName='Utu', tgtTypeID=shapashTypeID, tgtName='Shapash')
|
||||
attrMap = {
|
||||
# Fitting
|
||||
'powerOutput': 50,
|
||||
'cpuOutput': 225,
|
||||
'capacitorCapacity': 420,
|
||||
'rechargeRate': 187500,
|
||||
# Slots
|
||||
'hiSlots': 3,
|
||||
'medSlots': 4,
|
||||
'lowSlots': 4,
|
||||
'launcherSlotsLeft': 0,
|
||||
'turretSlotsLeft': 3,
|
||||
# Rigs
|
||||
'rigSlots': 2,
|
||||
'rigSize': 1,
|
||||
'upgradeCapacity': 400,
|
||||
# Shield
|
||||
'shieldCapacity': 575,
|
||||
'shieldRechargeRate': 625000,
|
||||
'shieldEmDamageResonance': 1 - 0.0,
|
||||
'shieldThermalDamageResonance': 1 - 0.6,
|
||||
'shieldKineticDamageResonance': 1 - 0.85,
|
||||
'shieldExplosiveDamageResonance': 1 - 0.5,
|
||||
# Armor
|
||||
'armorHP': 1015,
|
||||
'armorEmDamageResonance': 1 - 0.5,
|
||||
'armorThermalDamageResonance': 1 - 0.675,
|
||||
'armorKineticDamageResonance': 1 - 0.8375,
|
||||
'armorExplosiveDamageResonance': 1 - 0.1,
|
||||
# Structure
|
||||
'hp': 1274,
|
||||
'emDamageResonance': 1 - 0.33,
|
||||
'thermalDamageResonance': 1 - 0.33,
|
||||
'kineticDamageResonance': 1 - 0.33,
|
||||
'explosiveDamageResonance': 1 - 0.33,
|
||||
'mass': 1215000,
|
||||
'volume': 29500,
|
||||
'capacity': 165,
|
||||
# Navigation
|
||||
'maxVelocity': 325,
|
||||
'agility': 3.467,
|
||||
'warpSpeedMultiplier': 5.5,
|
||||
# Drones
|
||||
'droneCapacity': 75,
|
||||
'droneBandwidth': 25,
|
||||
# Targeting
|
||||
'maxTargetRange': 49000,
|
||||
'maxLockedTargets': 6,
|
||||
'scanRadarStrength': 0,
|
||||
'scanLadarStrength': 0,
|
||||
'scanMagnetometricStrength': 9,
|
||||
'scanGravimetricStrength': 0,
|
||||
'signatureRadius': 39,
|
||||
'scanResolution': 550,
|
||||
# Misc
|
||||
'energyWarfareResistance': 0,
|
||||
'stasisWebifierResistance': 0,
|
||||
'weaponDisruptionResistance': 0}
|
||||
effectMap = {
|
||||
100100: 'pyfaCustomShapashAfArAmount',
|
||||
100101: 'pyfaCustomShapashAfShtTrackingOptimal',
|
||||
100102: 'pyfaCustomShapashGfShtDamage',
|
||||
100103: 'pyfaCustomShapashGfPointRange',
|
||||
100104: 'pyfaCustomShapashGfPropOverheat',
|
||||
100105: 'pyfaCustomShapashRolePlateMass',
|
||||
100106: 'pyfaCustomShapashRoleHeat'}
|
||||
_hardcodeAttribs(shapashTypeID, attrMap)
|
||||
_hardcodeEffects(shapashTypeID, effectMap)
|
||||
|
||||
def hardcodeCybele():
|
||||
cybeleTypeID = 1000001
|
||||
_copyItem(srcName='Adrestia', tgtTypeID=cybeleTypeID, tgtName='Cybele')
|
||||
attrMap = {
|
||||
# Fitting
|
||||
'powerOutput': 1284,
|
||||
'cpuOutput': 400,
|
||||
'capacitorCapacity': 2400,
|
||||
'rechargeRate': 334000,
|
||||
'hiSlots': 5,
|
||||
'medSlots': 4,
|
||||
'lowSlots': 6,
|
||||
'launcherSlotsLeft': 0,
|
||||
'turretSlotsLeft': 5,
|
||||
# Rigs
|
||||
'rigSlots': 2,
|
||||
'rigSize': 2,
|
||||
'upgradeCapacity': 400,
|
||||
# Shield
|
||||
'shieldCapacity': 1200,
|
||||
'shieldRechargeRate': 1250000,
|
||||
'shieldEmDamageResonance': 1 - 0.0,
|
||||
'shieldThermalDamageResonance': 1 - 0.5,
|
||||
'shieldKineticDamageResonance': 1 - 0.9,
|
||||
'shieldExplosiveDamageResonance': 1 - 0.5,
|
||||
# Armor
|
||||
'armorHP': 1900,
|
||||
'armorEmDamageResonance': 1 - 0.5,
|
||||
'armorThermalDamageResonance': 1 - 0.69,
|
||||
'armorKineticDamageResonance': 1 - 0.85,
|
||||
'armorExplosiveDamageResonance': 1 - 0.1,
|
||||
# Structure
|
||||
'hp': 2300,
|
||||
'emDamageResonance': 1 - 0.33,
|
||||
'thermalDamageResonance': 1 - 0.33,
|
||||
'kineticDamageResonance': 1 - 0.33,
|
||||
'explosiveDamageResonance': 1 - 0.33,
|
||||
'mass': 11100000,
|
||||
'volume': 112000,
|
||||
'capacity': 450,
|
||||
# Navigation
|
||||
'maxVelocity': 235,
|
||||
'agility': 0.457,
|
||||
'warpSpeedMultiplier': 4.5,
|
||||
# Drones
|
||||
'droneCapacity': 100,
|
||||
'droneBandwidth': 50,
|
||||
# Targeting
|
||||
'maxTargetRange': 60000,
|
||||
'maxLockedTargets': 6,
|
||||
'scanRadarStrength': 0,
|
||||
'scanLadarStrength': 0,
|
||||
'scanMagnetometricStrength': 15,
|
||||
'scanGravimetricStrength': 0,
|
||||
'signatureRadius': 115,
|
||||
'scanResolution': 330,
|
||||
# Misc
|
||||
'energyWarfareResistance': 0,
|
||||
'stasisWebifierResistance': 0,
|
||||
'weaponDisruptionResistance': 0}
|
||||
effectMap = {
|
||||
100200: 'pyfaCustomCybeleHacMhtFalloff',
|
||||
100201: 'pyfaCustomCybeleHacMhtTracking',
|
||||
100202: 'pyfaCustomCybeleGcMhtDamage',
|
||||
100203: 'pyfaCustomCybeleGcArAmount',
|
||||
100204: 'pyfaCustomCybeleGcPointRange',
|
||||
100205: 'pyfaCustomCybeleRoleVelocity',
|
||||
100206: 'pyfaCustomCybeleRolePlateMass'}
|
||||
_hardcodeAttribs(cybeleTypeID, attrMap)
|
||||
_hardcodeEffects(cybeleTypeID, effectMap)
|
||||
|
||||
# hardcodeShapash()
|
||||
# hardcodeCybele()
|
||||
|
||||
eos.db.gamedata_session.commit()
|
||||
eos.db.gamedata_engine.execute('VACUUM')
|
||||
|
||||
|
||||
70
dist_assets/linux/AppImageBuilder.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
version: 1
|
||||
|
||||
AppDir:
|
||||
path: ./AppDir
|
||||
|
||||
app_info:
|
||||
id: pyfa
|
||||
name: pyfa
|
||||
icon: pyfa
|
||||
version: '{{PYFA_VERSION}}'
|
||||
exec: usr/bin/python3.11
|
||||
exec_args: "-s $APPDIR/opt/pyfa/pyfa.py $@"
|
||||
|
||||
apt:
|
||||
arch: [ amd64 ]
|
||||
sources:
|
||||
- sourceline: 'deb http://us.archive.ubuntu.com/ubuntu jammy main restricted universe multiverse'
|
||||
key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x871920d1991bc93c'
|
||||
- sourceline: 'deb http://us.archive.ubuntu.com/ubuntu jammy-updates main restricted universe multiverse'
|
||||
key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x871920d1991bc93c'
|
||||
- sourceline: 'deb http://us.archive.ubuntu.com/ubuntu jammy-backports main restricted universe multiverse'
|
||||
key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x871920d1991bc93c'
|
||||
- sourceline: 'deb http://us.archive.ubuntu.com/ubuntu jammy-security main restricted universe multiverse'
|
||||
key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x871920d1991bc93c'
|
||||
- sourceline: 'deb https://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu jammy main'
|
||||
key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0xf23c5a6cf475977595c89f51ba6932366a755776'
|
||||
|
||||
include:
|
||||
- python3.11
|
||||
# wx dependencies
|
||||
- libgtk-3-0
|
||||
- librsvg2-common # GTK3 recommendation; without it, search in char editor crashes
|
||||
- libwebkit2gtk-4.0-37 # Needed for wx's HTML lib
|
||||
exclude:
|
||||
- hicolor-icon-theme
|
||||
- humanity-icon-theme
|
||||
- ubuntu-mono
|
||||
|
||||
after_bundle:
|
||||
# Install python dependencies to bundled interpreter
|
||||
- export PYTHONHOME="AppDir/usr"
|
||||
- export PYTHONPATH="AppDir/usr/lib/python3.11/site-packages"
|
||||
- curl -L https://bootstrap.pypa.io/get-pip.py -o get-pip.py
|
||||
- AppDir/usr/bin/python3.11 get-pip.py
|
||||
# Just to bundle certificates with AppImage
|
||||
- AppDir/usr/bin/python3.11 -s -m pip install certifi
|
||||
- AppDir/usr/bin/python3.11 -s -m pip install -f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-22.04 -r requirements.txt
|
||||
|
||||
files:
|
||||
exclude:
|
||||
- usr/lib/x86_64-linux-gnu/gconv
|
||||
- usr/share/man
|
||||
- usr/share/doc/*/README.*
|
||||
- usr/share/doc/*/changelog.*
|
||||
- usr/share/doc/*/NEWS.*
|
||||
- usr/share/doc/*/TODO.*
|
||||
- usr/include
|
||||
|
||||
runtime:
|
||||
env:
|
||||
PYTHONHOME: '${APPDIR}/usr'
|
||||
PYTHONPATH: '${APPDIR}/usr/lib/python3.11/site-packages'
|
||||
SSL_CERT_FILE: '${APPDIR}/usr/local/lib/python3.11/dist-packages/certifi/cacert.pem'
|
||||
# Workaround for https://github.com/AppImageCrafters/appimage-builder/issues/336
|
||||
XDG_DATA_DIRS: '${APPDIR}/usr/local/share:${APPDIR}/usr/share:/usr/local/share:/usr/share:$XDG_DATA_DIRS'
|
||||
|
||||
AppImage:
|
||||
sign-key: None
|
||||
arch: x86_64
|
||||
file_name: 'pyfa-{{PYFA_VERSION}}-linux.AppImage'
|
||||
@@ -1,19 +0,0 @@
|
||||
#! /bin/bash -i
|
||||
|
||||
# Export APPRUN if running from an extracted image
|
||||
self="$(readlink -f -- $0)"
|
||||
here="${self%/*}"
|
||||
APPDIR="${APPDIR:-${here}}"
|
||||
|
||||
# Export TCl/Tk
|
||||
export TCL_LIBRARY="${APPDIR}/usr/share/tcltk/tcl8.4"
|
||||
export TK_LIBRARY="${APPDIR}/usr/share/tcltk/tk8.4"
|
||||
export TKPATH="${TK_LIBRARY}"
|
||||
|
||||
# Export SSL certificate
|
||||
export SSL_CERT_FILE="${APPDIR}/opt/_internal/certs.pem"
|
||||
|
||||
# Call the entry point
|
||||
#! /bin/bash -i
|
||||
|
||||
${APPDIR}/usr/bin/pyfa "$@"
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>org.pyfa.pyfa</id>
|
||||
<metadata_license>MIT</metadata_license>
|
||||
<project_license>GPL-3</project_license>
|
||||
<name>Pyfa</name>
|
||||
<summary>Pyfa </summary>
|
||||
<description>
|
||||
<p> Python Fitting Assitant for EVE Online
|
||||
</p>
|
||||
</description>
|
||||
<launchable type="desktop-id">pyfa.desktop</launchable>
|
||||
<url type="homepage">https://github.com/pyfa-org/Pyfa</url>
|
||||
<provides>
|
||||
<binary>pyfa</binary>
|
||||
</provides>
|
||||
</component>
|
||||
@@ -1,3 +0,0 @@
|
||||
#! /bin/bash
|
||||
|
||||
${APPDIR}/usr/bin/python3.7 -s "${APPDIR}/opt/pyfa/pyfa.py" "$@"
|
||||
@@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Pyfa
|
||||
Exec=pyfa
|
||||
Comment=Python Fitting Assistant for EVE: Online
|
||||
Icon=python
|
||||
Categories=Game;
|
||||
@@ -80,6 +80,7 @@ exe = EXE(pyz,
|
||||
app = BUNDLE(
|
||||
exe,
|
||||
name='pyfa.app',
|
||||
version=os.getenv('PYFA_VERSION'),
|
||||
icon=icon,
|
||||
bundle_identifier=None,
|
||||
info_plist={
|
||||
@@ -88,5 +89,7 @@ app = BUNDLE(
|
||||
'CFBundleName': 'pyfa',
|
||||
'CFBundleDisplayName': 'pyfa',
|
||||
'CFBundleIdentifier': 'org.pyfaorg.pyfa',
|
||||
'CFBundleVersion': os.getenv('PYFA_VERSION'),
|
||||
'CFBundleShortVersionString': os.getenv('PYFA_VERSION'),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -42,10 +42,10 @@ CloseApplications=yes
|
||||
DefaultDirName={pf}\{#MyAppName}
|
||||
DefaultGroupName={#MyAppName}
|
||||
AllowNoIcons=yes
|
||||
LicenseFile={#MyAppDir}\LICENSE
|
||||
LicenseFile={#MyAppDir}\app\LICENSE
|
||||
OutputDir={#MyOutputDir}
|
||||
OutputBaseFilename={#MyOutputFile}
|
||||
SetupIconFile={#MyAppDir}\pyfa.ico
|
||||
SetupIconFile={#MyAppDir}\app\pyfa.ico
|
||||
SolidCompression=yes
|
||||
|
||||
[Languages]
|
||||
|
||||
@@ -51,7 +51,7 @@ mapper(DynamicItemAttribute, dynamicAttributes_table,
|
||||
properties={"info": relation(AttributeInfo, lazy=False)})
|
||||
|
||||
mapper(DynamicItemItem, dynamicApplicable_table, properties={
|
||||
"mutaplasmid": relation(DynamicItem),
|
||||
"mutaplasmid": relation(DynamicItem, viewonly=True),
|
||||
})
|
||||
|
||||
DynamicItemAttribute.ID = association_proxy("info", "attributeID")
|
||||
|
||||
@@ -69,7 +69,8 @@ props = {
|
||||
primaryjoin=dynamicApplicable_table.c.applicableTypeID == items_table.c.typeID,
|
||||
secondaryjoin=dynamicApplicable_table.c.typeID == DynamicItem.typeID,
|
||||
secondary=dynamicApplicable_table,
|
||||
backref="applicableItems"
|
||||
backref="applicableItems",
|
||||
viewonly=True
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -175,12 +175,13 @@ mapper(es_Fit, fits_table,
|
||||
collection_class=HandledModuleList,
|
||||
primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == False), # noqa
|
||||
order_by=modules_table.c.position,
|
||||
overlaps='owner',
|
||||
cascade='all, delete, delete-orphan'),
|
||||
"_Fit__projectedModules": relation(
|
||||
Module,
|
||||
collection_class=HandledProjectedModList,
|
||||
overlaps='owner, _Fit__modules',
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == True)), # noqa
|
||||
"owner": relation(
|
||||
User,
|
||||
@@ -190,37 +191,37 @@ mapper(es_Fit, fits_table,
|
||||
"_Fit__boosters": relation(
|
||||
Booster,
|
||||
collection_class=HandledBoosterList,
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True),
|
||||
overlaps='owner',
|
||||
cascade='all, delete, delete-orphan'),
|
||||
"_Fit__drones": relation(
|
||||
Drone,
|
||||
collection_class=HandledDroneCargoList,
|
||||
overlaps='owner',
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == False)), # noqa
|
||||
"_Fit__fighters": relation(
|
||||
Fighter,
|
||||
collection_class=HandledDroneCargoList,
|
||||
overlaps='owner',
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == False)), # noqa
|
||||
"_Fit__cargo": relation(
|
||||
Cargo,
|
||||
collection_class=HandledDroneCargoList,
|
||||
overlaps='owner',
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(cargo_table.c.fitID == fits_table.c.ID)),
|
||||
"_Fit__projectedDrones": relation(
|
||||
Drone,
|
||||
collection_class=HandledProjectedDroneList,
|
||||
overlaps='owner, _Fit__drones',
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == True)), # noqa
|
||||
"_Fit__projectedFighters": relation(
|
||||
Fighter,
|
||||
collection_class=HandledProjectedDroneList,
|
||||
overlaps='owner, _Fit__fighters',
|
||||
cascade='all, delete, delete-orphan',
|
||||
single_parent=True,
|
||||
primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == True)), # noqa
|
||||
"_Fit__implants": relation(
|
||||
Implant,
|
||||
|
||||
2960
eos/effects.py
@@ -66,7 +66,7 @@ BUILTINS = OrderedDict([
|
||||
(-25, (_c(_t('Condenser Packs')) + _t('SlamBolt'), 23376, 0, 76624, 0)),
|
||||
(-26, (_c(_t('Condenser Packs')) + _t('BlastShot'), 19820, 0, 80180, 0)),
|
||||
(-27, (_c(_t('Condenser Packs')) + _t('GalvaSurge'), 80206, 0, 19794, 0)),
|
||||
(-28, (_c(_t('Condenser Packs')) + '|' + _t('[T2] ElectroPunch'), 0, 50547, 0, 49453)),
|
||||
(-28, (_c(_t('Condenser Packs')) + '|' + _t('[T2] ElectroPunch'), 50547, 0, 49453, 0)),
|
||||
|
||||
(-29, (_c(_t('Hybrid Charges')) + '|' + _t('[T2] Spike'), 0, 4, 4, 0)),
|
||||
(-30, (_c(_t('Hybrid Charges')) + '|' + _t('[T2] Null'), 0, 6, 5, 0)),
|
||||
@@ -216,11 +216,11 @@ class DamagePattern:
|
||||
pattern.builtin = True
|
||||
cls._builtins[id] = pattern
|
||||
|
||||
def calculateEhp(self, fit):
|
||||
def calculateEhp(self, item):
|
||||
ehp = {}
|
||||
for (type, attr) in (('shield', 'shieldCapacity'), ('armor', 'armorHP'), ('hull', 'hp')):
|
||||
rawCapacity = fit.ship.getModifiedItemAttr(attr)
|
||||
ehp[type] = self.effectivify(fit, rawCapacity, type)
|
||||
rawCapacity = item.getModifiedItemAttr(attr)
|
||||
ehp[type] = self.effectivify(item, rawCapacity, type)
|
||||
|
||||
return ehp
|
||||
|
||||
@@ -236,10 +236,10 @@ class DamagePattern:
|
||||
ereps = {}
|
||||
for field in tankInfo:
|
||||
if field in typeMap:
|
||||
ereps[field] = self.effectivify(fit, tankInfo[field], typeMap[field])
|
||||
ereps[field] = self.effectivify(fit.ship, tankInfo[field], typeMap[field])
|
||||
return ereps
|
||||
|
||||
def effectivify(self, fit, amount, type):
|
||||
def effectivify(self, item, amount, type):
|
||||
type = type if type != "hull" else ""
|
||||
totalDamage = sum((self.emAmount, self.thermalAmount, self.kineticAmount, self.explosiveAmount))
|
||||
specificDivider = 0
|
||||
@@ -248,7 +248,7 @@ class DamagePattern:
|
||||
attrName = "%s%sDamageResonance" % (type, damageType.capitalize())
|
||||
attrName = attrName[0].lower() + attrName[1:]
|
||||
|
||||
resonance = fit.ship.getModifiedItemAttr(attrName)
|
||||
resonance = item.getModifiedItemAttr(attrName)
|
||||
damage = getattr(self, "%sAmount" % damageType)
|
||||
|
||||
specificDivider += damage / float(totalDamage or 1) * resonance
|
||||
|
||||
@@ -82,6 +82,7 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, Mu
|
||||
self.__baseRRAmount = None
|
||||
self.__miningYield = None
|
||||
self.__miningWaste = None
|
||||
self.__ehp = None
|
||||
self.__itemModifiedAttributes = ModifiedAttributeDict()
|
||||
self.__itemModifiedAttributes.original = self._item.attributes
|
||||
self.__itemModifiedAttributes.overrides = self._item.overrides
|
||||
@@ -287,6 +288,29 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, Mu
|
||||
if delay is not None and speed is not None:
|
||||
return delay / 1000.0 * speed
|
||||
|
||||
@property
|
||||
def hp(self):
|
||||
hp = {}
|
||||
for (type, attr) in (('shield', 'shieldCapacity'), ('armor', 'armorHP'), ('hull', 'hp')):
|
||||
hp[type] = self.getModifiedItemAttr(attr)
|
||||
|
||||
return hp
|
||||
|
||||
@property
|
||||
def ehp(self):
|
||||
if self.__ehp is None:
|
||||
if self.owner is None or self.owner.damagePattern is None:
|
||||
ehp = self.hp
|
||||
else:
|
||||
ehp = self.owner.damagePattern.calculateEhp(self)
|
||||
self.__ehp = ehp
|
||||
return self.__ehp
|
||||
|
||||
def calculateShieldRecharge(self):
|
||||
capacity = self.getModifiedItemAttr("shieldCapacity")
|
||||
rechargeRate = self.getModifiedItemAttr("shieldRechargeRate") / 1000.0
|
||||
return 10 / rechargeRate * math.sqrt(0.25) * (1 - math.sqrt(0.25)) * capacity
|
||||
|
||||
# Had to add this to match the falloff property in modules.py
|
||||
# Fscking ship scanners. If you find any other falloff attributes,
|
||||
# Put them in the attrs tuple.
|
||||
@@ -318,6 +342,7 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, Mu
|
||||
self.__baseRRAmount = None
|
||||
self.__miningYield = None
|
||||
self.__miningWaste = None
|
||||
self.__ehp = None
|
||||
self.itemModifiedAttributes.clear()
|
||||
self.chargeModifiedAttributes.clear()
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
self.__charge = None
|
||||
self.__baseVolley = None
|
||||
self.__miningyield = None
|
||||
self.__ehp = None
|
||||
self.__itemModifiedAttributes = ModifiedAttributeDict()
|
||||
self.__chargeModifiedAttributes = ModifiedAttributeDict()
|
||||
|
||||
@@ -345,6 +346,29 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
if falloff is not None:
|
||||
return falloff
|
||||
|
||||
@property
|
||||
def hp(self):
|
||||
hp = {}
|
||||
for (type, attr) in (('shield', 'shieldCapacity'), ('armor', 'armorHP'), ('hull', 'hp')):
|
||||
hp[type] = self.getModifiedItemAttr(attr)
|
||||
|
||||
return hp
|
||||
|
||||
@property
|
||||
def ehp(self):
|
||||
if self.__ehp is None:
|
||||
if self.owner is None or self.owner.damagePattern is None:
|
||||
ehp = self.hp
|
||||
else:
|
||||
ehp = self.owner.damagePattern.calculateEhp(self)
|
||||
self.__ehp = ehp
|
||||
return self.__ehp
|
||||
|
||||
def calculateShieldRecharge(self):
|
||||
capacity = self.getModifiedItemAttr("shieldCapacity")
|
||||
rechargeRate = self.getModifiedItemAttr("shieldRechargeRate") / 1000.0
|
||||
return 10 / rechargeRate * math.sqrt(0.25) * (1 - math.sqrt(0.25)) * capacity
|
||||
|
||||
@validates("ID", "itemID", "chargeID", "amount")
|
||||
def validator(self, key, val):
|
||||
map = {
|
||||
@@ -361,6 +385,7 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
def clear(self):
|
||||
self.__baseVolley = None
|
||||
self.__miningyield = None
|
||||
self.__ehp = None
|
||||
self.itemModifiedAttributes.clear()
|
||||
self.chargeModifiedAttributes.clear()
|
||||
[x.clear() for x in self.abilities]
|
||||
|
||||
@@ -159,6 +159,12 @@ class Fit:
|
||||
self.gangBoosts = None
|
||||
self.__ecmProjectedList = []
|
||||
self.commandBonuses = {}
|
||||
# Reps received, as a list of (amount, cycle time in seconds)
|
||||
self._hullRr = []
|
||||
self._armorRr = []
|
||||
self._armorRrPreSpool = []
|
||||
self._armorRrFullSpool = []
|
||||
self._shieldRr = []
|
||||
|
||||
def clearFactorReloadDependentData(self):
|
||||
# Here we clear all data known to rely on cycle parameters
|
||||
@@ -550,6 +556,12 @@ class Fit:
|
||||
if stuff is not None and stuff != self:
|
||||
stuff.clear()
|
||||
|
||||
self._hullRr.clear()
|
||||
self._armorRr.clear()
|
||||
self._armorRrPreSpool.clear()
|
||||
self._armorRrFullSpool.clear()
|
||||
self._shieldRr.clear()
|
||||
|
||||
# If this is the active fit that we are clearing, not a projected fit,
|
||||
# then this will run and clear the projected ships and flag the next
|
||||
# iteration to skip this part to prevent recursion.
|
||||
@@ -621,7 +633,7 @@ class Fit:
|
||||
"duration", value)
|
||||
|
||||
if warfareBuffID == 12: # Shield Burst: Shield Extension: Shield HP
|
||||
self.ship.boostItemAttr("shieldCapacity", value, stackingPenalties=True)
|
||||
self.ship.boostItemAttr("shieldCapacity", value)
|
||||
|
||||
if warfareBuffID == 13: # Armor Burst: Armor Energizing: Armor Resistance
|
||||
for damageType in ("Em", "Thermal", "Explosive", "Kinetic"):
|
||||
@@ -640,7 +652,7 @@ class Fit:
|
||||
"duration", value)
|
||||
|
||||
if warfareBuffID == 15: # Armor Burst: Armor Reinforcement: Armor HP
|
||||
self.ship.boostItemAttr("armorHP", value, stackingPenalties=True)
|
||||
self.ship.boostItemAttr("armorHP", value)
|
||||
|
||||
if warfareBuffID == 16: # Information Burst: Sensor Optimization: Scan Resolution
|
||||
self.ship.boostItemAttr("scanResolution", value, stackingPenalties=True)
|
||||
@@ -734,7 +746,7 @@ class Fit:
|
||||
self.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 42: # Erebus Effect Generator : Armor HP bonus
|
||||
self.ship.boostItemAttr("armorHP", value, stackingPenalties=True)
|
||||
self.ship.boostItemAttr("armorHP", value)
|
||||
|
||||
if warfareBuffID == 43: # Erebus Effect Generator : Explosive resistance bonus
|
||||
for attr in ("armorExplosiveDamageResonance", "shieldExplosiveDamageResonance", "explosiveDamageResonance"):
|
||||
@@ -756,7 +768,7 @@ class Fit:
|
||||
self.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 48: # Leviathan Effect Generator : Shield HP bonus
|
||||
self.ship.boostItemAttr("shieldCapacity", value, stackingPenalties=True)
|
||||
self.ship.boostItemAttr("shieldCapacity", value)
|
||||
|
||||
if warfareBuffID == 49: # Leviathan Effect Generator : EM resistance bonus
|
||||
for attr in ("armorEmDamageResonance", "shieldEmDamageResonance", "emDamageResonance"):
|
||||
@@ -870,6 +882,14 @@ class Fit:
|
||||
if warfareBuffID == 100: # Weather_caustic_toxin_scan_resolution_bonus
|
||||
self.ship.boostItemAttr("scanResolution", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 2405: # Insurgency Suppression Bonus: Interdiction Range
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Navigation"),
|
||||
"maxRange", value, stackingPenalties=True)
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.group.name == "Stasis Web",
|
||||
"maxRange", value, stackingPenalties=True)
|
||||
|
||||
del self.commandBonuses[warfareBuffID]
|
||||
|
||||
def __resetDependentCalcs(self):
|
||||
@@ -1469,7 +1489,7 @@ class Fit:
|
||||
if self.damagePattern is None:
|
||||
ehp = self.hp
|
||||
else:
|
||||
ehp = self.damagePattern.calculateEhp(self)
|
||||
ehp = self.damagePattern.calculateEhp(self.ship)
|
||||
self.__ehp = ehp
|
||||
|
||||
return self.__ehp
|
||||
@@ -1478,11 +1498,11 @@ class Fit:
|
||||
def tank(self):
|
||||
reps = {
|
||||
"passiveShield": self.calculateShieldRecharge(),
|
||||
"shieldRepair": self.extraAttributes["shieldRepair"],
|
||||
"armorRepair": self.extraAttributes["armorRepair"],
|
||||
"armorRepairPreSpool": self.extraAttributes["armorRepairPreSpool"],
|
||||
"armorRepairFullSpool": self.extraAttributes["armorRepairFullSpool"],
|
||||
"hullRepair": self.extraAttributes["hullRepair"]
|
||||
"shieldRepair": self.extraAttributes["shieldRepair"] + self._getAppliedShieldRr(),
|
||||
"armorRepair": self.extraAttributes["armorRepair"] + self._getAppliedArmorRr(),
|
||||
"armorRepairPreSpool": self.extraAttributes["armorRepairPreSpool"] + self._getAppliedArmorPreSpoolRr(),
|
||||
"armorRepairFullSpool": self.extraAttributes["armorRepairFullSpool"] + self._getAppliedArmorFullSpoolRr(),
|
||||
"hullRepair": self.extraAttributes["hullRepair"] + self._getAppliedHullRr()
|
||||
}
|
||||
return reps
|
||||
|
||||
@@ -1519,11 +1539,11 @@ class Fit:
|
||||
if self.__sustainableTank is None:
|
||||
sustainable = {
|
||||
"passiveShield": self.calculateShieldRecharge(),
|
||||
"shieldRepair": self.extraAttributes["shieldRepair"],
|
||||
"armorRepair": self.extraAttributes["armorRepair"],
|
||||
"armorRepairPreSpool": self.extraAttributes["armorRepairPreSpool"],
|
||||
"armorRepairFullSpool": self.extraAttributes["armorRepairFullSpool"],
|
||||
"hullRepair": self.extraAttributes["hullRepair"]
|
||||
"shieldRepair": self.extraAttributes["shieldRepair"] + self._getAppliedShieldRr(),
|
||||
"armorRepair": self.extraAttributes["armorRepair"] + self._getAppliedArmorRr(),
|
||||
"armorRepairPreSpool": self.extraAttributes["armorRepairPreSpool"] + self._getAppliedArmorPreSpoolRr(),
|
||||
"armorRepairFullSpool": self.extraAttributes["armorRepairFullSpool"] + self._getAppliedArmorFullSpoolRr(),
|
||||
"hullRepair": self.extraAttributes["hullRepair"] + self._getAppliedHullRr()
|
||||
}
|
||||
if not self.capStable or self.factorReload:
|
||||
# Map a local repairer type to the attribute it uses
|
||||
@@ -1760,6 +1780,38 @@ class Fit:
|
||||
mults.setdefault(stackingGroup, []).append((1 + strength / 100, None))
|
||||
return calculateMultiplier(mults)
|
||||
|
||||
def _getAppliedHullRr(self):
|
||||
return self.__getAppliedRr(self._hullRr)
|
||||
|
||||
def _getAppliedArmorRr(self):
|
||||
return self.__getAppliedRr(self._armorRr)
|
||||
|
||||
def _getAppliedArmorPreSpoolRr(self):
|
||||
return self.__getAppliedRr(self._armorRrPreSpool)
|
||||
|
||||
def _getAppliedArmorFullSpoolRr(self):
|
||||
return self.__getAppliedRr(self._armorRrFullSpool)
|
||||
|
||||
def _getAppliedShieldRr(self):
|
||||
return self.__getAppliedRr(self._shieldRr)
|
||||
|
||||
@staticmethod
|
||||
def __getAppliedRr(rrList):
|
||||
totalRaw = 0
|
||||
for amount, cycleTime in rrList:
|
||||
# That's right, for considerations of RR diminishing returns cycle time is rounded this way
|
||||
totalRaw += amount / int(cycleTime)
|
||||
RR_ADDITION = 7000
|
||||
RR_MULTIPLIER = 10
|
||||
appliedRr = 0
|
||||
for amount, cycleTime in rrList:
|
||||
rrps = amount / int(cycleTime)
|
||||
modified_rrps = RR_ADDITION + (rrps * RR_MULTIPLIER)
|
||||
rrps_mult = 1 - (((rrps + modified_rrps) / (totalRaw + modified_rrps)) - 1) ** 2
|
||||
appliedRr += rrps_mult * amount / cycleTime
|
||||
return appliedRr
|
||||
|
||||
|
||||
def __deepcopy__(self, memo=None):
|
||||
fitCopy = Fit()
|
||||
# Character and owner are not copied
|
||||
|
||||
@@ -477,7 +477,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
# Some delay attributes have non-0 default value, so we have to pick according to effects
|
||||
if {'superWeaponAmarr', 'superWeaponCaldari', 'superWeaponGallente', 'superWeaponMinmatar', 'lightningWeapon'}.intersection(self.item.effects):
|
||||
dmgDelay = self.getModifiedItemAttr("damageDelayDuration", 0)
|
||||
elif {'doomsdayBeamDOT', 'doomsdaySlash', 'doomsdayConeDOT'}.intersection(self.item.effects):
|
||||
elif {'doomsdayBeamDOT', 'doomsdaySlash', 'doomsdayConeDOT', 'debuffLance'}.intersection(self.item.effects):
|
||||
dmgDelay = self.getModifiedItemAttr("doomsdayWarningDuration", 0)
|
||||
else:
|
||||
dmgDelay = 0
|
||||
@@ -696,16 +696,22 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, M
|
||||
return False
|
||||
|
||||
# Check max group fitted
|
||||
max = self.getModifiedItemAttr("maxGroupFitted")
|
||||
if max:
|
||||
current = 0 # if self.owner != fit else -1 # Disabled, see #1278
|
||||
for mod in fit.modules:
|
||||
if (mod.item and mod.item.groupID == self.item.groupID and
|
||||
self.getModPosition(fit) != mod.getModPosition(fit)):
|
||||
current += 1
|
||||
# use raw value, since it seems what EVE uses. Example is FAXes with their capacitor boosters,
|
||||
# which have unmodified value of 10, and modified of 1, and you can actually fit multiples
|
||||
try:
|
||||
max = self.item.attributes.get('maxGroupFitted').value
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if max:
|
||||
current = 0 # if self.owner != fit else -1 # Disabled, see #1278
|
||||
for mod in fit.modules:
|
||||
if (mod.item and mod.item.groupID == self.item.groupID and
|
||||
self.getModPosition(fit) != mod.getModPosition(fit)):
|
||||
current += 1
|
||||
|
||||
if current >= max:
|
||||
return False
|
||||
if current >= max:
|
||||
return False
|
||||
|
||||
# Check this only if we're told to do so
|
||||
if hardpointLimit:
|
||||
|
||||
@@ -211,7 +211,7 @@ def getDoomsdayMult(mod, tgt, distance, tgtSigRadius):
|
||||
# Disallow only against subcaps, allow against caps and tgt profiles
|
||||
if tgt.isFit and not tgt.item.ship.item.requiresSkill('Capital Ships'):
|
||||
return 0
|
||||
damageSig = mod.getModifiedItemAttr('doomsdayDamageRadius') or mod.getModifiedItemAttr('signatureRadius')
|
||||
damageSig = mod.getModifiedItemAttr('signatureRadius')
|
||||
if not damageSig:
|
||||
return 1
|
||||
return min(1, tgtSigRadius / damageSig)
|
||||
|
||||
@@ -66,7 +66,7 @@ class FitShieldRegenGraph(FitGraph):
|
||||
('shieldAmount', '%'): lambda v, src, tgt: v / 100 * src.item.ship.getModifiedItemAttr('shieldCapacity'),
|
||||
('shieldAmountT0', '%'): lambda v, src, tgt: None if v is None else v / 100 * src.item.ship.getModifiedItemAttr('shieldCapacity'),
|
||||
# Needed only for "x mark" support, to convert EHP x into normalized value
|
||||
('shieldAmount', 'EHP'): lambda v, src, tgt: v / src.item.damagePattern.effectivify(src.item, 1, 'shield')}
|
||||
('shieldAmount', 'EHP'): lambda v, src, tgt: v / src.item.damagePattern.effectivify(src.item.ship, 1, 'shield')}
|
||||
_limiters = {
|
||||
'shieldAmount': lambda src, tgt: (0, src.item.ship.getModifiedItemAttr('shieldCapacity')),
|
||||
'shieldAmountT0': lambda src, tgt: (0, src.item.ship.getModifiedItemAttr('shieldCapacity'))}
|
||||
@@ -77,5 +77,5 @@ class FitShieldRegenGraph(FitGraph):
|
||||
('shieldAmount', 'shieldRegen'): ShieldAmount2ShieldRegenGetter}
|
||||
_denormalizers = {
|
||||
('shieldAmount', '%'): lambda v, src, tgt: v * 100 / src.item.ship.getModifiedItemAttr('shieldCapacity'),
|
||||
('shieldAmount', 'EHP'): lambda v, src, tgt: src.item.damagePattern.effectivify(src.item, v, 'shield'),
|
||||
('shieldRegen', 'EHP/s'): lambda v, src, tgt: src.item.damagePattern.effectivify(src.item, v, 'shield')}
|
||||
('shieldAmount', 'EHP'): lambda v, src, tgt: src.item.damagePattern.effectivify(src.item.ship, v, 'shield'),
|
||||
('shieldRegen', 'EHP/s'): lambda v, src, tgt: src.item.damagePattern.effectivify(src.item.ship, v, 'shield')}
|
||||
|
||||
@@ -114,7 +114,7 @@ class GraphFrame(AuxiliaryFrame):
|
||||
newW = max(curW, bestW)
|
||||
newH = max(curH, bestH)
|
||||
if newW > curW or newH > curH:
|
||||
newSize = wx.Size(newW, newH)
|
||||
newSize = wx.Size(round(newW), round(newH))
|
||||
self.SetSize(newSize)
|
||||
self.SetMinSize(newSize)
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class VectorPicker(wx.Window):
|
||||
self._directionOnly = kwargs.pop('directionOnly', False)
|
||||
super().__init__(*args, **kwargs)
|
||||
self._fontsize = max(1, float(kwargs.pop('fontsize', 8 / self.GetContentScaleFactor())))
|
||||
self._font = wx.Font(self._fontsize, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False)
|
||||
self._font = wx.Font(round(self._fontsize), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False)
|
||||
self._angle = 0
|
||||
self.__length = 1
|
||||
self._left = False
|
||||
@@ -76,7 +76,7 @@ class VectorPicker(wx.Window):
|
||||
self.__length = newLength
|
||||
|
||||
def DoGetBestSize(self):
|
||||
return wx.Size(self._size, self._size)
|
||||
return wx.Size(round(self._size), round(self._size))
|
||||
|
||||
def AcceptsFocusFromKeyboard(self):
|
||||
return False
|
||||
@@ -121,35 +121,37 @@ class VectorPicker(wx.Window):
|
||||
|
||||
radius = min(width, height) / 2 - 2
|
||||
dc.SetBrush(wx.WHITE_BRUSH)
|
||||
dc.DrawCircle(radius + 2, radius + 2, radius)
|
||||
dc.DrawCircle(round(radius + 2), round(radius + 2), round(radius))
|
||||
a = math.radians(self._angle + self._offset)
|
||||
x = math.cos(a) * radius
|
||||
y = math.sin(a) * radius
|
||||
# See PR #2260 on why this is needed
|
||||
pointRadius = 2 / self.GetContentScaleFactor() if 'wxGTK' in wx.PlatformInfo else 2
|
||||
dc.DrawLine(radius + 2, radius + 2, radius + 2 + x * self._length, radius + 2 - y * self._length)
|
||||
dc.DrawLine(
|
||||
round(radius + 2), round(radius + 2),
|
||||
round(radius + 2 + x * self._length), round(radius + 2 - y * self._length))
|
||||
dc.SetBrush(wx.BLACK_BRUSH)
|
||||
dc.DrawCircle(radius + 2 + x * self._length, radius + 2 - y * self._length, pointRadius)
|
||||
dc.DrawCircle(round(radius + 2 + x * self._length), round(radius + 2 - y * self._length), round(pointRadius))
|
||||
|
||||
if self._label:
|
||||
labelText = self._label
|
||||
labelTextW, labelTextH = dc.GetTextExtent(labelText)
|
||||
labelTextX = (radius * 2 + 4 - labelTextW) if (self._labelpos & 1) else 0
|
||||
labelTextY = (radius * 2 + 4 - labelTextH) if (self._labelpos & 2) else 0
|
||||
dc.DrawText(labelText, labelTextX, labelTextY)
|
||||
dc.DrawText(labelText, round(labelTextX), round(labelTextY))
|
||||
|
||||
if not self._directionOnly:
|
||||
lengthText = '%d%%' % (100 * self._length,)
|
||||
lengthTextW, lengthTextH = dc.GetTextExtent(lengthText)
|
||||
lengthTextX = radius + 2 + x / 2 - y / 3 - lengthTextW / 2
|
||||
lengthTextY = radius + 2 - y / 2 - x / 3 - lengthTextH / 2
|
||||
dc.DrawText(lengthText, lengthTextX, lengthTextY)
|
||||
dc.DrawText(lengthText, round(lengthTextX), round(lengthTextY))
|
||||
|
||||
angleText = '%d\u00B0' % (self._angle,)
|
||||
angleTextW, angleTextH = dc.GetTextExtent(angleText)
|
||||
angleTextX = radius + 2 - x / 2 - angleTextW / 2
|
||||
angleTextY = radius + 2 + y / 2 - angleTextH / 2
|
||||
dc.DrawText(angleText, angleTextX, angleTextY)
|
||||
dc.DrawText(angleText, round(angleTextX), round(angleTextY))
|
||||
|
||||
def OnEraseBackground(self, event):
|
||||
pass
|
||||
|
||||
@@ -199,7 +199,7 @@ def _getAutoResists(fit):
|
||||
armorHp = hpData['armor']
|
||||
hullHp = hpData['hull']
|
||||
uniformDamagePattern = DamagePattern(emAmount=25, thermalAmount=25, kineticAmount=25, explosiveAmount=25)
|
||||
ehpData = uniformDamagePattern.calculateEhp(fit)
|
||||
ehpData = uniformDamagePattern.calculateEhp(fit.ship)
|
||||
shieldEhp = ehpData['shield']
|
||||
armorEhp = ehpData['armor']
|
||||
hullEhp = ehpData['hull']
|
||||
|
||||
@@ -212,7 +212,7 @@ class AttributeGauge(wx.Window):
|
||||
for x in range(1, 20):
|
||||
dc.SetBrush(wx.Brush(wx.LIGHT_GREY))
|
||||
dc.SetPen(wx.Pen(wx.LIGHT_GREY))
|
||||
dc.DrawRectangle(x * 10, 1, 1, rect.height)
|
||||
dc.DrawRectangle(round(x * 10), 1, 1, round(rect.height))
|
||||
|
||||
dc.SetBrush(wx.Brush(colour))
|
||||
dc.SetPen(wx.Pen(colour))
|
||||
@@ -222,19 +222,19 @@ class AttributeGauge(wx.Window):
|
||||
|
||||
if value >= 0:
|
||||
padding = (half if is_even else math.ceil(half - 1)) + 1
|
||||
dc.DrawRectangle(padding, 1, w, rect.height)
|
||||
dc.DrawRectangle(round(padding), 1, round(w), round(rect.height))
|
||||
else:
|
||||
padding = half - w + 1 if is_even else math.ceil(half) - (w - 1)
|
||||
dc.DrawRectangle(padding, 1, w, rect.height)
|
||||
dc.DrawRectangle(round(padding), 1, round(w), round(rect.height))
|
||||
|
||||
if self.leading_edge and (self.edge_on_neutral or value != 0):
|
||||
dc.SetPen(wx.Pen(wx.WHITE))
|
||||
dc.SetBrush(wx.Brush(wx.WHITE))
|
||||
|
||||
if value > 0:
|
||||
dc.DrawRectangle(min(padding + w, rect.width), 1, 1, rect.height)
|
||||
dc.DrawRectangle(round(min(padding + w, rect.width)), 1, 1, round(rect.height))
|
||||
else:
|
||||
dc.DrawRectangle(max(padding - 1, 1), 1, 1, rect.height)
|
||||
dc.DrawRectangle(round(max(padding - 1, 1)), 1, 1, round(rect.height))
|
||||
|
||||
def OnTimer(self, event):
|
||||
old_value = self._old_percentage
|
||||
|
||||
@@ -103,10 +103,9 @@ class BitmapLoader:
|
||||
pyfalog.warning("Missing icon file: {0}/{1}".format(location, filename))
|
||||
return None
|
||||
|
||||
bmp: wx.Bitmap = img.ConvertToBitmap()
|
||||
if scale > 1:
|
||||
bmp.SetSize((bmp.GetWidth() // scale, bmp.GetHeight() // scale))
|
||||
return bmp
|
||||
return img.Scale(round(img.GetWidth() // scale), round(img.GetHeight() // scale)).ConvertToBitmap()
|
||||
return img.ConvertToBitmap()
|
||||
|
||||
@classmethod
|
||||
def loadScaledBitmap(cls, name, location, scale=0):
|
||||
|
||||
@@ -66,6 +66,8 @@ class DroneView(Display):
|
||||
"Max Range",
|
||||
"Miscellanea",
|
||||
"attr:maxVelocity",
|
||||
"Drone HP",
|
||||
"Drone Regen",
|
||||
"Price",
|
||||
]
|
||||
|
||||
|
||||
@@ -151,6 +151,8 @@ class FighterDisplay(d.Display):
|
||||
# "Max Range",
|
||||
# "Miscellanea",
|
||||
"attr:maxVelocity",
|
||||
"Drone HP",
|
||||
"Drone Regen",
|
||||
"Fighter Abilities",
|
||||
"Price",
|
||||
]
|
||||
|
||||
@@ -44,7 +44,6 @@ class AddCommandFit(ContextMenuUnconditional):
|
||||
def display(self, callingWindow, srcContext):
|
||||
if self.mainFrame.getActiveFit() is None or len(self.__class__.commandFits) == 0 or srcContext != "commandView":
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def getText(self, callingWindow, itmContext):
|
||||
@@ -52,6 +51,8 @@ class AddCommandFit(ContextMenuUnconditional):
|
||||
|
||||
def addFit(self, menu, fit, includeShip=False):
|
||||
label = fit.name if not includeShip else "({}) {}".format(fit.ship.item.name, fit.name)
|
||||
if not label:
|
||||
label = ' '
|
||||
id = ContextMenuUnconditional.nextID()
|
||||
self.fitMenuItemIds[id] = fit
|
||||
menuItem = wx.MenuItem(menu, id, label)
|
||||
|
||||
@@ -123,9 +123,9 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
|
||||
data.groups[_t('Abyssal Weather')] = self.getAbyssalWeather()
|
||||
data.groups[_t('Sansha Incursion')] = self.getEffectBeacons(
|
||||
_t('ContextMenu|ProjectedEffectManipulation|Sansha Incursion'))
|
||||
data.groups[_t('Triglavian Invasion')] = self.getEffectBeacons(
|
||||
_t('ContextMenu|ProjectedEffectManipulation|Triglavian Invasion'))
|
||||
data.groups[_t('Triglavian Invasion')].groups[_t('Destructible Beacons')] = self.getDestructibleBeacons()
|
||||
data.groups[_t('Triglavian Invasion')] = self.getInvasionBeacons()
|
||||
# data.groups[_t('Pirate Insurgency')] = self.getEffectBeacons(
|
||||
# _t('ContextMenu|ProjectedEffectManipulation|Insurgency'))
|
||||
return data
|
||||
|
||||
def getEffectBeacons(self, *groups, extra_garbage=()):
|
||||
@@ -233,5 +233,19 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
|
||||
data.sort()
|
||||
return data
|
||||
|
||||
def getInvasionBeacons(self):
|
||||
data = self.getDestructibleBeacons()
|
||||
# Turnur weather
|
||||
item = Market.getInstance().getItem(74002)
|
||||
data.items.append(Entry(item.ID, item.name, item.name))
|
||||
return data
|
||||
|
||||
def getInsurgencyBeacons(self):
|
||||
data = self.getDestructibleBeacons()
|
||||
# Suppression Interdiction Range Beacon
|
||||
item = Market.getInstance().getItem(79839)
|
||||
data.items.append(Entry(item.ID, item.name, item.name))
|
||||
return data
|
||||
|
||||
|
||||
AddEnvironmentEffect.register()
|
||||
|
||||
@@ -10,7 +10,10 @@ class AutoListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.ListRowH
|
||||
wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
|
||||
listmix.ListCtrlAutoWidthMixin.__init__(self)
|
||||
listmix.ListRowHighlighter.__init__(self)
|
||||
|
||||
if wx.SystemSettings.GetAppearance().IsDark():
|
||||
listcol = wx.SystemSettings.GetColour(wx.SYS_COLOUR_LISTBOX)
|
||||
highlight = listcol.ChangeLightness(110)
|
||||
listmix.ListRowHighlighter.SetHighlightColor(self, highlight)
|
||||
|
||||
class AutoListCtrlNoHighlight(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.ListRowHighlighter):
|
||||
def __init__(self, parent, ID, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0):
|
||||
|
||||
@@ -36,6 +36,8 @@ class ItemCompare(wx.Panel):
|
||||
self.item = item
|
||||
self.items = sorted(items, key=defaultSort)
|
||||
self.attrs = {}
|
||||
self.HighlightOn = wx.Colour(255, 255, 0, wx.ALPHA_OPAQUE)
|
||||
self.highlightedNames = []
|
||||
|
||||
# get a dict of attrName: attrInfo of all unique attributes across all items
|
||||
for item in self.items:
|
||||
@@ -88,6 +90,21 @@ class ItemCompare(wx.Panel):
|
||||
self.toggleViewBtn.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleViewMode)
|
||||
self.Bind(wx.EVT_LIST_COL_CLICK, self.SortCompareCols)
|
||||
|
||||
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.HighlightRow)
|
||||
|
||||
def HighlightRow(self, event):
|
||||
itemIdx = event.GetIndex()
|
||||
name = self.paramList.GetItem(itemIdx).Text
|
||||
if name in self.highlightedNames:
|
||||
self.highlightedNames.remove(name)
|
||||
else:
|
||||
self.highlightedNames.append(name)
|
||||
self.Freeze()
|
||||
self.paramList.ClearAll()
|
||||
self.PopulateList()
|
||||
self.Thaw()
|
||||
event.Skip()
|
||||
|
||||
def SortCompareCols(self, event):
|
||||
self.Freeze()
|
||||
self.paramList.ClearAll()
|
||||
@@ -155,6 +172,8 @@ class ItemCompare(wx.Panel):
|
||||
self.paramList.InsertColumn(len(self.attrs) + 1, _t("Price"))
|
||||
self.paramList.SetColumnWidth(len(self.attrs) + 1, 60)
|
||||
|
||||
toHighlight = []
|
||||
|
||||
for item in self.items:
|
||||
i = self.paramList.InsertItem(self.paramList.GetItemCount(), item.name)
|
||||
for x, attr in enumerate(self.attrs.keys()):
|
||||
@@ -172,10 +191,19 @@ class ItemCompare(wx.Panel):
|
||||
|
||||
# Add prices
|
||||
self.paramList.SetItem(i, len(self.attrs) + 1, formatAmount(item.price.price, 3, 3, 9, currency=True) if item.price.price else "")
|
||||
if item.name in self.highlightedNames:
|
||||
toHighlight.append(i)
|
||||
|
||||
self.paramList.RefreshRows()
|
||||
self.Layout()
|
||||
|
||||
# Highlight after layout, otherwise colors are getting overwritten
|
||||
for itemIdx in toHighlight:
|
||||
listItem = self.paramList.GetItem(itemIdx)
|
||||
listItem.SetBackgroundColour(self.HighlightOn)
|
||||
listItem.SetFont(listItem.GetFont().MakeBold())
|
||||
self.paramList.SetItem(listItem)
|
||||
|
||||
@staticmethod
|
||||
def TranslateValueUnit(value, unitName, unitDisplayName):
|
||||
def itemIDCallback():
|
||||
|
||||
@@ -253,8 +253,8 @@ class PFSearchBox(wx.Window):
|
||||
else:
|
||||
spad = 0
|
||||
|
||||
dc.DrawBitmap(self.searchBitmapShadow, self.searchButtonX + 1, self.searchButtonY + 1)
|
||||
dc.DrawBitmap(self.searchBitmap, self.searchButtonX + spad, self.searchButtonY + spad)
|
||||
dc.DrawBitmap(self.searchBitmapShadow, round(self.searchButtonX + 1), round(self.searchButtonY + 1))
|
||||
dc.DrawBitmap(self.searchBitmap, round(self.searchButtonX + spad), round(self.searchButtonY + spad))
|
||||
|
||||
if self.isCancelButtonVisible:
|
||||
if self.cancelBitmap:
|
||||
@@ -262,8 +262,8 @@ class PFSearchBox(wx.Window):
|
||||
cpad = 1
|
||||
else:
|
||||
cpad = 0
|
||||
dc.DrawBitmap(self.cancelBitmapShadow, self.cancelButtonX + 1, self.cancelButtonY + 1)
|
||||
dc.DrawBitmap(self.cancelBitmap, self.cancelButtonX + cpad, self.cancelButtonY + cpad)
|
||||
dc.DrawBitmap(self.cancelBitmapShadow, round(self.cancelButtonX + 1), round(self.cancelButtonY + 1))
|
||||
dc.DrawBitmap(self.cancelBitmap, round(self.cancelButtonX + cpad), round(self.cancelButtonY + cpad))
|
||||
|
||||
dc.SetPen(wx.Pen(sepColor, 1))
|
||||
dc.DrawLine(0, rect.height - 1, rect.width, rect.height - 1)
|
||||
|
||||
@@ -40,7 +40,7 @@ class PFGeneralPref(PreferenceView):
|
||||
|
||||
langSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.langChoices = sorted([langInfo for lang, langInfo in LocaleSettings.supported_langauges().items()], key=lambda x: x.Description)
|
||||
self.langChoices = sorted([langInfo for lang, langInfo in LocaleSettings.supported_languages().items()], key=lambda x: x.Description)
|
||||
pyfaLangsEnabled = bool(self.langChoices)
|
||||
|
||||
if pyfaLangsEnabled:
|
||||
@@ -64,7 +64,7 @@ class PFGeneralPref(PreferenceView):
|
||||
langBox.Add(hl.HyperLinkCtrl(panel, -1,
|
||||
_t("Interested in helping with translations?"),
|
||||
URL="https://github.com/pyfa-org/Pyfa/blob/master/locale/README.md"
|
||||
), 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 15)
|
||||
), 0, wx.LEFT, 15)
|
||||
else:
|
||||
self.stLangLabel = wx.StaticText(panel, wx.ID_ANY, _t("Pyfa language selection disabled. Please check if .mo files have been generated.\nRefer to locale/README.md for info."), wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stLangLabel.Wrap(-1)
|
||||
@@ -93,7 +93,7 @@ class PFGeneralPref(PreferenceView):
|
||||
langBox.Add(wx.StaticText(panel, wx.ID_ANY,
|
||||
_t("Auto will use the same language pyfa uses if available, otherwise English"),
|
||||
wx.DefaultPosition,
|
||||
wx.DefaultSize, 0), 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 15)
|
||||
wx.DefaultSize, 0), 0, wx.LEFT, 15)
|
||||
|
||||
self.cbGlobalChar = wx.CheckBox(panel, wx.ID_ANY, _t("Use global character"), wx.DefaultPosition, wx.DefaultSize,
|
||||
0)
|
||||
|
||||
@@ -104,14 +104,14 @@ class CategoryItem(SFBrowserItem):
|
||||
textColor = colorUtils.GetSuitable(windowColor, 1)
|
||||
|
||||
mdc.SetTextForeground(textColor)
|
||||
mdc.DrawBitmap(self.dropShadowBitmap, self.shipBmpx + 1, self.shipBmpy + 1)
|
||||
mdc.DrawBitmap(self.shipBmp, self.shipBmpx, self.shipBmpy, 0)
|
||||
mdc.DrawBitmap(self.dropShadowBitmap, round(self.shipBmpx + 1), round(self.shipBmpy + 1))
|
||||
mdc.DrawBitmap(self.shipBmp, round(self.shipBmpx), round(self.shipBmpy), 0)
|
||||
|
||||
mdc.SetFont(self.fontBig)
|
||||
|
||||
categoryName, fittings = self.fittingInfo
|
||||
|
||||
mdc.DrawText(categoryName, self.catx, self.caty)
|
||||
mdc.DrawText(categoryName, round(self.catx), round(self.caty))
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
||||
@@ -416,9 +416,18 @@ class FitItem(SFItem.SFBrowserItem):
|
||||
if self.dragging:
|
||||
if not self.dragged:
|
||||
if self.dragMotionTrigger < 0:
|
||||
if not self.dragTLFBmp:
|
||||
tdc = wx.MemoryDC()
|
||||
bmpWidth = self.toolbarx if self.toolbarx < 200 else 200
|
||||
self.dragTLFBmp = wx.Bitmap(round(bmpWidth), round(self.GetRect().height))
|
||||
tdc.SelectObject(self.dragTLFBmp)
|
||||
tdc.SetBrush(wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)))
|
||||
tdc.DrawRectangle(0, 0, bmpWidth, self.GetRect().height)
|
||||
self.DrawItem(tdc)
|
||||
tdc.SelectObject(wx.NullBitmap)
|
||||
if not self.HasCapture():
|
||||
self.CaptureMouse()
|
||||
self.dragWindow = PFBitmapFrame(self, pos, self.dragTLFBmp)
|
||||
self.dragWindow = PFBitmapFrame(self, pos, self.dragTLFBmp)
|
||||
self.dragWindow.Show()
|
||||
self.dragged = True
|
||||
self.dragMotionTrigger = self.dragMotionTrail
|
||||
@@ -493,9 +502,9 @@ class FitItem(SFItem.SFBrowserItem):
|
||||
else:
|
||||
shipEffBk = self.shipEffBk
|
||||
|
||||
mdc.DrawBitmap(shipEffBk, self.shipEffx, self.shipEffy, 0)
|
||||
mdc.DrawBitmap(shipEffBk, round(self.shipEffx), round(self.shipEffy), 0)
|
||||
|
||||
mdc.DrawBitmap(self.shipBmp, self.shipBmpx, self.shipBmpy, 0)
|
||||
mdc.DrawBitmap(self.shipBmp, round(self.shipBmpx), round(self.shipBmpy), 0)
|
||||
|
||||
mdc.SetFont(self.fontNormal)
|
||||
|
||||
@@ -504,26 +513,21 @@ class FitItem(SFItem.SFBrowserItem):
|
||||
pfdate = drawUtils.GetPartialText(mdc, fitLocalDate,
|
||||
self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
|
||||
mdc.DrawText(pfdate, self.textStartx, self.timestampy)
|
||||
mdc.DrawText(pfdate, round(self.textStartx), round(self.timestampy))
|
||||
|
||||
mdc.SetFont(self.fontSmall)
|
||||
mdc.DrawText(self.toolbar.hoverLabel, self.thoverx, self.thovery)
|
||||
mdc.DrawText(self.toolbar.hoverLabel, round(self.thoverx), round(self.thovery))
|
||||
|
||||
mdc.SetFont(self.fontBig)
|
||||
|
||||
psname = drawUtils.GetPartialText(mdc, self.fitName,
|
||||
self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
|
||||
mdc.DrawText(psname, self.textStartx, self.fitNamey)
|
||||
mdc.DrawText(psname, round(self.textStartx), round(self.fitNamey))
|
||||
|
||||
if self.tcFitName.IsShown():
|
||||
self.AdjustControlSizePos(self.tcFitName, self.textStartx, self.toolbarx - self.editWidth - self.padding)
|
||||
|
||||
tdc = wx.MemoryDC()
|
||||
self.dragTLFBmp = wx.Bitmap((self.toolbarx if self.toolbarx < 200 else 200), rect.height, 24)
|
||||
tdc.SelectObject(self.dragTLFBmp)
|
||||
tdc.Blit(0, 0, (self.toolbarx if self.toolbarx < 200 else 200), rect.height, mdc, 0, 0, wx.COPY)
|
||||
tdc.SelectObject(wx.NullBitmap)
|
||||
|
||||
def AdjustControlSizePos(self, editCtl, start, end):
|
||||
fnEditSize = editCtl.GetSize()
|
||||
|
||||
@@ -231,7 +231,7 @@ class NavigationPanel(SFItem.SFBrowserItem):
|
||||
|
||||
self.toolbar.SetPosition((self.toolbarx, self.toolbary))
|
||||
mdc.SetFont(self.fontSmall)
|
||||
mdc.DrawText(self.toolbar.hoverLabel, self.thoverx, self.thovery)
|
||||
mdc.DrawText(self.toolbar.hoverLabel, round(self.thoverx), round(self.thovery))
|
||||
mdc.SetPen(wx.Pen(sepColor, 1))
|
||||
mdc.DrawLine(0, rect.height - 1, rect.width, rect.height - 1)
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ class PFBitmapFrame(wx.Frame):
|
||||
# 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)
|
||||
canvas = wx.Bitmap(round(rect.width), round(rect.height))
|
||||
# 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)
|
||||
@@ -63,4 +63,4 @@ class PFBitmapFrame(wx.Frame):
|
||||
mdc.DrawBitmap(self.bitmap, 0, 0)
|
||||
mdc.SetPen(wx.Pen("#000000", width=1))
|
||||
mdc.SetBrush(wx.TRANSPARENT_BRUSH)
|
||||
mdc.DrawRectangle(0, 0, rect.width, rect.height)
|
||||
mdc.DrawRectangle(0, 0, round(rect.width), round(rect.height))
|
||||
|
||||
@@ -57,7 +57,7 @@ class PFListPane(wx.ScrolledWindow):
|
||||
|
||||
posy = self.GetScrollPos(wx.VERTICAL)
|
||||
posy -= self.itemsHeight
|
||||
self.Scroll(0, posy)
|
||||
self.Scroll(0, round(posy))
|
||||
|
||||
event.Skip()
|
||||
|
||||
@@ -65,7 +65,7 @@ class PFListPane(wx.ScrolledWindow):
|
||||
|
||||
posy = self.GetScrollPos(wx.VERTICAL)
|
||||
posy += self.itemsHeight
|
||||
self.Scroll(0, posy)
|
||||
self.Scroll(0, round(posy))
|
||||
|
||||
event.Skip()
|
||||
|
||||
@@ -109,7 +109,7 @@ class PFListPane(wx.ScrolledWindow):
|
||||
|
||||
# if we need to adjust
|
||||
if new_vs_x != -1 or new_vs_y != -1:
|
||||
self.Scroll(new_vs_x, new_vs_y)
|
||||
self.Scroll(round(new_vs_x), round(new_vs_y))
|
||||
|
||||
def AddWidget(self, widget):
|
||||
widget.Reparent(self)
|
||||
|
||||
@@ -68,7 +68,7 @@ class RaceSelector(wx.Window):
|
||||
img = img.Rotate90(False)
|
||||
img.Replace(0, 0, 0, sysTextColour[0], sysTextColour[1], sysTextColour[2])
|
||||
if layout == wx.VERTICAL:
|
||||
img = img.Scale(self.minWidth, 8, wx.IMAGE_QUALITY_HIGH)
|
||||
img = img.Scale(round(self.minWidth), 8, wx.IMAGE_QUALITY_HIGH)
|
||||
|
||||
self.bmpArrow = wx.Bitmap(img)
|
||||
|
||||
@@ -194,25 +194,25 @@ class RaceSelector(wx.Window):
|
||||
bmp = wx.Bitmap(img)
|
||||
|
||||
if self.layout == wx.VERTICAL:
|
||||
mdc.DrawBitmap(dropShadow, rect.width - self.buttonsPadding - bmp.GetWidth() + 1, y + 1)
|
||||
mdc.DrawBitmap(bmp, rect.width - self.buttonsPadding - bmp.GetWidth(), y)
|
||||
mdc.DrawBitmap(dropShadow, round(rect.width - self.buttonsPadding - bmp.GetWidth() + 1), round(y + 1))
|
||||
mdc.DrawBitmap(bmp, round(rect.width - self.buttonsPadding - bmp.GetWidth()), round(y))
|
||||
y += raceBmp.GetHeight() + self.buttonsPadding
|
||||
mdc.SetPen(wx.Pen(sepColor, 1))
|
||||
mdc.DrawLine(rect.width - 1, 0, rect.width - 1, rect.height)
|
||||
else:
|
||||
mdc.DrawBitmap(dropShadow, x + 1, self.buttonsPadding + 1)
|
||||
mdc.DrawBitmap(bmp, x, self.buttonsPadding)
|
||||
mdc.DrawBitmap(dropShadow, round(x + 1), round(self.buttonsPadding + 1))
|
||||
mdc.DrawBitmap(bmp, round(x), round(self.buttonsPadding))
|
||||
x += raceBmp.GetWidth() + self.buttonsPadding
|
||||
mdc.SetPen(wx.Pen(sepColor, 1))
|
||||
mdc.DrawLine(0, 0, rect.width, 0)
|
||||
|
||||
if self.direction < 1:
|
||||
if self.layout == wx.VERTICAL:
|
||||
mdc.DrawBitmap(self.bmpArrow, -2, (rect.height - self.bmpArrow.GetHeight()) / 2)
|
||||
mdc.DrawBitmap(self.bmpArrow, -2, round((rect.height - self.bmpArrow.GetHeight()) / 2))
|
||||
else:
|
||||
mdc.SetPen(wx.Pen(sepColor, 1))
|
||||
mdc.DrawLine(0, 0, rect.width, 0)
|
||||
mdc.DrawBitmap(self.bmpArrow, (rect.width - self.bmpArrow.GetWidth()) / 2, -2)
|
||||
mdc.DrawBitmap(self.bmpArrow, round((rect.width - self.bmpArrow.GetWidth()) / 2), -2)
|
||||
|
||||
def OnTimer(self, event):
|
||||
if event.GetId() == self.animTimerID:
|
||||
|
||||
@@ -233,8 +233,8 @@ class PFToolbar:
|
||||
|
||||
bmpWidth = bmp.GetWidth()
|
||||
|
||||
pdc.DrawBitmap(dropShadowBmp, bx + self.padding / 2, self.toolbarY + self.padding / 2)
|
||||
pdc.DrawBitmap(bmp, tbx, by)
|
||||
pdc.DrawBitmap(dropShadowBmp, round(bx + self.padding / 2), round(self.toolbarY + self.padding / 2))
|
||||
pdc.DrawBitmap(bmp, round(tbx), round(by))
|
||||
|
||||
bx += bmpWidth + self.padding
|
||||
|
||||
|
||||
@@ -247,12 +247,12 @@ class ShipItem(SFItem.SFBrowserItem):
|
||||
else:
|
||||
shipEffBk = self.shipEffBk
|
||||
|
||||
mdc.DrawBitmap(shipEffBk, self.shipEffx, self.shipEffy, 0)
|
||||
mdc.DrawBitmap(shipEffBk, round(self.shipEffx), round(self.shipEffy), 0)
|
||||
|
||||
mdc.DrawBitmap(self.shipBmp, self.shipBmpx, self.shipBmpy, 0)
|
||||
mdc.DrawBitmap(self.shipBmp, round(self.shipBmpx), round(self.shipBmpy), 0)
|
||||
|
||||
mdc.DrawBitmap(self.raceDropShadowBmp, self.raceBmpx + 1, self.raceBmpy + 1)
|
||||
mdc.DrawBitmap(self.raceBmp, self.raceBmpx, self.raceBmpy)
|
||||
mdc.DrawBitmap(self.raceDropShadowBmp, round(self.raceBmpx + 1), round(self.raceBmpy + 1))
|
||||
mdc.DrawBitmap(self.raceBmp, round(self.raceBmpx), round(self.raceBmpy))
|
||||
|
||||
shipName, shipTrait, fittings = self.shipFittingInfo
|
||||
|
||||
@@ -264,17 +264,17 @@ class ShipItem(SFItem.SFBrowserItem):
|
||||
fformat = "%d fits"
|
||||
|
||||
mdc.SetFont(self.fontNormal)
|
||||
mdc.DrawText(fformat % fittings if fittings > 0 else fformat, self.textStartx, self.fittingsy)
|
||||
mdc.DrawText(fformat % fittings if fittings > 0 else fformat, round(self.textStartx), round(self.fittingsy))
|
||||
|
||||
mdc.SetFont(self.fontSmall)
|
||||
mdc.DrawText(self.toolbar.hoverLabel, self.thoverx, self.thovery)
|
||||
mdc.DrawText(self.toolbar.hoverLabel, round(self.thoverx), round(self.thovery))
|
||||
|
||||
mdc.SetFont(self.fontBig)
|
||||
|
||||
psname = drawUtils.GetPartialText(mdc, shipName,
|
||||
self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
|
||||
mdc.DrawText(psname, self.textStartx, self.shipNamey)
|
||||
mdc.DrawText(psname, round(self.textStartx), round(self.shipNamey))
|
||||
|
||||
if self.tcFitName.IsShown():
|
||||
self.AdjustControlSizePos(self.tcFitName, self.textStartx, self.toolbarx - self.editWidth - self.padding)
|
||||
|
||||
@@ -146,8 +146,8 @@ class ResistancesViewFull(StatsView):
|
||||
|
||||
lbl = PyGauge(contentPanel, font, 100)
|
||||
lbl.SetMinSize((48, 16))
|
||||
lbl.SetBackgroundColour(wx.Colour(bc[0], bc[1], bc[2]))
|
||||
lbl.SetBarColour(wx.Colour(fc[0], fc[1], fc[2]))
|
||||
lbl.SetBackgroundColour(wx.Colour(round(bc[0]), round(bc[1]), round(bc[2])))
|
||||
lbl.SetBarColour(wx.Colour(round(fc[0]), round(fc[1]), round(fc[2])))
|
||||
lbl.SetBarGradient()
|
||||
lbl.SetFractionDigits(1)
|
||||
|
||||
|
||||
@@ -127,7 +127,9 @@ class TargetingMiscViewMinimal(StatsView):
|
||||
("specialSalvageHoldCapacity", _t("Salvage hold")),
|
||||
("specialCommandCenterHoldCapacity", _t("Command center hold")),
|
||||
("specialPlanetaryCommoditiesHoldCapacity", _t("Planetary goods hold")),
|
||||
("specialQuafeHoldCapacity", _t("Quafe hold"))))
|
||||
("specialQuafeHoldCapacity", _t("Quafe hold")),
|
||||
("specialMobileDepotHoldCapacity", _t("Mobile depot hold")),
|
||||
))
|
||||
|
||||
cargoValues = {
|
||||
"main": lambda: fit.ship.getModifiedItemAttr("capacity"),
|
||||
@@ -148,7 +150,8 @@ class TargetingMiscViewMinimal(StatsView):
|
||||
"specialSalvageHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialSalvageHoldCapacity"),
|
||||
"specialCommandCenterHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialCommandCenterHoldCapacity"),
|
||||
"specialPlanetaryCommoditiesHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialPlanetaryCommoditiesHoldCapacity"),
|
||||
"specialQuafeHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialQuafeHoldCapacity")
|
||||
"specialQuafeHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialQuafeHoldCapacity"),
|
||||
"specialMobileDepotHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialMobileDepotHoldCapacity"),
|
||||
}
|
||||
|
||||
stats = (("labelTargets", {"main": lambda: fit.maxTargets}, 3, 0, 0, ""),
|
||||
|
||||
87
gui/builtinViewColumns/droneEhp.py
Normal file
@@ -0,0 +1,87 @@
|
||||
# =============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of pyfa.
|
||||
#
|
||||
# pyfa is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pyfa 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
import gui.mainFrame
|
||||
from eos.saveddata.drone import Drone
|
||||
from eos.saveddata.fighter import Fighter
|
||||
from service.attribute import Attribute
|
||||
from gui.viewColumn import ViewColumn
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.utils.numberFormatter import formatAmount
|
||||
|
||||
|
||||
_t = wx.GetTranslation
|
||||
|
||||
|
||||
class DroneEhpColumn(ViewColumn):
|
||||
name = "Drone HP"
|
||||
|
||||
def __init__(self, fittingView, params=None):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
if params is None:
|
||||
params = {"showIcon": True, "displayName": False}
|
||||
|
||||
ViewColumn.__init__(self, fittingView)
|
||||
|
||||
sAttr = Attribute.getInstance()
|
||||
info = sAttr.getAttributeInfo("shieldCapacity")
|
||||
self.info = info
|
||||
if params["showIcon"]:
|
||||
iconFile = info.iconID
|
||||
if iconFile:
|
||||
self.imageId = fittingView.imageList.GetImageIndex(iconFile, "icons")
|
||||
self.bitmap = BitmapLoader.getBitmap(iconFile, "icons")
|
||||
else:
|
||||
self.imageId = -1
|
||||
self.mask = wx.LIST_MASK_IMAGE
|
||||
else:
|
||||
self.imageId = -1
|
||||
|
||||
if params["displayName"] or self.imageId == -1:
|
||||
self.columnText = info.displayName if info.displayName != "" else info.name
|
||||
self.mask |= wx.LIST_MASK_TEXT
|
||||
|
||||
def getText(self, stuff):
|
||||
if not isinstance(stuff, (Drone, Fighter)):
|
||||
return ""
|
||||
if self.mainFrame.statsPane.nameViewMap["resistancesViewFull"].showEffective:
|
||||
ehp = sum(stuff.ehp.values())
|
||||
else:
|
||||
ehp = sum(stuff.hp.values())
|
||||
return formatAmount(ehp, 3, 0, 9)
|
||||
|
||||
def getImageId(self, mod):
|
||||
return -1
|
||||
|
||||
def getParameters(self):
|
||||
return ("displayName", bool, False), ("showIcon", bool, True)
|
||||
|
||||
def getToolTip(self, stuff):
|
||||
if not isinstance(stuff, (Drone, Fighter)):
|
||||
return ""
|
||||
if self.mainFrame.statsPane.nameViewMap["resistancesViewFull"].showEffective:
|
||||
return _t("Effective HP")
|
||||
else:
|
||||
return _t("HP")
|
||||
|
||||
|
||||
DroneEhpColumn.register()
|
||||
81
gui/builtinViewColumns/droneRegen.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# =============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of pyfa.
|
||||
#
|
||||
# pyfa is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pyfa 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
import gui.mainFrame
|
||||
from eos.saveddata.drone import Drone
|
||||
from eos.saveddata.fighter import Fighter
|
||||
from gui.viewColumn import ViewColumn
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.utils.numberFormatter import formatAmount
|
||||
|
||||
|
||||
_t = wx.GetTranslation
|
||||
|
||||
|
||||
class DroneRegenColumn(ViewColumn):
|
||||
name = "Drone Regen"
|
||||
|
||||
def __init__(self, fittingView, params=None):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
if params is None:
|
||||
params = {"showIcon": True, "displayName": False}
|
||||
|
||||
ViewColumn.__init__(self, fittingView)
|
||||
|
||||
if params["showIcon"]:
|
||||
self.imageId = fittingView.imageList.GetImageIndex("shieldPassive_small", "gui")
|
||||
self.bitmap = BitmapLoader.getBitmap("shieldPassive_small", "gui")
|
||||
self.mask = wx.LIST_MASK_IMAGE
|
||||
else:
|
||||
self.imageId = -1
|
||||
|
||||
if params["displayName"] or self.imageId == -1:
|
||||
self.columnText = _("Misc data")
|
||||
self.mask |= wx.LIST_MASK_TEXT
|
||||
|
||||
def getText(self, stuff):
|
||||
if not isinstance(stuff, (Drone, Fighter)):
|
||||
return ""
|
||||
regen = stuff.calculateShieldRecharge()
|
||||
if (
|
||||
self.mainFrame.statsPane.nameViewMap["resistancesViewFull"].showEffective
|
||||
and stuff.owner and stuff.owner.damagePattern is not None
|
||||
):
|
||||
regen = stuff.owner.damagePattern.effectivify(stuff, regen, 'shield')
|
||||
return '{}/s'.format(formatAmount(regen, 3, 0, 9))
|
||||
|
||||
def getImageId(self, mod):
|
||||
return -1
|
||||
|
||||
def getParameters(self):
|
||||
return ("displayName", bool, False), ("showIcon", bool, True)
|
||||
|
||||
def getToolTip(self, stuff):
|
||||
if not isinstance(stuff, (Drone, Fighter)):
|
||||
return ""
|
||||
if self.mainFrame.statsPane.nameViewMap["resistancesViewFull"].showEffective:
|
||||
return _t("Effective Shield Regeneration")
|
||||
else:
|
||||
return _t("Shield Regeneration")
|
||||
|
||||
|
||||
DroneRegenColumn.register()
|
||||
@@ -167,7 +167,7 @@ class Miscellanea(ViewColumn):
|
||||
text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3))
|
||||
tooltip = "Energy neutralization per second"
|
||||
return text, tooltip
|
||||
elif itemGroup == "Salvager":
|
||||
elif itemGroup in ("Salvager", "Salvage Drone"):
|
||||
chance = stuff.getModifiedItemAttr("accessDifficultyBonus")
|
||||
if not chance:
|
||||
return "", None
|
||||
@@ -182,6 +182,13 @@ class Miscellanea(ViewColumn):
|
||||
text = "{0} | {1}".format(formatAmount(strength, 3, 0, 3), formatAmount(coherence, 3, 0, 3))
|
||||
tooltip = "Virus strength and coherence"
|
||||
return text, tooltip
|
||||
elif itemGroup == "Damage Control":
|
||||
duration = stuff.getModifiedItemAttr("duration")
|
||||
if not duration:
|
||||
return "", None
|
||||
text = "{0}s".format(formatAmount(duration / 1000, 3, 0, 0))
|
||||
tooltip = "Assault ability duration"
|
||||
return text, tooltip
|
||||
elif itemGroup in ("Warp Scrambler", "Warp Core Stabilizer", "Structure Warp Scrambler"):
|
||||
scramStr = stuff.getModifiedItemAttr("warpScrambleStrength")
|
||||
if not scramStr:
|
||||
|
||||
@@ -895,7 +895,7 @@ class FittingView(d.Display):
|
||||
opts.m_labelText = name
|
||||
|
||||
if imgId != -1:
|
||||
opts.m_labelBitmap = wx.Bitmap(isize, isize)
|
||||
opts.m_labelBitmap = wx.Bitmap(round(isize), round(isize))
|
||||
|
||||
width = render.DrawHeaderButton(self, tdc, (0, 0, 16, 16), sortArrow=wx.HDR_SORT_ICON_NONE, params=opts)
|
||||
|
||||
@@ -911,7 +911,7 @@ class FittingView(d.Display):
|
||||
maxWidth += columnsWidths[i]
|
||||
|
||||
mdc = wx.MemoryDC()
|
||||
mbmp = wx.Bitmap(maxWidth, maxRowHeight * rows + padding * 4 + headerSize)
|
||||
mbmp = wx.Bitmap(round(maxWidth), round(maxRowHeight * rows + padding * 4 + headerSize))
|
||||
|
||||
mdc.SelectObject(mbmp)
|
||||
|
||||
@@ -956,7 +956,7 @@ class FittingView(d.Display):
|
||||
cx = padding
|
||||
|
||||
if slotMap[st.slot]:
|
||||
mdc.DrawRectangle(cx, cy, maxWidth - cx, maxRowHeight)
|
||||
mdc.DrawRectangle(round(cx), round(cy), round(maxWidth - cx), round(maxRowHeight))
|
||||
|
||||
for i, col in enumerate(self.activeColumns):
|
||||
if i > maxColumns:
|
||||
|
||||
@@ -371,7 +371,7 @@ class SkillTreeView(wx.Panel):
|
||||
bSizerButtons.AddStretchSpacer()
|
||||
|
||||
importExport = ((_t("Import skills from clipboard"), wx.ART_FILE_OPEN, "import"),
|
||||
(_t("Export skills from clipboard"), wx.ART_FILE_SAVE_AS, "export"))
|
||||
(_t("Export skills to clipboard"), wx.ART_FILE_SAVE_AS, "export"))
|
||||
|
||||
for tooltip, art, attr in importExport:
|
||||
bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON)
|
||||
@@ -446,6 +446,7 @@ class SkillTreeView(wx.Panel):
|
||||
|
||||
text = fromClipboard().strip()
|
||||
if text:
|
||||
sCharacter = Character.getInstance()
|
||||
char = self.charEditor.entityEditor.getActiveEntity()
|
||||
try:
|
||||
lines = text.splitlines()
|
||||
@@ -455,7 +456,7 @@ class SkillTreeView(wx.Panel):
|
||||
skill, level = s.rsplit(None, 1)[0], arabicOrRomanToInt(s.rsplit(None, 1)[1])
|
||||
skill = char.getSkill(skill)
|
||||
if skill:
|
||||
skill.setLevel(level, ignoreRestrict=True)
|
||||
sCharacter.changeLevel(char.ID, skill.item.ID, level)
|
||||
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
@@ -516,7 +517,10 @@ class SkillTreeView(wx.Panel):
|
||||
def populateSkillTreeSkillSearch(self, event=None):
|
||||
sChar = Character.getInstance()
|
||||
char = self.charEditor.entityEditor.getActiveEntity()
|
||||
search = self.searchInput.GetLineText(0)
|
||||
try:
|
||||
search = self.searchInput.GetLineText(0)
|
||||
except AttributeError:
|
||||
search = self.searchInput.GetValue()
|
||||
|
||||
root = self.root
|
||||
tree = self.skillTreeListCtrl
|
||||
@@ -530,7 +534,7 @@ class SkillTreeView(wx.Panel):
|
||||
iconId = self.skillBookDirtyImageId
|
||||
|
||||
childId = tree.AppendItem(root, name, iconId, data=('skill', id))
|
||||
tree.SetItemText(childId, 1, _t("Level {}d").format(int(level)) if isinstance(level, float) else level)
|
||||
tree.SetItemText(childId, 1, _t("Level {}").format(int(level)) if isinstance(level, float) else level)
|
||||
|
||||
def populateSkillTree(self, event=None):
|
||||
sChar = Character.getInstance()
|
||||
@@ -588,7 +592,6 @@ class SkillTreeView(wx.Panel):
|
||||
iconId = self.skillBookDirtyImageId
|
||||
|
||||
childId = tree.AppendItem(root, name, iconId, data=('skill', id))
|
||||
|
||||
tree.SetItemText(childId, 1, _t("Level {}").format(int(level)) if isinstance(level, float) else level)
|
||||
|
||||
def spawnMenu(self, event):
|
||||
|
||||
@@ -22,6 +22,7 @@ import traceback
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
import roman
|
||||
from logbook import Logger
|
||||
|
||||
import config
|
||||
@@ -105,6 +106,9 @@ class CharacterSelection(wx.Panel):
|
||||
exportItem = menu.Append(wx.ID_ANY, _t("Copy Missing Skills"))
|
||||
self.Bind(wx.EVT_MENU, self.exportSkills, exportItem)
|
||||
|
||||
exportItem = menu.Append(wx.ID_ANY, _t("Copy Missing Skills (EVEMon)"))
|
||||
self.Bind(wx.EVT_MENU, self.exportSkillsEveMon, exportItem)
|
||||
|
||||
self.PopupMenu(menu, pos)
|
||||
|
||||
event.Skip()
|
||||
@@ -264,6 +268,15 @@ class CharacterSelection(wx.Panel):
|
||||
|
||||
toClipboard(list)
|
||||
|
||||
def exportSkillsEveMon(self, evt):
|
||||
skillsMap = self._buildSkillsTooltipCondensed(self.reqs, skillsMap={})
|
||||
|
||||
list = ""
|
||||
for key in sorted(skillsMap):
|
||||
list += "%s %s\n" % (key, roman.toRoman(skillsMap[key][0]))
|
||||
|
||||
toClipboard(list)
|
||||
|
||||
def _buildSkillsTooltip(self, reqs, currItem="", tabulationLevel=0):
|
||||
tip = ""
|
||||
sCharacter = Character.getInstance()
|
||||
|
||||
@@ -514,7 +514,7 @@ class _TabRenderer:
|
||||
Creates the tab background bitmap based upon calculated dimension values
|
||||
and modified bitmaps via InitBitmaps()
|
||||
"""
|
||||
bk_bmp = wx.Bitmap(self.tab_width, self.tab_height)
|
||||
bk_bmp = wx.Bitmap(round(self.tab_width), round(self.tab_height))
|
||||
|
||||
mdc = wx.MemoryDC()
|
||||
mdc.SelectObject(bk_bmp)
|
||||
@@ -525,16 +525,16 @@ class _TabRenderer:
|
||||
|
||||
# convert middle bitmap and scale to tab width
|
||||
cm = self.ctab_middle_bmp.ConvertToImage()
|
||||
mimg = cm.Scale(self.content_width, self.ctab_middle.GetHeight(),
|
||||
mimg = cm.Scale(round(self.content_width), round(self.ctab_middle.GetHeight()),
|
||||
wx.IMAGE_QUALITY_NORMAL)
|
||||
mbmp = wx.Bitmap(mimg)
|
||||
|
||||
# draw middle bitmap, offset by left
|
||||
mdc.DrawBitmap(mbmp, self.left_width, 0)
|
||||
mdc.DrawBitmap(mbmp, round(self.left_width), 0)
|
||||
|
||||
# draw right bitmap offset by left + middle
|
||||
mdc.DrawBitmap(self.ctab_right_bmp,
|
||||
self.content_width + self.left_width, 0)
|
||||
round(self.content_width + self.left_width), 0)
|
||||
|
||||
mdc.SelectObject(wx.NullBitmap)
|
||||
|
||||
@@ -555,7 +555,7 @@ class _TabRenderer:
|
||||
+ self.left_width \
|
||||
- self.ctab_close_bmp.GetWidth() / 2
|
||||
y_offset = (self.tab_height - self.ctab_close_bmp.GetHeight()) / 2
|
||||
self.close_region.Offset(x_offset, y_offset)
|
||||
self.close_region.Offset(round(x_offset), round(y_offset))
|
||||
|
||||
def InitColors(self):
|
||||
"""Determines colors used for tab, based on system settings"""
|
||||
@@ -573,7 +573,7 @@ class _TabRenderer:
|
||||
|
||||
height = self.tab_height
|
||||
|
||||
canvas = wx.Bitmap(self.tab_width, self.tab_height, 24)
|
||||
canvas = wx.Bitmap(round(self.tab_width), round(self.tab_height), 24)
|
||||
|
||||
mdc = wx.MemoryDC()
|
||||
|
||||
@@ -590,8 +590,8 @@ class _TabRenderer:
|
||||
# Draw tab icon
|
||||
mdc.DrawBitmap(
|
||||
bmp,
|
||||
self.left_width + self.padding - bmp.GetWidth() / 2,
|
||||
(height - bmp.GetHeight()) / 2)
|
||||
round(self.left_width + self.padding - bmp.GetWidth() / 2),
|
||||
round((height - bmp.GetHeight()) / 2))
|
||||
|
||||
# draw close button
|
||||
if self.closeable:
|
||||
@@ -604,8 +604,8 @@ class _TabRenderer:
|
||||
|
||||
mdc.DrawBitmap(
|
||||
cbmp,
|
||||
self.content_width + self.left_width - cbmp.GetWidth() / 2,
|
||||
(height - cbmp.GetHeight()) / 2)
|
||||
round(self.content_width + self.left_width - cbmp.GetWidth() / 2),
|
||||
round((height - cbmp.GetHeight()) / 2))
|
||||
|
||||
mdc.SelectObject(wx.NullBitmap)
|
||||
|
||||
@@ -640,7 +640,7 @@ class _TabRenderer:
|
||||
# draw text (with no ellipses)
|
||||
text = draw.GetPartialText(dc, self.text, maxsize, "")
|
||||
tx, ty = dc.GetTextExtent(text)
|
||||
dc.DrawText(text, text_start + self.padding, height / 2 - ty / 2)
|
||||
dc.DrawText(text, round(text_start + self.padding), round(height / 2 - ty / 2))
|
||||
|
||||
def __repr__(self):
|
||||
return "_TabRenderer(text={}, disabled={}) at {}".format(
|
||||
@@ -1005,7 +1005,7 @@ class _TabsContainer(wx.Panel):
|
||||
|
||||
region = tab.GetCloseButtonRegion()
|
||||
posx, posy = tab.GetPosition()
|
||||
region.Offset(posx, posy)
|
||||
region.Offset(round(posx), round(posy))
|
||||
|
||||
if region.Contains(x, y):
|
||||
index = self.tabs.index(tab)
|
||||
@@ -1036,7 +1036,7 @@ class _TabsContainer(wx.Panel):
|
||||
|
||||
region = self.add_button.GetRegion()
|
||||
ax, ay = self.add_button.GetPosition()
|
||||
region.Offset(ax, ay)
|
||||
region.Offset(round(ax), round(ay))
|
||||
|
||||
if region.Contains(x, y):
|
||||
ev = PageAdding()
|
||||
@@ -1058,7 +1058,7 @@ class _TabsContainer(wx.Panel):
|
||||
for tab in self.tabs:
|
||||
region = tab.GetCloseButtonRegion()
|
||||
posx, posy = tab.GetPosition()
|
||||
region.Offset(posx, posy)
|
||||
region.Offset(round(posx), round(posy))
|
||||
|
||||
if region.Contains(x, y):
|
||||
if not tab.GetCloseButtonHoverStatus():
|
||||
@@ -1093,7 +1093,7 @@ class _TabsContainer(wx.Panel):
|
||||
tabRegion = tab.GetTabRegion()
|
||||
tabPos = tab.GetPosition()
|
||||
tabPosX, tabPosY = tabPos
|
||||
tabRegion.Offset(tabPosX, tabPosY)
|
||||
tabRegion.Offset(round(tabPosX), round(tabPosY))
|
||||
|
||||
if tabRegion.Contains(x, y):
|
||||
return True
|
||||
@@ -1166,7 +1166,7 @@ class _TabsContainer(wx.Panel):
|
||||
|
||||
region = self.add_button.GetRegion()
|
||||
ax, ay = self.add_button.GetPosition()
|
||||
region.Offset(ax, ay)
|
||||
region.Offset(round(ax), round(ay))
|
||||
|
||||
if region.Contains(x, y):
|
||||
if not self.add_button.IsHighlighted():
|
||||
@@ -1198,7 +1198,7 @@ class _TabsContainer(wx.Panel):
|
||||
|
||||
if self.show_add_button:
|
||||
ax, ay = self.add_button.GetPosition()
|
||||
mdc.DrawBitmap(self.add_button.Render(), ax, ay, True)
|
||||
mdc.DrawBitmap(self.add_button.Render(), round(ax), round(ay), True)
|
||||
|
||||
for i in range(len(self.tabs) - 1, -1, -1):
|
||||
tab = self.tabs[i]
|
||||
@@ -1206,14 +1206,14 @@ class _TabsContainer(wx.Panel):
|
||||
|
||||
if not tab.IsSelected():
|
||||
# drop shadow first
|
||||
mdc.DrawBitmap(self.fxBmps[tab], posx, posy, True)
|
||||
mdc.DrawBitmap(self.fxBmps[tab], round(posx), (posy), True)
|
||||
bmp = tab.Render()
|
||||
img = bmp.ConvertToImage()
|
||||
img = img.AdjustChannels(1, 1, 1, 0.85)
|
||||
bmp = wx.Bitmap(img)
|
||||
mdc.DrawBitmap(bmp, posx, posy, True)
|
||||
mdc.DrawBitmap(bmp, round(posx), (posy), True)
|
||||
|
||||
mdc.SetDeviceOrigin(posx, posy)
|
||||
mdc.SetDeviceOrigin(round(posx), round(posy))
|
||||
tab.DrawText(mdc)
|
||||
mdc.SetDeviceOrigin(0, 0)
|
||||
else:
|
||||
@@ -1224,7 +1224,7 @@ class _TabsContainer(wx.Panel):
|
||||
if selected:
|
||||
posx, posy = selected.GetPosition()
|
||||
# drop shadow first
|
||||
mdc.DrawBitmap(self.fxBmps[selected], posx, posy, True)
|
||||
mdc.DrawBitmap(self.fxBmps[selected], round(posx), round(posy), True)
|
||||
|
||||
bmp = selected.Render()
|
||||
|
||||
@@ -1233,9 +1233,9 @@ class _TabsContainer(wx.Panel):
|
||||
img = img.AdjustChannels(1.2, 1.2, 1.2, 0.7)
|
||||
bmp = wx.Bitmap(img)
|
||||
|
||||
mdc.DrawBitmap(bmp, posx, posy, True)
|
||||
mdc.DrawBitmap(bmp, round(posx), round(posy), True)
|
||||
|
||||
mdc.SetDeviceOrigin(posx, posy)
|
||||
mdc.SetDeviceOrigin(round(posx), round(posy))
|
||||
selected.DrawText(mdc)
|
||||
mdc.SetDeviceOrigin(0, 0)
|
||||
|
||||
@@ -1501,7 +1501,7 @@ class PFNotebookPagePreview(wx.Frame):
|
||||
|
||||
def OnWindowPaint(self, event):
|
||||
rect = self.GetRect()
|
||||
canvas = wx.Bitmap(rect.width, rect.height)
|
||||
canvas = wx.Bitmap(round(rect.width), round(rect.height))
|
||||
mdc = wx.BufferedPaintDC(self)
|
||||
mdc.SelectObject(canvas)
|
||||
color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)
|
||||
@@ -1514,7 +1514,7 @@ class PFNotebookPagePreview(wx.Frame):
|
||||
x, y = mdc.GetTextExtent(self.title)
|
||||
|
||||
mdc.SetBrush(wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)))
|
||||
mdc.DrawRectangle(0, 0, rect.width, 16)
|
||||
mdc.DrawRectangle(0, 0, round(rect.width), 16)
|
||||
|
||||
mdc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW))
|
||||
|
||||
@@ -1523,4 +1523,4 @@ class PFNotebookPagePreview(wx.Frame):
|
||||
mdc.SetPen(wx.Pen("#000000", width=1))
|
||||
mdc.SetBrush(wx.TRANSPARENT_BRUSH)
|
||||
|
||||
mdc.DrawRectangle(0, 16, rect.width, rect.height - 16)
|
||||
mdc.DrawRectangle(0, 16, round(rect.width), round(rect.height - 16))
|
||||
|
||||
@@ -193,7 +193,7 @@ class CopySelectDialog(wx.Dialog):
|
||||
|
||||
def exportEsi(self, options, callback):
|
||||
fit = getFit(self.mainFrame.getActiveFit())
|
||||
Port.exportESI(fit, True, callback)
|
||||
Port.exportESI(fit, False, False, False, callback)
|
||||
|
||||
def exportXml(self, options, callback):
|
||||
fit = getFit(self.mainFrame.getActiveFit())
|
||||
|
||||
@@ -29,8 +29,9 @@ class Display(wx.ListCtrl):
|
||||
DEFAULT_COLS = None
|
||||
|
||||
def __init__(self, parent, size=wx.DefaultSize, style=0):
|
||||
|
||||
wx.ListCtrl.__init__(self, parent, size=size, style=wx.LC_REPORT | style)
|
||||
wx.ListCtrl.__init__(self)
|
||||
self.EnableSystemTheme(False)
|
||||
self.Create(parent, size=size, style=wx.LC_REPORT | style)
|
||||
self.imageList = CachingImageList(16, 16)
|
||||
self.SetImageList(self.imageList, wx.IMAGE_LIST_SMALL)
|
||||
self.activeColumns = []
|
||||
|
||||
@@ -268,7 +268,7 @@ class ExportToEve(AuxiliaryFrame):
|
||||
def __init__(self, parent):
|
||||
super().__init__(
|
||||
parent, id=wx.ID_ANY, title=_t("Export fit to EVE"), pos=wx.DefaultPosition,
|
||||
size=wx.Size(400, 140) if "wxGTK" in wx.PlatformInfo else wx.Size(350, 115), resizeable=True)
|
||||
size=wx.Size(400, 175) if "wxGTK" in wx.PlatformInfo else wx.Size(350, 145), resizeable=True)
|
||||
|
||||
self.mainFrame = parent
|
||||
|
||||
@@ -290,6 +290,16 @@ class ExportToEve(AuxiliaryFrame):
|
||||
self.exportChargesCb.Bind(wx.EVT_CHECKBOX, self.OnChargeExportChange)
|
||||
mainSizer.Add(self.exportChargesCb, 0, 0, 5)
|
||||
|
||||
self.exportImplantsCb = wx.CheckBox(self, wx.ID_ANY, _t('Export Implants'), wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.exportImplantsCb.SetValue(EsiSettings.getInstance().get('exportImplants'))
|
||||
self.exportImplantsCb.Bind(wx.EVT_CHECKBOX, self.OnImplantsExportChange)
|
||||
mainSizer.Add(self.exportImplantsCb, 0, 0, 5)
|
||||
|
||||
self.exportBoostersCb = wx.CheckBox(self, wx.ID_ANY, _t('Export Boosters'), wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.exportBoostersCb.SetValue(EsiSettings.getInstance().get('exportBoosters'))
|
||||
self.exportBoostersCb.Bind(wx.EVT_CHECKBOX, self.OnBoostersExportChange)
|
||||
mainSizer.Add(self.exportBoostersCb, 0, 0, 5)
|
||||
|
||||
self.exportBtn.Bind(wx.EVT_BUTTON, self.exportFitting)
|
||||
|
||||
self.statusbar = wx.StatusBar(self)
|
||||
@@ -309,6 +319,14 @@ class ExportToEve(AuxiliaryFrame):
|
||||
EsiSettings.getInstance().set('exportCharges', self.exportChargesCb.GetValue())
|
||||
event.Skip()
|
||||
|
||||
def OnImplantsExportChange(self, event):
|
||||
EsiSettings.getInstance().set('exportImplants', self.exportImplantsCb.GetValue())
|
||||
event.Skip()
|
||||
|
||||
def OnBoostersExportChange(self, event):
|
||||
EsiSettings.getInstance().set('exportBoosters', self.exportBoostersCb.GetValue())
|
||||
event.Skip()
|
||||
|
||||
def updateCharList(self):
|
||||
sEsi = Esi.getInstance()
|
||||
chars = sEsi.getSsoCharacters()
|
||||
@@ -345,8 +363,10 @@ class ExportToEve(AuxiliaryFrame):
|
||||
|
||||
sFit = Fit.getInstance()
|
||||
exportCharges = self.exportChargesCb.GetValue()
|
||||
exportImplants = self.exportImplantsCb.GetValue()
|
||||
exportBoosters = self.exportBoostersCb.GetValue()
|
||||
try:
|
||||
data = sPort.exportESI(sFit.getFit(fitID), exportCharges)
|
||||
data = sPort.exportESI(sFit.getFit(fitID), exportCharges, exportImplants, exportBoosters)
|
||||
except ESIExportException as e:
|
||||
msg = str(e)
|
||||
if not msg:
|
||||
|
||||
@@ -42,7 +42,7 @@ class DmgPatternNameValidator(BaseValidator):
|
||||
return DmgPatternNameValidator()
|
||||
|
||||
def Validate(self, win):
|
||||
entityEditor = win.parent
|
||||
entityEditor = win.Parent.parent
|
||||
textCtrl = self.GetWindow()
|
||||
text = textCtrl.GetValue().strip()
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ class PyGauge(wx.Window):
|
||||
else:
|
||||
w = rect.width * (float(value) / 100)
|
||||
r = copy.copy(rect)
|
||||
r.width = w
|
||||
r.width = round(w)
|
||||
dc.DrawRectangle(r)
|
||||
else:
|
||||
# if bar color is not set, then we use pre-defined transitions
|
||||
@@ -269,7 +269,7 @@ class PyGauge(wx.Window):
|
||||
else:
|
||||
w = rect.width * (float(value) / 100)
|
||||
r = copy.copy(rect)
|
||||
r.width = w
|
||||
r.width = round(w)
|
||||
|
||||
# determine transition range number and calculate xv (which is the
|
||||
# progress between the two transition ranges)
|
||||
@@ -317,7 +317,7 @@ class PyGauge(wx.Window):
|
||||
gradient_color
|
||||
)
|
||||
if gradient_bitmap is not None:
|
||||
dc.DrawBitmap(gradient_bitmap, r.left, r.top)
|
||||
dc.DrawBitmap(gradient_bitmap, round(r.left), round(r.top))
|
||||
|
||||
# font stuff begins here
|
||||
dc.SetFont(self.font)
|
||||
|
||||
@@ -39,7 +39,7 @@ class ImplantTextValidor(BaseValidator):
|
||||
return ImplantTextValidor()
|
||||
|
||||
def Validate(self, win):
|
||||
entityEditor = win.parent
|
||||
entityEditor = win.Parent.parent
|
||||
textCtrl = self.GetWindow()
|
||||
text = textCtrl.GetValue().strip()
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ class TargetProfileNameValidator(BaseValidator):
|
||||
return TargetProfileNameValidator()
|
||||
|
||||
def Validate(self, win):
|
||||
entityEditor = win.parent
|
||||
entityEditor = win.Parent.parent
|
||||
textCtrl = self.GetWindow()
|
||||
text = textCtrl.GetValue().strip()
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ class LoadAnimation(wx.Window):
|
||||
bh = rect.height
|
||||
y = 0
|
||||
|
||||
dc.DrawRectangle(x, y, barWidth, bh)
|
||||
dc.DrawRectangle(round(x), round(y), round(barWidth), round(bh))
|
||||
x += barWidth
|
||||
|
||||
textColor = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)
|
||||
|
||||
@@ -12,7 +12,7 @@ def Brighten(color, factor):
|
||||
b += (255 - b) * factor
|
||||
g += (255 - g) * factor
|
||||
|
||||
return wx.Colour(r, g, b, a)
|
||||
return wx.Colour(round(r), round(g), round(b), round(a))
|
||||
|
||||
|
||||
def Darken(color, factor):
|
||||
@@ -30,7 +30,7 @@ def Darken(color, factor):
|
||||
b = min(max(b, 0), 255)
|
||||
g = min(max(g, 0), 255)
|
||||
|
||||
return wx.Colour(r, g, b, a)
|
||||
return wx.Colour(round(r), round(g), round(b), round(a))
|
||||
|
||||
|
||||
def _getBrightness(color):
|
||||
@@ -70,4 +70,4 @@ def CalculateTransition(s_color, e_color, delta):
|
||||
tG = sG + (eG - sG) * delta
|
||||
tB = sB + (eB - sB) * delta
|
||||
|
||||
return wx.Colour(tR, tG, tB, (sA + eA) / 2)
|
||||
return wx.Colour(round(tR), round(tG), round(tB), round((sA + eA) / 2))
|
||||
|
||||
@@ -21,7 +21,7 @@ def RenderGradientBar(windowColor, width, height, sFactor, eFactor, mFactor=None
|
||||
|
||||
|
||||
def DrawFilledBitmap(width, height, color):
|
||||
canvas = wx.Bitmap(width, height)
|
||||
canvas = wx.Bitmap(round(width), round(height))
|
||||
|
||||
mdc = wx.MemoryDC()
|
||||
mdc.SelectObject(canvas)
|
||||
@@ -37,20 +37,20 @@ def DrawFilledBitmap(width, height, color):
|
||||
def DrawGradientBar(width, height, gStart, gEnd, gMid=None, fillRatio=4):
|
||||
if width == 0 or height == 0:
|
||||
return None
|
||||
canvas = wx.Bitmap(width, height)
|
||||
canvas = wx.Bitmap(round(width), round(height))
|
||||
|
||||
mdc = wx.MemoryDC()
|
||||
mdc.SelectObject(canvas)
|
||||
|
||||
r = wx.Rect(0, 0, width, height)
|
||||
r.SetHeight(height / fillRatio)
|
||||
r.SetHeight(round(height / fillRatio))
|
||||
|
||||
if gMid is None:
|
||||
gMid = gStart
|
||||
|
||||
mdc.GradientFillLinear(r, gStart, gMid, wx.SOUTH)
|
||||
r.SetTop(r.GetHeight())
|
||||
r.SetHeight(height * (fillRatio - 1) / fillRatio + (1 if height % fillRatio != 0 else 0))
|
||||
r.SetHeight(round(height * (fillRatio - 1) / fillRatio + (1 if height % fillRatio != 0 else 0)))
|
||||
|
||||
mdc.GradientFillLinear(r, gMid, gEnd, wx.SOUTH)
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ class exportHtmlThread(threading.Thread):
|
||||
# Market group header
|
||||
HTML += (
|
||||
' <li data-role="collapsible" data-iconpos="right" data-shadow="false" data-corners="false">\n'
|
||||
' <h2>' + group.groupName + ' <span class="ui-li-count">' + str(groupFits) + '</span></h2>\n'
|
||||
' <h2>' + group.name + ' <span class="ui-li-count">' + str(groupFits) + '</span></h2>\n'
|
||||
' <ul data-role="listview" data-shadow="false" data-inset="true" data-corners="false">\n' +
|
||||
HTMLgroup +
|
||||
' </ul>\n'
|
||||
|
||||
@@ -78,6 +78,8 @@ from gui.builtinViewColumns import ( # noqa: E402, F401
|
||||
baseName,
|
||||
capacitorUse,
|
||||
dampScanRes,
|
||||
droneEhp,
|
||||
droneRegen,
|
||||
graphColor,
|
||||
graphLightness,
|
||||
graphLineStyle,
|
||||
|
||||
BIN
imgs/gui/shieldPassive_small.png
Normal file
|
After Width: | Height: | Size: 662 B |
BIN
imgs/icons/1168@1x.png
Normal file
|
After Width: | Height: | Size: 857 B |
BIN
imgs/icons/1168@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
imgs/icons/21831@1x.png
Normal file
|
After Width: | Height: | Size: 812 B |
BIN
imgs/icons/21831@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/icons/21894@1x.png
Normal file
|
After Width: | Height: | Size: 808 B |
BIN
imgs/icons/21894@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/icons/24296@1x.png
Normal file
|
After Width: | Height: | Size: 667 B |
BIN
imgs/icons/24296@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
imgs/icons/24404@1x.png
Normal file
|
After Width: | Height: | Size: 676 B |
BIN
imgs/icons/24404@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
imgs/icons/24411@1x.png
Normal file
|
After Width: | Height: | Size: 849 B |
BIN
imgs/icons/24411@2x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
imgs/icons/24419@1x.png
Normal file
|
After Width: | Height: | Size: 640 B |
BIN
imgs/icons/24419@2x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
imgs/icons/24585@1x.png
Normal file
|
After Width: | Height: | Size: 878 B |
BIN
imgs/icons/24585@2x.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
imgs/icons/25328@1x.png
Normal file
|
After Width: | Height: | Size: 791 B |
BIN
imgs/icons/25328@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
imgs/icons/25329@1x.png
Normal file
|
After Width: | Height: | Size: 769 B |
BIN
imgs/icons/25329@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
imgs/icons/25330@1x.png
Normal file
|
After Width: | Height: | Size: 799 B |
BIN
imgs/icons/25330@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
imgs/icons/25331@1x.png
Normal file
|
After Width: | Height: | Size: 802 B |
BIN
imgs/icons/25331@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
imgs/icons/25355@1x.png
Normal file
|
After Width: | Height: | Size: 796 B |
BIN
imgs/icons/25355@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
imgs/icons/25356@1x.png
Normal file
|
After Width: | Height: | Size: 603 B |
BIN
imgs/icons/25356@2x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
imgs/icons/25467@1x.png
Normal file
|
After Width: | Height: | Size: 605 B |
BIN
imgs/icons/25467@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
imgs/icons/25468@1x.png
Normal file
|
After Width: | Height: | Size: 625 B |
BIN
imgs/icons/25468@2x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
imgs/icons/25621@1x.png
Normal file
|
After Width: | Height: | Size: 825 B |
BIN
imgs/icons/25621@2x.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |