diff --git a/eos/db/saveddata/fighter.py b/eos/db/saveddata/fighter.py index 3adb422bc..1daa37ae7 100644 --- a/eos/db/saveddata/fighter.py +++ b/eos/db/saveddata/fighter.py @@ -31,6 +31,7 @@ fighters_table = Table("fighters", saveddata_meta, Column("groupID", Integer, primary_key=True), Column("fitID", Integer, ForeignKey("fits.ID"), nullable = False, index = True), Column("itemID", Integer, nullable = False), + Column("active", Boolean, nullable=True), Column("amount", Integer, nullable = False), Column("projected", Boolean, default = False)) diff --git a/eos/saveddata/fighter.py b/eos/saveddata/fighter.py index 69c67a9e1..957feb27b 100644 --- a/eos/saveddata/fighter.py +++ b/eos/saveddata/fighter.py @@ -41,6 +41,7 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): self.itemID = item.ID if item is not None else None self.projected = False + self.active = True # -1 is a placeholder that represents max squadron size, which we may not know yet as ships may modify this with # their effects. If user changes this, it is then overridden with user value. @@ -257,7 +258,8 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): return copy def fits(self, fit): - if fit.getSlotsFree(self.slot) <= 0: + # If ships doesn't support this type of fighter, don't add it + if fit.getNumSlots(self.slot) == 0: return False return True diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 198b44623..aa7997737 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -616,30 +616,36 @@ class Fit(object): def getSlotsUsed(self, type, countDummies=False): amount = 0 + for mod in chain(self.modules, self.fighters): if mod.slot is type and (not getattr(mod, "isEmpty", False) or countDummies): + if type in (Slot.F_HEAVY, Slot.F_SUPPORT, Slot.F_LIGHT) and not mod.active: + continue amount += 1 return amount - def getSlotsFree(self, type, countDummies=False): - slots = {Slot.LOW: "lowSlots", - Slot.MED: "medSlots", - Slot.HIGH: "hiSlots", - Slot.RIG: "rigSlots", - Slot.SUBSYSTEM: "maxSubSystems", - Slot.F_LIGHT: "fighterLightSlots", - Slot.F_SUPPORT: "fighterSupportSlots", - Slot.F_HEAVY: "fighterHeavySlots"} + slots = {Slot.LOW: "lowSlots", + Slot.MED: "medSlots", + Slot.HIGH: "hiSlots", + Slot.RIG: "rigSlots", + Slot.SUBSYSTEM: "maxSubSystems", + Slot.F_LIGHT: "fighterLightSlots", + Slot.F_SUPPORT: "fighterSupportSlots", + Slot.F_HEAVY: "fighterHeavySlots"} + def getSlotsFree(self, type, countDummies=False): if type in (Slot.MODE, Slot.SYSTEM): # These slots don't really exist, return default 0 return 0 slotsUsed = self.getSlotsUsed(type, countDummies) - totalSlots = self.ship.getModifiedItemAttr(slots[type]) or 0 + totalSlots = self.ship.getModifiedItemAttr(self.slots[type]) or 0 return int(totalSlots - slotsUsed) + def getNumSlots(self, type): + return self.ship.getModifiedItemAttr(self.slots[type]) or 0 + @property def calibrationUsed(self): return self.getItemAttrOnlineSum(self.modules, 'upgradeCost') @@ -668,6 +674,23 @@ class Fit(object): return amount + @property + def fighterBayUsed(self): + amount = 0 + for f in self.fighters: + amount += f.item.volume * f.amountActive + + return amount + + @property + def fighterTubesUsed(self): + amount = 0 + for f in self.fighters: + if f.active: + amount += 1 + + return amount + @property def cargoBayUsed(self): amount = 0 diff --git a/gui/additionsPane.py b/gui/additionsPane.py index ec8617a4c..d108686cc 100644 --- a/gui/additionsPane.py +++ b/gui/additionsPane.py @@ -51,6 +51,7 @@ class AdditionsPane(TogglePanel): baseSizer.Add(self.notebook, 1, wx.EXPAND) droneImg = BitmapLoader.getImage("drone_small", "gui") + fighterImg = BitmapLoader.getImage("fighter_small", "gui") implantImg = BitmapLoader.getImage("implant_small", "gui") boosterImg = BitmapLoader.getImage("booster_small", "gui") projectedImg = BitmapLoader.getImage("projected_small", "gui") @@ -58,7 +59,7 @@ class AdditionsPane(TogglePanel): cargoImg = BitmapLoader.getImage("cargo_small", "gui") self.notebook.AddPage(DroneView(self.notebook), "Drones", tabImage = droneImg, showClose = False) - self.notebook.AddPage(FighterView(self.notebook), "Fighters", tabImage = droneImg, showClose = False) + self.notebook.AddPage(FighterView(self.notebook), "Fighters", tabImage = fighterImg, showClose = False) self.notebook.AddPage(CargoView(self.notebook), "Cargo", tabImage = cargoImg, showClose = False) self.notebook.AddPage(ImplantView(self.notebook), "Implants", tabImage = implantImg, showClose = False) self.notebook.AddPage(BoosterView(self.notebook), "Boosters", tabImage = boosterImg, showClose = False) diff --git a/gui/builtinStatsViews/resourcesViewFull.py b/gui/builtinStatsViews/resourcesViewFull.py index 24497ecfc..f292d39ab 100644 --- a/gui/builtinStatsViews/resourcesViewFull.py +++ b/gui/builtinStatsViews/resourcesViewFull.py @@ -31,6 +31,8 @@ from gui.utils.numberFormatter import formatAmount class ResourcesViewFull(StatsView): name = "resourcesViewFull" + contexts = ["drone", "fighter", "cargo"] + def __init__(self, parent): StatsView.__init__(self) self.parent = parent @@ -40,21 +42,37 @@ class ResourcesViewFull(StatsView): def pageChanged(self, event): page = self.mainFrame.additionsPane.getName(event.GetSelection()) if page == "Cargo": - self.toggleCargoGauge(True) + self.toggleContext("cargo") + elif page == "Fighters": + self.toggleContext("fighter") else: - self.toggleCargoGauge(False) + self.toggleContext("drone") - def toggleCargoGauge(self, showCargo = False): - if showCargo: - self.bitmapFullCargoBay.Show() - self.baseFullCargoBay.Show(True) - self.bitmapFullDroneBay.Hide() - self.baseFullDroneBay.Hide(True) + def toggleContext(self, context): + # Apparently you cannot .Hide(True) on a Window, otherwise I would just .Hide(context !== x). + # This is a gimpy way to toggle this shit + for x in self.contexts: + bitmap = getattr(self, "bitmapFull{}Bay".format(x.capitalize())) + base = getattr(self, "baseFull{}Bay".format(x.capitalize())) + + if context == x: + bitmap.Show() + base.Show(True) + else: + bitmap.Hide() + base.Hide(True) + + fighter_sizer = getattr(self, "boxSizerFighter") + drone_sizer = getattr(self, "boxSizerDrones") + + print drone_sizer + if context != "fighter": + fighter_sizer.ShowItems(False) + drone_sizer.ShowItems(True) else: - self.bitmapFullDroneBay.Show() - self.baseFullDroneBay.Show(True) - self.bitmapFullCargoBay.Hide() - self.baseFullCargoBay.Hide(True) + fighter_sizer.ShowItems(True) + drone_sizer.ShowItems(False) + self.panel.Layout() self.headerPanel.Layout() @@ -72,7 +90,7 @@ class ResourcesViewFull(StatsView): root = wx.BoxSizer(wx.VERTICAL) contentSizer.Add(root, 0, wx.EXPAND, 0) - sizer = wx.GridSizer(1, 4) + sizer = wx.BoxSizer(wx.HORIZONTAL) root.Add(sizer, 0, wx.EXPAND) root.Add(wx.StaticLine(contentPanel, wx.ID_ANY, style=wx.HORIZONTAL), 0, wx.EXPAND) @@ -85,10 +103,10 @@ class ResourcesViewFull(StatsView): base = sizerResources - + sizer.AddSpacer((0, 0), 1, wx.EXPAND, 5) #Turrets & launcher hardslots display - tooltipText = {"turret":"Turret hardpoints", "launcher":"Launcher hardpoints", "drones":"Drones active", "calibration":"Calibration"} - for type in ("turret", "launcher", "drones", "calibration"): + tooltipText = {"turret":"Turret hardpoints", "launcher":"Launcher hardpoints", "drones":"Drones active", "fighter": "Fighter squadrons active", "calibration":"Calibration"} + for type in ("turret", "launcher", "drones", "fighter", "calibration"): box = wx.BoxSizer(wx.HORIZONTAL) bitmap = BitmapLoader.getStaticBitmap("%s_big" % type, parent, "gui") @@ -99,7 +117,7 @@ class ResourcesViewFull(StatsView): sizer.Add(box, 0, wx.ALIGN_CENTER) - suffix = {'turret':'Hardpoints', 'launcher':'Hardpoints', 'drones':'Active', 'calibration':'Points'} + suffix = {'turret':'Hardpoints', 'launcher':'Hardpoints', 'drones':'Active', 'fighter':'Tubes', 'calibration':'Points'} lbl = wx.StaticText(parent, wx.ID_ANY, "0") setattr(self, "label%sUsed%s%s" % (panel.capitalize(), type.capitalize(), suffix[type].capitalize()), lbl) box.Add(lbl, 0, wx.ALIGN_CENTER | wx.LEFT, 5) @@ -109,11 +127,17 @@ class ResourcesViewFull(StatsView): lbl = wx.StaticText(parent, wx.ID_ANY, "0") setattr(self, "label%sTotal%s%s" % (panel.capitalize(), type.capitalize(), suffix[type].capitalize()), lbl) box.Add(lbl, 0, wx.ALIGN_CENTER) + setattr(self, "boxSizer{}".format(type.capitalize()), box) + + # Hack - We add a spacer after each thing, but we are always hiding something. The spacer is stil there. + # This way, we only have one space after the drones/fighters + if type != "drones": + sizer.AddSpacer((0, 0), 1, wx.EXPAND, 5) #PG, Cpu & drone stuff - tooltipText = {"cpu":"CPU", "pg":"PowerGrid", "droneBay":"Drone bay", "droneBandwidth":"Drone bandwidth", "cargoBay":"Cargo bay"} - for i, group in enumerate((("cpu", "pg"), ("cargoBay", "droneBay", "droneBandwidth"))): + tooltipText = {"cpu":"CPU", "pg":"PowerGrid", "droneBay":"Drone bay", "fighterBay": "Fighter bay", "droneBandwidth":"Drone bandwidth", "cargoBay":"Cargo bay"} + for i, group in enumerate((("cpu", "pg"), ("cargoBay", "droneBay", "fighterBay", "droneBandwidth"))): main = wx.BoxSizer(wx.VERTICAL) base.Add(main, 1 , wx.ALIGN_CENTER) @@ -144,7 +168,7 @@ class ResourcesViewFull(StatsView): setattr(self, "label%sTotal%s" % (panel.capitalize(), capitalizedType), lbl) absolute.Add(lbl, 0, wx.ALIGN_LEFT) - units = {"cpu":" tf", "pg":" MW", "droneBandwidth":" mbit/s", "droneBay":u" m\u00B3", "cargoBay":u" m\u00B3"} + units = {"cpu":" tf", "pg":" MW", "droneBandwidth":" mbit/s", "droneBay":u" m\u00B3", "fighterBay":u" m\u00B3", "cargoBay":u" m\u00B3"} lbl = wx.StaticText(parent, wx.ID_ANY, "%s" % units[type]) absolute.Add(lbl, 0, wx.ALIGN_LEFT) @@ -161,7 +185,7 @@ class ResourcesViewFull(StatsView): setattr(self, "base%s%s" % (panel.capitalize(), capitalizedType), b) setattr(self, "bitmap%s%s" % (panel.capitalize(), capitalizedType), bitmap) - self.toggleCargoGauge(False) + self.toggleContext("drone") def refreshPanel(self, fit): #If we did anything intresting, we'd update our labels to reflect the new fit's stats here @@ -172,6 +196,8 @@ class ResourcesViewFull(StatsView): ("label%sTotalLauncherHardpoints", lambda: fit.ship.getModifiedItemAttr('launcherSlotsLeft'), 0, 0, 0), ("label%sUsedDronesActive", lambda: fit.activeDrones, 0, 0, 0), ("label%sTotalDronesActive", lambda: fit.extraAttributes["maxActiveDrones"], 0, 0, 0), + ("label%sUsedFighterTubes", lambda: fit.fighterTubesUsed, 3, 0, 9), + ("label%sTotalFighterTubes", lambda: fit.ship.getModifiedItemAttr("fighterTubes"), 3, 0, 9), ("label%sUsedCalibrationPoints", lambda: fit.calibrationUsed, 0, 0, 0), ("label%sTotalCalibrationPoints", lambda: fit.ship.getModifiedItemAttr('upgradeCapacity'), 0, 0, 0), ("label%sUsedPg", lambda: fit.pgUsed, 4, 0, 9), @@ -179,9 +205,11 @@ class ResourcesViewFull(StatsView): ("label%sTotalPg", lambda: fit.ship.getModifiedItemAttr("powerOutput"), 4, 0, 9), ("label%sTotalCpu", lambda: fit.ship.getModifiedItemAttr("cpuOutput"), 4, 0, 9), ("label%sUsedDroneBay", lambda: fit.droneBayUsed, 3, 0, 9), + ("label%sUsedFighterBay", lambda: fit.fighterBayUsed, 3, 0, 9), ("label%sUsedDroneBandwidth", lambda: fit.droneBandwidthUsed, 3, 0, 9), ("label%sTotalDroneBay", lambda: fit.ship.getModifiedItemAttr("droneCapacity"), 3, 0, 9), ("label%sTotalDroneBandwidth", lambda: fit.ship.getModifiedItemAttr("droneBandwidth"), 3, 0, 9), + ("label%sTotalFighterBay", lambda: fit.ship.getModifiedItemAttr("fighterCapacity"), 3, 0, 9), ("label%sUsedCargoBay", lambda: fit.cargoBayUsed, 3, 0, 9), ("label%sTotalCargoBay", lambda: fit.ship.getModifiedItemAttr("capacity"), 3, 0, 9)) panel = "Full" @@ -218,6 +246,14 @@ class ResourcesViewFull(StatsView): totalDronesActive = value labelTDA = label + if labelName % panel == "label%sUsedFighterTubes" % panel: + usedFighterTubes = value + labelUFT = label + + if labelName % panel == "label%sTotalFighterTubes" % panel: + totalFighterTubes = value + labelTFT = label + if labelName % panel == "label%sUsedCalibrationPoints" % panel: usedCalibrationPoints = value labelUCP = label @@ -248,6 +284,10 @@ class ResourcesViewFull(StatsView): colorD = colorWarn else: colorD = colorNormal + if usedFighterTubes > totalFighterTubes: + colorF = colorWarn + else: + colorF = colorNormal if usedCalibrationPoints > totalCalibrationPoints: colorC = colorWarn else: @@ -259,6 +299,8 @@ class ResourcesViewFull(StatsView): labelTLH.SetForegroundColour(colorL) labelUDA.SetForegroundColour(colorD) labelTDA.SetForegroundColour(colorD) + labelUFT.SetForegroundColour(colorF) + labelTFT.SetForegroundColour(colorF) labelUCP.SetForegroundColour(colorC) labelTCP.SetForegroundColour(colorC) @@ -266,11 +308,12 @@ class ResourcesViewFull(StatsView): resMax = (lambda: fit.ship.getModifiedItemAttr("cpuOutput"), lambda: fit.ship.getModifiedItemAttr("powerOutput"), lambda: fit.ship.getModifiedItemAttr("droneCapacity"), + lambda: fit.ship.getModifiedItemAttr("fighterCapacity"), lambda: fit.ship.getModifiedItemAttr("droneBandwidth"), lambda: fit.ship.getModifiedItemAttr("capacity")) i = 0 - for resourceType in ("cpu", "pg", "droneBay", "droneBandwidth", "cargoBay"): + for resourceType in ("cpu", "pg", "droneBay", "fighterBay", "droneBandwidth", "cargoBay"): if fit is not None: capitalizedType = resourceType[0].capitalize() + resourceType[1:] diff --git a/gui/fighterView.py b/gui/fighterView.py index bf0a7dd77..991663eb3 100644 --- a/gui/fighterView.py +++ b/gui/fighterView.py @@ -22,8 +22,10 @@ import wx import service import gui.globalEvents as GE import gui.marketBrowser as mb +import gui.mainFrame import gui.display as d from gui.builtinViewColumns.state import State +from eos.types import Slot from gui.contextMenu import ContextMenu class FighterViewDrop(wx.PyDropTarget): @@ -40,8 +42,68 @@ class FighterViewDrop(wx.PyDropTarget): self.dropFn(x, y, data) return t -class FighterView(d.Display): - DEFAULT_COLS = [#"State", + +class FighterView(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, style=wx.TAB_TRAVERSAL ) + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.labels = ["Light", "Heavy", "Support"] + + mainSizer = wx.BoxSizer(wx.VERTICAL) + + self.fighterDisplay = FighterDisplay(self) + mainSizer.Add(self.fighterDisplay, 1, wx.EXPAND, 0) + + textSizer = wx.BoxSizer(wx.HORIZONTAL) + textSizer.AddSpacer(( 0, 0), 1, wx.EXPAND, 5) + + for x in self.labels: + lbl = wx.StaticText(self, wx.ID_ANY, x.capitalize()) + textSizer.Add(lbl, 0, wx.ALIGN_CENTER | wx.LEFT, 5) + + lbl = wx.StaticText(self, wx.ID_ANY, "0") + setattr(self, "label%sUsed" % (x.capitalize()), lbl) + textSizer.Add(lbl, 0, wx.ALIGN_CENTER | wx.LEFT, 5) + + textSizer.Add(wx.StaticText(self, wx.ID_ANY, "/"), 0, wx.ALIGN_CENTER) + + lbl = wx.StaticText(self, wx.ID_ANY, "0") + setattr(self, "label%sTotal" % (x.capitalize()), lbl) + textSizer.Add(lbl, 0, wx.ALIGN_CENTER) + textSizer.AddSpacer((0, 0), 1, wx.EXPAND, 5) + + mainSizer.Add(textSizer, 0, wx.EXPAND, 5) + + self.SetSizer( mainSizer ) + self.SetAutoLayout(True) + + + self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) + + def fitChanged(self, event): + sFit = service.Fit.getInstance() + activeFitID = self.mainFrame.getActiveFit() + fit = sFit.getFit(activeFitID) + + for x in self.labels: + slot = getattr(Slot, "F_{}".format(x.upper())) + used = fit.getSlotsUsed(slot) + total = fit.getNumSlots(slot) + color = wx.Colour(204, 51, 51) if used > total else wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT) + + lbl = getattr(self, "label%sUsed" % x.capitalize()) + lbl.SetLabel(str(int(used))) + lbl.SetForegroundColour(color) + + lbl = getattr(self, "label%sTotal" % x.capitalize()) + lbl.SetLabel(str(int(total))) + lbl.SetForegroundColour(color) + + self.Refresh() + + +class FighterDisplay(d.Display): + DEFAULT_COLS = ["State", #"Base Icon", "Base Name", # "prop:droneDps,droneBandwidth", diff --git a/imgs/gui/fighterBay_big.png b/imgs/gui/fighterBay_big.png new file mode 100644 index 000000000..ad6171cee Binary files /dev/null and b/imgs/gui/fighterBay_big.png differ diff --git a/imgs/gui/fighterTubes_big.png b/imgs/gui/fighterTubes_big.png new file mode 100644 index 000000000..077115e18 Binary files /dev/null and b/imgs/gui/fighterTubes_big.png differ diff --git a/imgs/gui/fighter_big.png b/imgs/gui/fighter_big.png new file mode 100644 index 000000000..afc5c3734 Binary files /dev/null and b/imgs/gui/fighter_big.png differ diff --git a/imgs/gui/fighter_small.png b/imgs/gui/fighter_small.png new file mode 100644 index 000000000..1e6696414 Binary files /dev/null and b/imgs/gui/fighter_small.png differ diff --git a/service/fit.py b/service/fit.py index a9d6e23a0..355cf0076 100644 --- a/service/fit.py +++ b/service/fit.py @@ -749,6 +749,15 @@ class Fit(object): self.recalc(fit) return True + def toggleFighter(self, fitID, i): + fit = eos.db.getFit(fitID) + f = fit.fighters[i] + f.active = not f.active + + eos.db.commit() + self.recalc(fit) + return True + def toggleImplant(self, fitID, i): fit = eos.db.getFit(fitID) implant = fit.implants[i]