Merge branch 'master' into charImplants

Conflicts:
	gui/characterEditor.py
This commit is contained in:
blitzmann
2015-11-08 21:19:04 -05:00
1885 changed files with 3742 additions and 928 deletions

2
.gitignore vendored
View File

@@ -13,7 +13,7 @@
*.patch
#Personal
saveddata/
/saveddata/
#PyCharm
.idea/

View File

View File

@@ -1,22 +1,48 @@
# Pyfa
# pyfa
Pyfa is a cross-platform desktop fitting application for EVE online that can be used natively on any platform where python and wxwidgets are available.
![pyfa](https://cloud.githubusercontent.com/assets/3904767/10271512/af385ef2-6ade-11e5-8f67-52b8b1e4c797.PNG)
It provides many advanced features such as graphs and full calculations of any possible combination of modules, fits, etc.
## What is it?
Please see the [FAQ](https://github.com/DarkFenX/Pyfa/wiki/FAQ) for answers to common questions / concerns
pyfa, short for **py**thon **f**itting **a**ssistant, allows you to create, experiment with, and save ship fittings without being in game. Open source and written in Python, it is available on any platform where Python 2.x and wxWidgets are available, including Windows, Mac OS X, and Linux.
#### A note for Linux users
pyfa currently only supports wxPython 2.8. However, there are some distros that have started to support 3.0 and subsequently dropped support for 2.8 altogether (such as Debian Jessie). If this is the case and wxPython 3.0 is the only version installed, the official pyfa releases will not run. You must either find a package for 2.8 or compile it yourself.
## Latest Version and Changelogs
The latest version along with release notes can always be found on the projects [Releases](https://github.com/DarkFenX/Pyfa/releases) page. pyfa will notify you if you are running an outdated version.
For Debian Jessie, wxPython 2.8 is available in Sid (the unstable repo). you can use apt-pinning to install select packages from unstable and still keep your stable system. See http://jaqque.sbih.org/kplug/apt-pinning.html for me details.
## Installing
Windows and OS X users are supplied self-contained builds of pyfa that can be run without additional software. An `.exe` installer is also available for the Windows builds. There is no self-contained package for Linux users, which are expected to run pyfa through their distributions Python interpreter. However, there are a number of third-party packages available that handle the dependencies and updates for pyfa (for example, [pyfa for Arch Linux](https://aur.archlinux.org/packages/pyfa/)). Please check your distributions repositories.
3.0 support is being worked on and can be found on the wx3 branch. It may be stable enough for you, but there are a few bugs related to it. Please see the wx3 label on the GitHub issues area for me information on known issues (biggest one currently is GTK warning spam): https://github.com/DarkFenX/Pyfa/labels/wx3
## Requirements
If you wish to help with development or simply need to run pyfa through a Python interpreter, the following software is required:
#### Links
* [Development repository: http://github.com/DarkFenX/Pyfa](http://github.com/DarkFenX/Pyfa)
* [XMPP conference:
pyfa@conference.jabber.org](pyfa@conference.jabber.org)
* Python >= 2.6
* `wxPython` 2.8/3.0
* `sqlalchemy` >= 0.6
* `dateutil`
* `matplotlib` (for some Linux distributions, you may need to install separate wxPython bindings, such as `python-matplotlib-wx`)
* `requests`
## Bug Reporting
The preferred method of reporting bugs is through the projects GitHub Issues interface. Alternatively, posting a report in the pyfa thread on the official EVE Online forums is acceptable. Guidelines for bug reporting can be found on [this wiki page](https://github.com/DarkFenX/Pyfa/wiki/Bug-Reporting).
## License
pyfa is licensed under the GNU GPL v3.0, see LICENSE
## Resources
* Development repository: [http://github.com/DarkFenX/Pyfa](http://github.com/DarkFenX/Pyfa)
* XMPP conference: [pyfa@conference.jabber.org](pyfa@conference.jabber.org)
* [EVE forum thread](http://forums.eveonline.com/default.aspx?g=posts&t=247609)
* [EVE University guide using pyfa](http://wiki.eveuniversity.org/Guide_to_using_PYFA)
* [EVE Online website](http://www.eveonline.com/)
## Contacts:
* Kadesh Priestess
* GitHub: @DarkFenX
* [TweetFleet Slack](https://www.fuzzwork.co.uk/tweetfleet-slack-invites/): @kadesh
* Sable Blitzmann
* GitHub: @blitzmann
* [TweetFleet Slack](https://www.fuzzwork.co.uk/tweetfleet-slack-invites/): @blitzmann
* Email: sable.blitzmann@gmail.com
## CCP Copyright Notice
EVE Online, the EVE logo, EVE and all associated logos and designs are the intellectual property of CCP hf. All artwork, screenshots, characters, vehicles, storylines, world facts or other recognizable features of the intellectual property relating to these trademarks are likewise the intellectual property of CCP hf. EVE Online and the EVE logo are the registered trademarks of CCP hf. All rights are reserved worldwide. All other trademarks are the property of their respective owners. CCP hf. has granted permission to Osmium to use EVE Online and all associated logos and designs for promotional and information purposes on its website but does not endorse, and is not in any way affiliated with, Osmium. CCP is in no way responsible for the content on or functioning of this website, nor can it be liable for any damage arising from the use of this website.

View File

@@ -17,21 +17,15 @@ debug = False
# Defines if our saveddata will be in pyfa root or not
saveInRoot = False
if debug:
logLevel = logging.DEBUG
else:
logLevel = logging.WARN
# Version data
version = "1.14.1"
tag = "git"
expansionName = "Galatea"
expansionVersion = "1.2"
version = "1.16.2"
tag = "Stable"
expansionName = "Parallax"
expansionVersion = "1.1"
evemonMinVersion = "4081"
pyfaPath = None
savePath = None
staticPath = None
saveDB = None
gameDB = None
@@ -50,23 +44,40 @@ class StreamToLogger(object):
for line in buf.rstrip().splitlines():
self.logger.log(self.log_level, line.rstrip())
def isFrozen():
if hasattr(sys, 'frozen'):
return True
else:
return False
def getPyfaRoot():
base = getattr(sys.modules['__main__'], "__file__", sys.executable) if isFrozen() else sys.argv[0]
root = os.path.dirname(os.path.realpath(os.path.abspath(base)))
root = unicode(root, sys.getfilesystemencoding())
return root
def __createDirs(path):
if not os.path.exists(path):
os.makedirs(path)
def defPaths():
global debug
global pyfaPath
global savePath
global staticPath
global saveDB
global gameDB
global saveInRoot
if debug:
logLevel = logging.DEBUG
else:
logLevel = logging.WARN
# The main pyfa directory which contains run.py
# Python 2.X uses ANSI by default, so we need to convert the character encoding
pyfaPath = getattr(configforced, "pyfaPath", pyfaPath)
if pyfaPath is None:
pyfaPath = unicode(os.path.dirname(os.path.realpath(os.path.abspath(
sys.modules['__main__'].__file__))), sys.getfilesystemencoding())
pyfaPath = getPyfaRoot()
# Where we store the saved fits etc, default is the current users home directory
if saveInRoot is True:
@@ -81,6 +92,9 @@ def defPaths():
__createDirs(savePath)
if isFrozen():
os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(pyfaPath, "cacert.pem")
format = '%(asctime)s %(name)-24s %(levelname)-8s %(message)s'
logging.basicConfig(format=format, level=logLevel)
handler = logging.handlers.RotatingFileHandler(os.path.join(savePath, "log.txt"), maxBytes=1000000, backupCount=3)
@@ -95,13 +109,10 @@ def defPaths():
sl = StreamToLogger(stdout_logger, logging.INFO)
sys.stdout = sl
stderr_logger = logging.getLogger('STDERR')
sl = StreamToLogger(stderr_logger, logging.ERROR)
sys.stderr = sl
# Static EVE Data from the staticdata repository, should be in the staticdata
# directory in our pyfa directory
staticPath = os.path.join(pyfaPath, "staticdata")
# This interferes with cx_Freeze's own handling of exceptions. Find a way to fix this.
#stderr_logger = logging.getLogger('STDERR')
#sl = StreamToLogger(stderr_logger, logging.ERROR)
#sys.stderr = sl
# The database where we store all the fits etc
saveDB = os.path.join(savePath, "saveddata.db")
@@ -109,7 +120,7 @@ def defPaths():
# The database where the static EVE data from the datadump is kept.
# This is not the standard sqlite datadump but a modified version created by eos
# maintenance script
gameDB = os.path.join(staticPath, "eve.db")
gameDB = os.path.join(pyfaPath, "eve.db")
## DON'T MODIFY ANYTHING BELOW ##
import eos.config

BIN
dist_assets/mac/pyfa.icns Normal file

Binary file not shown.

BIN
dist_assets/win/pyfa.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

@@ -59,26 +59,20 @@ class CapSimulator(object):
return duration, capNeed
def init(self, modules):
"""prepare modules. a list of (duration, capNeed, clipSize) tuples is
"""prepare modules. a list of (duration, capNeed, clipSize, disableStagger) tuples is
expected, with clipSize 0 if the module has infinite ammo.
"""
mods = {}
for module in modules:
if module in mods:
mods[module] += 1
else:
mods[module] = 1
self.modules = mods
self.modules = modules
def reset(self):
"""Reset the simulator state"""
self.state = []
mods = {}
period = 1
disable_period = False
for (duration, capNeed, clipSize), amount in self.modules.iteritems():
# Loop over modules, clearing clipSize if applicable, and group modules based on attributes
for (duration, capNeed, clipSize, disableStagger) in self.modules:
if self.scale:
duration, capNeed = self.scale_activation(duration, capNeed)
@@ -87,7 +81,15 @@ class CapSimulator(object):
if not self.reload and capNeed > 0:
clipSize = 0
if self.stagger:
# Group modules based on their properties
if (duration, capNeed, clipSize, disableStagger) in mods:
mods[(duration, capNeed, clipSize, disableStagger)] += 1
else:
mods[(duration, capNeed, clipSize, disableStagger)] = 1
# Loop over grouped modules, configure staggering and push to the simulation state
for (duration, capNeed, clipSize, disableStagger), amount in mods.iteritems():
if self.stagger and not disableStagger:
if clipSize == 0:
duration = int(duration/amount)
else:
@@ -167,13 +169,13 @@ class CapSimulator(object):
iterations += 1
t_last = t_now
if cap < cap_lowest:
if cap < 0.0:
break
cap_lowest = cap
t_last = t_now
# queue the next activation of this module
t_now += duration
shot += 1

View File

@@ -4,7 +4,7 @@ import sys
debug = False
gamedataCache = True
saveddataCache = True
gamedata_connectionstring = 'sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "staticdata", "eve.db")), sys.getfilesystemencoding())
gamedata_connectionstring = 'sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "eve.db")), sys.getfilesystemencoding())
saveddata_connectionstring = 'sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "saveddata", "saveddata.db")), sys.getfilesystemencoding())
#Autodetect path, only change if the autodetection bugs out.

View File

@@ -68,14 +68,8 @@ from eos.db.gamedata import *
from eos.db.saveddata import *
#Import queries
from eos.db.gamedata.queries import getItem, searchItems, getVariations, getItemsByCategory, directAttributeRequest, \
getMarketGroup, getGroup, getCategory, getAttributeInfo, getMetaData, getMetaGroup
from eos.db.saveddata.queries import getUser, getCharacter, getFit, getFitsWithShip, countFitsWithShip, searchFits, \
getCharacterList, getPrice, getDamagePatternList, getDamagePattern, \
getFitList, getFleetList, getFleet, save, remove, commit, add, \
getCharactersForUser, getMiscData, getSquadsIDsWithFitID, getWing, \
getSquad, getBoosterFits, getProjectedFits, getTargetResistsList, getTargetResists,\
clearPrices, countAllFits
from eos.db.gamedata.queries import *
from eos.db.saveddata.queries import *
#If using in memory saveddata, you'll want to reflect it so the data structure is good.
if config.saveddata_connectionstring == "sqlite:///:memory:":

View File

@@ -3,22 +3,15 @@ import shutil
import time
import re
import os
def getAppVersion():
# calculate app version based on upgrade files we have
appVersion = 0
for fname in os.listdir(os.path.join(os.path.dirname(__file__), "migrations")):
m = re.match("^upgrade(?P<index>\d+)\.py$", fname)
if not m:
continue
index = int(m.group("index"))
appVersion = max(appVersion, index)
return appVersion
import migrations
def getVersion(db):
cursor = db.execute('PRAGMA user_version')
return cursor.fetchone()[0]
def getAppVersion():
return migrations.appVersion
def update(saveddata_engine):
dbVersion = getVersion(saveddata_engine)
appVersion = getAppVersion()
@@ -37,10 +30,11 @@ def update(saveddata_engine):
shutil.copyfile(config.saveDB, toFile)
for version in xrange(dbVersion, appVersion):
module = __import__("eos.db.migrations.upgrade{}".format(version + 1), fromlist=True)
upgrade = getattr(module, "upgrade", False)
if upgrade:
upgrade(saveddata_engine)
func = migrations.updates[version+1]
if func:
print "applying update",version+1
func(saveddata_engine)
# when all is said and done, set version to current
saveddata_engine.execute("PRAGMA user_version = {}".format(appVersion))

View File

@@ -7,3 +7,25 @@ define an upgrade() function with the logic. Please note that there must be as
many upgrade files as there are database versions (version 5 would include
upgrade files 1-5)
"""
import pkgutil
import re
updates = {}
appVersion = 0
prefix = __name__ + "."
for importer, modname, ispkg in pkgutil.iter_modules(__path__, prefix):
# loop through python files, extracting update number and function, and
# adding it to a list
modname_tail = modname.rsplit('.', 1)[-1]
module = __import__(modname, fromlist=True)
m = re.match("^upgrade(?P<index>\d+)$", modname_tail)
if not m:
continue
index = int(m.group("index"))
appVersion = max(appVersion, index)
upgrade = getattr(module, "upgrade", False)
if upgrade:
updates[index] = upgrade

View File

@@ -1,3 +1,18 @@
__all__ = ["character", "fit", "module", "user", "skill", "price",
"booster", "drone", "implant", "fleet", "damagePattern",
"miscData", "targetResists"]
__all__ = [
"character",
"fit",
"module",
"user",
"skill",
"price",
"booster",
"drone",
"implant",
"fleet",
"damagePattern",
"miscData",
"targetResists",
"override",
"crest"
]

31
eos/db/saveddata/crest.py Normal file
View File

@@ -0,0 +1,31 @@
#===============================================================================
# Copyright (C) 2010 Diego Duclos
#
# This file is part of eos.
#
# eos is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# eos is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with eos. If not, see <http://www.gnu.org/licenses/>.
#===============================================================================
from sqlalchemy import Table, Column, Integer, String, Boolean
from sqlalchemy.orm import mapper
from eos.db import saveddata_meta
from eos.types import CrestChar
crest_table = Table("crest", saveddata_meta,
Column("ID", Integer, primary_key = True),
Column("name", String, nullable = False, unique = True),
Column("refresh_token", String, nullable = False))
mapper(CrestChar, crest_table)

View File

@@ -0,0 +1,31 @@
#===============================================================================
# Copyright (C) 2010 Diego Duclos
#
# This file is part of eos.
#
# eos is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# eos is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with eos. If not, see <http://www.gnu.org/licenses/>.
#===============================================================================
from sqlalchemy import Table, Column, Integer, Float
from sqlalchemy.orm import mapper
from eos.db import saveddata_meta
from eos.types import Override
overrides_table = Table("overrides", saveddata_meta,
Column("itemID", Integer, primary_key=True, index = True),
Column("attrID", Integer, primary_key=True, index = True),
Column("value", Float, nullable = False))
mapper(Override, overrides_table)

View File

@@ -19,7 +19,8 @@
from eos.db.util import processEager, processWhere
from eos.db import saveddata_session, sd_lock
from eos.types import User, Character, Fit, Price, DamagePattern, Fleet, MiscData, Wing, Squad, TargetResists
from eos.types import User, Character, Fit, Price, DamagePattern, Fleet, MiscData, Wing, Squad, TargetResists, Override, CrestChar
from eos.db.saveddata.fleet import squadmembers_table
from eos.db.saveddata.fit import projectedFits_table
from sqlalchemy.sql import and_
@@ -182,7 +183,7 @@ def getFit(lookfor, eager=None):
else:
eager = processEager(eager)
with sd_lock:
fit = saveddata_session.query(Fit).options(*eager).filter(Fit.ID == fitID).first()
fit = saveddata_session.query(Fit).options(*eager).filter(Fit.ID == lookfor).first()
else:
raise TypeError("Need integer as argument")
@@ -416,6 +417,45 @@ def getProjectedFits(fitID):
else:
raise TypeError("Need integer as argument")
def getCrestCharacters(eager=None):
eager = processEager(eager)
with sd_lock:
characters = saveddata_session.query(CrestChar).options(*eager).all()
return characters
@cachedQuery(CrestChar, 1, "lookfor")
def getCrestCharacter(lookfor, eager=None):
if isinstance(lookfor, int):
if eager is None:
with sd_lock:
character = saveddata_session.query(CrestChar).get(lookfor)
else:
eager = processEager(eager)
with sd_lock:
character = saveddata_session.query(CrestChar).options(*eager).filter(CrestChar.ID == lookfor).first()
elif isinstance(lookfor, basestring):
eager = processEager(eager)
with sd_lock:
character = saveddata_session.query(CrestChar).options(*eager).filter(CrestChar.name == lookfor).first()
else:
raise TypeError("Need integer or string as argument")
return character
def getOverrides(itemID, eager=None):
if isinstance(itemID, int):
return saveddata_session.query(Override).filter(Override.itemID == itemID).all()
else:
raise TypeError("Need integer as argument")
def clearOverrides():
with sd_lock:
deleted_rows = saveddata_session.query(Override).delete()
commit()
return deleted_rows
def getAllOverrides(eager=None):
return saveddata_session.query(Override).all()
def removeInvalid(fits):
invalids = [f for f in fits if f.isInvalid]

View File

@@ -1,4 +1,4 @@
# armorTankingGang2
# armorWarfareArmorHpReplacer
#
# Used by:
# Implant: Armored Warfare Mindlink

View File

@@ -0,0 +1,9 @@
# battlecruiserDroneSpeed
#
# Used by:
# Ship: Myrmidon
# Ship: Prophecy
type = "passive"
def handler(fit, ship, context):
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Drones"),
"maxVelocity", ship.getModifiedItemAttr("roleBonusCBC"))

View File

@@ -0,0 +1,10 @@
# battlecruiserMETRange
#
# Used by:
# Ships named like: Harbinger (2 of 2)
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Medium Energy Turret"),
"maxRange", ship.getModifiedItemAttr("roleBonusCBC"))
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Medium Energy Turret"),
"falloff", ship.getModifiedItemAttr("roleBonusCBC"))

View File

@@ -0,0 +1,11 @@
# battlecruiserMHTRange
#
# Used by:
# Ships named like: Brutix (2 of 2)
# Ship: Ferox
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Medium Hybrid Turret"),
"maxRange", ship.getModifiedItemAttr("roleBonusCBC"))
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Medium Hybrid Turret"),
"falloff", ship.getModifiedItemAttr("roleBonusCBC"))

View File

@@ -0,0 +1,9 @@
# battlecruiserMissileRange
#
# Used by:
# Ships named like: Drake (2 of 2)
# Ship: Cyclone
type = "passive"
def handler(fit, skill, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"),
"maxVelocity", skill.getModifiedItemAttr("roleBonusCBC"))

View File

@@ -0,0 +1,10 @@
# battlecruiserMPTRange
#
# Used by:
# Ships named like: Hurricane (2 of 2)
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Medium Projectile Turret"),
"maxRange", ship.getModifiedItemAttr("roleBonusCBC"))
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Medium Projectile Turret"),
"falloff", ship.getModifiedItemAttr("roleBonusCBC"))

View File

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

View File

@@ -0,0 +1,8 @@
# entosisCPUAddition
#
# Used by:
# Modules from group: Entosis Link (2 of 2)
type = "passive"
def handler(fit, module, context):
module.increaseItemAttr("cpu", module.getModifiedItemAttr("entosisCPUAdd"))

View File

@@ -0,0 +1,8 @@
# entosisCPUPenalty
#
# Used by:
# Ships from group: Interceptor (10 of 10)
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Infomorph Psychology"),
"entosisCPUAdd", ship.getModifiedItemAttr("entosisCPUPenalty"))

View File

@@ -0,0 +1,11 @@
# informationWarfareMaxTargetRangeBonus
#
# Used by:
# Implant: Caldari Navy Warfare Mindlink
# Implant: Imperial Navy Warfare Mindlink
# Implant: Information Warfare Mindlink
type = "gang"
gangBoost = "maxTargetRange"
gangBonus = "maxTargetRangeBonus"
def handler(fit, container, context):
fit.ship.boostItemAttr(gangBoost, container.getModifiedItemAttr(gangBonus))

View File

@@ -2,7 +2,6 @@
#
# Used by:
# Implant: Caldari Navy Warfare Mindlink
# Implant: Imperial Navy Warfare Mindlink
# Implant: Information Warfare Mindlink
type = "passive"
def handler(fit, implant, context):

View File

@@ -3,6 +3,7 @@
# Used by:
# Module: Medium Mercoxit Mining Crystal Optimization I
type = "passive"
runTime="early"
def handler(fit, module, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Mercoxit Processing"),
"specialisationAsteroidYieldMultiplier", module.getModifiedItemAttr("miningAmountBonus"))

View File

@@ -0,0 +1,10 @@
# miningForemanMindLinkMiningAmountBonusReplacer
#
# Used by:
# Implant: Mining Foreman Mindlink
type = "gang"
gangBoost = "miningAmount"
gangBonus = "miningAmountBonus"
def handler(fit, container, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining"),
gangBoost, container.getModifiedItemAttr(gangBonus) * level)

View File

@@ -5,4 +5,4 @@
# Charges named like: Mining Crystal (32 of 32)
type = "passive"
def handler(fit, module, context):
module.multiplyItemAttr("miningAmount", module.getModifiedChargeAttr("specialisationAsteroidYieldMultiplier"))
module.multiplyItemAttr("specialtyMiningAmount", module.getModifiedChargeAttr("specialisationAsteroidYieldMultiplier"))

View File

@@ -1,7 +1,6 @@
# miningYieldGangBonusFixed
#
# Used by:
# Implant: Mining Foreman Mindlink
# Skill: Mining Foreman
type = "gang"
gangBoost = "miningAmount"

View File

@@ -1,9 +1,9 @@
# overloadSelfThermalHardeningBonus
#
# Used by:
# Variations of module: Armor Thermic Hardener I (39 of 39)
# Variations of module: Thermic Dissipation Field I (19 of 19)
# Module: Civilian Thermic Dissipation Field
# Variations of module: Armor Thermal Hardener I (39 of 39)
# Variations of module: Thermal Dissipation Field I (19 of 19)
# Module: Civilian Thermal Dissipation Field
type = "overheat"
def handler(fit, module, context):
module.boostItemAttr("thermalDamageResistanceBonus", module.getModifiedItemAttr("overloadHardeningBonus"))

View File

@@ -1,9 +1,6 @@
# reconOperationsMaxTargetRangeBonusPostPercentMaxTargetRangeGangShips
#
# Used by:
# Implant: Caldari Navy Warfare Mindlink
# Implant: Imperial Navy Warfare Mindlink
# Implant: Information Warfare Mindlink
# Skill: Information Warfare
type = "gang"
gangBoost = "maxTargetRange"

View File

@@ -1,9 +1,6 @@
# shieldDefensiveOperationsShieldCapacityBonusPostPercentShieldCapacityGangShips
#
# Used by:
# Implant: Caldari Navy Warfare Mindlink
# Implant: Republic Fleet Warfare Mindlink
# Implant: Siege Warfare Mindlink
# Skill: Siege Warfare
type = "gang"
gangBoost = "shieldCapacity"

View File

@@ -2,8 +2,10 @@
#
# Used by:
# Ship: Devoter
# Ship: Gold Magnate
# Ship: Impairor
# Ship: Phobos
# Ship: Silver Magnate
type = "passive"
def handler(fit, ship, context):
fit.ship.boostItemAttr("armorEmDamageResonance", ship.getModifiedItemAttr("rookieArmorResistanceBonus"))

View File

@@ -2,8 +2,10 @@
#
# Used by:
# Ship: Devoter
# Ship: Gold Magnate
# Ship: Impairor
# Ship: Phobos
# Ship: Silver Magnate
type = "passive"
def handler(fit, ship, context):
fit.ship.boostItemAttr("armorExplosiveDamageResonance", ship.getModifiedItemAttr("rookieArmorResistanceBonus"))

View File

@@ -2,8 +2,10 @@
#
# Used by:
# Ship: Devoter
# Ship: Gold Magnate
# Ship: Impairor
# Ship: Phobos
# Ship: Silver Magnate
type = "passive"
def handler(fit, ship, context):
fit.ship.boostItemAttr("armorKineticDamageResonance", ship.getModifiedItemAttr("rookieArmorResistanceBonus"))

View File

@@ -2,8 +2,10 @@
#
# Used by:
# Ship: Devoter
# Ship: Gold Magnate
# Ship: Impairor
# Ship: Phobos
# Ship: Silver Magnate
type = "passive"
def handler(fit, ship, context):
fit.ship.boostItemAttr("armorThermalDamageResonance", ship.getModifiedItemAttr("rookieArmorResistanceBonus"))

View File

@@ -0,0 +1,8 @@
# shipBonusProjectileTrackingMBC2
#
# Used by:
# Ship: Hurricane Fleet Issue
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Medium Projectile Turret"),
"trackingSpeed", ship.getModifiedItemAttr("shipBonusMBC2"), skill="Minmatar Battlecruiser")

View File

@@ -1,4 +1,4 @@
# shipBonusWDFGnullSpeedEffects
# shipBonusWDFGnullPenalties
#
# Used by:
# Ship: Fiend

View File

@@ -1,8 +0,0 @@
# shipHeavyAssaultMissileVelocityCBC2
#
# Used by:
# Ship: Drake Navy Issue
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Assault Missiles"),
"maxVelocity", ship.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")

View File

@@ -1,8 +0,0 @@
# shipHeavyMissileVelocityCBC2
#
# Used by:
# Ship: Drake Navy Issue
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Heavy Missiles"),
"maxVelocity", ship.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")

View File

@@ -0,0 +1,8 @@
# shipHybridDmg1CBC2
#
# Used by:
# Ship: Ferox
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Medium Hybrid Turret"),
"damageMultiplier", ship.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")

View File

@@ -1,7 +1,7 @@
# shipProjectileRof1MBC2
#
# Used by:
# Ships named like: Hurricane (2 of 2)
# Ship: Hurricane
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Medium Projectile Turret"),

View File

@@ -1,9 +1,8 @@
# shipShieldEmResistance1CBC2
#
# Used by:
# Variations of ship: Ferox (2 of 2)
# Ship: Drake
# Ship: Nighthawk
# Variations of ship: Drake (3 of 3)
# Ship: Vulture
type = "passive"
def handler(fit, ship, context):
fit.ship.boostItemAttr("shieldEmDamageResonance", ship.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")

View File

@@ -1,9 +1,8 @@
# shipShieldExplosiveResistance1CBC2
#
# Used by:
# Variations of ship: Ferox (2 of 2)
# Ship: Drake
# Ship: Nighthawk
# Variations of ship: Drake (3 of 3)
# Ship: Vulture
type = "passive"
def handler(fit, ship, context):
fit.ship.boostItemAttr("shieldExplosiveDamageResonance", ship.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")

View File

@@ -1,9 +1,8 @@
# shipShieldKineticResistance1CBC2
#
# Used by:
# Variations of ship: Ferox (2 of 2)
# Ship: Drake
# Ship: Nighthawk
# Variations of ship: Drake (3 of 3)
# Ship: Vulture
type = "passive"
def handler(fit, ship, context):
fit.ship.boostItemAttr("shieldKineticDamageResonance", ship.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")

View File

@@ -1,9 +1,8 @@
# shipShieldThermalResistance1CBC2
#
# Used by:
# Variations of ship: Ferox (2 of 2)
# Ship: Drake
# Ship: Nighthawk
# Variations of ship: Drake (3 of 3)
# Ship: Vulture
type = "passive"
def handler(fit, ship, context):
fit.ship.boostItemAttr("shieldThermalDamageResonance", ship.getModifiedItemAttr("shipBonusCBC2"), skill="Caldari Battlecruiser")

View File

@@ -0,0 +1,11 @@
# siegeWarfareShieldCapacityBonusReplacer
#
# Used by:
# Implant: Caldari Navy Warfare Mindlink
# Implant: Republic Fleet Warfare Mindlink
# Implant: Siege Warfare Mindlink
type = "gang"
gangBoost = "shieldCapacity"
gangBonus = "shieldCapacityBonus"
def handler(fit, container, context):
fit.ship.boostItemAttr(gangBoost, container.getModifiedItemAttr(gangBonus) * level)

View File

@@ -1,9 +1,6 @@
# skirmishWarfareAgilityBonus
#
# Used by:
# Implant: Federation Navy Warfare Mindlink
# Implant: Republic Fleet Warfare Mindlink
# Implant: Skirmish Warfare Mindlink
# Skill: Skirmish Warfare
type = "gang"
gangBoost = "agility"

View File

@@ -0,0 +1,11 @@
# skirmishWarfareAgilityBonusReplacer
#
# Used by:
# Implant: Federation Navy Warfare Mindlink
# Implant: Republic Fleet Warfare Mindlink
# Implant: Skirmish Warfare Mindlink
type = "gang"
gangBoost = "agility"
gangBonus = "agilityBonus"
def handler(fit, container, context):
fit.ship.boostItemAttr(gangBoost, container.getModifiedItemAttr(gangBonus) * level)

View File

@@ -2,6 +2,8 @@
#
# Used by:
# Ship: Coercer
# Ship: Gold Magnate
# Ship: Silver Magnate
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Small Energy Turret"),

View File

@@ -1,7 +1,7 @@
# thermalShieldCompensationHardeningBonusGroupShieldAmp
#
# Used by:
# Skill: Thermic Shield Compensation
# Skill: Thermal Shield Compensation
type = "passive"
def handler(fit, skill, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Shield Amplifier",

View File

@@ -1,7 +1,7 @@
# thermicArmorCompensationHardeningBonusGroupArmorCoating
#
# Used by:
# Skill: Thermic Armor Compensation
# Skill: Thermal Armor Compensation
type = "passive"
def handler(fit, skill, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Armor Coating",

View File

@@ -1,7 +1,7 @@
# thermicArmorCompensationHardeningBonusGroupEnergized
#
# Used by:
# Skill: Thermic Armor Compensation
# Skill: Thermal Armor Compensation
type = "passive"
def handler(fit, skill, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Armor Plating Energized",

View File

@@ -9,7 +9,8 @@ def handler(fit, module, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
"duration", module.getModifiedItemAttr("remoteArmorDamageDurationBonus"))
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
"armorDamageAmount", module.getModifiedItemAttr("remoteArmorDamageAmountBonus"))
"armorDamageAmount", module.getModifiedItemAttr("remoteArmorDamageAmountBonus"),
stackingPenalties=True)
# Remote hull reppers
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Remote Hull Repair Systems"),
@@ -19,7 +20,8 @@ def handler(fit, module, context):
# Shield Transporters
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Shield Emission Systems"),
"shieldBonus", module.getModifiedItemAttr("shieldTransportAmountBonus"))
"shieldBonus", module.getModifiedItemAttr("shieldTransportAmountBonus"),
stackingPenalties=True)
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Shield Emission Systems"),
"duration", module.getModifiedItemAttr("shieldTransportDurationBonus"))
@@ -34,26 +36,29 @@ def handler(fit, module, context):
"shieldBonus", module.getModifiedItemAttr("shieldBoostMultiplier"),
stackingPenalties=True)
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Shield Operation"),
"duration", module.getModifiedItemAttr("shieldBonusDurationBonus"),
stackingPenalties=True)
"duration", module.getModifiedItemAttr("shieldBonusDurationBonus"))
# Armor reps
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Armor Repair Unit",
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Repair Systems"),
"armorDamageAmount", module.getModifiedItemAttr("armorDamageAmountBonus"))
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Armor Repair Unit",
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Repair Systems"),
"duration", module.getModifiedItemAttr("armorDamageDurationBonus"))
# Speed bonus
fit.ship.boostItemAttr("maxVelocity", module.getModifiedItemAttr("speedFactor"))
fit.ship.boostItemAttr("maxVelocity", module.getModifiedItemAttr("speedFactor"),
stackingPenalties=True)
# Scan resolution multiplier
fit.ship.multiplyItemAttr("scanResolution", module.getModifiedItemAttr("scanResolutionMultiplier"))
fit.ship.multiplyItemAttr("scanResolution", module.getModifiedItemAttr("scanResolutionMultiplier"),
stackingPenalties=True)
# Mass multiplier
fit.ship.multiplyItemAttr("mass", module.getModifiedItemAttr("massMultiplier"))
fit.ship.multiplyItemAttr("mass", module.getModifiedItemAttr("massMultiplier"),
stackingPenalties=True)
# Lock range
fit.ship.multiplyItemAttr("maxTargetRange", module.getModifiedItemAttr("maxTargetRangeMultiplier"))
fit.ship.multiplyItemAttr("maxTargetRange", module.getModifiedItemAttr("maxTargetRangeMultiplier"),
stackingPenalties=True)
# Max locked targets
fit.ship.increaseItemAttr("maxLockedTargets", module.getModifiedItemAttr("maxLockedTargetsBonus"))
@@ -61,3 +66,16 @@ def handler(fit, module, context):
# Block EWAR & projected effects
fit.ship.forceItemAttr("disallowOffensiveModifiers", module.getModifiedItemAttr("disallowOffensiveModifiers"))
fit.ship.forceItemAttr("disallowAssistance", module.getModifiedItemAttr("disallowAssistance"))
# EW cap need increase
groups = [
'ECM Burst',
'Remote ECM Burst',
'Tracking Disruptor',
'ECM',
'Remote Sensor Damper',
'Target Painter']
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups or
mod.item.requiresSkill("Propulsion Jamming"),
"capacitorNeed", module.getModifiedItemAttr("ewCapacitorNeedBonus"))

View File

@@ -9,7 +9,8 @@ def handler(fit, module, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
"duration", module.getModifiedItemAttr("remoteArmorDamageDurationBonus"))
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
"armorDamageAmount", module.getModifiedItemAttr("remoteArmorDamageAmountBonus"))
"armorDamageAmount", module.getModifiedItemAttr("remoteArmorDamageAmountBonus"),
stackingPenalties=True)
# Remote hull reppers
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Remote Hull Repair Systems"),
@@ -19,7 +20,8 @@ def handler(fit, module, context):
# Shield Transporters
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Shield Emission Systems"),
"shieldBonus", module.getModifiedItemAttr("shieldTransportAmountBonus"))
"shieldBonus", module.getModifiedItemAttr("shieldTransportAmountBonus"),
stackingPenalties=True)
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Shield Emission Systems"),
"duration", module.getModifiedItemAttr("shieldTransportDurationBonus"))
@@ -34,26 +36,29 @@ def handler(fit, module, context):
"shieldBonus", module.getModifiedItemAttr("shieldBoostMultiplier"),
stackingPenalties=True)
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Shield Operation"),
"duration", module.getModifiedItemAttr("shieldBonusDurationBonus"),
stackingPenalties=True)
"duration", module.getModifiedItemAttr("shieldBonusDurationBonus"))
# Armor reps
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Armor Repair Unit",
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Repair Systems"),
"armorDamageAmount", module.getModifiedItemAttr("armorDamageAmountBonus"))
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Armor Repair Unit",
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Repair Systems"),
"duration", module.getModifiedItemAttr("armorDamageDurationBonus"))
# Speed bonus
fit.ship.boostItemAttr("maxVelocity", module.getModifiedItemAttr("speedFactor"))
fit.ship.boostItemAttr("maxVelocity", module.getModifiedItemAttr("speedFactor"),
stackingPenalties=True)
# Scan resolution multiplier
fit.ship.multiplyItemAttr("scanResolution", module.getModifiedItemAttr("scanResolutionMultiplier"))
fit.ship.multiplyItemAttr("scanResolution", module.getModifiedItemAttr("scanResolutionMultiplier"),
stackingPenalties=True)
# Mass multiplier
fit.ship.multiplyItemAttr("mass", module.getModifiedItemAttr("massMultiplier"))
fit.ship.multiplyItemAttr("mass", module.getModifiedItemAttr("massMultiplier"),
stackingPenalties=True)
# Lock range
fit.ship.multiplyItemAttr("maxTargetRange", module.getModifiedItemAttr("maxTargetRangeMultiplier"))
fit.ship.multiplyItemAttr("maxTargetRange", module.getModifiedItemAttr("maxTargetRangeMultiplier"),
stackingPenalties=True)
# Max locked targets
fit.ship.increaseItemAttr("maxLockedTargets", module.getModifiedItemAttr("maxLockedTargetsBonus"))
@@ -69,3 +74,18 @@ def handler(fit, module, context):
"capacitorNeed", module.getModifiedItemAttr("triageRemoteModuleCapNeed"))
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Shield Emission Systems"),
"capacitorNeed", module.getModifiedItemAttr("triageRemoteModuleCapNeed"))
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Capital Capacitor Emission Systems"),
"capacitorNeed", module.getModifiedItemAttr("triageRemoteModuleCapNeed"))
# EW cap need increase
groups = [
'ECM Burst',
'Remote ECM Burst',
'Tracking Disruptor',
'ECM',
'Remote Sensor Damper',
'Target Painter']
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups or
mod.item.requiresSkill("Propulsion Jamming"),
"capacitorNeed", module.getModifiedItemAttr("ewCapacitorNeedBonus"))

View File

@@ -24,6 +24,7 @@ from sqlalchemy.orm import reconstructor
from eqBase import EqBase
import traceback
import eos.db
try:
from collections import OrderedDict
@@ -168,7 +169,6 @@ class Item(EqBase):
info = getattr(cls, "MOVE_ATTR_INFO", None)
if info is None:
cls.MOVE_ATTR_INFO = info = []
import eos.db
for id in cls.MOVE_ATTRS:
info.append(eos.db.getAttributeInfo(id))
@@ -191,6 +191,7 @@ class Item(EqBase):
self.__moved = False
self.__offensive = None
self.__assistive = None
self.__overrides = None
@property
def attributes(self):
@@ -210,6 +211,32 @@ class Item(EqBase):
return False
@property
def overrides(self):
if self.__overrides is None:
self.__overrides = {}
overrides = eos.db.getOverrides(self.ID)
for x in overrides:
if x.attr.name in self.__attributes:
self.__overrides[x.attr.name] = x
return self.__overrides
def setOverride(self, attr, value):
from eos.saveddata.override import Override
if attr.name in self.__overrides:
override = self.__overrides.get(attr.name)
override.value = value
else:
override = Override(self, attr, value)
self.__overrides[attr.name] = override
eos.db.save(override)
def deleteOverride(self, attr):
override = self.__overrides.pop(attr.name, None)
eos.db.saveddata_session.delete(override)
eos.db.commit()
@property
def requiredSkills(self):
if self.__requiredSkills is None:
@@ -345,6 +372,12 @@ class Item(EqBase):
return False
def __repr__(self):
return "Item(ID={}, name={}) at {}".format(
self.ID, self.name, hex(id(self))
)
class MetaData(EqBase):
pass

View File

@@ -43,7 +43,8 @@ class FitDpsGraph(Graph):
if "ewTargetPaint" in mod.item.effects:
ew['signatureRadius'].append(1+(mod.getModifiedItemAttr("signatureRadiusBonus") / 100))
if "decreaseTargetSpeed" in mod.item.effects:
ew['velocity'].append(1+(mod.getModifiedItemAttr("speedFactor") / 100))
if distance <= mod.getModifiedItemAttr("maxRange"):
ew['velocity'].append(1+(mod.getModifiedItemAttr("speedFactor") / 100))
ew['signatureRadius'].sort(key=abssort)
ew['velocity'].sort(key=abssort)

View File

@@ -38,6 +38,9 @@ class ChargeAttrShortcut(object):
return None
class ModifiedAttributeDict(collections.MutableMapping):
OVERRIDES = False
class CalculationPlaceholder():
pass
@@ -51,6 +54,8 @@ class ModifiedAttributeDict(collections.MutableMapping):
self.__modified = {}
# Affected by entities
self.__affectedBy = {}
# Overrides
self.__overrides = {}
# Dictionaries for various value modification types
self.__forced = {}
self.__preAssigns = {}
@@ -79,6 +84,14 @@ class ModifiedAttributeDict(collections.MutableMapping):
self.__original = val
self.__modified.clear()
@property
def overrides(self):
return self.__overrides
@overrides.setter
def overrides(self, val):
self.__overrides = val
def __getitem__(self, key):
# Check if we have final calculated value
if key in self.__modified:
@@ -99,6 +112,8 @@ class ModifiedAttributeDict(collections.MutableMapping):
del self.__intermediary[key]
def getOriginal(self, key):
if self.OVERRIDES and key in self.__overrides:
return self.__overrides.get(key).value
val = self.__original.get(key)
if val is None:
return None
@@ -285,7 +300,7 @@ class ModifiedAttributeDict(collections.MutableMapping):
else:
if not attributeName in self.__multipliers:
self.__multipliers[attributeName] = 1
self.__multipliers[attributeName] *= multiplier
self.__multipliers[attributeName] *= multiplier if multiplier is not None else 1
self.__placehold(attributeName)
self.__afflict(attributeName, "%s*" % ("s" if stackingPenalties else ""), multiplier, multiplier != 1)

View File

@@ -58,6 +58,7 @@ class Booster(HandledItem, ItemAttrShortcut):
self.__sideEffects = []
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = self.__item.attributes
self.__itemModifiedAttributes.overrides = self.__item.overrides
self.__slot = self.__calculateSlot(self.__item)
for effect in self.__item.effects.itervalues():

View File

@@ -34,6 +34,7 @@ class Cargo(HandledItem, ItemAttrShortcut):
self.amount = 0
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = item.attributes
self.__itemModifiedAttributes.overrides = item.overrides
@reconstructor
def init(self):
@@ -48,6 +49,7 @@ class Cargo(HandledItem, ItemAttrShortcut):
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = self.__item.attributes
self.__itemModifiedAttributes.overrides = self.__item.overrides
@property
def itemModifiedAttributes(self):

View File

@@ -23,7 +23,9 @@ from sqlalchemy.orm import validates, reconstructor
from eos.effectHandlerHelpers import HandledItem, HandledImplantBoosterList
import eos.db
import eos
import logging
logger = logging.getLogger(__name__)
class Character(object):
__itemList = None
@@ -221,6 +223,11 @@ class Character(object):
if map[key](val) == False: raise ValueError(str(val) + " is not a valid value for " + key)
else: return val
def __repr__(self):
return "Character(ID={}, name={}) at {}".format(
self.ID, self.name, hex(id(self))
)
class Skill(HandledItem):
def __init__(self, item, level=0, ro=False, learned=True):
self.__item = item if not isinstance(item, int) else None

View File

@@ -0,0 +1,46 @@
#===============================================================================
# Copyright (C) 2010 Diego Duclos
#
# This file is part of eos.
#
# eos is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# eos is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with eos. If not, see <http://www.gnu.org/licenses/>.
#===============================================================================
import urllib
from cStringIO import StringIO
from sqlalchemy.orm import reconstructor
#from tomorrow import threads
class CrestChar(object):
def __init__(self, id, name, refresh_token=None):
self.ID = id
self.name = name
self.refresh_token = refresh_token
@reconstructor
def init(self):
pass
'''
@threads(1)
def fetchImage(self):
url = 'https://image.eveonline.com/character/%d_128.jpg'%self.ID
fp = urllib.urlopen(url)
data = fp.read()
fp.close()
self.img = StringIO(data)
'''

View File

@@ -67,6 +67,7 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
self.__miningyield = None
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = self.__item.attributes
self.__itemModifiedAttributes.overrides = self.__item.overrides
self.__chargeModifiedAttributes = ModifiedAttributeDict()
chargeID = self.getModifiedItemAttr("entityMissileTypeID")
@@ -74,6 +75,7 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
charge = eos.db.getItem(int(chargeID))
self.__charge = charge
self.__chargeModifiedAttributes.original = charge.attributes
self.__chargeModifiedAttributes.overrides = charge.overrides
@property
def itemModifiedAttributes(self):

View File

@@ -25,7 +25,7 @@ from eos import capSim
from copy import deepcopy
from math import sqrt, log, asinh
from eos.types import Drone, Cargo, Ship, Character, State, Slot, Module, Implant, Booster, Skill
from eos.saveddata.module import State
from eos.saveddata.module import State, Hardpoint
from eos.saveddata.mode import Mode
import eos.db
import time
@@ -390,9 +390,9 @@ class Fit(object):
self.__modifier = currModifier
self.__origin = origin
if hasattr(currModifier, "itemModifiedAttributes"):
currModifier.itemModifiedAttributes.fit = self
currModifier.itemModifiedAttributes.fit = origin or self
if hasattr(currModifier, "chargeModifiedAttributes"):
currModifier.chargeModifiedAttributes.fit = self
currModifier.chargeModifiedAttributes.fit = origin or self
def getModifier(self):
return self.__modifier
@@ -480,17 +480,22 @@ class Fit(object):
self.__calculated = True
for runTime in ("early", "normal", "late"):
c = chain(
# Items that are unrestricted. These items are run on the local fit
# first and then projected onto the target fit it one is designated
u = [
(self.character, self.ship),
self.drones,
self.boosters,
self.appliedImplants,
self.modules
)
]
if not projected:
# if not a projected fit, add a couple of more things
c = chain(c, (self.mode,), self.projectedDrones, self.projectedModules)
# Items that are restricted. These items are only run on the local
# fit. They are NOT projected onto the target fit. # See issue 354
r = [(self.mode,), self.projectedDrones, self.projectedModules]
# chain unrestricted and restricted into one iterable
c = chain.from_iterable(u+r)
# We calculate gang bonuses first so that projected fits get them
if self.gangBoosts is not None:
@@ -500,9 +505,12 @@ class Fit(object):
# Registering the item about to affect the fit allows us to
# track "Affected By" relations correctly
if item is not None:
# apply effects locally
self.register(item)
item.calculateModifiedAttributes(self, runTime, False)
if projected is True:
if projected is True and item not in chain.from_iterable(r):
# apply effects onto target fit
for _ in xrange(projectionInfo.amount):
targetFit.register(item, origin=self)
item.calculateModifiedAttributes(targetFit, runTime, True)
@@ -839,10 +847,14 @@ class Fit(object):
else:
capAdded -= capNeed
drains.append((int(fullCycleTime), mod.getModifiedItemAttr("capacitorNeed") or 0, mod.numShots or 0))
# If this is a turret, don't stagger activations
disableStagger = mod.hardpoint == Hardpoint.TURRET
drains.append((int(fullCycleTime), mod.getModifiedItemAttr("capacitorNeed") or 0, mod.numShots or 0, disableStagger))
for fullCycleTime, capNeed, clipSize in self.iterDrains():
drains.append((int(fullCycleTime), capNeed, clipSize))
# Stagger incoming effects for cap simulation
drains.append((int(fullCycleTime), capNeed, clipSize, False))
if capNeed > 0:
capUsed += capNeed / (fullCycleTime / 1000.0)
else:

View File

@@ -56,6 +56,7 @@ class Implant(HandledItem, ItemAttrShortcut):
""" Build object. Assumes proper and valid item already set """
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = self.__item.attributes
self.__itemModifiedAttributes.overrides = self.__item.overrides
self.__slot = self.__calculateSlot(self.__item)
@property

View File

@@ -30,6 +30,7 @@ class Mode(ItemAttrShortcut, HandledItem):
self.__item = item
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = self.item.attributes
self.__itemModifiedAttributes.overrides = self.item.overrides
@property
def item(self):

View File

@@ -113,10 +113,13 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if self.__item:
self.__itemModifiedAttributes.original = self.__item.attributes
self.__itemModifiedAttributes.overrides = self.__item.overrides
self.__hardpoint = self.__calculateHardpoint(self.__item)
self.__slot = self.__calculateSlot(self.__item)
if self.__charge:
self.__chargeModifiedAttributes.original = self.__charge.attributes
self.__chargeModifiedAttributes.overrides = self.__charge.overrides
@classmethod
def buildEmpty(cls, slot):
@@ -283,9 +286,11 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if charge is not None:
self.chargeID = charge.ID
self.__chargeModifiedAttributes.original = charge.attributes
self.__chargeModifiedAttributes.overrides = charge.overrides
else:
self.chargeID = None
self.__chargeModifiedAttributes.original = None
self.__chargeModifiedAttributes.overrides = {}
self.__itemModifiedAttributes.clear()
@@ -316,7 +321,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
self.__miningyield = 0
else:
if self.state >= State.ACTIVE:
volley = sum(map(lambda attr: self.getModifiedItemAttr(attr) or 0, self.MINING_ATTRIBUTES))
volley = self.getModifiedItemAttr("specialtyMiningAmount") or self.getModifiedItemAttr("miningAmount") or 0
if volley:
cycleTime = self.cycleTime
self.__miningyield = volley / (cycleTime / 1000.0)

59
eos/saveddata/override.py Normal file
View File

@@ -0,0 +1,59 @@
#===============================================================================
# Copyright (C) 2015 Ryan Holmes
#
# This file is part of eos.
#
# eos is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# eos is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with eos. If not, see <http://www.gnu.org/licenses/>.
#===============================================================================
from eos.eqBase import EqBase
from sqlalchemy.orm import validates, reconstructor
import eos.db
import logging
logger = logging.getLogger(__name__)
class Override(EqBase):
def __init__(self, item, attr, value):
self.itemID = item.ID
self.__item = item
self.attrID = attr.ID
self.__attr = attr
self.value = value
@reconstructor
def init(self):
self.__attr = None
self.__item = None
if self.attrID:
self.__attr = eos.db.getAttributeInfo(self.attrID)
if self.__attr is None:
logger.error("Attribute (id: %d) does not exist", self.attrID)
return
if self.itemID:
self.__item = eos.db.getItem(self.itemID)
if self.__item is None:
logger.error("Item (id: %d) does not exist", self.itemID)
return
@property
def attr(self):
return self.__attr
@property
def item(self):
return self.__item

View File

@@ -51,6 +51,7 @@ class Ship(ItemAttrShortcut, HandledItem):
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = dict(self.item.attributes)
self.__itemModifiedAttributes.original.update(self.EXTRA_ATTRIBUTES)
self.__itemModifiedAttributes.overrides = self.item.overrides
self.commandBonus = 0
@@ -121,3 +122,8 @@ class Ship(ItemAttrShortcut, HandledItem):
def __deepcopy__(self, memo):
copy = Ship(self.item)
return copy
def __repr__(self):
return "Ship(ID={}, name={}) at {}".format(
self.item.ID, self.item.name, hex(id(self))
)

View File

@@ -21,6 +21,7 @@ from eos.gamedata import Attribute, Category, Effect, Group, Icon, Item, MarketG
MetaGroup, AttributeInfo, Unit, EffectInfo, MetaType, MetaData, Traits
from eos.saveddata.price import Price
from eos.saveddata.user import User
from eos.saveddata.crestchar import CrestChar
from eos.saveddata.damagePattern import DamagePattern
from eos.saveddata.targetResists import TargetResists
from eos.saveddata.character import Character, Skill
@@ -35,4 +36,5 @@ from eos.saveddata.fit import Fit
from eos.saveddata.mode import Mode
from eos.saveddata.fleet import Fleet, Wing, Squad
from eos.saveddata.miscData import MiscData
from eos.saveddata.override import Override
import eos.db

Binary file not shown.

View File

@@ -1,7 +1,7 @@
import wx
import gui.utils.colorUtils as colorUtils
import gui.utils.drawUtils as drawUtils
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
SearchButton, EVT_SEARCH_BTN = wx.lib.newevent.NewEvent()
@@ -11,7 +11,7 @@ TextTyped, EVT_TEXT = wx.lib.newevent.NewEvent()
class PFSearchBox(wx.Window):
def __init__(self, parent, id = wx.ID_ANY, value = "", pos = wx.DefaultPosition, size = wx.Size(-1,24), style = 0):
wx.Window.__init__(self, parent, id, pos, size, style = 0)
wx.Window.__init__(self, parent, id, pos, size, style = style)
self.isSearchButtonVisible = False
self.isCancelButtonVisible = False
@@ -49,10 +49,6 @@ class PFSearchBox(wx.Window):
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_MOTION, self.OnMouseMove)
self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterLeaveWindow)
self.Bind(wx.EVT_LEAVE_WINDOW, self.OnEnterLeaveWindow)
# self.EditBox.ChangeValue(self.descriptiveText)
@@ -64,25 +60,26 @@ class PFSearchBox(wx.Window):
self.SetMinSize(size)
def OnEnterLeaveWindow(self, event):
self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
self._hl = False
def OnText(self, event):
wx.PostEvent(self, TextTyped())
event.Skip()
def OnTextEnter(self, event):
wx.PostEvent(self, TextEnter())
event.Skip()
def OnEditSetFocus(self, event):
# value = self.EditBox.GetValue()
# if value == self.descriptiveText:
# self.EditBox.ChangeValue("")
pass
event.Skip()
def OnEditKillFocus(self, event):
if self.EditBox.GetValue() == "":
self.Clear()
event.Skip()
def Clear(self):
self.EditBox.Clear()
@@ -138,20 +135,6 @@ class PFSearchBox(wx.Window):
btnsize.append( (cw,ch))
return btnsize
def OnMouseMove(self, event):
btnpos = self.GetButtonsPos()
btnsize = self.GetButtonsSize()
for btn in xrange(2):
if self.HitTest(btnpos[btn], event.GetPosition(), btnsize[btn]):
if not self._hl:
self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
self._hl = True
break
else:
if self._hl:
self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
self._hl = False
def OnLeftDown(self, event):
btnpos = self.GetButtonsPos()
btnsize = self.GetButtonsSize()

View File

@@ -20,7 +20,7 @@ import config
versionString = "{0} {1} - {2} {3}".format(config.version, config.tag, config.expansionName, config.expansionVersion)
licenses = (
"pyfa is released under GNU GPLv3 - see included gpl.txt",
"pyfa is released under GNU GPLv3 - see included LICENSE file",
"All EVE-Online related materials are property of CCP hf.",
"Silk Icons Set by famfamfam.com - Creative Commons Attribution 2.5 License",
"Fat Cow Icons by fatcow.com - Creative Commons Attribution 3.0 License"

View File

@@ -26,7 +26,7 @@ from gui.implantView import ImplantView
from gui.projectedView import ProjectedView
from gui.pyfatogglepanel import TogglePanel
from gui.gangView import GangView
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
import gui.chromeTabs
@@ -45,18 +45,16 @@ class AdditionsPane(TogglePanel):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.notebook = gui.chromeTabs.PFNotebook(pane, False)
size = wx.Size()
# This size lets you see 4 drones at a time
size.SetHeight(180)
self.notebook.SetMinSize(size)
self.notebook.SetMinSize((-1, 1000))
baseSizer.Add(self.notebook, 1, wx.EXPAND)
droneImg = bitmapLoader.getImage("drone_small", "icons")
implantImg = bitmapLoader.getImage("implant_small", "icons")
boosterImg = bitmapLoader.getImage("booster_small", "icons")
projectedImg = bitmapLoader.getImage("projected_small", "icons")
gangImg = bitmapLoader.getImage("fleet_fc_small", "icons")
cargoImg = bitmapLoader.getImage("cargo_small", "icons")
droneImg = BitmapLoader.getImage("drone_small", "gui")
implantImg = BitmapLoader.getImage("implant_small", "gui")
boosterImg = BitmapLoader.getImage("booster_small", "gui")
projectedImg = BitmapLoader.getImage("projected_small", "gui")
gangImg = BitmapLoader.getImage("fleet_fc_small", "gui")
cargoImg = BitmapLoader.getImage("cargo_small", "gui")
self.notebook.AddPage(DroneView(self.notebook), "Drones", tabImage = droneImg, showClose = False)
self.notebook.AddPage(CargoView(self.notebook), "Cargo", tabImage = cargoImg, showClose = False)
@@ -76,3 +74,21 @@ class AdditionsPane(TogglePanel):
def getName(self, idx):
return self.PANES[idx]
def toggleContent(self, event):
TogglePanel.toggleContent(self, event)
h = self.headerPanel.GetSize()[1]+4
if self.IsCollapsed():
self.old_pos = self.parent.GetSashPosition()
self.parent.SetMinimumPaneSize(h)
self.parent.SetSashPosition(h*-1, True)
# only available in >= wx2.9
if getattr(self.parent, "SetSashInvisible", None):
self.parent.SetSashInvisible(True)
else:
if getattr(self.parent, "SetSashInvisible", None):
self.parent.SetSashInvisible(False)
self.parent.SetMinimumPaneSize(200)
self.parent.SetSashPosition(self.old_pos, True)

View File

@@ -20,87 +20,74 @@
import os.path
import config
import wx
import time
import zipfile
import cStringIO
try:
from collections import OrderedDict
except ImportError:
from utils.compat import OrderedDict
cachedBitmapsCount = 0
cachedBitmaps = OrderedDict()
dontUseCachedBitmaps = False
class BitmapLoader():
def getStaticBitmap(name, parent, location):
static = wx.StaticBitmap(parent)
static.SetBitmap(getBitmap(name,location))
return static
try:
archive = zipfile.ZipFile(os.path.join(config.pyfaPath, 'imgs.zip'), 'r')
except IOError:
archive = None
locationMap = {"pack": os.path.join(config.staticPath, "icons"),
"ships": os.path.join(config.staticPath, "icons/ships")}
cachedBitmaps = OrderedDict()
dontUseCachedBitmaps = False
max_bmps = 500
def getBitmap(name,location):
@classmethod
def getStaticBitmap(cls, name, parent, location):
static = wx.StaticBitmap(parent)
static.SetBitmap(cls.getBitmap(name,location))
return static
global cachedBitmaps
global cachedBitmapsCount
global dontUseCachedBitmaps
@classmethod
def getBitmap(cls, name, location):
if cls.dontUseCachedBitmaps:
img = cls.getImage(name, location)
if img is not None:
return img.ConvertToBitmap()
if dontUseCachedBitmaps:
img = getImage(name, location)
if img is not None:
return img.ConvertToBitmap()
path = "%s%s" % (name, location)
path = "%s%s" % (name,location)
MAX_BMPS = 500
# start = time.clock()
if cachedBitmapsCount == MAX_BMPS:
cachedBitmaps.popitem(False)
cachedBitmapsCount -=1
if len(cls.cachedBitmaps) == cls.max_bmps:
cls.cachedBitmaps.popitem(False)
if path not in cachedBitmaps:
img = getImage(name, location)
if img is not None:
bmp = img.ConvertToBitmap()
if path not in cls.cachedBitmaps:
img = cls.getImage(name, location)
if img is not None:
bmp = img.ConvertToBitmap()
else:
bmp = None
cls.cachedBitmaps[path] = bmp
else:
bmp = None
cachedBitmaps[path] = bmp
cachedBitmapsCount += 1
else:
bmp = cachedBitmaps[path]
bmp = cls.cachedBitmaps[path]
# print "#BMPs:%d - Current took: %.8f" % (cachedBitmapsCount,time.clock() - start)
return bmp
return bmp
def stripPath(fname):
"""
Here we extract 'core' of icon name. Path and
extension are sometimes specified in database
but we don't need them.
"""
# Path before the icon file name
fname = fname.split('/')[-1]
# Extension
fname = fname.rsplit('.', 1)[0]
return fname
def getImage(name, location):
if location in locationMap:
if location == "pack":
location = locationMap[location]
name = stripPath(name)
filename = "icon{0}.png".format(name)
path = os.path.join(location, filename)
else:
location = locationMap[location]
filename = "{0}.png".format(name)
path = os.path.join(location, filename)
else:
location = os.path.join(config.pyfaPath, location)
@classmethod
def getImage(cls, name, location):
filename = "{0}.png".format(name)
path = os.path.join(location, filename)
if os.path.exists(path):
return wx.Image(path)
else:
print "Missing icon file: {0}".format(filename)
if cls.archive:
path = os.path.join(location, filename)
if os.sep != "/" and os.sep in path:
path = path.replace(os.sep, "/")
try:
img_data = cls.archive.read(path)
sbuf = cStringIO.StringIO(img_data)
return wx.ImageFromStream(sbuf)
except KeyError:
print "Missing icon file from zip: {0}".format(path)
else:
path = os.path.join(config.pyfaPath, 'imgs', location, filename)
if os.path.exists(path):
return wx.Image(path)
else:
print "Missing icon file: {0}".format(path)

View File

@@ -20,7 +20,6 @@ class ChangeAmount(ContextMenu):
srcContext = fullContext[0]
dlg = AmountChanger(self.mainFrame, selection[0], srcContext)
dlg.ShowModal()
dlg.Destroy()
ChangeAmount.register()
@@ -59,7 +58,7 @@ class AmountChanger(wx.Dialog):
wx.PostEvent(mainFrame, GE.FitChanged(fitID=fitID))
event.Skip()
self.Destroy()
self.Close()
## checks to make sure it's valid number
def onChar(self, event):

View File

@@ -3,7 +3,7 @@ from gui.contextMenu import ContextMenu
import gui.mainFrame
import service
import wx
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
from eos.types import Skill
import gui.globalEvents as GE
@@ -74,7 +74,7 @@ class ChangeAffectingSkills(ContextMenu):
grandSub = wx.Menu()
skillItem.SetSubMenu(grandSub)
if skill.learned:
bitmap = bitmapLoader.getBitmap("lvl%s" % skill.level, "icons")
bitmap = BitmapLoader.getBitmap("lvl%s" % skill.level, "gui")
if bitmap is not None:
skillItem.SetBitmap(bitmap)

View File

@@ -3,7 +3,7 @@ import gui.mainFrame
import service
import gui.globalEvents as GE
import wx
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
try:
from collections import OrderedDict
@@ -65,7 +65,7 @@ class DamagePattern(ContextMenu):
dp = f.damagePattern
if dp == pattern:
bitmap = bitmapLoader.getBitmap("state_active_small", "icons")
bitmap = BitmapLoader.getBitmap("state_active_small", "gui")
menuItem.SetBitmap(bitmap)
return menuItem
@@ -80,7 +80,7 @@ class DamagePattern(ContextMenu):
self.patternIds[id] = self.singles[i]
rootMenu.Bind(wx.EVT_MENU, self.handlePatternSwitch, pitem)
if self.patternIds[id] == self.fit.damagePattern:
bitmap = bitmapLoader.getBitmap("state_active_small", "icons")
bitmap = BitmapLoader.getBitmap("state_active_small", "gui")
pitem.SetBitmap(bitmap)
return False

View File

@@ -3,7 +3,7 @@ import gui.mainFrame
import service
import gui.globalEvents as GE
import wx
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
class FactorReload(ContextMenu):
def __init__(self):
@@ -27,7 +27,7 @@ class FactorReload(ContextMenu):
fitID = self.mainFrame.getActiveFit()
fit = sFit.getFit(fitID)
if fit.factorReload:
return bitmapLoader.getBitmap("state_active_small", "icons")
return BitmapLoader.getBitmap("state_active_small", "gui")
else:
return None

View File

@@ -3,7 +3,7 @@ from gui.contextMenu import ContextMenu
import gui.mainFrame
import service
import wx
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
from eos.types import Hardpoint
import gui.globalEvents as GE
@@ -105,7 +105,7 @@ class ModuleAmmoPicker(ContextMenu):
menu.Bind(wx.EVT_MENU, self.handleAmmoSwitch, item)
item.charge = charge
if charge is not None and charge.icon is not None:
bitmap = bitmapLoader.getBitmap(charge.icon.iconFile, "pack")
bitmap = BitmapLoader.getBitmap(charge.icon.iconFile, "icons")
if bitmap is not None:
item.SetBitmap(bitmap)
@@ -181,7 +181,7 @@ class ModuleAmmoPicker(ContextMenu):
type = currType
item = wx.MenuItem(m, wx.ID_ANY, type.capitalize())
bitmap = bitmapLoader.getBitmap("%s_small" % type, "icons")
bitmap = BitmapLoader.getBitmap("%s_small" % type, "gui")
if bitmap is not None:
item.SetBitmap(bitmap)

View File

@@ -3,7 +3,7 @@ from gui.contextMenu import ContextMenu
import gui.mainFrame
import service
import wx
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
from eos.types import Hardpoint
import gui.globalEvents as GE
from gui.builtinContextMenus.moduleAmmoPicker import ModuleAmmoPicker

View File

@@ -3,7 +3,7 @@ import gui.mainFrame
import service
import gui.globalEvents as GE
import wx
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
try:
from collections import OrderedDict
@@ -56,7 +56,7 @@ class TargetResists(ContextMenu):
tr = f.targetResists
if tr == pattern:
bitmap = bitmapLoader.getBitmap("state_active_small", "icons")
bitmap = BitmapLoader.getBitmap("state_active_small", "gui")
item.SetBitmap(bitmap)
return item

View File

@@ -19,7 +19,7 @@
from gui.graph import Graph
import service
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
from eos.graph.fitDps import FitDpsGraph as FitDps
from eos.graph import Data
import gui.mainFrame
@@ -56,7 +56,7 @@ class FitDpsGraph(Graph):
sAttr = service.Attribute.getInstance()
for key, attrName in self.propertyAttributeMap.iteritems():
iconFile = sAttr.getAttributeInfo(attrName).icon.iconFile
bitmap = bitmapLoader.getBitmap(iconFile, "pack")
bitmap = BitmapLoader.getBitmap(iconFile, "icons")
if bitmap:
icons[key] = bitmap

View File

@@ -1 +1,6 @@
__all__ = ["pyfaGeneralPreferences","pyfaHTMLExportPreferences","pyfaUpdatePreferences","pyfaNetworkPreferences"]
import wx
if not 'wxMac' in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3,0)):
__all__.append("pyfaCrestPreferences")

View File

@@ -19,7 +19,7 @@
import wx
from gui.preferenceView import PreferenceView
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
class DummyView(PreferenceView):
title = "Dummy"

View File

@@ -0,0 +1,120 @@
import wx
from gui.preferenceView import PreferenceView
from gui.bitmapLoader import BitmapLoader
import gui.mainFrame
import service
from service.crest import CrestModes
class PFCrestPref ( PreferenceView):
title = "CREST"
def populatePanel( self, panel ):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.settings = service.settings.CRESTSettings.getInstance()
self.dirtySettings = False
dlgWidth = panel.GetParent().GetParent().ClientSize.width
mainSizer = wx.BoxSizer( wx.VERTICAL )
self.stTitle = wx.StaticText( panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0 )
self.stTitle.Wrap( -1 )
self.stTitle.SetFont( wx.Font( 12, 70, 90, 90, False, wx.EmptyString ) )
mainSizer.Add( self.stTitle, 0, wx.ALL, 5 )
self.m_staticline1 = wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
mainSizer.Add( self.m_staticline1, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5 )
self.stInfo = wx.StaticText( panel, wx.ID_ANY, u"Please see the pyfa wiki on GitHub for information regarding these options.", wx.DefaultPosition, wx.DefaultSize, 0 )
self.stInfo.Wrap(dlgWidth - 50)
mainSizer.Add( self.stInfo, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5 )
rbSizer = wx.BoxSizer(wx.HORIZONTAL)
self.rbMode = wx.RadioBox(panel, -1, "Mode", wx.DefaultPosition, wx.DefaultSize, ['Implicit', 'User-supplied details'], 1, wx.RA_SPECIFY_COLS)
self.rbServer = wx.RadioBox(panel, -1, "Server", wx.DefaultPosition, wx.DefaultSize, ['Tranquility', 'Singularity'], 1, wx.RA_SPECIFY_COLS)
self.rbMode.SetSelection(self.settings.get('mode'))
self.rbServer.SetSelection(self.settings.get('server'))
rbSizer.Add(self.rbMode, 1, wx.TOP | wx.RIGHT, 5 )
rbSizer.Add(self.rbServer, 1, wx.ALL, 5 )
self.rbMode.Bind(wx.EVT_RADIOBOX, self.OnModeChange)
self.rbServer.Bind(wx.EVT_RADIOBOX, self.OnServerChange)
mainSizer.Add(rbSizer, 1, wx.ALL|wx.EXPAND, 0)
detailsTitle = wx.StaticText( panel, wx.ID_ANY, "CREST client details", wx.DefaultPosition, wx.DefaultSize, 0 )
detailsTitle.Wrap( -1 )
detailsTitle.SetFont( wx.Font( 12, 70, 90, 90, False, wx.EmptyString ) )
mainSizer.Add( detailsTitle, 0, wx.ALL, 5 )
mainSizer.Add( wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ), 0, wx.EXPAND, 5 )
fgAddrSizer = wx.FlexGridSizer( 2, 2, 0, 0 )
fgAddrSizer.AddGrowableCol( 1 )
fgAddrSizer.SetFlexibleDirection( wx.BOTH )
fgAddrSizer.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED )
self.stSetID = wx.StaticText( panel, wx.ID_ANY, u"Client ID:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.stSetID.Wrap( -1 )
fgAddrSizer.Add( self.stSetID, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.inputClientID = wx.TextCtrl( panel, wx.ID_ANY, self.settings.get('clientID'), wx.DefaultPosition, wx.DefaultSize, 0 )
fgAddrSizer.Add( self.inputClientID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5 )
self.stSetSecret = wx.StaticText( panel, wx.ID_ANY, u"Client Secret:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.stSetSecret.Wrap( -1 )
fgAddrSizer.Add( self.stSetSecret, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.inputClientSecret = wx.TextCtrl( panel, wx.ID_ANY, self.settings.get('clientSecret'), wx.DefaultPosition, wx.DefaultSize, 0 )
fgAddrSizer.Add( self.inputClientSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5 )
self.btnApply = wx.Button( panel, wx.ID_ANY, u"Save Client Settings", wx.DefaultPosition, wx.DefaultSize, 0 )
self.btnApply.Bind(wx.EVT_BUTTON, self.OnBtnApply)
mainSizer.Add( fgAddrSizer, 0, wx.EXPAND, 5)
mainSizer.Add( self.btnApply, 0, wx.ALIGN_RIGHT, 5)
self.ToggleProxySettings(self.settings.get('mode'))
panel.SetSizer( mainSizer )
panel.Layout()
def OnModeChange(self, event):
self.settings.set('mode', event.GetInt())
self.ToggleProxySettings(self.settings.get('mode'))
service.Crest.restartService()
def OnServerChange(self, event):
self.settings.set('server', event.GetInt())
service.Crest.restartService()
def OnBtnApply(self, event):
self.settings.set('clientID', self.inputClientID.GetValue())
self.settings.set('clientSecret', self.inputClientSecret.GetValue())
sCrest = service.Crest.getInstance()
sCrest.delAllCharacters()
def ToggleProxySettings(self, mode):
if mode:
self.stSetID.Enable()
self.inputClientID.Enable()
self.stSetSecret.Enable()
self.inputClientSecret.Enable()
else:
self.stSetID.Disable()
self.inputClientID.Disable()
self.stSetSecret.Disable()
self.inputClientSecret.Disable()
def getImage(self):
return BitmapLoader.getBitmap("eve", "gui")
PFCrestPref.register()

View File

@@ -6,7 +6,7 @@ import wx
import copy
from gui.preferenceView import PreferenceView
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
from gui.utils import colorUtils
import gui.utils.drawUtils as drawUtils
@@ -313,7 +313,7 @@ class PFGaugePref ( PreferenceView):
self.cp103105E.Bind( wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged )
def getImage(self):
return bitmapLoader.getBitmap("pref-gauges_big", "icons")
return BitmapLoader.getBitmap("pref-gauges_big", "gui")
def InitDefaultColours(self):
self.c0100S = wx.Colour(191, 191, 191, 255)

View File

@@ -1,7 +1,7 @@
import wx
from gui.preferenceView import PreferenceView
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
import gui.mainFrame
import service
@@ -144,6 +144,6 @@ class PFGeneralPref ( PreferenceView):
self.sFit.serviceFittingOptions["showMarketShortcuts"] = self.cbMarketShortcuts.GetValue()
def getImage(self):
return bitmapLoader.getBitmap("prefs_settings", "icons")
return BitmapLoader.getBitmap("prefs_settings", "gui")
PFGeneralPref.register()

View File

@@ -2,7 +2,7 @@ import wx
import os
from gui.preferenceView import PreferenceView
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
import gui.mainFrame
import service
@@ -76,6 +76,6 @@ class PFHTMLExportPref ( PreferenceView):
self.HTMLExportSettings.setEnabled(self.exportEnabled.GetValue())
def getImage(self):
return bitmapLoader.getBitmap("prefs_html", "icons")
return BitmapLoader.getBitmap("prefs_html", "gui")
PFHTMLExportPref.register()

View File

@@ -1,7 +1,7 @@
import wx
from gui.preferenceView import PreferenceView
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
import gui.mainFrame
import service
@@ -223,6 +223,6 @@ class PFNetworkPref ( PreferenceView):
self.editProxySettingsPort.Disable()
def getImage(self):
return bitmapLoader.getBitmap("prefs_proxy", "icons")
return BitmapLoader.getBitmap("prefs_proxy", "gui")
PFNetworkPref.register()

View File

@@ -3,7 +3,7 @@ import service
import os
from gui.preferenceView import PreferenceView
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
import service
import gui.globalEvents as GE
@@ -99,6 +99,6 @@ class PFUpdatePref (PreferenceView):
wx.LaunchDefaultBrowser('https://github.com/DarkFenX/Pyfa/releases/tag/'+self.UpdateSettings.get('version'))
def getImage(self):
return bitmapLoader.getBitmap("prefs_update", "icons")
return BitmapLoader.getBitmap("prefs_update", "gui")
PFUpdatePref.register()

View File

@@ -20,7 +20,7 @@
import wx
from gui.statsView import StatsView
from gui import builtinStatsViews
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
from gui.utils.numberFormatter import formatAmount
class CapacitorViewFull(StatsView):
@@ -48,7 +48,7 @@ class CapacitorViewFull(StatsView):
baseBox = wx.BoxSizer(wx.HORIZONTAL)
sizerCapacitor.Add(baseBox, 0, wx.ALIGN_LEFT)
bitmap = bitmapLoader.getStaticBitmap("capacitorInfo_big", parent, "icons")
bitmap = BitmapLoader.getStaticBitmap("capacitorInfo_big", parent, "gui")
tooltip = wx.ToolTip("Capacitor stability")
bitmap.SetToolTip(tooltip)
baseBox.Add(bitmap, 0, wx.ALIGN_CENTER)
@@ -83,7 +83,7 @@ class CapacitorViewFull(StatsView):
sizerCapacitor.Add(baseBox, 0, wx.ALIGN_CENTER_HORIZONTAL)
tooltip = wx.ToolTip("Capacitor throughput")
bitmap = bitmapLoader.getStaticBitmap("capacitorRecharge_big", parent, "icons")
bitmap = BitmapLoader.getStaticBitmap("capacitorRecharge_big", parent, "gui")
bitmap.SetToolTip(tooltip)
baseBox.Add(bitmap, 0, wx.ALIGN_CENTER)

View File

@@ -21,7 +21,7 @@ import wx
import service
import gui.mainFrame
from gui.statsView import StatsView
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
from gui.utils.numberFormatter import formatAmount
class FirepowerViewFull(StatsView):
@@ -61,7 +61,7 @@ class FirepowerViewFull(StatsView):
baseBox = wx.BoxSizer(wx.HORIZONTAL)
sizerFirepower.Add(baseBox, 1, wx.ALIGN_LEFT if counter == 0 else wx.ALIGN_CENTER_HORIZONTAL)
baseBox.Add(bitmapLoader.getStaticBitmap("%s_big" % image, parent, "icons"), 0, wx.ALIGN_CENTER)
baseBox.Add(BitmapLoader.getStaticBitmap("%s_big" % image, parent, "gui"), 0, wx.ALIGN_CENTER)
box = wx.BoxSizer(wx.VERTICAL)
baseBox.Add(box, 0, wx.ALIGN_CENTER)
@@ -82,7 +82,7 @@ class FirepowerViewFull(StatsView):
baseBox = wx.BoxSizer(wx.HORIZONTAL)
targetSizer.Add(baseBox, 0, wx.ALIGN_RIGHT)
baseBox.Add(bitmapLoader.getStaticBitmap("volley_big", parent, "icons"), 0, wx.ALIGN_CENTER)
baseBox.Add(BitmapLoader.getStaticBitmap("volley_big", parent, "gui"), 0, wx.ALIGN_CENTER)
gridS = wx.GridSizer(2,2,0,0)
@@ -103,7 +103,7 @@ class FirepowerViewFull(StatsView):
gridS.Add(lbl, 0, wx.ALIGN_LEFT)
image = bitmapLoader.getBitmap("mining_small", "icons")
image = BitmapLoader.getBitmap("mining_small", "gui")
self.miningyield = wx.BitmapButton(contentPanel, -1, image)
self.miningyield.SetToolTip(wx.ToolTip("Click to toggle to Mining Yield "))
self.miningyield.Bind(wx.EVT_BUTTON, self.switchToMiningYieldView)

View File

@@ -21,7 +21,7 @@ import wx
import service
import gui.mainFrame
from gui.statsView import StatsView
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
from gui.utils.numberFormatter import formatAmount
class MiningYieldViewFull(StatsView):
@@ -55,7 +55,7 @@ class MiningYieldViewFull(StatsView):
baseBox = wx.BoxSizer(wx.HORIZONTAL)
sizerMiningYield.Add(baseBox, 1, wx.ALIGN_LEFT if counter == 0 else wx.ALIGN_CENTER_HORIZONTAL)
baseBox.Add(bitmapLoader.getStaticBitmap("%s_big" % image, parent, "icons"), 0, wx.ALIGN_CENTER)
baseBox.Add(BitmapLoader.getStaticBitmap("%s_big" % image, parent, "gui"), 0, wx.ALIGN_CENTER)
box = wx.BoxSizer(wx.VERTICAL)
baseBox.Add(box, 0, wx.ALIGN_CENTER)
@@ -76,7 +76,7 @@ class MiningYieldViewFull(StatsView):
baseBox = wx.BoxSizer(wx.HORIZONTAL)
targetSizer.Add(baseBox, 0, wx.ALIGN_LEFT)
baseBox.Add(bitmapLoader.getStaticBitmap("cargoBay_big", parent, "icons"), 0, wx.ALIGN_CENTER)
baseBox.Add(BitmapLoader.getStaticBitmap("cargoBay_big", parent, "gui"), 0, wx.ALIGN_CENTER)
box = wx.BoxSizer(wx.VERTICAL)
baseBox.Add(box, 0, wx.EXPAND)
@@ -92,7 +92,7 @@ class MiningYieldViewFull(StatsView):
self._cachedValues.append(0)
image = bitmapLoader.getBitmap("turret_small", "icons")
image = BitmapLoader.getBitmap("turret_small", "gui")
firepower = wx.BitmapButton(contentPanel, -1, image)
firepower.SetToolTip(wx.ToolTip("Click to toggle to Firepower View"))
firepower.Bind(wx.EVT_BUTTON, self.switchToFirepowerView)

View File

@@ -20,7 +20,7 @@
import wx
from gui.statsView import StatsView
from gui import builtinStatsViews
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
from gui.utils.numberFormatter import formatAmount
import service
import locale
@@ -56,7 +56,7 @@ class PriceViewFull(StatsView):
box = wx.BoxSizer(wx.HORIZONTAL)
gridPrice.Add(box, 0, wx.ALIGN_TOP)
box.Add(bitmapLoader.getStaticBitmap(image, contentPanel, "icons"), 0, wx.ALIGN_CENTER)
box.Add(BitmapLoader.getStaticBitmap(image, contentPanel, "gui"), 0, wx.ALIGN_CENTER)
vbox = wx.BoxSizer(wx.VERTICAL)
box.Add(vbox, 1, wx.EXPAND)

View File

@@ -19,7 +19,7 @@
import wx
from gui.statsView import StatsView
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
from gui.utils.numberFormatter import formatAmount
import gui.mainFrame
import gui.builtinStatsViews.resistancesViewFull as rvf
@@ -62,14 +62,14 @@ class RechargeViewFull(StatsView):
sizerTankStats.Add(wx.StaticText(contentPanel, wx.ID_ANY, ""), 0)
toolTipText = {"shieldPassive" : "Passive shield recharge", "shieldActive" : "Active shield boost", "armorActive" : "Armor repair amount", "hullActive" : "Hull repair amount"}
for tankType in ("shieldPassive", "shieldActive", "armorActive", "hullActive"):
bitmap = bitmapLoader.getStaticBitmap("%s_big" % tankType, contentPanel, "icons")
bitmap = BitmapLoader.getStaticBitmap("%s_big" % tankType, contentPanel, "gui")
tooltip = wx.ToolTip(toolTipText[tankType])
bitmap.SetToolTip(tooltip)
sizerTankStats.Add(bitmap, 0, wx.ALIGN_CENTER)
toolTipText = {"reinforced" : "Reinforced", "sustained" : "Sustained"}
for stability in ("reinforced", "sustained"):
bitmap = bitmapLoader.getStaticBitmap("regen%s_big" % stability.capitalize(), contentPanel, "icons")
bitmap = BitmapLoader.getStaticBitmap("regen%s_big" % stability.capitalize(), contentPanel, "gui")
tooltip = wx.ToolTip(toolTipText[stability])
bitmap.SetToolTip(tooltip)
sizerTankStats.Add(bitmap, 0, wx.ALIGN_CENTER)

View File

@@ -20,7 +20,7 @@
import wx
from gui.statsView import StatsView
from gui import builtinStatsViews
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
from gui import pygauge as PG
from gui.utils.numberFormatter import formatAmount
import service
@@ -74,18 +74,15 @@ class ResistancesViewFull(StatsView):
# Display table
col = 0
row = 0
sizerResistances = wx.GridBagSizer(0, 0)
sizerResistances = wx.GridBagSizer()
contentSizer.Add( sizerResistances, 0, wx.EXPAND , 0)
for i in xrange(6):
sizerResistances.AddGrowableCol(i + 1)
# Add an empty label, then the rest.
sizerResistances.Add(wx.StaticText(contentPanel, wx.ID_ANY), wx.GBPosition( row, col ), wx.GBSpan( 1, 1 ))
col+=1
toolTipText = {"em" : "Electromagnetic resistance", "thermal" : "Thermal resistance", "kinetic" : "Kinetic resistance", "explosive" : "Explosive resistance"}
for damageType in ("em", "thermal", "kinetic", "explosive"):
bitmap = bitmapLoader.getStaticBitmap("%s_big" % damageType, contentPanel, "icons")
bitmap = BitmapLoader.getStaticBitmap("%s_big" % damageType, contentPanel, "gui")
tooltip = wx.ToolTip(toolTipText[damageType])
bitmap.SetToolTip(tooltip)
sizerResistances.Add(bitmap, wx.GBPosition( row, col ), wx.GBSpan( 1, 1 ), wx.ALIGN_CENTER)
@@ -95,6 +92,8 @@ class ResistancesViewFull(StatsView):
self.stEHPs.Bind(wx.EVT_BUTTON, self.toggleEHP)
for i in xrange(4):
sizerResistances.AddGrowableCol(i+1)
sizerResistances.Add(self.stEHPs, wx.GBPosition( row, col ), wx.GBSpan( 1, 1 ), wx.ALIGN_CENTER)
col=0
@@ -105,7 +104,7 @@ class ResistancesViewFull(StatsView):
toolTipText = {"shield" : "Shield resistance", "armor" : "Armor resistance", "hull" : "Hull resistance", "damagePattern" : "Incoming damage pattern"}
for tankType in ("shield", "armor", "hull", "separator", "damagePattern"):
if tankType != "separator":
bitmap = bitmapLoader.getStaticBitmap("%s_big" % tankType, contentPanel, "icons")
bitmap = BitmapLoader.getStaticBitmap("%s_big" % tankType, contentPanel, "gui")
tooltip = wx.ToolTip(toolTipText[tankType])
bitmap.SetToolTip(tooltip)
sizerResistances.Add(bitmap, wx.GBPosition( row, col ), wx.GBSpan( 1, 1 ), wx.ALIGN_CENTER)

View File

@@ -20,7 +20,7 @@
import wx
from gui.statsView import StatsView
from gui import builtinStatsViews
from gui import bitmapLoader
from gui.bitmapLoader import BitmapLoader
from gui import pygauge as PG
import gui.mainFrame
import gui.chromeTabs
@@ -91,7 +91,7 @@ class ResourcesViewFull(StatsView):
for type in ("turret", "launcher", "drones", "calibration"):
box = wx.BoxSizer(wx.HORIZONTAL)
bitmap = bitmapLoader.getStaticBitmap("%s_big" % type, parent, "icons")
bitmap = BitmapLoader.getStaticBitmap("%s_big" % type, parent, "gui")
tooltip = wx.ToolTip(tooltipText[type])
bitmap.SetToolTip(tooltip)
@@ -119,7 +119,7 @@ class ResourcesViewFull(StatsView):
for type in group:
capitalizedType = type[0].capitalize() + type[1:]
bitmap = bitmapLoader.getStaticBitmap(type + "_big", parent, "icons")
bitmap = BitmapLoader.getStaticBitmap(type + "_big", parent, "gui")
tooltip = wx.ToolTip(tooltipText[type])
bitmap.SetToolTip(tooltip)

View File

@@ -52,7 +52,7 @@ class TargetingMiscViewFull(StatsView):
gridTargetingMisc.AddGrowableCol(2)
# Targeting
gridTargeting = wx.FlexGridSizer(4, 2)
gridTargeting = wx.FlexGridSizer(5, 2)
gridTargeting.AddGrowableCol(1)
gridTargetingMisc.Add(gridTargeting, 0, wx.ALIGN_LEFT | wx.ALL, 5)
@@ -77,7 +77,7 @@ class TargetingMiscViewFull(StatsView):
# Misc
gridTargetingMisc.Add( wx.StaticLine( contentPanel, wx.ID_ANY, style = wx.VERTICAL),0, wx.EXPAND, 3 )
gridMisc = wx.FlexGridSizer(4, 2)
gridMisc = wx.FlexGridSizer(5, 2)
gridMisc.AddGrowableCol(1)
gridTargetingMisc.Add(gridMisc,0 , wx.ALIGN_LEFT | wx.ALL, 5)

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