From 3177713447fdbe7ef6514da84d078ca4a1a2532b Mon Sep 17 00:00:00 2001 From: blitzmann Date: Mon, 4 Apr 2016 22:04:23 -0400 Subject: [PATCH] Add preliminary (database/gui) fighter support. No effects / calculations. --- eos/db/saveddata/fighter.py | 33 ++++ eos/db/saveddata/fit.py | 9 +- eos/saveddata/fighter.py | 253 +++++++++++++++++++++++++++ eos/saveddata/fit.py | 9 +- eos/types.py | 1 + gui/additionsPane.py | 4 +- gui/builtinContextMenus/itemStats.py | 2 +- gui/fighterView.py | 251 ++++++++++++++++++++++++++ service/fit.py | 39 +++++ service/market.py | 2 +- 10 files changed, 598 insertions(+), 5 deletions(-) create mode 100644 eos/db/saveddata/fighter.py create mode 100644 eos/saveddata/fighter.py create mode 100644 gui/fighterView.py diff --git a/eos/db/saveddata/fighter.py b/eos/db/saveddata/fighter.py new file mode 100644 index 000000000..0cc66d13f --- /dev/null +++ b/eos/db/saveddata/fighter.py @@ -0,0 +1,33 @@ +#=============================================================================== +# 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 . +#=============================================================================== + +from sqlalchemy import Table, Column, Integer, ForeignKey, Boolean +from sqlalchemy.orm import mapper +from eos.db import saveddata_meta +from eos.types import Fighter + +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("amount", Integer, nullable = False), + Column("amountActive", Integer, nullable = False), + Column("projected", Boolean, default = False)) + +mapper(Fighter, fighters_table) diff --git a/eos/db/saveddata/fit.py b/eos/db/saveddata/fit.py index a40d8c7fb..77e6eb04b 100644 --- a/eos/db/saveddata/fit.py +++ b/eos/db/saveddata/fit.py @@ -26,9 +26,10 @@ from sqlalchemy.orm.collections import attribute_mapped_collection from eos.db import saveddata_meta from eos.db.saveddata.module import modules_table from eos.db.saveddata.drone import drones_table +from eos.db.saveddata.fighter import fighters_table from eos.db.saveddata.cargo import cargo_table from eos.db.saveddata.implant import fitImplants_table -from eos.types import Fit, Module, User, Booster, Drone, Cargo, Implant, Character, DamagePattern, TargetResists +from eos.types import Fit, Module, User, Booster, Drone, Fighter, Cargo, Implant, Character, DamagePattern, TargetResists from eos.effectHandlerHelpers import * fits_table = Table("fits", saveddata_meta, @@ -117,6 +118,12 @@ mapper(Fit, fits_table, cascade='all, delete, delete-orphan', single_parent=True, primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == False)), + "_Fit__fighters": relation( + Fighter, + collection_class=HandledDroneCargoList, + cascade='all, delete, delete-orphan', + single_parent=True, + primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == False)), "_Fit__cargo": relation( Cargo, collection_class=HandledDroneCargoList, diff --git a/eos/saveddata/fighter.py b/eos/saveddata/fighter.py new file mode 100644 index 000000000..4e16f2423 --- /dev/null +++ b/eos/saveddata/fighter.py @@ -0,0 +1,253 @@ +#=============================================================================== +# 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 . +#=============================================================================== + +from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, ChargeAttrShortcut +from eos.effectHandlerHelpers import HandledItem, HandledCharge +from sqlalchemy.orm import validates, reconstructor +import eos.db +import logging + +logger = logging.getLogger(__name__) + +class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): + DAMAGE_TYPES = ("em", "kinetic", "explosive", "thermal") + MINING_ATTRIBUTES = ("miningAmount",) + + def __init__(self, item): + """Initialize a fighter from the program""" + self.__item = item + print self.__item.category.name + if self.isInvalid: + raise ValueError("Passed item is not a Fighter") + + self.itemID = item.ID if item is not None else None + self.amount = 0 + self.amountActive = 0 + self.projected = False + self.build() + + @reconstructor + def init(self): + """Initialize a fighter from the database and validate""" + self.__item = None + + 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 + + if self.isInvalid: + logger.error("Item (id: %d) is not a Fighter", self.itemID) + return + + self.build() + + def build(self): + """ Build object. Assumes proper and valid item already set """ + self.__charge = None + self.__dps = None + self.__volley = None + 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") + if chargeID is not None: + charge = eos.db.getItem(int(chargeID)) + self.__charge = charge + self.__chargeModifiedAttributes.original = charge.attributes + self.__chargeModifiedAttributes.overrides = charge.overrides + + @property + def itemModifiedAttributes(self): + return self.__itemModifiedAttributes + + @property + def chargeModifiedAttributes(self): + return self.__chargeModifiedAttributes + + @property + def isInvalid(self): + return self.__item is None or self.__item.category.name != "Fighter" + + @property + def item(self): + return self.__item + + @property + def charge(self): + return self.__charge + + @property + def dealsDamage(self): + for attr in ("emDamage", "kineticDamage", "explosiveDamage", "thermalDamage"): + if attr in self.itemModifiedAttributes or attr in self.chargeModifiedAttributes: + return True + + @property + def mines(self): + if "miningAmount" in self.itemModifiedAttributes: + return True + + @property + def hasAmmo(self): + return self.charge is not None + + @property + def dps(self): + return self.damageStats() + + def damageStats(self, targetResists = None): + if self.__dps == None: + self.__volley = 0 + self.__dps = 0 + if self.dealsDamage is True and self.amountActive > 0: + if self.hasAmmo: + attr = "missileLaunchDuration" + getter = self.getModifiedChargeAttr + else: + attr = "speed" + getter = self.getModifiedItemAttr + + cycleTime = self.getModifiedItemAttr(attr) + + volley = sum(map(lambda d: (getter("%sDamage"%d) or 0) * (1-getattr(targetResists, "%sAmount"%d, 0)), self.DAMAGE_TYPES)) + volley *= self.amountActive + volley *= self.getModifiedItemAttr("damageMultiplier") or 1 + self.__volley = volley + self.__dps = volley / (cycleTime / 1000.0) + + return self.__dps, self.__volley + + @property + def miningStats(self): + if self.__miningyield == None: + if self.mines is True and self.amountActive > 0: + attr = "duration" + getter = self.getModifiedItemAttr + + cycleTime = self.getModifiedItemAttr(attr) + volley = sum(map(lambda d: getter(d), self.MINING_ATTRIBUTES)) * self.amountActive + self.__miningyield = volley / (cycleTime / 1000.0) + else: + self.__miningyield = 0 + + return self.__miningyield + + @property + def maxRange(self): + attrs = ("shieldTransferRange", "powerTransferRange", + "energyDestabilizationRange", "empFieldRange", + "ecmBurstRange", "maxRange") + for attr in attrs: + maxRange = self.getModifiedItemAttr(attr) + if maxRange is not None: return maxRange + if self.charge is not None: + delay = self.getModifiedChargeAttr("explosionDelay") + speed = self.getModifiedChargeAttr("maxVelocity") + if delay is not None and speed is not None: + return delay / 1000.0 * speed + + # Had to add this to match the falloff property in modules.py + # Fscking ship scanners. If you find any other falloff attributes, + # Put them in the attrs tuple. + @property + def falloff(self): + attrs = ("falloff", "falloffEffectiveness") + for attr in attrs: + falloff = self.getModifiedItemAttr(attr) + if falloff is not None: return falloff + + @validates("ID", "itemID", "chargeID", "amount", "amountActive") + def validator(self, key, val): + map = {"ID": lambda val: isinstance(val, int), + "itemID" : lambda val: isinstance(val, int), + "chargeID" : lambda val: isinstance(val, int), + "amount" : lambda val: isinstance(val, int) and val >= 0, + "amountActive" : lambda val: isinstance(val, int) and val <= self.amount and val >= 0} + + if map[key](val) == False: raise ValueError(str(val) + " is not a valid value for " + key) + else: return val + + def clear(self): + self.__dps = None + self.__volley = None + self.__miningyield = None + self.itemModifiedAttributes.clear() + self.chargeModifiedAttributes.clear() + + def canBeApplied(self, projectedOnto): + """Check if fighter can engage specific fitting""" + item = self.item + # Do not allow to apply offensive modules on ship with offensive module immunite, with few exceptions + # (all effects which apply instant modification are exception, generally speaking) + if item.offensive and projectedOnto.ship.getModifiedItemAttr("disallowOffensiveModifiers") == 1: + offensiveNonModifiers = set(("energyDestabilizationNew", "leech", "energyNosferatuFalloff", "energyNeutralizerFalloff")) + if not offensiveNonModifiers.intersection(set(item.effects)): + return False + # If assistive modules are not allowed, do not let to apply these altogether + if item.assistive and projectedOnto.ship.getModifiedItemAttr("disallowAssistance") == 1: + return False + else: + return True + + def calculateModifiedAttributes(self, fit, runTime, forceProjected = False): + if self.projected or forceProjected: + context = "projected", "fighter" + projected = True + else: + context = ("fighter",) + projected = False + + for effect in self.item.effects.itervalues(): + if effect.runTime == runTime and \ + ((projected == True and effect.isType("projected")) or \ + projected == False and effect.isType("passive")): + i = 0 + while i != self.amountActive: + effect.handler(fit, self, context) + i += 1 + + if self.charge: + for effect in self.charge.effects.itervalues(): + if effect.runTime == runTime: + effect.handler(fit, self, ("fighterCharge",)) + + def __deepcopy__(self, memo): + copy = Fighter(self.item) + copy.amount = self.amount + copy.amountActive = self.amountActive + return copy + + def fits(self, fit): + return True + + fitDroneGroupLimits = set() + for i in xrange(1, 3): + groneGrp = fit.ship.getModifiedItemAttr("allowedDroneGroup%d" % i) + if groneGrp is not None: + fitDroneGroupLimits.add(int(groneGrp)) + if len(fitDroneGroupLimits) == 0: + return True + if self.item.groupID in fitDroneGroupLimits: + return True + return False diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 611478a6d..50d7d8934 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -53,6 +53,7 @@ class Fit(object): self.__modules = HandledModuleList() self.__drones = HandledDroneCargoList() + self.__fighters = HandledDroneCargoList() self.__cargo = HandledDroneCargoList() self.__implants = HandledImplantBoosterList() self.__boosters = HandledImplantBoosterList() @@ -185,6 +186,10 @@ class Fit(object): def drones(self): return self.__drones + @property + def fighters(self): + return self.__fighters + @property def cargo(self): return self.__cargo @@ -365,6 +370,7 @@ class Fit(object): c = chain( self.modules, self.drones, + self.fighters, self.boosters, self.implants, self.projectedDrones, @@ -482,6 +488,7 @@ class Fit(object): u = [ (self.character, self.ship), self.drones, + self.fighters, self.boosters, self.appliedImplants, self.modules @@ -999,7 +1006,7 @@ class Fit(object): copy.damagePattern = self.damagePattern copy.targetResists = self.targetResists - toCopy = ("modules", "drones", "cargo", "implants", "boosters", "projectedModules", "projectedDrones") + toCopy = ("modules", "drones", "fighters", "cargo", "implants", "boosters", "projectedModules", "projectedDrones") for name in toCopy: orig = getattr(self, name) c = getattr(copy, name) diff --git a/eos/types.py b/eos/types.py index c1cafd1f5..26e36ef90 100644 --- a/eos/types.py +++ b/eos/types.py @@ -27,6 +27,7 @@ from eos.saveddata.targetResists import TargetResists from eos.saveddata.character import Character, Skill from eos.saveddata.module import Module, State, Slot, Hardpoint, Rack from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter from eos.saveddata.cargo import Cargo from eos.saveddata.implant import Implant from eos.saveddata.booster import SideEffect diff --git a/gui/additionsPane.py b/gui/additionsPane.py index 61490671c..ec8617a4c 100644 --- a/gui/additionsPane.py +++ b/gui/additionsPane.py @@ -21,6 +21,7 @@ import wx import gui.mainFrame from gui.boosterView import BoosterView from gui.droneView import DroneView +from gui.fighterView import FighterView from gui.cargoView import CargoView from gui.implantView import ImplantView from gui.projectedView import ProjectedView @@ -57,6 +58,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(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) @@ -68,7 +70,7 @@ class AdditionsPane(TogglePanel): self.notebook.AddPage(self.gangPage, "Fleet", tabImage = gangImg, showClose = False) self.notebook.SetSelection(0) - PANES = ["Drones", "Cargo", "Implants", "Boosters", "Projected", "Fleet"] + PANES = ["Drones", "Fighters", "Cargo", "Implants", "Boosters", "Projected", "Fleet"] def select(self, name): self.notebook.SetSelection(self.PANES.index(name)) diff --git a/gui/builtinContextMenus/itemStats.py b/gui/builtinContextMenus/itemStats.py index 73ba66a56..a05064d24 100644 --- a/gui/builtinContextMenus/itemStats.py +++ b/gui/builtinContextMenus/itemStats.py @@ -16,7 +16,7 @@ class ItemStats(ContextMenu): "implantItem", "boosterItem", "skillItem", "projectedModule", "projectedDrone", "projectedCharge", - "itemStats") + "itemStats", "fighterItem") def getText(self, itmContext, selection): return "{0} Stats".format(itmContext if itmContext is not None else "Item") diff --git a/gui/fighterView.py b/gui/fighterView.py new file mode 100644 index 000000000..31a902b6b --- /dev/null +++ b/gui/fighterView.py @@ -0,0 +1,251 @@ +#=============================================================================== +# Copyright (C) 2010 Diego Duclos +# +# This file is part of pyfa. +# +# pyfa is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pyfa is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pyfa. If not, see . +#=============================================================================== + +import wx + +import service +import gui.globalEvents as GE +import gui.marketBrowser as mb +import gui.display as d +from gui.builtinViewColumns.state import State +from gui.contextMenu import ContextMenu + +class FighterViewDrop(wx.PyDropTarget): + def __init__(self, dropFn): + wx.PyDropTarget.__init__(self) + self.dropFn = dropFn + # this is really transferring an EVE itemID + self.dropData = wx.PyTextDataObject() + self.SetDataObject(self.dropData) + + def OnData(self, x, y, t): + if self.GetData(): + data = self.dropData.GetText().split(':') + self.dropFn(x, y, data) + return t + +class FighterView(d.Display): + DEFAULT_COLS = [#"State", + #"Base Icon", + "Base Name", + # "prop:droneDps,droneBandwidth", + #"Max Range", + #"Miscellanea", + #"attr:maxVelocity", + "Price",] + + def __init__(self, parent): + d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE) + + self.lastFitId = None + + self.hoveredRow = None + self.hoveredColumn = None + + self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) + self.mainFrame.Bind(mb.ITEM_SELECTED, self.addItem) + self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem) + self.Bind(wx.EVT_LEFT_DOWN, self.click) + self.Bind(wx.EVT_KEY_UP, self.kbEvent) + self.Bind(wx.EVT_MOTION, self.OnMouseMove) + self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) + + if "__WXGTK__" in wx.PlatformInfo: + self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu) + else: + self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu) + + + self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag) + self.SetDropTarget(FighterViewDrop(self.handleDragDrop)) + + def OnLeaveWindow(self, event): + self.SetToolTip(None) + self.hoveredRow = None + self.hoveredColumn = None + event.Skip() + + def OnMouseMove(self, event): + row, _, col = self.HitTestSubItem(event.Position) + if row != self.hoveredRow or col != self.hoveredColumn: + if self.ToolTip is not None: + self.SetToolTip(None) + else: + self.hoveredRow = row + self.hoveredColumn = col + if row != -1 and col != -1 and col < len(self.DEFAULT_COLS): + mod = self.fighters[self.GetItemData(row)] + if self.DEFAULT_COLS[col] == "Miscellanea": + tooltip = self.activeColumns[col].getToolTip(mod) + if tooltip is not None: + self.SetToolTipString(tooltip) + else: + self.SetToolTip(None) + else: + self.SetToolTip(None) + else: + self.SetToolTip(None) + event.Skip() + + def kbEvent(self, event): + keycode = event.GetKeyCode() + if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE: + row = self.GetFirstSelected() + firstSel = row + if row != -1: + fighter = self.fighters[self.GetItemData(row)] + self.removeFighter(fighter) + + event.Skip() + + def startDrag(self, event): + row = event.GetIndex() + if row != -1: + data = wx.PyTextDataObject() + data.SetText("fighter:"+str(row)) + + dropSource = wx.DropSource(self) + dropSource.SetData(data) + res = dropSource.DoDragDrop() + + def handleDragDrop(self, x, y, data): + ''' + Handles dragging of items from various pyfa displays which support it + + data is list with two indices: + data[0] is hard-coded str of originating source + data[1] is typeID or index of data we want to manipulate + ''' + if data[0] == "fighter": # we want to merge fighters + srcRow = int(data[1]) + dstRow, _ = self.HitTest((x, y)) + if srcRow != -1 and dstRow != -1: + self._merge(srcRow, dstRow) + elif data[0] == "market": + wx.PostEvent(self.mainFrame, mb.ItemSelected(itemID=int(data[1]))) + + def _merge(self, src, dst): + print "merge fighters {} -> {}".format(src, dst) + raise NotImplementedError() + + sFit = service.Fit.getInstance() + fitID = self.mainFrame.getActiveFit() + if sFit.mergeDrones(fitID, self.drones[src], self.drones[dst]): + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + + ''' + DRONE_ORDER = ('Light Scout Drones', 'Medium Scout Drones', + 'Heavy Attack Drones', 'Sentry Drones', 'Fighters', + 'Fighter Bombers', 'Combat Utility Drones', + 'Electronic Warfare Drones', 'Logistic Drones', 'Mining Drones', 'Salvage Drones', + 'Light Fighters', 'Heavy Fighters', 'Support Fighters') + def droneKey(self, drone): + sMkt = service.Market.getInstance() + + groupName = sMkt.getMarketGroupByItem(drone.item).name + print groupName + return (self.DRONE_ORDER.index(groupName), + drone.item.name) + ''' + + def fitChanged(self, event): + + #Clear list and get out if current fitId is None + if event.fitID is None and self.lastFitId is not None: + self.DeleteAllItems() + self.lastFitId = None + event.Skip() + return + + sFit = service.Fit.getInstance() + fit = sFit.getFit(event.fitID) + + self.original = fit.fighters if fit is not None else None + self.fighters = stuff = fit.fighters[:] if fit is not None else None + + ''' + if stuff is not None: + stuff.sort(key=self.droneKey) + ''' + + if event.fitID != self.lastFitId: + self.lastFitId = event.fitID + + item = self.GetNextItem(-1, wx.LIST_NEXT_ALL, wx.LIST_STATE_DONTCARE) + + if item != -1: + self.EnsureVisible(item) + + self.deselectItems() + + self.update(stuff) + event.Skip() + + + def addItem(self, event): + sFit = service.Fit.getInstance() + fitID = self.mainFrame.getActiveFit() + trigger = sFit.addFighter(fitID, event.itemID) + if trigger: + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.additionsPane.select("Fighters") + + event.Skip() + + def removeItem(self, event): + row, _ = self.HitTest(event.Position) + if row != -1: + col = self.getColumn(event.Position) + if col != self.getColIndex(State): + fighter = self.fighters[self.GetItemData(row)] + self.removeFighter(fighter) + + def removeFighter(self, fighter): + fitID = self.mainFrame.getActiveFit() + sFit = service.Fit.getInstance() + sFit.removeFighter(fitID, self.original.index(fighter)) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + + def click(self, event): + event.Skip() + row, _ = self.HitTest(event.Position) + if row != -1: + col = self.getColumn(event.Position) + if col == self.getColIndex(State): + fitID = self.mainFrame.getActiveFit() + sFit = service.Fit.getInstance() + fighter = self.fighters[row] + sFit.toggleFighter(fitID, self.original.index(fighter)) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + + def scheduleMenu(self, event): + event.Skip() + if self.getColumn(event.Position) != self.getColIndex(State): + wx.CallAfter(self.spawnMenu) + + def spawnMenu(self): + sel = self.GetFirstSelected() + if sel != -1: + fighter = self.fighters[sel] + + sMkt = service.Market.getInstance() + sourceContext = "fighterItem" + itemContext = sMkt.getCategoryByItem(fighter.item).name + menu = ContextMenu.getMenu((fighter,), (sourceContext, itemContext)) + self.PopupMenu(menu) diff --git a/service/fit.py b/service/fit.py index 590651abe..e15faaf8a 100644 --- a/service/fit.py +++ b/service/fit.py @@ -615,6 +615,45 @@ class Fit(object): self.recalc(fit) return True + def addFighter(self, fitID, itemID): + if fitID is None: + return False + + fit = eos.db.getFit(fitID) + item = eos.db.getItem(itemID, eager=("attributes", "group.category")) + if item.category.name == "Fighter": + fighter = None + ''' + for d in fit.fighters.find(item): + if d is not None and d.amountActive == 0 and d.amount < max(5, fit.extraAttributes["maxActiveDrones"]): + drone = d + break + ''' + if fighter is None: + fighter = eos.types.Fighter(item) + if fighter.fits(fit) is True: + fit.fighters.append(fighter) + else: + return False + fighter.amount += 1 + eos.db.commit() + self.recalc(fit) + return True + else: + return False + + def removeFighter(self, fitID, i): + fit = eos.db.getFit(fitID) + f = fit.fighters[i] + f.amount -= 1 + + if f.amount == 0: + del fit.fighters[i] + + eos.db.commit() + self.recalc(fit) + return True + def addDrone(self, fitID, itemID): if fitID is None: return False diff --git a/service/market.py b/service/market.py index 39c700ce5..00323b78b 100644 --- a/service/market.py +++ b/service/market.py @@ -318,7 +318,7 @@ class Market(): ("faction", frozenset((4, 3))), ("complex", frozenset((6,))), ("officer", frozenset((5,)))]) - self.SEARCH_CATEGORIES = ("Drone", "Module", "Subsystem", "Charge", "Implant", "Deployable") + self.SEARCH_CATEGORIES = ("Drone", "Module", "Subsystem", "Charge", "Implant", "Deployable", "Fighter") self.ROOT_MARKET_GROUPS = (9, # Modules 1111, # Rigs 157, # Drones