Merge branch 'master' into efs_port
@@ -24,10 +24,10 @@ saveInRoot = False
|
||||
|
||||
# Version data
|
||||
|
||||
version = "2.3.1"
|
||||
version = "2.4.0"
|
||||
tag = "Stable"
|
||||
expansionName = "YC120.7"
|
||||
expansionVersion = "1.2"
|
||||
expansionName = "YC120.8"
|
||||
expansionVersion = "1.0"
|
||||
evemonMinVersion = "4081"
|
||||
|
||||
minItemSearchLength = 3
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# boosterShieldCapacityPenalty
|
||||
#
|
||||
# Used by:
|
||||
# Implants from group: Booster (12 of 66)
|
||||
# Implants from group: Booster (12 of 65)
|
||||
type = "boosterSideEffect"
|
||||
|
||||
# User-friendly name for the side effect
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
# Used by:
|
||||
# Ships from group: Black Ops (5 of 5)
|
||||
# Ships from group: Blockade Runner (4 of 4)
|
||||
# Ships from group: Covert Ops (7 of 7)
|
||||
# Ships from group: Covert Ops (8 of 8)
|
||||
# Ships from group: Expedition Frigate (2 of 2)
|
||||
# Ships from group: Force Recon Ship (8 of 8)
|
||||
# Ships from group: Force Recon Ship (9 of 9)
|
||||
# Ships from group: Stealth Bomber (5 of 5)
|
||||
# Ships named like: Stratios (2 of 2)
|
||||
# Subsystems named like: Defensive Covert Reconfiguration (4 of 4)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# covertOpsCloakCpuPercentBonus1
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Covert Ops (5 of 7)
|
||||
# Ships from group: Covert Ops (6 of 8)
|
||||
type = "passive"
|
||||
runTime = "early"
|
||||
|
||||
|
||||
9
eos/effects/covertopswarpresistance.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# covertOpsWarpResistance
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Covert Ops (5 of 8)
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.ship.increaseItemAttr("warpFactor", src.getModifiedItemAttr("eliteBonusCovertOps1"), skill="Covert Ops")
|
||||
@@ -1,7 +1,7 @@
|
||||
# cynosuralDurationBonus
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Force Recon Ship (7 of 8)
|
||||
# Ships from group: Force Recon Ship (8 of 9)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# cynosuralTheoryConsumptionBonus
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Force Recon Ship (7 of 8)
|
||||
# Ships from group: Force Recon Ship (8 of 9)
|
||||
# Skill: Cynosural Field Theory
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# eliteBonusCoverOpsScanProbeStrength2
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Covert Ops (7 of 7)
|
||||
# Ships from group: Covert Ops (8 of 8)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
10
eos/effects/elitebonusmaxdmgmultibonusadd.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# eliteBonusMaxDmgMultiBonusAdd
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Hydra
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Small Precursor Weapon"), "damageMultiplierBonusMax",
|
||||
src.getModifiedItemAttr("eliteBonusCovertOps3"), skill="Covert Ops")
|
||||
10
eos/effects/elitebonusreconmaxdmgmultimaxhpt.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# eliteBonusReconMaxDmgMultiMaxHPT
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Tiamat
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Medium Precursor Weapon"), "damageMultiplierBonusMax",
|
||||
src.getModifiedItemAttr("eliteBonusReconShip3"), skill="Recon Ships")
|
||||
10
eos/effects/elitebonusreconscanprobestrength2.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# eliteBonusReconScanProbeStrength2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Tiamat
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Astrometrics"), "baseSensorStrength",
|
||||
src.getModifiedItemAttr("eliteBonusReconShip2"), skill="Recon Ships")
|
||||
@@ -7,3 +7,9 @@ type = "active"
|
||||
|
||||
def handler(fit, module, context):
|
||||
fit.ship.forceItemAttr("disallowAssistance", module.getModifiedItemAttr("disallowAssistance"))
|
||||
for scanType in ("Gravimetric", "Magnetometric", "Radar", "Ladar"):
|
||||
fit.ship.boostItemAttr(
|
||||
"scan{}Strength".format(scanType),
|
||||
module.getModifiedItemAttr("scan{}StrengthPercent".format(scanType)),
|
||||
stackingPenalties=True
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# minigameVirusStrengthBonus
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Covert Ops (7 of 7)
|
||||
# Ships from group: Covert Ops (7 of 8)
|
||||
# Ships named like: Stratios (2 of 2)
|
||||
# Subsystems named like: Defensive Covert Reconfiguration (4 of 4)
|
||||
# Ship: Astero
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# reconShipCloakCpuBonus1
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Force Recon Ship (6 of 8)
|
||||
# Ships from group: Force Recon Ship (7 of 9)
|
||||
type = "passive"
|
||||
runTime = "early"
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Hydra
|
||||
# Ship: Leshak
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# shipbonusPCTDamagePC1
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Hydra
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Hydra
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# shipbonusPCTTrackingPC2
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Hydra
|
||||
# Ship: Leshak
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Hydra
|
||||
# Ship: Leshak
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Ship: Damavik
|
||||
# Ship: Hydra
|
||||
# Ship: Leshak
|
||||
# Ship: Tiamat
|
||||
# Ship: Vedmak
|
||||
type = "passive"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# shipBonusSurveyProbeExplosionDelaySkillSurveyCovertOps3
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Covert Ops (5 of 7)
|
||||
# Ships from group: Covert Ops (5 of 8)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -685,15 +685,13 @@ class Fit(object):
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"),
|
||||
"armorDamageAmount", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 88: # AOE_Beacon_filament_cloud_shield_booster
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Operation") or
|
||||
mod.item.requiresSkill("Shield Emission Systems"),
|
||||
"capacitorNeed", value, stackingPenalties=True)
|
||||
if warfareBuffID == 88: # AOE_Beacon_filament_cloud_shield_booster_shield_bonus
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Operation"),
|
||||
"shieldBonus", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 89: # AOE_Beacon_filament_cloud_ancillary_charge_usage
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Operation") or
|
||||
mod.item.requiresSkill("Shield Emission Systems"),
|
||||
"chargeRate", value, stackingPenalties=True)
|
||||
if warfareBuffID == 89: # AOE_Beacon_filament_cloud_shield_booster_duration
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Operation"),
|
||||
"duration", value, stackingPenalties=True)
|
||||
|
||||
# Abysmal Weather Effects
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ class ModuleAmmoPicker(ContextMenu):
|
||||
|
||||
type_ = currType
|
||||
item = wx.MenuItem(m, wx.ID_ANY, type_.capitalize())
|
||||
bitmap = BitmapLoader.getBitmap("%s_small" % type, "gui")
|
||||
bitmap = BitmapLoader.getBitmap("%s_small" % type_, "gui")
|
||||
if bitmap is not None:
|
||||
item.SetBitmap(bitmap)
|
||||
|
||||
|
||||
@@ -125,11 +125,11 @@ class ItemCompare(wx.Panel):
|
||||
# Remember to reduce by 1, because the attrs array
|
||||
# starts at 0 while the list has the item name as column 0.
|
||||
attr = str(list(self.attrs.keys())[sort - 1])
|
||||
func = lambda _val: _val.attributes[attr].value if attr in _val.attributes else None
|
||||
func = lambda _val: _val.attributes[attr].value if attr in _val.attributes else 0.0
|
||||
except IndexError:
|
||||
# Clicked on a column that's not part of our array (price most likely)
|
||||
self.sortReverse = False
|
||||
func = lambda _val: _val.attributes['metaLevel'].value if 'metaLevel' in _val.attributes else None
|
||||
func = lambda _val: _val.attributes['metaLevel'].value if 'metaLevel' in _val.attributes else 0.0
|
||||
|
||||
self.items = sorted(self.items, key=func, reverse=self.sortReverse)
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@ import wx
|
||||
|
||||
from service.fit import Fit
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
import gui.globalEvents as GE
|
||||
from gui.preferenceView import PreferenceView
|
||||
from service.settings import EOSSettings
|
||||
import gui.mainFrame
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -21,6 +23,7 @@ class PFFittingEnginePref(PreferenceView):
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
def populatePanel(self, panel):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
@@ -98,6 +101,9 @@ class PFFittingEnginePref(PreferenceView):
|
||||
|
||||
def OnCBGlobalForceReloadStateChange(self, event):
|
||||
self.sFit.serviceFittingOptions["useGlobalForceReload"] = self.cbGlobalForceReload.GetValue()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
self.sFit.refreshFit(fitID)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
|
||||
|
||||
def OnCBStrictSkillLevelsChange(self, event):
|
||||
self.engine_settings.set("strictSkillLevels", self.cbStrictSkillLevels.GetValue())
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
import gui.utils.draw as drawUtils
|
||||
import gui.mainFrame
|
||||
|
||||
SB_ITEM_NORMAL = 0
|
||||
SB_ITEM_SELECTED = 1
|
||||
@@ -245,6 +246,7 @@ class SFBrowserItem(wx.Window):
|
||||
self.highlighted = False
|
||||
self.selected = False
|
||||
self.bkBitmap = None
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
self.canBeDragged = False
|
||||
|
||||
@@ -311,6 +313,10 @@ class SFBrowserItem(wx.Window):
|
||||
self.canBeDragged = mode
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
if self.mainFrame.supress_left_up:
|
||||
wx.Yield()
|
||||
self.mainFrame.supress_left_up = False
|
||||
return
|
||||
|
||||
if self.HasCapture():
|
||||
self.ReleaseMouse()
|
||||
|
||||
@@ -45,21 +45,21 @@ class Price(ViewColumn):
|
||||
if stuff.isEmpty:
|
||||
return ""
|
||||
|
||||
price = stuff.item.price.price
|
||||
price = stuff.item.price
|
||||
|
||||
if not price:
|
||||
return ""
|
||||
if not price or not price.isValid:
|
||||
return False
|
||||
|
||||
if isinstance(stuff, Drone) or isinstance(stuff, Cargo):
|
||||
price *= stuff.amount
|
||||
price.price *= stuff.amount
|
||||
|
||||
return formatAmount(price, 3, 3, 9, currency=True)
|
||||
return formatAmount(price.price, 3, 3, 9, currency=True)
|
||||
|
||||
def delayedText(self, mod, display, colItem):
|
||||
sPrice = ServicePrice.getInstance()
|
||||
|
||||
def callback(item):
|
||||
price = item.item.price
|
||||
price = item[0]
|
||||
text = formatAmount(price.price, 3, 3, 9, currency=True) if price.price else ""
|
||||
if price.failed:
|
||||
text += " (!)"
|
||||
|
||||
@@ -477,7 +477,7 @@ class FittingView(d.Display):
|
||||
return
|
||||
|
||||
if getattr(mod2, "modPosition") is not None:
|
||||
if clone and mod2.isEmpty:
|
||||
if clone and mod2.isEmpty and mod1.getModifiedItemAttr("maxGroupFitted", 0) < 1.0:
|
||||
sFit.cloneModule(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition)
|
||||
else:
|
||||
sFit.swapModules(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition)
|
||||
|
||||
@@ -552,24 +552,6 @@ class _TabRenderer:
|
||||
bmp,
|
||||
self.left_width + self.padding - bmp.GetWidth() / 2,
|
||||
(height - bmp.GetHeight()) / 2)
|
||||
text_start = self.left_width + self.padding + bmp.GetWidth() / 2
|
||||
else:
|
||||
text_start = self.left_width
|
||||
|
||||
mdc.SetFont(self.font)
|
||||
|
||||
maxsize = self.tab_width \
|
||||
- text_start \
|
||||
- self.right_width \
|
||||
- self.padding * 4
|
||||
color = self.selected_color if self.selected else self.inactive_color
|
||||
|
||||
mdc.SetTextForeground(color_utils.GetSuitable(color, 1))
|
||||
|
||||
# draw text (with no ellipses)
|
||||
text = draw.GetPartialText(mdc, self.text, maxsize, "")
|
||||
tx, ty = mdc.GetTextExtent(text)
|
||||
mdc.DrawText(text, text_start + self.padding, height / 2 - ty / 2)
|
||||
|
||||
# draw close button
|
||||
if self.closeable:
|
||||
@@ -596,6 +578,30 @@ class _TabRenderer:
|
||||
bmp = wx.Bitmap(img)
|
||||
self.tab_bitmap = bmp
|
||||
|
||||
# We draw the text separately in order to draw it directly on the native DC, rather than a memory one, because
|
||||
# drawing text on a memory DC draws it blurry on HD/Retina screens
|
||||
def DrawText(self, dc):
|
||||
height = self.tab_height
|
||||
dc.SetFont(self.font)
|
||||
|
||||
if self.tab_img:
|
||||
text_start = self.left_width + self.padding + self.tab_img.GetWidth() / 2
|
||||
else:
|
||||
text_start = self.left_width
|
||||
|
||||
maxsize = self.tab_width \
|
||||
- text_start \
|
||||
- self.right_width \
|
||||
- self.padding * 4
|
||||
color = self.selected_color if self.selected else self.inactive_color
|
||||
|
||||
dc.SetTextForeground(color_utils.GetSuitable(color, 1))
|
||||
|
||||
# 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)
|
||||
|
||||
def __repr__(self):
|
||||
return "_TabRenderer(text={}, disabled={}) at {}".format(
|
||||
self.text, self.disabled, hex(id(self))
|
||||
@@ -1145,6 +1151,10 @@ class _TabsContainer(wx.Panel):
|
||||
img = img.AdjustChannels(1, 1, 1, 0.85)
|
||||
bmp = wx.Bitmap(img)
|
||||
mdc.DrawBitmap(bmp, posx, posy, True)
|
||||
|
||||
mdc.SetDeviceOrigin(posx, posy)
|
||||
tab.DrawText(mdc)
|
||||
mdc.SetDeviceOrigin(0, 0)
|
||||
else:
|
||||
selected = tab
|
||||
|
||||
@@ -1164,6 +1174,10 @@ class _TabsContainer(wx.Panel):
|
||||
|
||||
mdc.DrawBitmap(bmp, posx, posy, True)
|
||||
|
||||
mdc.SetDeviceOrigin(posx, posy)
|
||||
selected.DrawText(mdc)
|
||||
mdc.SetDeviceOrigin(0, 0)
|
||||
|
||||
def OnErase(self, event):
|
||||
pass
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class CopySelectDialog(wx.Dialog):
|
||||
CopySelectDialog.copyFormatEftImps: "EFT text format",
|
||||
CopySelectDialog.copyFormatXml: "EVE native XML format",
|
||||
CopySelectDialog.copyFormatDna: "A one-line text format",
|
||||
CopySelectDialog.copyFormatEsi: "A JSON format used for EVE CREST",
|
||||
CopySelectDialog.copyFormatEsi: "A JSON format used for ESI",
|
||||
CopySelectDialog.copyFormatMultiBuy: "MultiBuy text format",
|
||||
CopySelectDialog.copyFormatEfs: "JSON data format used by EFS"}
|
||||
selector = wx.RadioBox(self, wx.ID_ANY, label="Copy to the clipboard using:", choices=copyFormats,
|
||||
|
||||
@@ -26,6 +26,7 @@ import traceback
|
||||
import config
|
||||
from logbook import Logger
|
||||
from service.prereqsCheck import version_block
|
||||
import datetime
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
@@ -63,6 +64,11 @@ class ErrorFrame(wx.Frame):
|
||||
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="pyfa error", pos=wx.DefaultPosition, size=wx.Size(500, 600),
|
||||
style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER | wx.STAY_ON_TOP)
|
||||
|
||||
from eos.config import gamedata_version, gamedata_date
|
||||
|
||||
time = datetime.datetime.fromtimestamp(int(gamedata_date)).strftime('%Y-%m-%d %H:%M:%S')
|
||||
version = "pyfa v" + config.getVersion() + '\nEVE Data Version: {} ({})\n\n'.format(gamedata_version, time) # gui.aboutData.versionString
|
||||
|
||||
desc = "pyfa has experienced an unexpected issue. Below is a message that contains crucial\n" \
|
||||
"information about how this was triggered. Please contact the developers with the\n" \
|
||||
"information provided through the EVE Online forums or file a GitHub issue."
|
||||
@@ -97,7 +103,7 @@ class ErrorFrame(wx.Frame):
|
||||
|
||||
# mainSizer.AddSpacer((0, 5), 0, wx.EXPAND, 5)
|
||||
|
||||
self.errorTextCtrl = wx.TextCtrl(self, wx.ID_ANY, version_block.strip(), wx.DefaultPosition,
|
||||
self.errorTextCtrl = wx.TextCtrl(self, wx.ID_ANY, version + version_block.strip(), wx.DefaultPosition,
|
||||
(-1, 400), wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2 | wx.TE_DONTWRAP)
|
||||
self.errorTextCtrl.SetFont(wx.Font(8, wx.FONTFAMILY_TELETYPE, wx.NORMAL, wx.NORMAL))
|
||||
mainSizer.Add(self.errorTextCtrl, 0, wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, 5)
|
||||
|
||||
@@ -155,6 +155,7 @@ class MainFrame(wx.Frame):
|
||||
pyfalog.debug("Initialize MainFrame")
|
||||
self.title = title
|
||||
wx.Frame.__init__(self, None, wx.ID_ANY, self.title)
|
||||
self.supress_left_up = False
|
||||
|
||||
MainFrame.__instance = self
|
||||
|
||||
@@ -433,6 +434,7 @@ class MainFrame(wx.Frame):
|
||||
style=wx.FD_SAVE,
|
||||
defaultFile=defaultFile)
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
self.supress_left_up = True
|
||||
format_ = dlg.GetFilterIndex()
|
||||
path = dlg.GetPath()
|
||||
if format_ == 0:
|
||||
@@ -977,6 +979,7 @@ class MainFrame(wx.Frame):
|
||||
)
|
||||
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
self.supress_left_up = True
|
||||
self.waitDialog = wx.BusyInfo("Importing Character...")
|
||||
sCharacter = Character.getInstance()
|
||||
sCharacter.importCharacter(dlg.GetPaths(), self.importCharacterCallback)
|
||||
|
||||
BIN
imgs/icons/10160.png
Normal file
|
After Width: | Height: | Size: 783 B |
BIN
imgs/icons/10851.png
Normal file
|
After Width: | Height: | Size: 682 B |
BIN
imgs/icons/21785.png
Normal file
|
After Width: | Height: | Size: 739 B |
BIN
imgs/icons/22029.png
Normal file
|
After Width: | Height: | Size: 883 B |
BIN
imgs/icons/22030.png
Normal file
|
After Width: | Height: | Size: 723 B |
BIN
imgs/icons/22031.png
Normal file
|
After Width: | Height: | Size: 874 B |
BIN
imgs/icons/22034.png
Normal file
|
After Width: | Height: | Size: 574 B |
BIN
imgs/icons/22036.png
Normal file
|
After Width: | Height: | Size: 812 B |
BIN
imgs/icons/22041.png
Normal file
|
After Width: | Height: | Size: 545 B |
BIN
imgs/renders/21344.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
imgs/renders/21362.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
imgs/renders/21405.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
imgs/renders/21406.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
@@ -141,6 +141,7 @@ def get_icon_file(res_path, size):
|
||||
icon for it. Return as PIL image object down-
|
||||
scaled for use in pyfa.
|
||||
"""
|
||||
res_path = res_path.replace('//', '/') #1703
|
||||
if res_path not in res_index:
|
||||
return None
|
||||
res_icon = res_index[res_path]
|
||||
@@ -192,7 +193,10 @@ if toadd:
|
||||
print(('Adding {} icons...'.format(len(toadd))))
|
||||
missing = set()
|
||||
for fname in sorted(toadd):
|
||||
icon = icon_json[str(fname)]
|
||||
icon = icon_json.get(str(fname), None)
|
||||
if icon is None:
|
||||
print("Can't find iconID {}".format(fname))
|
||||
continue
|
||||
key = icon['iconFile'].lower()
|
||||
icon = get_icon_file(key, ICON_SIZE)
|
||||
if icon is None:
|
||||
|
||||
@@ -25,7 +25,7 @@ import re
|
||||
|
||||
# Add eos root path to sys.path so we can import ourselves
|
||||
path = os.path.dirname(__file__)
|
||||
sys.path.insert(0, os.path.realpath(os.path.join(path, "..")))
|
||||
sys.path.insert(0, os.path.realpath(os.path.join(path, '..')))
|
||||
|
||||
import json
|
||||
import argparse
|
||||
@@ -54,65 +54,65 @@ def main(db, json_path):
|
||||
|
||||
# Config dict
|
||||
tables = {
|
||||
"clonegrades": eos.gamedata.AlphaCloneSkill,
|
||||
"dgmattribs": eos.gamedata.AttributeInfo,
|
||||
"dgmeffects": eos.gamedata.Effect,
|
||||
"dgmtypeattribs": eos.gamedata.Attribute,
|
||||
"dgmtypeeffects": eos.gamedata.ItemEffect,
|
||||
"dgmunits": eos.gamedata.Unit,
|
||||
"evecategories": eos.gamedata.Category,
|
||||
"evegroups": eos.gamedata.Group,
|
||||
"invmetagroups": eos.gamedata.MetaGroup,
|
||||
"invmetatypes": eos.gamedata.MetaType,
|
||||
"evetypes": eos.gamedata.Item,
|
||||
"phbtraits": eos.gamedata.Traits,
|
||||
"phbmetadata": eos.gamedata.MetaData,
|
||||
"mapbulk_marketGroups": eos.gamedata.MarketGroup,
|
||||
'clonegrades': eos.gamedata.AlphaCloneSkill,
|
||||
'dgmattribs': eos.gamedata.AttributeInfo,
|
||||
'dgmeffects': eos.gamedata.Effect,
|
||||
'dgmtypeattribs': eos.gamedata.Attribute,
|
||||
'dgmtypeeffects': eos.gamedata.ItemEffect,
|
||||
'dgmunits': eos.gamedata.Unit,
|
||||
'evecategories': eos.gamedata.Category,
|
||||
'evegroups': eos.gamedata.Group,
|
||||
'invmetagroups': eos.gamedata.MetaGroup,
|
||||
'invmetatypes': eos.gamedata.MetaType,
|
||||
'evetypes': eos.gamedata.Item,
|
||||
'phbtraits': eos.gamedata.Traits,
|
||||
'phbmetadata': eos.gamedata.MetaData,
|
||||
'mapbulk_marketGroups': eos.gamedata.MarketGroup,
|
||||
}
|
||||
|
||||
fieldMapping = {
|
||||
"dgmattribs": {
|
||||
"displayName_en-us": "displayName"
|
||||
'dgmattribs': {
|
||||
'displayName': 'displayName'
|
||||
},
|
||||
"dgmeffects": {
|
||||
"displayName_en-us": "displayName",
|
||||
"description_en-us": "description"
|
||||
'dgmeffects': {
|
||||
'displayName': 'displayName',
|
||||
'description': 'description'
|
||||
},
|
||||
"dgmunits": {
|
||||
"displayName_en-us": "displayName"
|
||||
'dgmunits': {
|
||||
'displayName': 'displayName'
|
||||
},
|
||||
#icons???
|
||||
"evecategories": {
|
||||
"categoryName_en-us": "categoryName"
|
||||
'evecategories': {
|
||||
'categoryName': 'categoryName'
|
||||
},
|
||||
"evegroups": {
|
||||
"groupName_en-us": "groupName"
|
||||
'evegroups': {
|
||||
'groupName': 'groupName'
|
||||
},
|
||||
"invmetagroups": {
|
||||
"metaGroupName_en-us": "metaGroupName"
|
||||
'invmetagroups': {
|
||||
'metaGroupName': 'metaGroupName'
|
||||
},
|
||||
"evetypes": {
|
||||
"typeName_en-us": "typeName",
|
||||
"description_en-us": "description"
|
||||
'evetypes': {
|
||||
'typeName': 'typeName',
|
||||
'description': 'description'
|
||||
},
|
||||
#phbtraits???
|
||||
"mapbulk_marketGroups": {
|
||||
"marketGroupName_en-us": "marketGroupName",
|
||||
"description_en-us": "description"
|
||||
'mapbulk_marketGroups': {
|
||||
'marketGroupName': 'marketGroupName',
|
||||
'description': 'description'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rowsInValues = (
|
||||
"evetypes",
|
||||
"evegroups",
|
||||
"evecategories"
|
||||
'evetypes',
|
||||
'evegroups',
|
||||
'evecategories'
|
||||
)
|
||||
|
||||
def convertIcons(data):
|
||||
new = []
|
||||
for k, v in list(data.items()):
|
||||
v["iconID"] = k
|
||||
v['iconID'] = k
|
||||
new.append(v)
|
||||
return new
|
||||
|
||||
@@ -126,23 +126,23 @@ def main(db, json_path):
|
||||
check = {}
|
||||
|
||||
for ID in data:
|
||||
for skill in data[ID]["skills"]:
|
||||
for skill in data[ID]['skills']:
|
||||
newData.append({
|
||||
"alphaCloneID": int(ID),
|
||||
"alphaCloneName": "Alpha Clone",
|
||||
"typeID": skill["typeID"],
|
||||
"level": skill["level"]})
|
||||
'alphaCloneID': int(ID),
|
||||
'alphaCloneName': 'Alpha Clone',
|
||||
'typeID': skill['typeID'],
|
||||
'level': skill['level']})
|
||||
if ID not in check:
|
||||
check[ID] = {}
|
||||
check[ID][int(skill["typeID"])] = int(skill["level"])
|
||||
check[ID][int(skill['typeID'])] = int(skill['level'])
|
||||
|
||||
if not functools.reduce(lambda a, b: a if a == b else False, [v for _, v in check.items()]):
|
||||
raise Exception("Alpha Clones not all equal")
|
||||
raise Exception('Alpha Clones not all equal')
|
||||
|
||||
newData = [x for x in newData if x['alphaCloneID'] == 1]
|
||||
|
||||
if len(newData) == 0:
|
||||
raise Exception("Alpha Clone processing failed")
|
||||
raise Exception('Alpha Clone processing failed')
|
||||
|
||||
return newData
|
||||
|
||||
@@ -150,28 +150,28 @@ def main(db, json_path):
|
||||
|
||||
def convertSection(sectionData):
|
||||
sectionLines = []
|
||||
headerText = "<b>{}</b>".format(sectionData["header"])
|
||||
headerText = '<b>{}</b>'.format(sectionData['header'])
|
||||
sectionLines.append(headerText)
|
||||
for bonusData in sectionData["bonuses"]:
|
||||
prefix = "{} ".format(bonusData["number"]) if "number" in bonusData else ""
|
||||
bonusText = "{}{}".format(prefix, bonusData["text"].replace("\u00B7", "\u2022 "))
|
||||
for bonusData in sectionData['bonuses']:
|
||||
prefix = '{} '.format(bonusData['number']) if 'number' in bonusData else ''
|
||||
bonusText = '{}{}'.format(prefix, bonusData['text'].replace('\u00B7', '\u2022 '))
|
||||
sectionLines.append(bonusText)
|
||||
sectionLine = "<br />\n".join(sectionLines)
|
||||
sectionLine = '<br />\n'.join(sectionLines)
|
||||
return sectionLine
|
||||
|
||||
newData = []
|
||||
for row in data:
|
||||
typeLines = []
|
||||
typeId = row["typeID"]
|
||||
traitData = row["traits"]
|
||||
for skillData in sorted(traitData.get("skills", ()), key=lambda i: i["header"]):
|
||||
typeId = row['typeID']
|
||||
traitData = row['traits']
|
||||
for skillData in sorted(traitData.get('skills', ()), key=lambda i: i['header']):
|
||||
typeLines.append(convertSection(skillData))
|
||||
if "role" in traitData:
|
||||
typeLines.append(convertSection(traitData["role"]))
|
||||
if "misc" in traitData:
|
||||
typeLines.append(convertSection(traitData["misc"]))
|
||||
traitLine = "<br />\n<br />\n".join(typeLines)
|
||||
newRow = {"typeID": typeId, "traitText": traitLine}
|
||||
if 'role' in traitData:
|
||||
typeLines.append(convertSection(traitData['role']))
|
||||
if 'misc' in traitData:
|
||||
typeLines.append(convertSection(traitData['misc']))
|
||||
traitLine = '<br />\n<br />\n'.join(typeLines)
|
||||
newRow = {'typeID': typeId, 'traitText': traitLine}
|
||||
newData.append(newRow)
|
||||
return newData
|
||||
|
||||
@@ -179,15 +179,15 @@ def main(db, json_path):
|
||||
|
||||
# Dump all data to memory so we can easely cross check ignored rows
|
||||
for jsonName, cls in tables.items():
|
||||
with open(os.path.join(jsonPath, "{}.json".format(jsonName)), encoding="utf-8") as f:
|
||||
with open(os.path.join(jsonPath, '{}.json'.format(jsonName)), encoding='utf-8') as f:
|
||||
tableData = json.load(f)
|
||||
if jsonName in rowsInValues:
|
||||
tableData = list(tableData.values())
|
||||
if jsonName == "icons":
|
||||
if jsonName == 'icons':
|
||||
tableData = convertIcons(tableData)
|
||||
if jsonName == "phbtraits":
|
||||
if jsonName == 'phbtraits':
|
||||
tableData = convertTraits(tableData)
|
||||
if jsonName == "clonegrades":
|
||||
if jsonName == 'clonegrades':
|
||||
tableData = convertClones(tableData)
|
||||
data[jsonName] = tableData
|
||||
|
||||
@@ -195,8 +195,8 @@ def main(db, json_path):
|
||||
# Sometimes CCP unpublishes some items we want to have published, we
|
||||
# can do it here - just add them to initial set
|
||||
eveTypes = set()
|
||||
for row in data["evetypes"]:
|
||||
if (row["published"]
|
||||
for row in data['evetypes']:
|
||||
if (row['published']
|
||||
or row['groupID'] == 1306 # group Ship Modifiers, for items like tactical t3 ship modes
|
||||
or row['typeName'].startswith('Civilian') # Civilian weapons
|
||||
or row['typeID'] in (41549, 41548, 41551, 41550) # Micro Bombs (Fighters)
|
||||
@@ -204,14 +204,14 @@ def main(db, json_path):
|
||||
1882,
|
||||
1975,
|
||||
1971,
|
||||
1983 # the "container" for the abysmal environments
|
||||
) # Abysmal weather (environment)
|
||||
1983 # the "container" for the abyssal environments
|
||||
) # Abyssal weather (environment)
|
||||
):
|
||||
eveTypes.add(row["typeID"])
|
||||
eveTypes.add(row['typeID'])
|
||||
|
||||
# ignore checker
|
||||
def isIgnored(file, row):
|
||||
if file in ("evetypes", "dgmtypeeffects", "dgmtypeattribs", "invmetatypes") and row['typeID'] not in eveTypes:
|
||||
if file in ('evetypes', 'dgmtypeeffects', 'dgmtypeattribs', 'invmetatypes') and row['typeID'] not in eveTypes:
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -220,31 +220,31 @@ def main(db, json_path):
|
||||
fieldMap = fieldMapping.get(jsonName, {})
|
||||
tmp = []
|
||||
|
||||
print("processing {}".format(jsonName))
|
||||
print('processing {}'.format(jsonName))
|
||||
|
||||
for row in table:
|
||||
# We don't care about some kind of rows, filter it out if so
|
||||
if not isIgnored(jsonName, row):
|
||||
if jsonName == 'evetypes' and row["typeName"].startswith('Civilian'): # Apparently people really want Civilian modules available
|
||||
row["published"] = True
|
||||
if jsonName == 'evetypes' and row['typeName'].startswith('Civilian'): # Apparently people really want Civilian modules available
|
||||
row['published'] = True
|
||||
|
||||
instance = tables[jsonName]()
|
||||
# fix for issue 80
|
||||
if jsonName is "icons" and "res:/ui/texture/icons/" in str(row["iconFile"]).lower():
|
||||
row["iconFile"] = row["iconFile"].lower().replace("res:/ui/texture/icons/", "").replace(".png", "")
|
||||
if jsonName is 'icons' and 'res:/ui/texture/icons/' in str(row['iconFile']).lower():
|
||||
row['iconFile'] = row['iconFile'].lower().replace('res:/ui/texture/icons/', '').replace('.png', '')
|
||||
# with res:/ui... references, it points to the actual icon file (including it's size variation of #_size_#)
|
||||
# strip this info out and get the identifying info
|
||||
split = row['iconFile'].split('_')
|
||||
if len(split) == 3:
|
||||
row['iconFile'] = "{}_{}".format(split[0], split[2])
|
||||
if jsonName is "icons" and "modules/" in str(row["iconFile"]).lower():
|
||||
row["iconFile"] = row["iconFile"].lower().replace("modules/", "").replace(".png", "")
|
||||
row['iconFile'] = '{}_{}'.format(split[0], split[2])
|
||||
if jsonName is 'icons' and 'modules/' in str(row['iconFile']).lower():
|
||||
row['iconFile'] = row['iconFile'].lower().replace('modules/', '').replace('.png', '')
|
||||
|
||||
if jsonName is "clonegrades":
|
||||
if (row["alphaCloneID"] not in tmp):
|
||||
if jsonName is 'clonegrades':
|
||||
if (row['alphaCloneID'] not in tmp):
|
||||
cloneParent = eos.gamedata.AlphaClone()
|
||||
setattr(cloneParent, "alphaCloneID", row["alphaCloneID"])
|
||||
setattr(cloneParent, "alphaCloneName", row["alphaCloneName"])
|
||||
setattr(cloneParent, 'alphaCloneID', row['alphaCloneID'])
|
||||
setattr(cloneParent, 'alphaCloneName', row['alphaCloneName'])
|
||||
eos.db.gamedata_session.add(cloneParent)
|
||||
tmp.append(row['alphaCloneID'])
|
||||
|
||||
@@ -256,7 +256,7 @@ def main(db, json_path):
|
||||
eos.db.gamedata_session.add(instance)
|
||||
|
||||
# quick and dirty hack to get this data in
|
||||
with open(os.path.join(jsonPath, "dynamicAttributes.json"), encoding="utf-8") as f:
|
||||
with open(os.path.join(jsonPath, 'dynamicAttributes.json'), encoding='utf-8') as f:
|
||||
bulkdata = json.load(f)
|
||||
for mutaID, data in bulkdata.items():
|
||||
muta = eos.gamedata.DynamicItem()
|
||||
@@ -283,25 +283,28 @@ def main(db, json_path):
|
||||
# CCP still has 5 subsystems assigned to T3Cs, even though only 4 are available / usable. They probably have some
|
||||
# old legacy requirement or assumption that makes it difficult for them to change this value in the data. But for
|
||||
# pyfa, we can do it here as a post-processing step
|
||||
eos.db.gamedata_engine.execute("UPDATE dgmtypeattribs SET value = 4.0 WHERE attributeID = ?", (1367,))
|
||||
eos.db.gamedata_engine.execute('UPDATE dgmtypeattribs SET value = 4.0 WHERE attributeID = ?', (1367,))
|
||||
|
||||
eos.db.gamedata_engine.execute("UPDATE invtypes SET published = 0 WHERE typeName LIKE '%abyssal%'")
|
||||
eos.db.gamedata_engine.execute('UPDATE invtypes SET published = 0 WHERE typeName LIKE \'%abyssal%\'')
|
||||
|
||||
# fix for #1722 until CCP gets their shit together
|
||||
eos.db.gamedata_engine.execute('UPDATE invtypes SET typeName = \'Small Abyssal Energy Nosferatu\' WHERE typeID = ? AND typeName = ?', (48419, ''))
|
||||
|
||||
print()
|
||||
for x in CATEGORIES_TO_REMOVE:
|
||||
cat = eos.db.gamedata_session.query(eos.gamedata.Category).filter(eos.gamedata.Category.ID == x).first()
|
||||
print ("Removing Category: {}".format(cat.name))
|
||||
print ('Removing Category: {}'.format(cat.name))
|
||||
eos.db.gamedata_session.delete(cat)
|
||||
|
||||
eos.db.gamedata_session.commit()
|
||||
eos.db.gamedata_engine.execute("VACUUM")
|
||||
eos.db.gamedata_engine.execute('VACUUM')
|
||||
|
||||
print("done")
|
||||
print('done')
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="This scripts dumps effects from an sqlite cache dump to mongo")
|
||||
parser.add_argument("-d", "--db", required=True, type=str, help="The sqlalchemy connectionstring, example: sqlite:///c:/tq.db")
|
||||
parser.add_argument("-j", "--json", required=True, type=str, help="The path to the json dump")
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='This scripts dumps effects from an sqlite cache dump to mongo')
|
||||
parser.add_argument('-d', '--db', required=True, type=str, help='The sqlalchemy connectionstring, example: sqlite:///c:/tq.db')
|
||||
parser.add_argument('-j', '--json', required=True, type=str, help='The path to the json dump')
|
||||
args = parser.parse_args()
|
||||
|
||||
main(args.db, args.json)
|
||||
|
||||
@@ -187,11 +187,11 @@ class Fit(object):
|
||||
# error during the command loop
|
||||
refreshFits = set()
|
||||
for projection in list(fit.projectedOnto.values()):
|
||||
if projection.victim_fit != fit and projection.victim_fit in eos.db.saveddata_session: # GH issue #359
|
||||
if projection.victim_fit and projection.victim_fit != fit and projection.victim_fit in eos.db.saveddata_session: # GH issue #359
|
||||
refreshFits.add(projection.victim_fit)
|
||||
|
||||
for booster in list(fit.boostedOnto.values()):
|
||||
if booster.boosted_fit != fit and booster.boosted_fit in eos.db.saveddata_session: # GH issue #359
|
||||
if booster.boosted_fit and booster.boosted_fit != fit and booster.boosted_fit in eos.db.saveddata_session: # GH issue #359
|
||||
refreshFits.add(booster.boosted_fit)
|
||||
|
||||
eos.db.remove(fit)
|
||||
@@ -626,12 +626,11 @@ class Fit(object):
|
||||
|
||||
def changeModule(self, fitID, position, newItemID):
|
||||
fit = eos.db.getFit(fitID)
|
||||
module = fit.modules[position]
|
||||
|
||||
# We're trying to add a charge to a slot, which won't work. Instead, try to add the charge to the module in that slot.
|
||||
if self.isAmmo(newItemID):
|
||||
module = fit.modules[position]
|
||||
if not module.isEmpty:
|
||||
self.setAmmo(fitID, newItemID, [module])
|
||||
if self.isAmmo(newItemID) and not module.isEmpty:
|
||||
self.setAmmo(fitID, newItemID, [module])
|
||||
return True
|
||||
|
||||
pyfalog.debug("Changing position of module from position ({0}) for fit ID: {1}", position, fitID)
|
||||
@@ -640,14 +639,17 @@ class Fit(object):
|
||||
|
||||
# Dummy it out in case the next bit fails
|
||||
fit.modules.toDummy(position)
|
||||
|
||||
ret = None
|
||||
try:
|
||||
m = es_Module(item)
|
||||
except ValueError:
|
||||
pyfalog.warning("Invalid item: {0}", newItemID)
|
||||
return False
|
||||
|
||||
if m.fits(fit):
|
||||
if m.slot != module.slot:
|
||||
fit.modules.toModule(position, module)
|
||||
# Fits, but we selected wrong slot type, so don't want to overwrite because we will append on failure (none)
|
||||
ret = None
|
||||
elif m.fits(fit):
|
||||
m.owner = fit
|
||||
fit.modules.toModule(position, m)
|
||||
if m.isValidState(State.ACTIVE):
|
||||
@@ -661,9 +663,8 @@ class Fit(object):
|
||||
fit.fill()
|
||||
eos.db.commit()
|
||||
|
||||
return True
|
||||
else:
|
||||
return None
|
||||
ret = True
|
||||
return ret
|
||||
|
||||
def moveCargoToModule(self, fitID, moduleIdx, cargoIdx, copyMod=False):
|
||||
"""
|
||||
|
||||
@@ -277,15 +277,8 @@ class Market(object):
|
||||
# Dictionary of items with forced market group (service assumes they have no
|
||||
# market group assigned in db, otherwise they'll appear in both original and forced groups)
|
||||
self.ITEMS_FORCEDMARKETGROUP = {
|
||||
"Advanced Cerebral Accelerator" : 977, # Implants & Boosters > Booster
|
||||
"Civilian Damage Control" : 615, # Ship Equipment > Hull & Armor > Damage Controls
|
||||
"Civilian EM Ward Field" : 1695,
|
||||
# Ship Equipment > Shield > Shield Hardeners > EM Shield Hardeners
|
||||
"Civilian Explosive Deflection Field" : 1694,
|
||||
# Ship Equipment > Shield > Shield Hardeners > Explosive Shield Hardeners
|
||||
"Advanced Cerebral Accelerator" : 2487, # Implants & Boosters > Booster > Cerebral Accelerators
|
||||
"Civilian Hobgoblin" : 837, # Drones > Combat Drones > Light Scout Drones
|
||||
"Civilian Kinetic Deflection Field" : 1693,
|
||||
# Ship Equipment > Shield > Shield Hardeners > Kinetic Shield Hardeners
|
||||
"Civilian Light Missile Launcher" : 640,
|
||||
# Ship Equipment > Turrets & Bays > Missile Launchers > Light Missile Launchers
|
||||
"Civilian Scourge Light Missile" : 920,
|
||||
@@ -293,8 +286,6 @@ class Market(object):
|
||||
"Civilian Small Remote Armor Repairer" : 1059,
|
||||
# Ship Equipment > Hull & Armor > Remote Armor Repairers > Small
|
||||
"Civilian Small Remote Shield Booster" : 603, # Ship Equipment > Shield > Remote Shield Boosters > Small
|
||||
"Civilian Stasis Webifier" : 683, # Ship Equipment > Electronic Warfare > Stasis Webifiers
|
||||
"Civilian Warp Disruptor" : 1935, # Ship Equipment > Electronic Warfare > Warp Disruptors
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX10" : 1493,
|
||||
# Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX100" : 1493,
|
||||
@@ -307,11 +298,9 @@ class Market(object):
|
||||
# Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX1100": 1493,
|
||||
# Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Nugoehuvi Synth Blue Pill Booster" : 977, # Implants & Boosters > Booster
|
||||
"Prototype Cerebral Accelerator" : 977, # Implants & Boosters > Booster
|
||||
"Prototype Cerebral Accelerator" : 2487, # Implants & Boosters > Booster > Cerebral Accelerators
|
||||
"Prototype Iris Probe Launcher" : 712, # Ship Equipment > Turrets & Bays > Scan Probe Launchers
|
||||
"Shadow" : 1310, # Drones > Combat Drones > Fighter Bombers
|
||||
"Standard Cerebral Accelerator" : 977, # Implants & Boosters > Booster
|
||||
"Standard Cerebral Accelerator" : 2487, # Implants & Boosters > Booster > Cerebral Accelerators
|
||||
}
|
||||
|
||||
self.ITEMS_FORCEDMARKETGROUP_R = self.__makeRevDict(self.ITEMS_FORCEDMARKETGROUP)
|
||||
@@ -538,7 +527,7 @@ class Market(object):
|
||||
categories = ['Drone', 'Fighter', 'Implant']
|
||||
|
||||
for item in items:
|
||||
if item.category.ID == 20: # Implants and Boosters
|
||||
if item.category.ID == 20 and item.group.ID != 303: # Implants not Boosters
|
||||
implant_remove_list = set()
|
||||
implant_remove_list.add("Low-Grade ")
|
||||
implant_remove_list.add("Low-grade ")
|
||||
@@ -552,15 +541,6 @@ class Market(object):
|
||||
implant_remove_list.add(" - Elite")
|
||||
implant_remove_list.add(" - Improved")
|
||||
implant_remove_list.add(" - Standard")
|
||||
implant_remove_list.add("Copper ")
|
||||
implant_remove_list.add("Gold ")
|
||||
implant_remove_list.add("Silver ")
|
||||
implant_remove_list.add("Advanced ")
|
||||
implant_remove_list.add("Improved ")
|
||||
implant_remove_list.add("Prototype ")
|
||||
implant_remove_list.add("Standard ")
|
||||
implant_remove_list.add("Strong ")
|
||||
implant_remove_list.add("Synth ")
|
||||
|
||||
for implant_prefix in ("-6", "-7", "-8", "-9", "-10"):
|
||||
for i in range(50):
|
||||
@@ -596,6 +576,16 @@ class Market(object):
|
||||
if trimmed_variations_list:
|
||||
variations_list = trimmed_variations_list
|
||||
|
||||
# If the items are boosters then filter variations to only include boosters for the same slot.
|
||||
BOOSTER_GROUP_ID = 303
|
||||
if all(map(lambda i: i.group.ID == BOOSTER_GROUP_ID, items)) and len(items) > 0:
|
||||
# 'boosterness' is the database's attribute name for Booster Slot
|
||||
reqSlot = next(items.__iter__()).getAttribute('boosterness')
|
||||
# If the item and it's variation both have a marketGroupID it should match for the variation to be considered valid.
|
||||
marketGroupID = [next(filter(None, map(lambda i: i.marketGroupID, items)), None), None]
|
||||
matchSlotAndMktGrpID = lambda v: v.getAttribute('boosterness') == reqSlot and v.marketGroupID in marketGroupID
|
||||
variations_list = list(filter(matchSlotAndMktGrpID, variations_list))
|
||||
|
||||
variations.update(variations_list)
|
||||
return variations
|
||||
|
||||
@@ -657,6 +647,12 @@ class Market(object):
|
||||
def marketGroupHasTypesCheck(self, mg):
|
||||
"""If market group has any items, return true"""
|
||||
if mg and mg.ID in self.ITEMS_FORCEDMARKETGROUP_R:
|
||||
# This shouldn't occur normally but makes errors more mild when ITEMS_FORCEDMARKETGROUP is outdated.
|
||||
if len(mg.children) > 0 and len(mg.items) == 0:
|
||||
pyfalog.error(("Market group \"{0}\" contains no items and has children. "
|
||||
"ITEMS_FORCEDMARKETGROUP is likely outdated and will need to be "
|
||||
"updated for {1} to display correctly.").format(mg, self.ITEMS_FORCEDMARKETGROUP_R[mg.ID]))
|
||||
return False
|
||||
return True
|
||||
elif len(mg.items) > 0:
|
||||
return True
|
||||
|
||||
157
service/port.py
@@ -24,7 +24,6 @@ from logbook import Logger
|
||||
import collections
|
||||
import json
|
||||
import threading
|
||||
import locale
|
||||
from bs4 import UnicodeDammit
|
||||
|
||||
|
||||
@@ -33,6 +32,7 @@ from codecs import open
|
||||
import xml.parsers.expat
|
||||
|
||||
from eos import db
|
||||
from eos.db.gamedata.queries import getAttributeInfo
|
||||
from service.fit import Fit as svcFit
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
@@ -1064,85 +1064,104 @@ class Port(object):
|
||||
|
||||
return fit_list
|
||||
|
||||
@staticmethod
|
||||
def _exportEftBase(fit):
|
||||
"""Basically EFT format does not require blank lines
|
||||
also, it's OK to arrange modules randomly?
|
||||
"""
|
||||
offineSuffix = " /OFFLINE"
|
||||
export = "[%s, %s]\n" % (fit.ship.item.name, fit.name)
|
||||
stuff = {}
|
||||
|
||||
@classmethod
|
||||
def exportEft(cls, fit, mutations=False, implants=False):
|
||||
# EFT formatted export is split in several sections, each section is
|
||||
# separated from another using 2 blank lines. Sections might have several
|
||||
# sub-sections, which are separated by 1 blank line
|
||||
sections = []
|
||||
|
||||
header = '[{}, {}]'.format(fit.ship.item.name, fit.name)
|
||||
|
||||
# Section 1: modules, rigs, subsystems, services
|
||||
def formatAttrVal(val):
|
||||
if int(val) == val:
|
||||
return int(val)
|
||||
return val
|
||||
|
||||
offineSuffix = ' /OFFLINE'
|
||||
modsBySlotType = {}
|
||||
sFit = svcFit.getInstance()
|
||||
for module in fit.modules:
|
||||
slot = module.slot
|
||||
if slot not in stuff:
|
||||
stuff[slot] = []
|
||||
curr = module.item.name if module.item \
|
||||
else ("[Empty %s slot]" % Slot.getName(slot).capitalize() if slot is not None else "")
|
||||
if module.charge and sFit.serviceFittingOptions["exportCharges"]:
|
||||
curr += ", %s" % module.charge.name
|
||||
if module.state == State.OFFLINE:
|
||||
curr += offineSuffix
|
||||
curr += "\n"
|
||||
stuff[slot].append(curr)
|
||||
|
||||
slotTypeMods = modsBySlotType.setdefault(slot, [])
|
||||
if module.item:
|
||||
mutatedMod = bool(module.mutators)
|
||||
# if module was mutated, use base item name for export
|
||||
if mutatedMod:
|
||||
modName = module.baseItem.name
|
||||
else:
|
||||
modName = module.item.name
|
||||
modOfflineSuffix = offineSuffix if module.state == State.OFFLINE else ''
|
||||
if module.charge and sFit.serviceFittingOptions['exportCharges']:
|
||||
slotTypeMods.append('{}, {}{}'.format(modName, module.charge.name, modOfflineSuffix))
|
||||
else:
|
||||
slotTypeMods.append('{}{}'.format(modName, modOfflineSuffix))
|
||||
if mutatedMod and mutations:
|
||||
mutationGrade = module.mutaplasmid.item.name.split(' ', 1)[0].lower()
|
||||
mutatedAttrs = {}
|
||||
for attrID, mutator in module.mutators.items():
|
||||
attrName = getAttributeInfo(attrID).name
|
||||
mutatedAttrs[attrName] = mutator.value
|
||||
customAttrsLine = ', '.join('{} {}'.format(a, formatAttrVal(mutatedAttrs[a])) for a in sorted(mutatedAttrs))
|
||||
slotTypeMods.append(' {}: {}'.format(mutationGrade, customAttrsLine))
|
||||
else:
|
||||
slotTypeMods.append('[Empty {} slot]'.format(Slot.getName(slot).capitalize() if slot is not None else ''))
|
||||
modSection = []
|
||||
for slotType in EFT_SLOT_ORDER:
|
||||
data = stuff.get(slotType)
|
||||
if data is not None:
|
||||
export += "\n"
|
||||
for curr in data:
|
||||
export += curr
|
||||
rackLines = []
|
||||
data = modsBySlotType.get(slotType, ())
|
||||
for line in data:
|
||||
rackLines.append(line)
|
||||
if rackLines:
|
||||
modSection.append('\n'.join(rackLines))
|
||||
if modSection:
|
||||
sections.append('\n\n'.join(modSection))
|
||||
|
||||
if len(fit.drones) > 0:
|
||||
export += "\n\n"
|
||||
for drone in fit.drones:
|
||||
export += "%s x%s\n" % (drone.item.name, drone.amount)
|
||||
# Section 2: drones, fighters
|
||||
minionSection = []
|
||||
droneLines = []
|
||||
for drone in sorted(fit.drones, key=lambda d: d.item.name):
|
||||
droneLines.append('{} x{}'.format(drone.item.name, drone.amount))
|
||||
if droneLines:
|
||||
minionSection.append('\n'.join(droneLines))
|
||||
fighterLines = []
|
||||
for fighter in sorted(fit.fighters, key=lambda f: f.item.name):
|
||||
fighterLines.append('{} x{}'.format(fighter.item.name, fighter.amountActive))
|
||||
if fighterLines:
|
||||
minionSection.append('\n'.join(fighterLines))
|
||||
if minionSection:
|
||||
sections.append('\n\n'.join(minionSection))
|
||||
|
||||
if len(fit.fighters) > 0:
|
||||
export += "\n\n"
|
||||
for fighter in fit.fighters:
|
||||
export += "%s x%s\n" % (fighter.item.name, fighter.amountActive)
|
||||
# Section 3: implants, boosters
|
||||
if implants:
|
||||
charSection = []
|
||||
implantLines = []
|
||||
for implant in fit.implants:
|
||||
implantLines.append(implant.item.name)
|
||||
if implantLines:
|
||||
charSection.append('\n'.join(implantLines))
|
||||
boosterLines = []
|
||||
for booster in fit.boosters:
|
||||
boosterLines.append(booster.item.name)
|
||||
if boosterLines:
|
||||
charSection.append('\n'.join(boosterLines))
|
||||
if charSection:
|
||||
sections.append('\n\n'.join(charSection))
|
||||
|
||||
if export[-1] == "\n":
|
||||
export = export[:-1]
|
||||
# Section 4: cargo
|
||||
cargoLines = []
|
||||
for cargo in sorted(fit.cargo, key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name)):
|
||||
cargoLines.append('{} x{}'.format(cargo.item.name, cargo.amount))
|
||||
if cargoLines:
|
||||
sections.append('\n'.join(cargoLines))
|
||||
|
||||
return export
|
||||
|
||||
@classmethod
|
||||
def exportEft(cls, fit):
|
||||
export = cls._exportEftBase(fit)
|
||||
|
||||
if len(fit.cargo) > 0:
|
||||
export += "\n\n\n"
|
||||
for cargo in fit.cargo:
|
||||
export += "%s x%s\n" % (cargo.item.name, cargo.amount)
|
||||
if export[-1] == "\n":
|
||||
export = export[:-1]
|
||||
|
||||
return export
|
||||
return '{}\n\n{}'.format(header, '\n\n\n'.join(sections))
|
||||
|
||||
@classmethod
|
||||
def exportEftImps(cls, fit):
|
||||
export = cls._exportEftBase(fit)
|
||||
|
||||
if len(fit.implants) > 0 or len(fit.boosters) > 0:
|
||||
export += "\n\n\n"
|
||||
for implant in fit.implants:
|
||||
export += "%s\n" % implant.item.name
|
||||
for booster in fit.boosters:
|
||||
export += "%s\n" % booster.item.name
|
||||
|
||||
if export[-1] == "\n":
|
||||
export = export[:-1]
|
||||
|
||||
if len(fit.cargo) > 0:
|
||||
export += "\n\n\n"
|
||||
for cargo in fit.cargo:
|
||||
export += "%s x%s\n" % (cargo.item.name, cargo.amount)
|
||||
if export[-1] == "\n":
|
||||
export = export[:-1]
|
||||
|
||||
return export
|
||||
return cls.exportEft(fit, implants=True)
|
||||
|
||||
@staticmethod
|
||||
def exportDna(fit):
|
||||
|
||||
@@ -228,10 +228,11 @@ class PriceWorkerThread(threading.Thread):
|
||||
def trigger(self, prices, callbacks):
|
||||
self.queue.put((callbacks, prices))
|
||||
|
||||
def setToWait(self, itemID, callback):
|
||||
if itemID not in self.wait:
|
||||
self.wait[itemID] = []
|
||||
self.wait[itemID].append(callback)
|
||||
def setToWait(self, prices, callback):
|
||||
for x in prices:
|
||||
if x.typeID not in self.wait:
|
||||
self.wait[x.typeID] = []
|
||||
self.wait[x.typeID].append(callback)
|
||||
|
||||
|
||||
from service.marketSources import evemarketer, evemarketdata # noqa: E402
|
||||
|
||||
@@ -248,6 +248,11 @@ class NetworkSettings(object):
|
||||
proto = "{0}://".format(prefix)
|
||||
if proxyline[:len(proto)] == proto:
|
||||
proxyline = proxyline[len(proto):]
|
||||
# sometimes proxyline contains "user:password@" section before proxy address
|
||||
# remove it if present, so later split by ":" works
|
||||
if '@' in proxyline:
|
||||
userPass, proxyline = proxyline.split("@")
|
||||
# TODO: do something with user/password?
|
||||
proxAddr, proxPort = proxyline.split(":")
|
||||
proxPort = int(proxPort.rstrip("/"))
|
||||
proxy = (proxAddr, proxPort)
|
||||
|
||||