Merge branch 'master' into wx3

Used code from the master on conflicts
This commit is contained in:
DarkPhoenix
2014-12-15 15:45:33 +03:00
14 changed files with 134 additions and 252 deletions

View File

@@ -13,8 +13,8 @@ debug = False
saveInRoot = False
# Version data
version = "1.7.0"
tag = "Stable"
version = "1.7.2"
tag = "git"
expansionName = "Rhea"
expansionVersion = "1.0"
evemonMinVersion = "4081"

View File

@@ -0,0 +1,9 @@
# shipMissileLauncherRoFAD1Fixed
#
# Used by:
# Ship: Heretic
type = "passive"
def handler(fit, ship, context):
level = fit.character.getSkill("Amarr Destroyer").level
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Missile Launcher Operation"),
"speed", ship.getModifiedItemAttr("shipBonusAD1") * level)

View File

@@ -71,7 +71,7 @@ class FitDpsGraph(Graph):
if distance <= fit.extraAttributes["droneControlRange"]:
for drone in fit.drones:
multiplier = 1 if drone.getModifiedItemAttr("maxVelocity") > 0 else self.calculateTurretMultiplier(drone, data)
dps = drone.damageStats(fit.targetResists)
dps, _ = drone.damageStats(fit.targetResists)
total += dps * multiplier
return total

View File

@@ -153,6 +153,8 @@ class Fit(object):
def ship(self, ship):
self.__ship = ship
self.shipID = ship.item.ID if ship is not None else None
# set mode of new ship
self.mode = self.ship.checkModeItem(None) if ship is not None else None
@property
def drones(self):

View File

@@ -29,6 +29,7 @@ class Ship(ItemAttrShortcut, HandledItem):
self.__item = item
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__modeItems = self._getModeItems()
if not isinstance(item, int):
self.__buildOriginal()
@@ -76,7 +77,7 @@ class Ship(ItemAttrShortcut, HandledItem):
@todo: rename this
"""
items = self.getModeItems()
items = self.__modeItems
if items != None:
if item == None or item not in items:
@@ -87,11 +88,15 @@ class Ship(ItemAttrShortcut, HandledItem):
return Mode(item)
return None
def getModes(self):
items = self.getModeItems()
return [Mode(item) for item in items] if items else None
@property
def modeItems(self):
return self.__modeItems
def getModeItems(self):
@property
def modes(self):
return [Mode(item) for item in self.__modeItems] if self.__modeItems else None
def _getModeItems(self):
"""
Returns a list of valid mode items for ship. Note that this returns the
valid Item objects, not the Mode objects. Returns None if not a

View File

@@ -16,7 +16,7 @@ class TacticalMode(ContextMenu):
fitID = self.mainFrame.getActiveFit()
fit = sFit.getFit(fitID)
self.modes = fit.ship.getModes()
self.modes = fit.ship.modes
self.currMode = fit.mode
return srcContext == "fittingShip" and self.modes is not None

View File

@@ -23,7 +23,7 @@ from gui.viewColumn import ViewColumn
from gui import bitmapLoader
from gui.utils.numberFormatter import formatAmount
from gui.utils.listFormatter import formatList
from service.fit import Fit
from service.fit import Fit, Market
import wx
@@ -424,6 +424,15 @@ class Miscellanea(ViewColumn):
text = "{0}s".format(cycleTime)
tooltip = "Spoolup time"
return text, tooltip
elif itemGroup in ("Siege Module", "Cynosural Field"):
amt = stuff.getModifiedItemAttr("consumptionQuantity")
if amt:
typeID = stuff.getModifiedItemAttr("consumptionType")
item = Market.getInstance().getItem(typeID)
text = "{0} units".format(formatAmount(amt, 3, 0, 3))
return text, item.name
else:
return "", None
elif itemGroup in ("Fueled Armor Repairer", "Fueled Shield Booster"):
hp = stuff.hpBeforeReload
cycles = stuff.numShots

View File

@@ -26,7 +26,7 @@ import gui.display as d
from gui.contextMenu import ContextMenu
import gui.shipBrowser
import gui.multiSwitch
from eos.types import Slot, Rack
from eos.types import Slot, Rack, Module
from gui.builtinViewColumns.state import State
from gui import bitmapLoader
import gui.builtinViews.emptyView
@@ -424,14 +424,16 @@ class FittingView(d.Display):
self.blanks[i] = x+i # modify blanks with actual index
self.mods.insert(x+i, Rack.buildRack(slot))
if fit.mode:
# Modes are special snowflakes and need a little manual loving
# We basically append the Mode rack and Mode to the modules
# while also marking their positions in the Blanks list
if fit.mode:
# Modes are special snowflakes and need a little manual loving
# We basically append the Mode rack and Mode to the modules
# while also marking their positions in the Blanks list
if sFit.serviceFittingOptions["rackSlots"]:
self.blanks.append(len(self.mods))
self.mods.append(Rack.buildRack(Slot.MODE))
self.blanks.append(len(self.mods))
self.mods.append(fit.mode)
self.blanks.append(len(self.mods))
self.mods.append(fit.mode)
else:
self.mods = None
@@ -557,12 +559,14 @@ class FittingView(d.Display):
font = (self.GetClassDefaultAttributes()).font
for i, mod in enumerate(self.mods):
if hasattr(mod,"slot") and slotMap[mod.slot]:
self.SetItemBackgroundColour(i, wx.Colour(204, 51, 51))
elif sFit.serviceFittingOptions["colorFitBySlot"] and not isinstance(mod, Rack):
self.SetItemBackgroundColour(i, self.slotColour(mod.slot))
else:
self.SetItemBackgroundColour(i, self.GetBackgroundColour())
self.SetItemBackgroundColour(i, self.GetBackgroundColour())
# only consider changing color if we're dealing with a Module
if type(mod) is Module:
if slotMap[mod.slot]: # Color too many modules as red
self.SetItemBackgroundColour(i, wx.Colour(204, 51, 51))
elif sFit.serviceFittingOptions["colorFitBySlot"]: # Color by slot it enabled
self.SetItemBackgroundColour(i, self.slotColour(mod.slot))
# Set rack face to bold
if isinstance(mod, Rack) and \

View File

@@ -23,6 +23,7 @@ import gui.utils.colorUtils as colorUtils
import gui.utils.drawUtils as drawUtils
import gui.utils.fonts as fonts
from gui import bitmapLoader
import gui.utils.fonts as fonts
_PageChanging, EVT_NOTEBOOK_PAGE_CHANGING = wx.lib.newevent.NewEvent()
_PageChanged, EVT_NOTEBOOK_PAGE_CHANGED = wx.lib.newevent.NewEvent()
@@ -322,7 +323,7 @@ class PFNotebook(wx.Panel):
class PFTabRenderer:
def __init__(self, size=(36, 24), text=wx.EmptyString, img=None, inclination=6 , closeButton=True, fontSize=14):
def __init__(self, size=(36, 24), text=wx.EmptyString, img=None, inclination=6 , closeButton=True):
"""
Renders a new tab
@@ -359,7 +360,7 @@ class PFTabRenderer:
self.tabBackBitmap = None
self.cbSize = 5
self.padding = 4
self.font = wx.FontFromPixelSize(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False)
self.font = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False)
self.tabImg = img
self.position = (0, 0) # Not used internally for rendering - helper for tab container
@@ -1277,7 +1278,7 @@ class PFNotebookPagePreview(wx.Frame):
self.padding = 15
self.transp = 0
hfont = wx.FontFromPixelSize(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False)
hfont = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False)
self.SetFont(hfont)
tx, ty = self.GetTextExtent(self.title)
@@ -1340,7 +1341,7 @@ class PFNotebookPagePreview(wx.Frame):
mdc.SetBackground(wx.Brush(color))
mdc.Clear()
font = wx.FontFromPixelSize(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False)
font = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL,wx.NORMAL, False)
mdc.SetFont(font)
x,y = mdc.GetTextExtent(self.title)

View File

@@ -75,7 +75,7 @@ class PyGauge(wx.PyWindow):
self._oldPercentage = 0
self._showRemaining = False
self.font = wx.FontFromPixelSize(fonts.NORMAL,wx.SWISS, wx.NORMAL, wx.NORMAL, False)
self.font = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False)
self.SetBarGradient((wx.Colour(119,119,119),wx.Colour(153,153,153)))
self.SetBackgroundColour(wx.Colour(51,51,51))
@@ -379,9 +379,15 @@ class PyGauge(wx.PyWindow):
dc.DrawLabel(formatStr, rect, wx.ALIGN_CENTER)
else:
if self.GetBarGradient() and self._showRemaining:
formatStr = "{0:." + str(self._fractionDigits) + "f} left"
range = self._range if self._range > 0.01 else 0
value = max( range - self._value , 0)
value = range - self._value
if value < 0:
label = "over"
value = -value
else:
label = "left"
formatStr = "{0:." + str(self._fractionDigits) + "f} " + label
else:
formatStr = "{0:." + str(self._fractionDigits) + "f}%"

View File

@@ -5,7 +5,6 @@ import gui.mainFrame
import gui.globalEvents as GE
import time
from gui.PFListPane import PFListPane
import service
from wx.lib.buttons import GenBitmapButton
@@ -19,6 +18,7 @@ from gui.contextMenu import ContextMenu
import gui.utils.fonts as fonts
import service
import gui.utils.fonts as fonts
FitRenamed, EVT_FIT_RENAMED = wx.lib.newevent.NewEvent()
FitSelected, EVT_FIT_SELECTED = wx.lib.newevent.NewEvent()
@@ -355,7 +355,7 @@ class NavigationPanel(SFItem.SFBrowserItem):
self.recentSearches = []
self.inSearch = False
self.fontSmall = wx.FontFromPixelSize(fonts.SMALL,wx.SWISS, wx.NORMAL, wx.NORMAL, False)
self.fontSmall = wx.Font(fonts.SMALL, wx.SWISS, wx.NORMAL, wx.NORMAL)
w,h = size
self.BrowserSearchBox = wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, (-1, h - 2 if 'wxGTK' in wx.PlatformInfo else -1 ), wx.TE_PROCESS_ENTER | (wx.BORDER_NONE if 'wxGTK' in wx.PlatformInfo else 0))
self.BrowserSearchBox.Show(False)
@@ -944,7 +944,7 @@ class CategoryItem(SFItem.SFBrowserItem):
self.padding = 4
self.fontBig = wx.FontFromPixelSize(fonts.BIG,wx.SWISS, wx.NORMAL, wx.NORMAL, False)
self.fontBig = wx.Font(fonts.BIG, wx.SWISS, wx.NORMAL, wx.NORMAL)
self.animTimerId = wx.NewId()
@@ -1058,9 +1058,9 @@ class ShipItem(SFItem.SFBrowserItem):
self.shipID = shipID
self.fontBig = wx.FontFromPixelSize(fonts.BIG,wx.SWISS, wx.NORMAL, wx.BOLD, False)
self.fontNormal = wx.FontFromPixelSize(fonts.NORMAL,wx.SWISS, wx.NORMAL, wx.NORMAL, False)
self.fontSmall = wx.FontFromPixelSize(fonts.SMALL,wx.SWISS, wx.NORMAL, wx.NORMAL, False)
self.fontBig = wx.Font(fonts.BIG, wx.SWISS, wx.NORMAL, wx.BOLD)
self.fontNormal = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL)
self.fontSmall = wx.Font(fonts.SMALL, wx.SWISS, wx.NORMAL, wx.NORMAL)
self.shipBmp = None
if shipID:
@@ -1446,9 +1446,9 @@ class FitItem(SFItem.SFBrowserItem):
self.dragMotionTrigger = self.dragMotionTrail
self.dragWindow = None
self.fontBig = wx.FontFromPixelSize(fonts.BIG,wx.SWISS, wx.NORMAL, wx.BOLD, False)
self.fontNormal = wx.FontFromPixelSize(fonts.NORMAL,wx.SWISS, wx.NORMAL, wx.NORMAL, False)
self.fontSmall = wx.FontFromPixelSize(fonts.SMALL,wx.SWISS, wx.NORMAL, wx.NORMAL, False)
self.fontBig = wx.Font(fonts.BIG, wx.SWISS, wx.NORMAL, wx.BOLD)
self.fontNormal = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL)
self.fontSmall = wx.Font(fonts.SMALL, wx.SWISS, wx.NORMAL, wx.NORMAL)
self.SetDraggable()

View File

@@ -5,11 +5,9 @@ different wxPython versions
import wx
if 'wxMSW' in wx.PlatformInfo and wx.VERSION < (2,9):
SMALL = (0,12)
NORMAL = (0,14)
BIG = (0,15)
if 'wxMac' in wx.PlatformInfo:
sizes = (10, 11, 12)
else:
SMALL = (0,10)
NORMAL = (0,11)
BIG = (0,12)
sizes = (7, 8, 9)
SMALL, NORMAL, BIG = sizes

View File

@@ -147,7 +147,6 @@ class Fit(object):
def newFit(self, shipID, name=None):
fit = eos.types.Fit()
fit.ship = eos.types.Ship(eos.db.getItem(shipID))
fit.mode = fit.ship.checkModeItem(None)
fit.name = name if name is not None else "New %s" % fit.ship.item.name
fit.damagePattern = self.pattern
fit.targetResists = self.targetResists

View File

@@ -29,10 +29,8 @@ try:
except ImportError:
from utils.compat import OrderedDict
FIT_WIN_HEADINGS = ["High power", "Medium power", "Low power", "Rig Slot", "Sub System", "Charges"]
EFT_SLOT_ORDER = [Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM]
class Port(object):
"""Service which houses all import/export format functions"""
@@ -42,27 +40,6 @@ class Port(object):
firstLine = re.split("[\n\r]+", string.strip(), maxsplit=1)[0]
firstLine = firstLine.strip()
# If string is from in-game copy of fitting window
# We match " power" instead of "High power" in case a fit has no high modules
if firstLine in FIT_WIN_HEADINGS and activeFit is not None:
return "FIT", (cls.importFittingWindow(string, activeFit),)
# If we have "<url=fitting", fit is coming from eve chat
# Gather data and send to DNA
chatDna = re.search("<url=fitting:(.*::)>.*</url>", firstLine)
if chatDna:
return "DNA", (cls.importDna(chatDna.group(1)),)
# If we have a CREST kill link
killLink = re.search("http://public-crest.eveonline.com/killmails/(.*)/", firstLine)
if killLink:
return "CREST", (cls.importCrest(tuple(killLink.group(1).split("/"))),)
# If we have "<url=killReport", fit is killmail from eve chat
killReport = re.search("<url=killReport:(.*)>.*</url>", firstLine)
if killReport:
return "CREST", (cls.importCrest(tuple(killReport.group(1).split(":"))),)
# If XML-style start of tag encountered, detect as XML
if re.match("<", firstLine):
return "XML", cls.importXml(string)
@@ -81,138 +58,6 @@ class Port(object):
# Use DNA format for all other cases
return "DNA", (cls.importDna(string),)
@staticmethod
def importFittingWindow(string, activeFit):
sMkt = service.Market.getInstance()
sFit = service.Fit.getInstance()
activeFit = sFit.getFit(activeFit)
# if the current fit has mods, do not mess with it. Instead, make new fit
if activeFit.modCount > 0:
fit = Fit()
fit.ship = Ship(sMkt.getItem(activeFit.ship.item.ID))
fit.name = "%s (copy)" % activeFit.name
else:
fit = activeFit
lines = re.split('[\n\r]+', string)
droneMap = {}
cargoMap = {}
modules = []
for i in range(1, len(lines)):
line = lines[i].strip()
if not line:
continue
try:
amount, modName = line.split("x ")
amount = int(amount)
item = sMkt.getItem(modName, eager="group.category")
except:
# if no data can be found (old names)
continue
if item.category.name == "Drone":
if not modName in droneMap:
droneMap[modName] = 0
droneMap[modName] += amount
elif item.category.name == "Charge":
if not modName in cargoMap:
cargoMap[modName] = 0
cargoMap[modName] += amount
else:
for _ in xrange(amount):
try:
m = Module(item)
except ValueError:
continue
# If we are importing T3 ship, we must apply subsystems first, then
# calcModAttr() to get the ship slots
if m.slot == Slot.SUBSYSTEM and m.fits(fit):
fit.modules.append(m)
else:
modules.append(m)
fit.clear()
fit.calculateModifiedAttributes()
for m in modules:
# we check to see if module fits as a basic sanity check
# if it doesn't then the imported fit is most likely invalid
# (ie: user tried to import Legion fit to a Rifter)
if m.fits(fit):
fit.modules.append(m)
if m.isValidState(State.ACTIVE):
m.state = State.ACTIVE
m.owner = fit # not sure why this is required when it's not for other import methods, but whatever
else:
return
for droneName in droneMap:
d = Drone(sMkt.getItem(droneName))
d.amount = droneMap[droneName]
fit.drones.append(d)
for cargoName in cargoMap:
c = Cargo(sMkt.getItem(cargoName))
c.amount = cargoMap[cargoName]
fit.cargo.append(c)
return fit
@staticmethod
def importCrest(info):
sMkt = service.Market.getInstance()
network = service.Network.getInstance()
try:
response = network.request("https://public-crest.eveonline.com/killmails/%s/%s/" % info, network.EVE)
except:
return
kill = (json.loads(response.read()))['victim']
fit = Fit()
fit.ship = Ship(sMkt.getItem(kill['shipType']['name']))
fit.name = "CREST: %s's %s" % (kill['character']['name'], kill['shipType']['name'])
# sort based on flag to get proper rack position
items = sorted(kill['items'], key=lambda k: k['flag'])
# We create a relation between module flag and module position on fit at time of append:
# this allows us to know which module to apply charges to if need be (see below)
flagMap = {}
# Charges may show up before or after the module. We process modules first,
# storing any charges that are fitted in a dict and noting their flag (module).
charges = {}
for mod in items:
if mod['flag'] == 5: # throw out cargo
continue
item = sMkt.getItem(mod['itemType']['name'], eager="group.category")
if item.category.name == "Drone":
d = Drone(item)
d.amount = mod['quantityDropped'] if 'quantityDropped' in mod else mod['quantityDestroyed']
fit.drones.append(d)
elif item.category.name == "Charge":
charges[mod['flag']] = item
else:
m = Module(item)
if m.isValidState(State.ACTIVE):
m.state = State.ACTIVE
fit.modules.append(m)
flagMap[mod['flag']] = fit.modules.index(m)
for flag, item in charges.items():
# we do not need to verify valid charge as it comes directly from CCP
fit.modules[flagMap[flag]].charge = item
return fit
@staticmethod
def importDna(string):
sMkt = service.Market.getInstance()
@@ -663,64 +508,68 @@ class Port(object):
fittings = doc.createElement("fittings")
doc.appendChild(fittings)
for fit in fits:
fitting = doc.createElement("fitting")
fitting.setAttribute("name", fit.name)
fittings.appendChild(fitting)
description = doc.createElement("description")
description.setAttribute("value", "")
fitting.appendChild(description)
shipType = doc.createElement("shipType")
shipType.setAttribute("value", fit.ship.item.name)
fitting.appendChild(shipType)
try:
fitting = doc.createElement("fitting")
fitting.setAttribute("name", fit.name)
fittings.appendChild(fitting)
description = doc.createElement("description")
description.setAttribute("value", "")
fitting.appendChild(description)
shipType = doc.createElement("shipType")
shipType.setAttribute("value", fit.ship.item.name)
fitting.appendChild(shipType)
charges = {}
slotNum = {}
for module in fit.modules:
if module.isEmpty:
continue
charges = {}
slotNum = {}
for module in fit.modules:
if module.isEmpty:
continue
slot = module.slot
slot = module.slot
if slot == Slot.SUBSYSTEM:
# Order of subsystem matters based on this attr. See GH issue #130
slotId = module.getModifiedItemAttr("subSystemSlot") - 124
else:
if not slot in slotNum:
slotNum[slot] = 0
if slot == Slot.SUBSYSTEM:
# Order of subsystem matters based on this attr. See GH issue #130
slotId = module.getModifiedItemAttr("subSystemSlot") - 124
else:
if not slot in slotNum:
slotNum[slot] = 0
slotId = slotNum[slot]
slotNum[slot] += 1
slotId = slotNum[slot]
slotNum[slot] += 1
hardware = doc.createElement("hardware")
hardware.setAttribute("type", module.item.name)
slotName = Slot.getName(slot).lower()
slotName = slotName if slotName != "high" else "hi"
hardware.setAttribute("slot", "%s slot %d" % (slotName, slotId))
fitting.appendChild(hardware)
hardware = doc.createElement("hardware")
hardware.setAttribute("type", module.item.name)
slotName = Slot.getName(slot).lower()
slotName = slotName if slotName != "high" else "hi"
hardware.setAttribute("slot", "%s slot %d" % (slotName, slotId))
fitting.appendChild(hardware)
if module.charge:
if not module.charge.name in charges:
charges[module.charge.name] = 0
# `or 1` because some charges (ie scripts) are without qty
charges[module.charge.name] += module.numCharges or 1
if module.charge:
if not module.charge.name in charges:
charges[module.charge.name] = 0
# `or 1` because some charges (ie scripts) are without qty
charges[module.charge.name] += module.numCharges or 1
for drone in fit.drones:
hardware = doc.createElement("hardware")
hardware.setAttribute("qty", "%d" % drone.amount)
hardware.setAttribute("slot", "drone bay")
hardware.setAttribute("type", drone.item.name)
fitting.appendChild(hardware)
for drone in fit.drones:
hardware = doc.createElement("hardware")
hardware.setAttribute("qty", "%d" % drone.amount)
hardware.setAttribute("slot", "drone bay")
hardware.setAttribute("type", drone.item.name)
fitting.appendChild(hardware)
for cargo in fit.cargo:
if not cargo.item.name in charges:
charges[cargo.item.name] = 0
charges[cargo.item.name] += cargo.amount
for cargo in fit.cargo:
if not cargo.item.name in charges:
charges[cargo.item.name] = 0
charges[cargo.item.name] += cargo.amount
for name, qty in charges.items():
hardware = doc.createElement("hardware")
hardware.setAttribute("qty", "%d" % qty)
hardware.setAttribute("slot", "cargo")
hardware.setAttribute("type", name)
fitting.appendChild(hardware)
for name, qty in charges.items():
hardware = doc.createElement("hardware")
hardware.setAttribute("qty", "%d" % qty)
hardware.setAttribute("slot", "cargo")
hardware.setAttribute("type", name)
fitting.appendChild(hardware)
except:
print "Failed on fitID: %d"%fit.ID
continue
return doc.toprettyxml()