def __handleProjectedItem(self, mainItem, selection): fitID = self.mainFrame.getActiveFit() if isinstance(mainItem, EosFit): self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand( fitID=fitID, items=selection, amount=math.inf)) elif isinstance(mainItem, EosModule): if wx.GetMouseState().GetModifiers() == wx.MOD_ALT: fit = Fit.getInstance().getFit(fitID) positions = getSimilarModPositions(fit.projectedModules, mainItem) items = [fit.projectedModules[p] for p in positions] else: items = selection self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand( fitID=fitID, items=items, amount=math.inf)) elif isinstance(mainItem, EosDrone): self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand( fitID=fitID, items=selection, amount=math.inf)) elif isinstance(mainItem, EosFighter): if wx.GetMouseState().GetModifiers() == wx.MOD_ALT: fit = Fit.getInstance().getFit(fitID) items = getSimilarFighters(fit.projectedFighters, mainItem) else: items = selection self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand( fitID=fitID, items=items, amount=math.inf)) else: self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand( fitID=fitID, items=selection, amount=math.inf))
def click(self, event): mainRow, _ = self.HitTest(event.Position) if mainRow != -1: col = self.getColumn(event.Position) if col == self.getColIndex(State): mainItem = self.get(mainRow) if mainItem is None: return selection = self.getSelectedProjectors() if mainItem not in selection: selection = [mainItem] modPressed = wx.GetMouseState().GetModifiers() == wx.MOD_ALT fitID = self.mainFrame.getActiveFit() if isinstance(mainItem, EosModule) and modPressed: fit = Fit.getInstance().getFit(fitID) positions = getSimilarModPositions(fit.projectedModules, mainItem) selection = [fit.projectedModules[p] for p in positions] elif isinstance(mainItem, EosFighter) and modPressed: fit = Fit.getInstance().getFit(fitID) selection = getSimilarFighters(fit.projectedFighters, mainItem) self.mainFrame.command.Submit(cmd.GuiChangeProjectedItemStatesCommand( fitID=fitID, mainItem=mainItem, items=selection, click='right' if event.GetButton() == 3 else 'left')) return event.Skip()
def Undo(self): for _ in self.internal_history.Commands: self.internal_history.Undo() eos.db.commit() Fit.getInstance().recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True
def importCrest(str_): fit = json.loads(str_) sMkt = Market.getInstance() f = Fit() f.name = fit['name'] try: try: f.ship = Ship(sMkt.getItem(fit['ship']['id'])) except ValueError: f.ship = Citadel(sMkt.getItem(fit['ship']['id'])) except: return None items = fit['items'] items.sort(key=lambda k: k['flag']) moduleList = [] for module in items: try: item = sMkt.getItem(module['type']['id'], eager="group.category") if module['flag'] == INV_FLAG_DRONEBAY: d = Drone(item) d.amount = module['quantity'] f.drones.append(d) elif module['flag'] == INV_FLAG_CARGOBAY: c = Cargo(item) c.amount = module['quantity'] f.cargo.append(c) elif module['flag'] == INV_FLAG_FIGHTER: fighter = Fighter(item) f.fighters.append(fighter) else: try: m = Module(item) # When item can't be added to any slot (unknown item or just charge), ignore it except ValueError: continue # Add subsystems before modules to make sure T3 cruisers have subsystems installed if item.category.name == "Subsystem": if m.fits(f): f.modules.append(m) else: if m.isValidState(State.ACTIVE): m.state = State.ACTIVE moduleList.append(m) except: continue # Recalc to get slot numbers correct for T3 cruisers svcFit.getInstance().recalc(f) for module in moduleList: if module.fits(f): f.modules.append(module) return f
def getText(self, stuff): if isinstance(stuff, Drone): return "%dx %s" % (stuff.amount, stuff.item.name) elif isinstance(stuff, Fighter): return "%d/%d %s" % \ (stuff.amountActive, stuff.getModifiedItemAttr("fighterSquadronMaxSize"), stuff.item.name) elif isinstance(stuff, Cargo): return "%dx %s" % (stuff.amount, stuff.item.name) elif isinstance(stuff, Fit): if self.projectedView: # we need a little more information for the projected view fitID = self.mainFrame.getActiveFit() info = stuff.getProjectionInfo(fitID) if info: return "%dx %s (%s)" % (stuff.getProjectionInfo(fitID).amount, stuff.name, stuff.ship.item.name) pyfalog.warning("Projected View trying to display things that aren't there. stuff: {}, info: {}", repr(stuff), info) return "<unknown>" else: return "%s (%s)" % (stuff.name, stuff.ship.item.name) elif isinstance(stuff, Rack): if FitSvc.getInstance().serviceFittingOptions["rackLabels"]: if stuff.slot == FittingSlot.MODE: return '─ Tactical Mode ─' else: return '─ {} {} Slot{}─'.format(stuff.num, FittingSlot(stuff.slot).name.capitalize(), '' if stuff.num == 1 else 's') else: return "" elif isinstance(stuff, Module): if self.projectedView: # check for projected abyssal name name_check = stuff.item.name[0:-2] type = WhProjector.abyssal_mapping.get(name_check, None) if type: sMkt = Market.getInstance() type = sMkt.getItem(type) return "{} {}".format(type.name, stuff.item.name[-1:]) if stuff.isEmpty: return "%s Slot" % FittingSlot(stuff.slot).name.capitalize() else: return stuff.item.name elif isinstance(stuff, Implant): return stuff.item.name else: item = getattr(stuff, "item", stuff) if FitSvc.getInstance().serviceFittingOptions["showMarketShortcuts"]: marketShortcut = getattr(item, "marketShortcut", None) if marketShortcut: # use unicode subscript to display shortcut value shortcut = chr(marketShortcut + 8320) + " " del item.marketShortcut return shortcut + item.name return item.name
def display(self, srcContext, mainItem): if not self.settings.get('changeAffectingSkills'): return False if srcContext not in ( "fittingModule", "fittingCharge", "fittingShip", "droneItem", "fighterItem" ): return False fitID = self.mainFrame.getActiveFit() if fitID is None: return False if (mainItem is None or getattr(mainItem, "isEmpty", False)) and srcContext != "fittingShip": return False self.sChar = Character.getInstance() self.sFit = Fit.getInstance() fit = self.sFit.getFit(fitID) self.charID = fit.character.ID # if self.sChar.getCharName(self.charID) in ("All 0", "All 5"): # return False if srcContext == "fittingShip": sFit = Fit.getInstance() self.stuff = sFit.getFit(fitID).ship cont = sFit.getFit(fitID).ship.itemModifiedAttributes elif srcContext == "fittingCharge": cont = mainItem.chargeModifiedAttributes else: cont = mainItem.itemModifiedAttributes skills = set() for attrName in cont.iterAfflictions(): if cont[attrName] == 0: continue for fit, afflictors in cont.getAfflictions(attrName).items(): for afflictor, modifier, amount, used in afflictors: # only add Skills if not isinstance(afflictor, Skill): continue skills.add(afflictor) self.skills = sorted(skills, key=lambda x: x.item.name) return len(self.skills) > 0
def getText(self, stuff): if isinstance(stuff, Drone): return "%dx %s" % (stuff.amount, stuff.item.name) elif isinstance(stuff, Fighter): return "%d/%d %s" % \ (stuff.amountActive, stuff.getModifiedItemAttr("fighterSquadronMaxSize"), stuff.item.name) elif isinstance(stuff, Cargo): return "%dx %s" % (stuff.amount, stuff.item.name) elif isinstance(stuff, Fit): if self.projectedView: # we need a little more information for the projected view fitID = self.mainFrame.getActiveFit() info = stuff.getProjectionInfo(fitID) if info: return "%dx %s (%s)" % (stuff.getProjectionInfo(fitID).amount, stuff.name, stuff.ship.item.name) pyfalog.warning("Projected View trying to display things that aren't there. stuff: {}, info: {}", repr(stuff), info) return "<unknown>" else: return "%s (%s)" % (stuff.name, stuff.ship.item.name) elif isinstance(stuff, Rack): if FitSvc.getInstance().serviceFittingOptions["rackLabels"]: if stuff.slot == Slot.MODE: return u'─ Tactical Mode ─' else: return u'─ {} Slots ─'.format(Slot.getName(stuff.slot).capitalize()) else: return "" elif isinstance(stuff, Module): if stuff.isEmpty: return "%s Slot" % Slot.getName(stuff.slot).capitalize() else: return stuff.item.name elif isinstance(stuff, Implant): return stuff.item.name else: item = getattr(stuff, "item", stuff) if FitSvc.getInstance().serviceFittingOptions["showMarketShortcuts"]: marketShortcut = getattr(item, "marketShortcut", None) if marketShortcut: # use unicode subscript to display shortcut value shortcut = unichr(marketShortcut + 8320) + u" " del item.marketShortcut return shortcut + item.name return item.name
def __init__(self, fitID, position): wx.Command.__init__(self, True, "") self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID self.position = position
def swapItems(self, x, y, srcIdx): """Swap two modules in fitting window""" mstate = wx.GetMouseState() sFit = Fit.getInstance() fit = sFit.getFit(self.activeFitID) dstRow, _ = self.HitTest((x, y)) if dstRow != -1 and dstRow not in self.blanks: mod1 = fit.modules[srcIdx] mod2 = self.mods[dstRow] if not isinstance(mod2, Module): return # can't swap modules to different racks if mod1.slot != mod2.slot: return clone = mstate.CmdDown() and mod2.isEmpty fitID = self.mainFrame.getActiveFit() if getattr(mod2, "modPosition") is not None: self.mainFrame.command.Submit(cmd.GuiModuleSwapOrCloneCommand(fitID, srcIdx, mod2.modPosition, clone)) else: pyfalog.error("Missing module position for: {0}", str(getattr(mod2, "ID", "Unknown")))
def run(self): # wait 1 second just in case a lot of modifications get made time.sleep(1) if self.stopRunning: return sMkt = Market.getInstance() sFit = Fit.getInstance() settings = HTMLExportSettings.getInstance() minimal = settings.getMinimalEnabled() dnaUrl = "https://o.smium.org/loadout/dna/" if minimal: HTML = self.generateMinimalHTML(sMkt, sFit, dnaUrl) else: HTML = self.generateFullHTML(sMkt, sFit, dnaUrl) try: FILE = open(settings.getPath(), "w", encoding='utf-8') FILE.write(HTML) FILE.close() except IOError as ex: print(("Failed to write to " + settings.getPath())) pass except Exception as ex: pass if self.callback: wx.CallAfter(self.callback, -1)
def fitSelected(self, event): count = -1 # @todo pheonix: _pages is supposed to be private? for index, page in enumerate(self.multiSwitch._pages): if not isinstance(page, gui.builtinViews.emptyView.BlankPage): # Don't try and process it if it's a blank page. try: if page.activeFitID == event.fitID: count += 1 self.multiSwitch.SetSelection(index) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=event.fitID)) break except Exception as e: pyfalog.critical("Caught exception in fitSelected") pyfalog.critical(e) if count < 0: startup = getattr(event, "startup", False) # see OpenFitsThread in gui.mainFrame from_import = getattr(event, "from_import", False) # always open imported into a new tab sFit = Fit.getInstance() openFitInNew = sFit.serviceFittingOptions["openFitInNew"] mstate = wx.GetMouseState() if from_import or (not openFitInNew and mstate.CmdDown()) or startup or (openFitInNew and not mstate.CmdDown()): self.multiSwitch.AddPage() view = self.multiSwitch.GetSelectedPage() if not isinstance(view, FittingView): view = FittingView(self.multiSwitch) pyfalog.debug("###################### Created new view:" + repr(view)) self.multiSwitch.ReplaceActivePage(view) view.fitSelected(event)
def fitRemoved(self, event): """ If fit is removed and active, the page is deleted. We also refresh the fit of the new current page in case delete fit caused change in stats (projected) todo: move this to the notebook, not the page. We don't want the page being responsible for deleting itself """ pyfalog.debug("FittingView::fitRemoved") if not self: event.Skip() return if event.fitID == self.getActiveFit(): pyfalog.debug(" Deleted fit is currently active") self.parent.DeletePage(self.parent.GetPageIndex(self)) try: # Sometimes there is no active page after deletion, hence the try block sFit = Fit.getInstance() # stopgap for #1384 fit = sFit.getFit(self.getActiveFit()) if fit: sFit.refreshFit(self.getActiveFit()) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.activeFitID)) except RuntimeError: pyfalog.warning("Caught dead object") pass event.Skip()
def appendItem(self, event): """ Adds items that are double clicks from the market browser. We handle both modules and ammo """ if not self: event.Skip() return if self.parent.IsActive(self): itemID = event.itemID fitID = self.activeFitID if fitID is not None: sFit = Fit.getInstance() if sFit.isAmmo(itemID): # If we've selected ammo, then apply to the selected module(s) modules = [] sel = self.GetFirstSelected() while sel != -1 and sel not in self.blanks: mod = self.mods[self.GetItemData(sel)] if isinstance(mod, Module) and not mod.isEmpty: modules.append(self.mods[self.GetItemData(sel)]) sel = self.GetNextSelected(sel) if len(modules) > 0: self.mainFrame.command.Submit(cmd.GuiModuleAddChargeCommand(fitID, itemID, modules)) else: self.mainFrame.command.Submit(cmd.GuiModuleAddCommand(fitID, itemID)) event.Skip()
def spawnMenu(self): sel = self.GetFirstSelected() menu = None sFit = Fit.getInstance() fit = sFit.getFit(self.mainFrame.getActiveFit()) if not fit: return if sel != -1: implant = fit.appliedImplants[sel] sMkt = Market.getInstance() sourceContext = "implantItem" if fit.implantSource == ImplantLocation.FIT else "implantItemChar" itemContext = sMkt.getCategoryByItem(implant.item).name menu = ContextMenu.getMenu((implant,), (sourceContext, itemContext)) elif sel == -1 and fit.implantSource == ImplantLocation.FIT: fitID = self.mainFrame.getActiveFit() if fitID is None: return context = (("implantView",),) menu = ContextMenu.getMenu([], *context) if menu is not None: self.PopupMenu(menu)
def Do(self): pyfalog.debug('Doing removal of booster from position {} on fit {}'.format(self.position, self.fitID)) fit = Fit.getInstance().getFit(self.fitID) booster = fit.boosters[self.position] self.savedBoosterInfo = BoosterInfo.fromBooster(booster) fit.boosters.remove(booster) return True
def getText(self, itmContext, selection): sDP = import_DamagePattern.getInstance() sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() self.fit = sFit.getFit(fitID) self.patterns = sDP.getDamagePatternList() self.patterns.sort(key=lambda p: (p.name not in ["Uniform", "Selected Ammo"], p.name)) self.patternIds = {} self.subMenus = OrderedDict() self.singles = [] # iterate and separate damage patterns based on "[Parent] Child" for pattern in self.patterns: start, end = pattern.name.find('['), pattern.name.find(']') if start is not -1 and end is not -1: currBase = pattern.name[start + 1:end] # set helper attr setattr(pattern, "_name", pattern.name[end + 1:].strip()) if currBase not in self.subMenus: self.subMenus[currBase] = [] self.subMenus[currBase].append(pattern) else: self.singles.append(pattern) # return list of names, with singles first followed by submenu names self.m = map(lambda p: p.name, self.singles) + self.subMenus.keys() return self.m
def fitChanged(self, event): sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) self.Parent.Parent.Parent.DisablePage(self.Parent, not fit or fit.isStructure) # 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 self.original = fit.implants if fit is not None else None self.implants = stuff = fit.appliedImplants if fit is not None else None if stuff is not None: stuff.sort(key=lambda implant: implant.slot) 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 fitChanged(self, event): sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) self.Parent.Parent.Parent.DisablePage(self.Parent, not fit) # 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 self.original = fit.fighters if fit is not None else None self.fighters = fit.fighters[:] if fit is not None else None if self.fighters is not None: self.fighters.sort(key=self.fighterKey) 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(self.fighters) event.Skip()
def fitChanged(self, event): sFit = Fit.getInstance() activeFitID = self.mainFrame.getActiveFit() fit = sFit.getFit(activeFitID) if fit: for x in self.labels: if fit.isStructure: slot = getattr(FittingSlot, "FS_{}".format(x.upper())) else: slot = getattr(FittingSlot, "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() event.Skip()
def refreshCharacterList(self, event=None): choice = self.charChoice sChar = Character.getInstance() activeChar = self.getActiveCharacter() choice.Clear() charList = sorted(sChar.getCharacterList(), key=lambda c: (not c.ro, c.name)) picked = False for char in charList: currId = choice.Append(char.name, char.ID) if char.ID == activeChar: choice.SetSelection(currId) self.charChanged(None) picked = True if not picked: charID = sChar.all5ID() self.selectChar(charID) fitID = self.mainFrame.getActiveFit() sFit = Fit.getInstance() sFit.changeChar(fitID, charID) choice.Append(u"\u2015 Open Character Editor \u2015", -1) self.charCache = self.charChoice.GetCurrentSelection() if event is not None: event.Skip()
def fitChanged(self, event): enable = event.fitID is not None self.Enable(wx.ID_SAVEAS, enable) self.Enable(wx.ID_COPY, enable) self.Enable(self.exportSkillsNeededId, enable) sChar = Character.getInstance() charID = self.mainFrame.charSelection.getActiveCharacter() char = sChar.getCharacter(charID) # enable/disable character saving stuff self.Enable(self.saveCharId, not char.ro and char.isDirty) self.Enable(self.saveCharAsId, char.isDirty) self.Enable(self.revertCharId, char.isDirty) self.Enable(self.toggleIgnoreRestrictionID, enable) if event.fitID: sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) if fit.ignoreRestrictions: self.ignoreRestrictionItem.SetItemLabel("Enable Fitting Restrictions") else: self.ignoreRestrictionItem.SetItemLabel("Disable Fitting Restrictions") event.Skip()
def swapModule(self, x, y, modIdx): """Swap a module from fitting window with cargo""" sFit = Fit.getInstance() fit = sFit.getFit(self.mainFrame.getActiveFit()) dstRow, _ = self.HitTest((x, y)) mstate = wx.GetMouseState() # Gather module information to get position module = fit.modules[modIdx] if module.item.isAbyssal: dlg = wx.MessageDialog(self, "Moving this Abyssal module to the cargo will convert it to the base module. Do you wish to proceed?", "Confirm", wx.YES_NO | wx.ICON_QUESTION) result = dlg.ShowModal() == wx.ID_YES if not result: return cargoPos = dstRow if dstRow > -1 else None self.mainFrame.command.Submit(cmd.GuiModuleToCargoCommand( self.mainFrame.getActiveFit(), module.modPosition, cargoPos, mstate.cmdDown ))
def fitChanged(self, event): sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) # self.Parent.Parent.DisablePage(self, not fit or fit.isStructure) # 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 self.original = fit.cargo if fit is not None else None self.cargo = stuff = fit.cargo if fit is not None else None if stuff is not None: stuff.sort(key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name)) 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.populate(stuff) self.refresh(stuff) event.Skip()
def swapItems(self, x, y, srcIdx): """Swap two modules in fitting window""" mstate = wx.GetMouseState() sFit = Fit.getInstance() fit = sFit.getFit(self.activeFitID) if mstate.CmdDown(): clone = True else: clone = False dstRow, _ = self.HitTest((x, y)) if dstRow != -1 and dstRow not in self.blanks: mod1 = fit.modules[srcIdx] mod2 = self.mods[dstRow] if not isinstance(mod2, Module): return # can't swap modules to different racks if mod1.slot != mod2.slot: return if getattr(mod2, "modPosition") is not None: if clone and mod2.isEmpty: sFit.cloneModule(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition) else: sFit.swapModules(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) else: pyfalog.error("Missing module position for: {0}", str(getattr(mod2, "ID", "Unknown")))
def _merge(self, src, dst): dstDrone = self.get(dst) if isinstance(dstDrone, es_Drone): sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() if sFit.mergeDrones(fitID, self.get(src), dstDrone, True): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
def activate(self, fullContext, selection, i): sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() trigger = sFit.project(fitID, selection[0]) if trigger: wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) self.mainFrame.additionsPane.select("Projected")
def exportFitting(self, event): sPort = Port.getInstance() fitID = self.mainFrame.getActiveFit() self.statusbar.SetStatusText("", 0) if fitID is None: self.statusbar.SetStatusText("Please select an active fitting in the main window", 1) return self.statusbar.SetStatusText("Sending request and awaiting response", 1) sCrest = Crest.getInstance() try: sFit = Fit.getInstance() data = sPort.exportCrest(sFit.getFit(fitID)) res = sCrest.postFitting(self.getActiveCharacter(), data) self.statusbar.SetStatusText("%d: %s" % (res.status_code, res.reason), 0) try: text = json.loads(res.text) self.statusbar.SetStatusText(text['message'], 1) except ValueError: self.statusbar.SetStatusText("", 1) except requests.exceptions.ConnectionError: self.statusbar.SetStatusText("Connection error, please check your internet connection", 1)
def appendItem(self, event): if self.parent.IsActive(self): itemID = event.itemID fitID = self.activeFitID if fitID is not None: sFit = Fit.getInstance() if sFit.isAmmo(itemID): modules = [] sel = self.GetFirstSelected() while sel != -1 and sel not in self.blanks: mod = self.mods[self.GetItemData(sel)] if isinstance(mod, Module) and not mod.isEmpty: modules.append(self.mods[self.GetItemData(sel)]) sel = self.GetNextSelected(sel) if len(modules) > 0: sFit.setAmmo(fitID, itemID, modules) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) else: populate = sFit.appendModule(fitID, itemID) if populate is not None: self.slotsChanged() wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID, action="modadd", typeID=itemID)) event.Skip()
def __init__(self, fitID, itemID): wx.Command.__init__(self, True, "Module Charge Add") self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID self.itemID = itemID
def fitChanged(self, event): sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) self.Parent.Parent.DisablePage(self, not fit or fit.isStructure) # 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 self.origional = fit.boosters if fit is not None else None self.boosters = stuff = fit.boosters[:] if fit is not None else None 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.populate(stuff) self.refresh(stuff) event.Skip()
def copyFit(self, event=None): sFit = Fit.getInstance() fitID = sFit.copyFit(self.fitID) self.shipBrowser.fitIDMustEditName = fitID wx.PostEvent(self.shipBrowser, Stage3Selected(shipID=self.shipID)) wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID))
def getText(self, stuff): if isinstance(stuff, BaseWrapper): stuff = stuff.item if isinstance(stuff, Drone): return "%dx %s" % (stuff.amount, stuff.item.name) elif isinstance(stuff, Fighter): return "%d/%d %s" % \ (stuff.amountActive, stuff.getModifiedItemAttr("fighterSquadronMaxSize"), stuff.item.name) elif isinstance(stuff, Cargo): return "%dx %s" % (stuff.amount, stuff.item.name) elif isinstance(stuff, Fit): if self.projectedView: # we need a little more information for the projected view fitID = self.mainFrame.getActiveFit() info = stuff.getProjectionInfo(fitID) if info: return "%dx %s (%s)" % (stuff.getProjectionInfo( fitID).amount, stuff.name, stuff.ship.item.name) pyfalog.warning( "Projected View trying to display things that aren't there. stuff: {}, info: {}", repr(stuff), info) return "<unknown>" else: return "%s (%s)" % (stuff.name, stuff.ship.item.name) elif isinstance(stuff, FitLite): return "{} ({})".format(stuff.name, stuff.shipName) elif isinstance(stuff, Rack): if FitSvc.getInstance().serviceFittingOptions["rackLabels"]: if stuff.slot == FittingSlot.MODE: return '─ Tactical Mode ─' else: return '─ {} {} Slot{}─'.format( stuff.num, FittingSlot(stuff.slot).name.capitalize(), '' if stuff.num == 1 else 's') else: return "" elif isinstance(stuff, Module): if self.projectedView: # check for projected abyssal name name_check = stuff.item.name[0:-2] type = AddEnvironmentEffect.abyssal_mapping.get( name_check, None) if type: sMkt = Market.getInstance() type = sMkt.getItem(type) return "{} {}".format(type.name, stuff.item.name[-1:]) if stuff.isEmpty: return "%s Slot" % FittingSlot(stuff.slot).name.capitalize() else: return stuff.item.name elif isinstance(stuff, Implant): return stuff.item.name elif isinstance(stuff, TargetProfile): return stuff.name else: item = getattr(stuff, "item", stuff) if FitSvc.getInstance( ).serviceFittingOptions["showMarketShortcuts"]: marketShortcut = getattr(item, "marketShortcut", None) if marketShortcut: # use unicode subscript to display shortcut value shortcut = chr(marketShortcut + 8320) + " " del item.marketShortcut return shortcut + item.name return item.name
def removeDrone(self, drone): fitID = self.mainFrame.getActiveFit() sFit = Fit.getInstance() sFit.removeDrone(fitID, self.original.index(drone)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
def activate(self, callingWindow, fullContext, i): fitID = self.mainFrame.getActiveFit() ship = Fit.getInstance().getFit(fitID).ship self.mainFrame.notebookBrowsers.SetSelection(1) wx.PostEvent(self.mainFrame.shipBrowser, Stage3Selected(shipID=ship.item.ID, back=True))
def MakeSnapshot(self, maxColumns=1337): if self.FVsnapshot: self.FVsnapshot = None tbmp = wx.Bitmap(16, 16) tdc = wx.MemoryDC() tdc.SelectObject(tbmp) tdc.SetFont(self.font) columnsWidths = [] for i in range(len(self.DEFAULT_COLS)): columnsWidths.append(0) sFit = Fit.getInstance() try: fit = sFit.getFit(self.activeFitID) except (KeyboardInterrupt, SystemExit): raise except Exception as e: pyfalog.critical("Failed to get fit") pyfalog.critical(e) return if fit is None: return slotMap = {} for slot in [e.value for e in FittingSlot]: slotMap[slot] = fit.getSlotsFree(slot) < 0 padding = 2 isize = 16 headerSize = max(isize, tdc.GetTextExtent("W")[0]) + padding * 2 maxRowHeight = isize rows = 0 for st in self.mods: for i, col in enumerate(self.activeColumns): if i > maxColumns: break name = col.getText(st) if not isinstance(name, str): name = "" nx, ny = tdc.GetTextExtent(name) imgId = col.getImageId(st) cw = 0 if imgId != -1: cw += isize + padding if name != "": cw += nx + 4 * padding if imgId == -1 and name == "": cw += isize + padding maxRowHeight = max(ny, maxRowHeight) columnsWidths[i] = max(columnsWidths[i], cw) rows += 1 render = wx.RendererNative.Get() # Fix column widths (use biggest between header or items) for i, col in enumerate(self.activeColumns): if i > maxColumns: break name = col.columnText imgId = col.imageId if not isinstance(name, str): name = "" opts = wx.HeaderButtonParams() if name != "": opts.m_labelText = name if imgId != -1: opts.m_labelBitmap = wx.Bitmap(isize, isize) width = render.DrawHeaderButton(self, tdc, (0, 0, 16, 16), sortArrow=wx.HDR_SORT_ICON_NONE, params=opts) columnsWidths[i] = max(columnsWidths[i], width) tdc.SelectObject(wx.NullBitmap) maxWidth = padding * 2 for i in range(len(self.DEFAULT_COLS)): if i > maxColumns: break maxWidth += columnsWidths[i] mdc = wx.MemoryDC() mbmp = wx.Bitmap(maxWidth, maxRowHeight * rows + padding * 4 + headerSize) mdc.SelectObject(mbmp) mdc.SetBackground(wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW))) mdc.Clear() mdc.SetFont(self.font) mdc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) cx = padding for i, col in enumerate(self.activeColumns): if i > maxColumns: break name = col.columnText imgId = col.imageId if not isinstance(name, str): name = "" opts = wx.HeaderButtonParams() opts.m_labelAlignment = wx.ALIGN_LEFT if name != "": opts.m_labelText = name if imgId != -1: bmp = col.bitmap opts.m_labelBitmap = bmp render.DrawHeaderButton(self, mdc, (cx, padding, columnsWidths[i], headerSize), wx.CONTROL_CURRENT, sortArrow=wx.HDR_SORT_ICON_NONE, params=opts) cx += columnsWidths[i] brush = wx.Brush(wx.Colour(224, 51, 51)) pen = wx.Pen(wx.Colour(224, 51, 51)) mdc.SetPen(pen) mdc.SetBrush(brush) cy = padding * 2 + headerSize for st in self.mods: cx = padding if slotMap[st.slot]: mdc.DrawRectangle(cx, cy, maxWidth - cx, maxRowHeight) for i, col in enumerate(self.activeColumns): if i > maxColumns: break name = col.getText(st) if not isinstance(name, str): name = "" imgId = col.getImageId(st) tcx = cx if imgId != -1: self.imageList.Draw(imgId, mdc, cx, cy, wx.IMAGELIST_DRAW_TRANSPARENT, False) tcx += isize + padding if name != "": nx, ny = mdc.GetTextExtent(name) rect = wx.Rect() rect.top = cy rect.left = cx + 2 * padding rect.width = nx rect.height = maxRowHeight + padding mdc.DrawLabel(name, rect, wx.ALIGN_CENTER_VERTICAL) tcx += nx + padding cx += columnsWidths[i] cy += maxRowHeight mdc.SelectObject(wx.NullBitmap) self.FVsnapshot = mbmp
def getWeaponBonusMultipliers(fit): def sumDamage(attr): totalDamage = 0 for damageType in [ "emDamage", "thermalDamage", "kineticDamage", "explosiveDamage" ]: if attr(damageType) is not None: totalDamage += attr(damageType) return totalDamage def getCurrentMultipliers(tf): fitMultipliers = {} getDroneMulti = lambda d: sumDamage(d.getModifiedItemAttr ) * d.getModifiedItemAttr( "damageMultiplier") fitMultipliers["drones"] = list(map(getDroneMulti, tf.drones)) getFitTurrets = lambda f: filter( lambda mod: mod.hardpoint == Hardpoint.TURRET, f.modules) getTurretMulti = lambda mod: mod.getModifiedItemAttr( "damageMultiplier") / mod.cycleTime fitMultipliers["turrets"] = list( map(getTurretMulti, getFitTurrets(tf))) getFitLaunchers = lambda f: filter( lambda mod: mod.hardpoint == Hardpoint.MISSILE, f.modules) getLauncherMulti = lambda mod: sumDamage(mod.getModifiedChargeAttr ) / mod.cycleTime fitMultipliers["launchers"] = list( map(getLauncherMulti, getFitLaunchers(tf))) return fitMultipliers multipliers = {"turret": 1, "launcher": 1, "droneBandwidth": 1} drones = EfsPort.getTestSet("drone") launchers = EfsPort.getTestSet("launcher") turrets = EfsPort.getTestSet("turret") for weaponTypeSet in [turrets, launchers, drones]: for mod in weaponTypeSet: mod.owner = fit turrets = list( filter(lambda mod: mod.getModifiedItemAttr("damageMultiplier"), turrets)) launchers = list( filter(lambda mod: sumDamage(mod.getModifiedChargeAttr), launchers)) # Since the effect modules are fairly opaque a mock test fit is used to test the impact of traits. # standin class used to prevent . notation causing issues when used as an arg class standin(): pass tf = standin() tf.modules = HandledList(turrets + launchers) tf.character = fit.character tf.ship = fit.ship tf.drones = HandledList(drones) tf.fighters = HandledList([]) tf.boosters = HandledList([]) tf.extraAttributes = fit.extraAttributes tf.mode = fit.mode preTraitMultipliers = getCurrentMultipliers(tf) for effect in fit.ship.item.effects.values(): if effect._Effect__effectModule is not None: effect.handler(tf, tf.ship, []) # Factor in mode effects for T3 Destroyers if fit.mode is not None: for effect in fit.mode.item.effects.values(): if effect._Effect__effectModule is not None: effect.handler(tf, fit.mode, []) if fit.ship.item.groupID == getGroup("Strategic Cruiser").ID: subSystems = list( filter(lambda mod: mod.slot == Slot.SUBSYSTEM and mod.item, fit.modules)) for sub in subSystems: for effect in sub.item.effects.values(): if effect._Effect__effectModule is not None: effect.handler(tf, sub, []) postTraitMultipliers = getCurrentMultipliers(tf) getMaxRatio = lambda dictA, dictB, key: max( map(lambda a, b: b / a, dictA[key], dictB[key])) multipliers["turret"] = round( getMaxRatio(preTraitMultipliers, postTraitMultipliers, "turrets"), 6) multipliers["launcher"] = round( getMaxRatio(preTraitMultipliers, postTraitMultipliers, "launchers"), 6) multipliers["droneBandwidth"] = round( getMaxRatio(preTraitMultipliers, postTraitMultipliers, "drones"), 6) Fit.getInstance().recalc(fit) return multipliers
def importDna(string, fitName=None): sMkt = Market.getInstance() ids = list(map(int, re.findall(r'\d+', string))) for id_ in ids: try: try: try: Ship(sMkt.getItem(sMkt.getItem(id_))) except ValueError: Citadel(sMkt.getItem(sMkt.getItem(id_))) except ValueError: Citadel(sMkt.getItem(id_)) string = string[string.index(str(id_)):] break except: pyfalog.warning("Exception caught in importDna") pass string = string[:string.index("::") + 2] info = string.split(":") f = Fit() try: try: f.ship = Ship(sMkt.getItem(int(info[0]))) except ValueError: f.ship = Citadel(sMkt.getItem(int(info[0]))) if fitName is None: f.name = "{0} - DNA Imported".format(f.ship.item.name) else: f.name = fitName except UnicodeEncodeError: def logtransform(s_): if len(s_) > 10: return s_[:10] + "..." return s_ pyfalog.exception("Couldn't import ship data {0}", [logtransform(s) for s in info]) return None moduleList = [] for itemInfo in info[1:]: if itemInfo: itemID, amount = itemInfo.split(";") item = sMkt.getItem(int(itemID), eager="group.category") if item.category.name == "Drone": d = Drone(item) d.amount = int(amount) f.drones.append(d) elif item.category.name == "Fighter": ft = Fighter(item) ft.amount = int( amount ) if ft.amount <= ft.fighterSquadronMaxSize else ft.fighterSquadronMaxSize if ft.fits(f): f.fighters.append(ft) elif item.category.name == "Charge": c = Cargo(item) c.amount = int(amount) f.cargo.append(c) else: for i in range(int(amount)): try: m = Module(item) except: pyfalog.warning("Exception caught in importDna") continue # Add subsystems before modules to make sure T3 cruisers have subsystems installed if item.category.name == "Subsystem": if m.fits(f): f.modules.append(m) else: m.owner = f if m.isValidState(FittingModuleState.ACTIVE): m.state = activeStateLimit(m.item) moduleList.append(m) # Recalc to get slot numbers correct for T3 cruisers sFit = svcFit.getInstance() sFit.recalc(f) sFit.fill(f) for module in moduleList: if module.fits(f): module.owner = f if module.isValidState(FittingModuleState.ACTIVE): module.state = activeStateLimit(module.item) f.modules.append(module) return f
def importEftCfg(shipname, lines, iportuser): """Handle import from EFT config store file""" # Check if we have such ship in database, bail if we don't sMkt = Market.getInstance() try: sMkt.getItem(shipname) except: return [] # empty list is expected fits = [] # List for fits fitIndices = [] # List for starting line numbers for each fit for line in lines: # Detect fit header if line[:1] == "[" and line[-1:] == "]": # Line index where current fit starts startPos = lines.index(line) fitIndices.append(startPos) for i, startPos in enumerate(fitIndices): # End position is last file line if we're trying to get it for last fit, # or start position of next fit minus 1 endPos = len(lines) if i == len(fitIndices) - 1 else fitIndices[i + 1] # Finally, get lines for current fitting fitLines = lines[startPos:endPos] try: # Create fit object fitobj = Fit() # Strip square brackets and pull out a fit name fitobj.name = fitLines[0][1:-1] # Assign ship to fitting try: fitobj.ship = Ship(sMkt.getItem(shipname)) except ValueError: fitobj.ship = Citadel(sMkt.getItem(shipname)) moduleList = [] for x in range(1, len(fitLines)): line = fitLines[x] if not line: continue # Parse line into some data we will need misc = re.match( "(Drones|Implant|Booster)_(Active|Inactive)=(.+)", line) cargo = re.match("Cargohold=(.+)", line) # 2017/03/27 NOTE: store description from EFT description = re.match("Description=(.+)", line) if misc: entityType = misc.group(1) entityState = misc.group(2) entityData = misc.group(3) if entityType == "Drones": droneData = re.match("(.+),([0-9]+)", entityData) # Get drone name and attempt to detect drone number droneName = droneData.group( 1) if droneData else entityData droneAmount = int( droneData.group(2)) if droneData else 1 # Bail if we can't get item or it's not from drone category try: droneItem = sMkt.getItem(droneName, eager="group.category") except: pyfalog.warning("Cannot get item.") continue if droneItem.category.name == "Drone": # Add drone to the fitting d = Drone(droneItem) d.amount = droneAmount if entityState == "Active": d.amountActive = droneAmount elif entityState == "Inactive": d.amountActive = 0 fitobj.drones.append(d) elif droneItem.category.name == "Fighter": # EFT saves fighter as drones ft = Fighter(droneItem) ft.amount = int( droneAmount ) if ft.amount <= ft.fighterSquadronMaxSize else ft.fighterSquadronMaxSize fitobj.fighters.append(ft) else: continue elif entityType == "Implant": # Bail if we can't get item or it's not from implant category try: implantItem = sMkt.getItem(entityData, eager="group.category") except: pyfalog.warning("Cannot get item.") continue if implantItem.category.name != "Implant": continue # Add implant to the fitting imp = Implant(implantItem) if entityState == "Active": imp.active = True elif entityState == "Inactive": imp.active = False fitobj.implants.append(imp) elif entityType == "Booster": # Bail if we can't get item or it's not from implant category try: boosterItem = sMkt.getItem(entityData, eager="group.category") except: pyfalog.warning("Cannot get item.") continue # All boosters have implant category if boosterItem.category.name != "Implant": continue # Add booster to the fitting b = Booster(boosterItem) if entityState == "Active": b.active = True elif entityState == "Inactive": b.active = False fitobj.boosters.append(b) # If we don't have any prefixes, then it's a module elif cargo: cargoData = re.match("(.+),([0-9]+)", cargo.group(1)) cargoName = cargoData.group( 1) if cargoData else cargo.group(1) cargoAmount = int(cargoData.group(2)) if cargoData else 1 # Bail if we can't get item try: item = sMkt.getItem(cargoName) except: pyfalog.warning("Cannot get item.") continue # Add Cargo to the fitting c = Cargo(item) c.amount = cargoAmount fitobj.cargo.append(c) # 2017/03/27 NOTE: store description from EFT elif description: fitobj.notes = description.group(1).replace("|", "\n") else: withCharge = re.match("(.+),(.+)", line) modName = withCharge.group(1) if withCharge else line chargeName = withCharge.group(2) if withCharge else None # If we can't get module item, skip it try: modItem = sMkt.getItem(modName) except: pyfalog.warning("Cannot get item.") continue # Create module m = Module(modItem) # Add subsystems before modules to make sure T3 cruisers have subsystems installed if modItem.category.name == "Subsystem": if m.fits(fitobj): fitobj.modules.append(m) else: m.owner = fitobj # Activate mod if it is activable if m.isValidState(FittingModuleState.ACTIVE): m.state = activeStateLimit(m.item) # Add charge to mod if applicable, on any errors just don't add anything if chargeName: try: chargeItem = sMkt.getItem( chargeName, eager="group.category") if chargeItem.category.name == "Charge": m.charge = chargeItem except: pyfalog.warning("Cannot get item.") pass # Append module to fit moduleList.append(m) # Recalc to get slot numbers correct for T3 cruisers sFit = svcFit.getInstance() sFit.recalc(fitobj) sFit.fill(fitobj) for module in moduleList: if module.fits(fitobj): fitobj.modules.append(module) # Append fit to list of fits fits.append(fitobj) if iportuser: # NOTE: Send current processing status processing_notify( iportuser, IPortUser.PROCESS_IMPORT | IPortUser.ID_UPDATE, "%s:\n%s" % (fitobj.ship.name, fitobj.name)) # Skip fit silently if we get an exception except Exception as e: pyfalog.error("Caught exception on fit.") pyfalog.error(e) pass return fits
def importEft(lines): lines = _importPrepare(lines) try: fit = _importCreateFit(lines) except EftImportError: return aFit = AbstractFit() aFit.mutations = _importGetMutationData(lines) stubPattern = '^\[.+?\]$' modulePattern = '^(?P<typeName>{0}+?)(,\s*(?P<chargeName>{0}+?))?(?P<offline>\s*{1})?(\s*\[(?P<mutation>\d+?)\])?$'.format( NAME_CHARS, OFFLINE_SUFFIX) droneCargoPattern = '^(?P<typeName>{}+?) x(?P<amount>\d+?)$'.format( NAME_CHARS) sections = [] for section in _importSectionIter(lines): for line in section.lines: # Stub line if re.match(stubPattern, line): section.itemSpecs.append(None) continue # Items with quantity specifier m = re.match(droneCargoPattern, line) if m: try: itemSpec = MultiItemSpec(m.group('typeName')) # Items which cannot be fetched are considered as stubs except EftImportError: section.itemSpecs.append(None) else: itemSpec.amount = int(m.group('amount')) section.itemSpecs.append(itemSpec) continue # All other items m = re.match(modulePattern, line) if m: try: itemSpec = RegularItemSpec( m.group('typeName'), chargeName=m.group('chargeName')) # Items which cannot be fetched are considered as stubs except EftImportError: section.itemSpecs.append(None) else: if m.group('offline'): itemSpec.offline = True if m.group('mutation'): itemSpec.mutationIdx = int(m.group('mutation')) section.itemSpecs.append(itemSpec) continue _clearTail(section.itemSpecs) sections.append(section) hasDroneBay = any(s.isDroneBay for s in sections) hasFighterBay = any(s.isFighterBay for s in sections) for section in sections: if section.isModuleRack: aFit.addModules(section.itemSpecs) elif section.isImplantRack: for itemSpec in section.itemSpecs: aFit.addImplant(itemSpec) elif section.isDroneBay: for itemSpec in section.itemSpecs: aFit.addDrone(itemSpec) elif section.isFighterBay: for itemSpec in section.itemSpecs: aFit.addFighter(itemSpec) elif section.isCargoHold: for itemSpec in section.itemSpecs: aFit.addCargo(itemSpec) # Mix between different kinds of item specs (can happen when some # blank lines are removed) else: for itemSpec in section.itemSpecs: if itemSpec is None: continue if itemSpec.isModule: aFit.addModule(itemSpec) elif itemSpec.isImplant: aFit.addImplant(itemSpec) elif itemSpec.isDrone and not hasDroneBay: aFit.addDrone(itemSpec) elif itemSpec.isFighter and not hasFighterBay: aFit.addFighter(itemSpec) elif itemSpec.isCargo: aFit.addCargo(itemSpec) # Subsystems first because they modify slot amount for i, m in enumerate(aFit.subsystems): if m is None: dummy = Module.buildEmpty(aFit.getSlotByContainer(aFit.subsystems)) dummy.owner = fit fit.modules.replaceRackPosition(i, dummy) elif m.fits(fit): m.owner = fit fit.modules.replaceRackPosition(i, m) sFit = svcFit.getInstance() sFit.recalc(fit) sFit.fill(fit) # Other stuff for modRack in ( aFit.rigs, aFit.services, aFit.modulesHigh, aFit.modulesMed, aFit.modulesLow, ): for i, m in enumerate(modRack): if m is None: dummy = Module.buildEmpty(aFit.getSlotByContainer(modRack)) dummy.owner = fit fit.modules.replaceRackPosition(i, dummy) elif m.fits(fit): m.owner = fit if not m.isValidState(m.state): pyfalog.warning( 'service.port.eft.importEft: module {} cannot have state {}', m, m.state) fit.modules.replaceRackPosition(i, m) for implant in aFit.implants: fit.implants.append(implant) for booster in aFit.boosters: fit.boosters.append(booster) for drone in aFit.drones.values(): fit.drones.append(drone) for fighter in aFit.fighters: fit.fighters.append(fighter) for cargo in aFit.cargo.values(): fit.cargo.append(cargo) return fit
def __init__(self, parent): wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=u"pyfa: Character Editor", pos=wx.DefaultPosition, size=wx.Size(640, 600), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER) i = wx.IconFromBitmap(BitmapLoader.getBitmap("character_small", "gui")) self.SetIcon(i) self.mainFrame = parent # self.disableWin = wx.WindowDisabler(self) sFit = Fit.getInstance() self.SetBackgroundColour( wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)) mainSizer = wx.BoxSizer(wx.VERTICAL) self.entityEditor = CharacterEntityEditor(self) mainSizer.Add(self.entityEditor, 0, wx.ALL | wx.EXPAND, 2) # Default drop down to current fit's character self.entityEditor.setActiveEntity(sFit.character) self.viewsNBContainer = wx.Notebook(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0) self.sview = SkillTreeView(self.viewsNBContainer) self.iview = ImplantEditorView(self.viewsNBContainer) self.aview = APIView(self.viewsNBContainer) self.viewsNBContainer.AddPage(self.sview, "Skills") self.viewsNBContainer.AddPage(self.iview, "Implants") self.viewsNBContainer.AddPage(self.aview, "API") mainSizer.Add(self.viewsNBContainer, 1, wx.EXPAND | wx.ALL, 5) bSizerButtons = wx.BoxSizer(wx.HORIZONTAL) self.btnSaveChar = wx.Button(self, wx.ID_ANY, "Save") self.btnSaveAs = wx.Button(self, wx.ID_ANY, "Save As...") self.btnRevert = wx.Button(self, wx.ID_ANY, "Revert") self.btnOK = wx.Button(self, wx.ID_OK) bSizerButtons.Add(self.btnSaveChar, 0, wx.ALL, 5) bSizerButtons.Add(self.btnSaveAs, 0, wx.ALL, 5) bSizerButtons.Add(self.btnRevert, 0, wx.ALL, 5) bSizerButtons.AddStretchSpacer() bSizerButtons.Add(self.btnOK, 0, wx.ALL, 5) self.btnSaveChar.Bind(wx.EVT_BUTTON, self.saveChar) self.btnSaveAs.Bind(wx.EVT_BUTTON, self.saveCharAs) self.btnRevert.Bind(wx.EVT_BUTTON, self.revertChar) self.btnOK.Bind(wx.EVT_BUTTON, self.editingFinished) mainSizer.Add(bSizerButtons, 0, wx.EXPAND, 5) self.btnRestrict() self.SetSizer(mainSizer) self.Layout() self.Centre(wx.BOTH) self.Bind(wx.EVT_CLOSE, self.closeEvent) self.Bind(GE.CHAR_LIST_UPDATED, self.refreshCharacterList) self.entityEditor.Bind(wx.EVT_CHOICE, self.charChanged) self.charChanged(None)
def searchStage(self, event): self.lpane.ShowLoading(False) self.navpanel.ShowNewFitButton(False) self.navpanel.ShowSwitchEmptyGroupsButton(False) if not event.back: if self._activeStage != 4: if len(self.browseHist) > 0: self.browseHist.append((self._activeStage, self.lastdata)) else: self.browseHist.append((1, 0)) self._lastStage = self._activeStage self._activeStage = 4 sMkt = Market.getInstance() sFit = Fit.getInstance() query = event.text self.lpane.Freeze() self.lpane.RemoveAllChildren() if query: ships = sMkt.searchShips(query) fitList = sFit.searchFits(query) for ship in ships: shipTrait = ship.traits.traitText if ( ship.traits is not None) else "" # empty string if no traits self.lpane.AddWidget( ShipItem(self.lpane, ship.ID, (ship.name, shipTrait, len(sFit.getFitsWithShip(ship.ID))), ship.race, ship.graphicID)) for ID, name, shipID, shipName, booster, timestamp, notes in fitList: ship = sMkt.getItem(shipID) if not sMkt.getPublicityByItem(ship): continue shipTrait = ship.traits.traitText if ( ship.traits is not None) else "" # empty string if no traits self.lpane.AddWidget( FitItem( self.lpane, ID, (shipName, shipTrait, name, booster, timestamp, notes), shipID, graphicID=ship.graphicID)) if len(ships) == 0 and len(fitList) == 0: self.lpane.AddWidget( PFStaticText(self.lpane, label="No matching results.")) self.lpane.RefreshList(doFocus=False) self.lpane.Thaw() self.raceselect.RebuildRaces(self.RACE_ORDER) if self.showRacesFilterInStage2Only: self.raceselect.Show(False) self.Layout()
def Undo(self): success = self.internalHistory.undoAll() Fit.getInstance().recalc(self.fitID) wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), GE.FitChanged(fitID=self.fitID)) return success
def stage2Callback(self, data): if self.GetActiveStage() != 2: return self.navpanel.ToggleRecentShips(False, False) categoryID = self._stage2Data ships = list(data[1]) sFit = Fit.getInstance() ships.sort(key=self.raceNameKey) racesList = [] subRacesFilter = {} t_fits = 0 # total number of fits in this category for ship in ships: if ship.race: if ship.race not in racesList: racesList.append(ship.race) for race, state in self.racesFilter.items(): if race in racesList: subRacesFilter[race] = self.racesFilter[race] override = True for race, state in subRacesFilter.items(): if state: override = False break for ship in ships: fits = sFit.countFitsWithShip(ship.ID) t_fits += fits filter_ = subRacesFilter[ship.race] if ship.race else True if override: filter_ = True shipTrait = ship.traits.traitText if ( ship.traits is not None) else "" # empty string if no traits if self.filterShipsWithNoFits: if fits > 0: if filter_: self.lpane.AddWidget( ShipItem(self.lpane, ship.ID, (ship.name, shipTrait, fits), ship.race, ship.graphicID)) else: if filter_: self.lpane.AddWidget( ShipItem(self.lpane, ship.ID, (ship.name, shipTrait, fits), ship.race, ship.graphicID)) self.raceselect.RebuildRaces(racesList) # refresh category cache if t_fits == 0: self.categoryFitCache[categoryID] = False else: self.categoryFitCache[categoryID] = True self.lpane.ShowLoading(False) self.lpane.RefreshList() if self.showRacesFilterInStage2Only: self.raceselect.Show(True) self.Layout()
def stage3(self, event): self.navpanel.ToggleRecentShips(False, False) self.lpane.ShowLoading(False) # If back is False, do not append to history. This could be us calling # the stage from previous history, creating / copying fit, etc. # We also have to use conditional for search stage since it's last data # is kept elsewhere if getattr(event, "back", False): if self._activeStage == 4 and self.navpanel.lastSearch != "": self.browseHist.append((4, self.navpanel.lastSearch)) else: self.browseHist.append((self._activeStage, self.lastdata)) shipID = event.shipID self.lastdata = shipID self._lastStage = self._activeStage self._activeStage = 3 sFit = Fit.getInstance() sMkt = Market.getInstance() ship = sMkt.getItem(shipID) categoryID = ship.group.ID self.lpane.Freeze() self.lpane.RemoveAllChildren() fitList = sFit.getFitsWithShip(shipID) if len(fitList) == 0: stage, data = self.browseHist.pop() self.lpane.Thaw() self.navpanel.gotoStage(stage, data) return self.categoryFitCache[categoryID] = True self.navpanel.ShowNewFitButton(True) self.navpanel.ShowSwitchEmptyGroupsButton(False) if self.showRacesFilterInStage2Only: self.raceselect.Show(False) self.Layout() fitList.sort(key=self.nameKey) shipName = ship.name self._stage3ShipName = shipName self._stage3Data = shipID shipTrait = ship.traits.traitText if ( ship.traits is not None) else "" # empty string if no traits for ID, name, booster, timestamp, notes, graphicID in fitList: self.lpane.AddWidget( FitItem(self.lpane, ID, (shipName, shipTrait, name, booster, timestamp, notes), shipID, graphicID=graphicID)) self.lpane.RefreshList() self.lpane.Thaw() self.raceselect.RebuildRaces(self.RACE_ORDER)
def toggleEffective(self, event): self.effective = event.effective sFit = Fit.getInstance() self.refreshPanel(sFit.getFit(self.mainFrame.getActiveFit())) event.Skip()
def fetchPrices(cls, prices): """Fetch all prices passed to this method""" # Dictionary for our price objects priceMap = {} # Check all provided price objects, and add invalid ones to dictionary for price in prices: if not price.isValid: priceMap[price.typeID] = price if len(priceMap) == 0: return # Set of items which are still to be requested from this service toRequest = set() # Compose list of items we're going to request for typeID in priceMap: # Get item object item = db.getItem(typeID) # We're not going to request items only with market group, as eve-central # doesn't provide any data for items not on the market if item is not None and item.marketGroupID: toRequest.add(typeID) # Do not waste our time if all items are not on the market if len(toRequest) == 0: return # This will store POST data for eve-central data = [] sFit = Fit.getInstance() # Base request URL baseurl = "https://eve-central.com/api/marketstat" data.append(("usesystem", cls.systemsList[sFit.serviceFittingOptions["priceSystem"]] )) # Use Jita for market for typeID in toRequest: # Add all typeID arguments data.append(("typeid", typeID)) # Attempt to send request and process it try: network = Network.getInstance() data = network.request(baseurl, network.PRICES, data) xml = minidom.parse(data) types = xml.getElementsByTagName("marketstat").item( 0).getElementsByTagName("type") # Cycle through all types we've got from request for type_ in types: # Get data out of each typeID details tree typeID = int(type_.getAttribute("id")) sell = type_.getElementsByTagName("sell").item(0) # If price data wasn't there, set price to zero try: percprice = float( sell.getElementsByTagName("percentile").item( 0).firstChild.data) except (TypeError, ValueError): pyfalog.warning("Failed to get price for: {0}", type_) percprice = 0 # Fill price data priceobj = priceMap[typeID] priceobj.price = percprice priceobj.time = time.time() + VALIDITY priceobj.failed = None # delete price from working dict del priceMap[typeID] # If getting or processing data returned any errors except TimeoutError: # Timeout error deserves special treatment pyfalog.warning("Price fetch timout") for typeID in priceMap.keys(): priceobj = priceMap[typeID] priceobj.time = time.time() + TIMEOUT priceobj.failed = True del priceMap[typeID] except: # all other errors will pass and continue onward to the REREQUEST delay pyfalog.warning("Caught exception in fetchPrices") pass # if we get to this point, then we've got an error. Set to REREQUEST delay for typeID in priceMap.keys(): priceobj = priceMap[typeID] priceobj.time = time.time() + REREQUEST priceobj.failed = True
def __getData(self, stuff): item = stuff.item if item is None: return "", None itemGroup = item.group.name itemCategory = item.category.name if itemGroup == "Ship Modifiers": return "", None elif itemGroup == "Booster": stuff.getModifiedItemAttr("boosterDuration") text = "{0} min".format( formatAmount( stuff.getModifiedItemAttr("boosterDuration") / 1000 / 60, 3, 0, 3)) return text, "Booster Duration" elif itemGroup in ("Super Weapon", "Structure Doomsday Weapon"): doomsday_duration = stuff.getModifiedItemAttr( "doomsdayDamageDuration", 1) doomsday_dottime = stuff.getModifiedItemAttr( "doomsdayDamageCycleTime", 1) func = stuff.getModifiedItemAttr volley = sum( map(lambda attr: (func("%sDamage" % attr) or 0), ("em", "thermal", "kinetic", "explosive"))) volley *= stuff.getModifiedItemAttr("damageMultiplier") or 1 if volley <= 0: text = "" tooltip = "" elif max(doomsday_duration / doomsday_dottime, 1) > 1: text = "{0} dmg over {1} s".format( formatAmount( volley * (doomsday_duration / doomsday_dottime), 3, 0, 3), doomsday_duration / 1000) tooltip = "Raw damage done over time" else: text = "{0} dmg".format( formatAmount( volley * (doomsday_duration / doomsday_dottime), 3, 0, 3)) tooltip = "Raw damage done" return text, tooltip pass elif itemGroup in ("Energy Weapon", "Hybrid Weapon", "Projectile Weapon", "Combat Drone", "Fighter Drone"): trackingSpeed = stuff.getModifiedItemAttr("trackingSpeed") if not trackingSpeed: return "", None text = "{0}".format(formatAmount(trackingSpeed, 3, 0, 3)) tooltip = "Tracking speed" return text, tooltip elif itemGroup == "Precursor Weapon": info = [] trackingSpeed = stuff.getModifiedItemAttr("trackingSpeed") if trackingSpeed: text = "{0}".format(formatAmount(trackingSpeed, 3, 0, 3)) tooltip = "tracking speed" info.append((text, tooltip)) maxBonusDamage = stuff.getModifiedItemAttr( "damageMultiplierBonusMax") bonusDamagePerCycle = stuff.getModifiedItemAttr( "damageMultiplierBonusPerCycle") cycleTime = stuff.getModifiedItemAttr("speed") if maxBonusDamage and bonusDamagePerCycle and cycleTime: cyclesToFullDamage = int(maxBonusDamage / bonusDamagePerCycle) timeToFullDamage = (cycleTime / 1000) * cyclesToFullDamage if cyclesToFullDamage: text = "{0}s".format( formatAmount(timeToFullDamage, 3, 0, 3)) tooltip = "spool-up time" info.append((text, tooltip)) if not info: return "", None text = ' | '.join(i[0] for i in info) tooltip = ' and '.join(i[1] for i in info).capitalize() return text, tooltip elif itemCategory == "Subsystem": slots = ("hi", "med", "low") info = [] for slot in slots: n = int(stuff.getModifiedItemAttr("%sSlotModifier" % slot)) if n > 0: info.append("{0}{1}".format(n, slot[0].upper())) return "+ " + ", ".join(info), "Slot Modifiers" elif itemGroup == "Energy Neutralizer": neutAmount = stuff.getModifiedItemAttr("energyNeutralizerAmount") cycleTime = stuff.cycleTime if not neutAmount or not cycleTime: return "", None capPerSec = float(-neutAmount) * 1000 / cycleTime text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3)) tooltip = "Energy neutralization per second" return text, tooltip elif itemGroup == "Energy Nosferatu": neutAmount = stuff.getModifiedItemAttr("powerTransferAmount") cycleTime = stuff.cycleTime if not neutAmount or not cycleTime: return "", None capPerSec = float(-neutAmount) * 1000 / cycleTime text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3)) tooltip = "Energy neutralization per second" return text, tooltip elif itemGroup == "Salvager": chance = stuff.getModifiedItemAttr("accessDifficultyBonus") if not chance: return "", None text = "{0}%".format(formatAmount(chance, 3, 0, 3)) tooltip = "Item retrieval chance" return text, tooltip elif itemGroup == "Data Miners": strength = stuff.getModifiedItemAttr("virusStrength") coherence = stuff.getModifiedItemAttr("virusCoherence") if not strength or not coherence: return "", None text = "{0} | {1}".format(formatAmount(strength, 3, 0, 3), formatAmount(coherence, 3, 0, 3)) tooltip = "Virus strength and coherence" return text, tooltip elif itemGroup in ("Warp Scrambler", "Warp Core Stabilizer"): scramStr = stuff.getModifiedItemAttr("warpScrambleStrength") if not scramStr: return "", None text = "{0}".format( formatAmount(-scramStr, 3, 0, 3, forceSign=True)) tooltip = "Warp core strength modification" return text, tooltip elif itemGroup in ("Stasis Web", "Stasis Webifying Drone"): speedFactor = stuff.getModifiedItemAttr("speedFactor") if not speedFactor: return "", None text = "{0}%".format(formatAmount(speedFactor, 3, 0, 3)) tooltip = "Speed reduction" return text, tooltip elif itemGroup == "Target Painter": sigRadBonus = stuff.getModifiedItemAttr("signatureRadiusBonus") if not sigRadBonus: return "", None text = "{0}%".format( formatAmount(sigRadBonus, 3, 0, 3, forceSign=True)) tooltip = "Signature radius increase" return text, tooltip elif itemGroup == "Sensor Dampener": lockRangeBonus = stuff.getModifiedItemAttr("maxTargetRangeBonus") scanResBonus = stuff.getModifiedItemAttr("scanResolutionBonus") if lockRangeBonus is None or scanResBonus is None: return "", None display = 0 for bonus in (lockRangeBonus, scanResBonus): if abs(bonus) > abs(display): display = bonus if not display: return "", None text = "{0}%".format(formatAmount(display, 3, 0, 3, forceSign=True)) ttEntries = [] if display == lockRangeBonus: ttEntries.append("lock range") if display == scanResBonus: ttEntries.append("scan resolution") tooltip = "{0} dampening".format( formatList(ttEntries)).capitalize() return text, tooltip elif itemGroup == "Weapon Disruptor": # Weapon disruption now covers both tracking and guidance (missile) disruptors # First get the attributes for tracking disruptors optimalRangeBonus = stuff.getModifiedItemAttr("maxRangeBonus") falloffRangeBonus = stuff.getModifiedItemAttr("falloffBonus") trackingSpeedBonus = stuff.getModifiedItemAttr( "trackingSpeedBonus") trackingDisruptorAttributes = { "optimal range": optimalRangeBonus, "falloff range": falloffRangeBonus, "tracking speed": trackingSpeedBonus } isTrackingDisruptor = any([ x is not None and x != 0 for x in list(trackingDisruptorAttributes.values()) ]) # Then get the attributes for guidance disruptors explosionVelocityBonus = stuff.getModifiedItemAttr( "aoeVelocityBonus") explosionRadiusBonus = stuff.getModifiedItemAttr( "aoeCloudSizeBonus") flightTimeBonus = stuff.getModifiedItemAttr("explosionDelayBonus") missileVelocityBonus = stuff.getModifiedItemAttr( "missileVelocityBonus") guidanceDisruptorAttributes = { "explosion velocity": explosionVelocityBonus, "explosion radius": explosionRadiusBonus, "flight time": flightTimeBonus, "missile velocity": missileVelocityBonus } isGuidanceDisruptor = any([ x is not None and x != 0 for x in list(guidanceDisruptorAttributes.values()) ]) if isTrackingDisruptor: attributes = trackingDisruptorAttributes elif isGuidanceDisruptor: attributes = guidanceDisruptorAttributes else: return "", None display = max(list(attributes.values()), key=lambda x: abs(x)) text = "{0}%".format(formatAmount(display, 3, 0, 3, forceSign=True)) ttEntries = [] for attributeName, attributeValue in list(attributes.items()): if attributeValue == display: ttEntries.append(attributeName) tooltip = "{0} disruption".format( formatList(ttEntries)).capitalize() return text, tooltip elif itemGroup in ("ECM", "Burst Jammer", "Burst Projectors"): grav = stuff.getModifiedItemAttr("scanGravimetricStrengthBonus") ladar = stuff.getModifiedItemAttr("scanLadarStrengthBonus") radar = stuff.getModifiedItemAttr("scanRadarStrengthBonus") magnet = stuff.getModifiedItemAttr( "scanMagnetometricStrengthBonus") displayMax = max(grav, ladar, radar, magnet) displayMin = min(grav, ladar, radar, magnet) if grav is None or ladar is None or radar is None or magnet is None or displayMax is None: return "", None if displayMax == displayMin or displayMin is None: text = "{0}".format(formatAmount(displayMax, 3, 0, 3), ) else: text = "{0} | {1}".format( formatAmount(displayMax, 3, 0, 3), formatAmount(displayMin, 3, 0, 3), ) tooltip = "ECM Jammer Strength:\n{0} Gravimetric | {1} Ladar | {2} Magnetometric | {3} Radar".format( formatAmount(grav, 3, 0, 3), formatAmount(ladar, 3, 0, 3), formatAmount(magnet, 3, 0, 3), formatAmount(radar, 3, 0, 3), ) return text, tooltip elif itemGroup in ("Remote Sensor Booster", "Sensor Booster", "Signal Amplifier"): scanResBonus = stuff.getModifiedItemAttr("scanResolutionBonus") lockRangeBonus = stuff.getModifiedItemAttr("maxTargetRangeBonus") gravBonus = stuff.getModifiedItemAttr( "scanGravimetricStrengthPercent") if scanResBonus is None or lockRangeBonus is None or gravBonus is None: return "", None text = "{0}% | {1}% | {2}%".format( formatAmount(scanResBonus, 3, 0, 3), formatAmount(lockRangeBonus, 3, 0, 3), formatAmount(gravBonus, 3, 0, 3), ) tooltip = "Applied bonuses:\n{0}% scan resolution | {1}% lock range | {2}% sensor strength".format( formatAmount(scanResBonus, 3, 0, 3), formatAmount(lockRangeBonus, 3, 0, 3), formatAmount(gravBonus, 3, 0, 3), ) return text, tooltip elif itemGroup in ("Projected ECCM", "ECCM", "Sensor Backup Array"): grav = stuff.getModifiedItemAttr("scanGravimetricStrengthPercent") ladar = stuff.getModifiedItemAttr("scanLadarStrengthPercent") radar = stuff.getModifiedItemAttr("scanRadarStrengthPercent") magnet = stuff.getModifiedItemAttr( "scanMagnetometricStrengthPercent") if grav is None or ladar is None or radar is None or magnet is None: return "", None display = max(grav, ladar, radar, magnet) if not display: return "", None text = "{0}%".format(formatAmount(display, 3, 0, 3, forceSign=True)) ttEntries = [] if display == grav: ttEntries.append("gravimetric") if display == ladar: ttEntries.append("ladar") if display == magnet: ttEntries.append("magnetometric") if display == radar: ttEntries.append("radar") plu = "" if len(ttEntries) == 1 else "s" tooltip = "{0} strength{1} bonus".format(formatList(ttEntries), plu).capitalize() return text, tooltip elif itemGroup == "Cloaking Device": recalibration = stuff.getModifiedItemAttr("cloakingTargetingDelay") if recalibration is None: return "", None text = "{0}s".format( formatAmount(float(recalibration) / 1000, 3, 0, 3)) tooltip = "Sensor recalibration time" return text, tooltip elif itemGroup == "Remote Armor Repairer": repAmount = stuff.getModifiedItemAttr("armorDamageAmount") cycleTime = stuff.getModifiedItemAttr("duration") if not repAmount or not cycleTime: return "", None repPerSec = float(repAmount) * 1000 / cycleTime text = "{0}/s".format( formatAmount(repPerSec, 3, 0, 3, forceSign=True)) tooltip = "Armor repaired per second" return text, tooltip elif itemGroup == "Remote Shield Booster": repAmount = stuff.getModifiedItemAttr("shieldBonus") cycleTime = stuff.cycleTime if not repAmount or not cycleTime: return "", None repPerSec = float(repAmount) * 1000 / cycleTime text = "{0}/s".format( formatAmount(repPerSec, 3, 0, 3, forceSign=True)) tooltip = "Shield transferred per second" return text, tooltip elif itemGroup == "Remote Capacitor Transmitter": repAmount = stuff.getModifiedItemAttr("powerTransferAmount") cycleTime = stuff.cycleTime if not repAmount or not cycleTime: return "", None repPerSec = float(repAmount) * 1000 / cycleTime text = "{0}/s".format( formatAmount(repPerSec, 3, 0, 3, forceSign=True)) tooltip = "Energy transferred per second" return text, tooltip elif itemGroup == "Remote Hull Repairer": repAmount = stuff.getModifiedItemAttr("structureDamageAmount") cycleTime = stuff.cycleTime if not repAmount or not cycleTime: return "", None repPerSec = float(repAmount) * 1000 / cycleTime text = "{0}/s".format( formatAmount(repPerSec, 3, 0, 3, forceSign=True)) tooltip = "Structure repaired per second" return text, tooltip elif itemGroup == "Gang Coordinator": command = stuff.getModifiedItemAttr( "commandBonus") or stuff.getModifiedItemAttr( "commandBonusHidden") if not command: return "", None text = "{0}%".format(formatAmount(command, 3, 0, 3, forceSign=True)) tooltip = "Gang bonus strength" return text, tooltip elif itemGroup == "Electronic Warfare Drone": sigRadBonus = stuff.getModifiedItemAttr("signatureRadiusBonus") lockRangeMult = stuff.getModifiedItemAttr( "maxTargetRangeMultiplier") scanResMult = stuff.getModifiedItemAttr("scanResolutionMultiplier") falloffRangeMult = stuff.getModifiedItemAttr("fallofMultiplier") optimalRangeMult = stuff.getModifiedItemAttr("maxRangeMultiplier") trackingSpeedMult = stuff.getModifiedItemAttr( "trackingSpeedMultiplier") grav = stuff.getModifiedItemAttr("scanGravimetricStrengthBonus") ladar = stuff.getModifiedItemAttr("scanLadarStrengthBonus") radar = stuff.getModifiedItemAttr("scanRadarStrengthBonus") magnet = stuff.getModifiedItemAttr( "scanMagnetometricStrengthBonus") if sigRadBonus: text = "{0}%".format( formatAmount(sigRadBonus, 3, 0, 3, forceSign=True)) tooltip = "Signature radius increase" return text, tooltip if lockRangeMult is not None and scanResMult is not None: lockRangeBonus = (lockRangeMult - 1) * 100 scanResBonus = (scanResMult - 1) * 100 display = 0 for bonus in (lockRangeBonus, scanResBonus): if abs(bonus) > abs(display): display = bonus if not display: return "", None text = "{0}%".format( formatAmount(display, 3, 0, 3, forceSign=True)) ttEntries = [] if display == lockRangeBonus: ttEntries.append("lock range") if display == scanResBonus: ttEntries.append("scan resolution") tooltip = "{0} dampening".format( formatList(ttEntries)).capitalize() return text, tooltip if falloffRangeMult is not None and optimalRangeMult is not None and trackingSpeedMult is not None: falloffRangeBonus = (falloffRangeMult - 1) * 100 optimalRangeBonus = (optimalRangeMult - 1) * 100 trackingSpeedBonus = (trackingSpeedMult - 1) * 100 display = 0 for bonus in (falloffRangeBonus, optimalRangeBonus, trackingSpeedBonus): if abs(bonus) > abs(display): display = bonus if not display: return "", None text = "{0}%".format(formatAmount(display, 3, 0, 3), forceSign=True) ttEntries = [] if display == optimalRangeBonus: ttEntries.append("optimal range") if display == falloffRangeBonus: ttEntries.append("falloff range") if display == trackingSpeedBonus: ttEntries.append("tracking speed") tooltip = "{0} disruption".format( formatList(ttEntries)).capitalize() return text, tooltip if grav is not None and ladar is not None and radar is not None and magnet is not None: display = max(grav, ladar, radar, magnet) if not display: return "", None text = "{0}".format(formatAmount(display, 3, 0, 3)) ttEntries = [] if display == grav: ttEntries.append("gravimetric") if display == ladar: ttEntries.append("ladar") if display == magnet: ttEntries.append("magnetometric") if display == radar: ttEntries.append("radar") plu = "" if len(ttEntries) == 1 else "s" tooltip = "{0} strength{1}".format(formatList(ttEntries), plu).capitalize() return text, tooltip else: return "", None elif itemGroup == "Fighter Bomber": optimalSig = stuff.getModifiedItemAttr("optimalSigRadius") if not optimalSig: return "", None text = "{0}m".format(formatAmount(optimalSig, 3, 0, 3)) tooltip = "Optimal signature radius" return text, tooltip elif itemGroup in ("Frequency Mining Laser", "Strip Miner", "Mining Laser", "Gas Cloud Harvester", "Mining Drone"): miningAmount = stuff.getModifiedItemAttr( "specialtyMiningAmount") or stuff.getModifiedItemAttr( "miningAmount") cycleTime = getattr(stuff, 'cycleTime', stuff.getModifiedItemAttr("duration")) if not miningAmount or not cycleTime: return "", None minePerSec = (float(miningAmount) * 1000 / cycleTime) text = "{0} m3/s".format(formatAmount(minePerSec, 3, 0, 3)) tooltip = "Mining Yield per second ({0} per hour)".format( formatAmount(minePerSec * 3600, 3, 0, 3)) return text, tooltip elif itemGroup == "Logistic Drone": armorAmount = stuff.getModifiedItemAttr("armorDamageAmount") shieldAmount = stuff.getModifiedItemAttr("shieldBonus") hullAmount = stuff.getModifiedItemAttr("structureDamageAmount") repAmount = armorAmount or shieldAmount or hullAmount cycleTime = stuff.getModifiedItemAttr("duration") if not repAmount or not cycleTime: return "", None repPerSecPerDrone = repPerSec = float(repAmount) * 1000 / cycleTime if isinstance(stuff, Drone): repPerSec *= stuff.amount text = "{0}/s".format(formatAmount(repPerSec, 3, 0, 3)) ttEntries = [] if hullAmount is not None and repAmount == hullAmount: ttEntries.append("structure") if armorAmount is not None and repAmount == armorAmount: ttEntries.append("armor") if shieldAmount is not None and repAmount == shieldAmount: ttEntries.append("shield") tooltip = "{0} HP repaired per second\n{1} HP/s per drone".format( formatList(ttEntries).capitalize(), repPerSecPerDrone) return text, tooltip elif itemGroup == "Energy Neutralizer Drone": neutAmount = stuff.getModifiedItemAttr("energyNeutralizerAmount") cycleTime = stuff.getModifiedItemAttr("energyNeutralizerDuration") if not neutAmount or not cycleTime: return "", None capPerSec = float(-neutAmount) * 1000 / cycleTime text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3)) tooltip = "Energy neutralization per second" return text, tooltip elif itemGroup == "Micro Jump Drive": cycleTime = stuff.getModifiedItemAttr("duration") / 1000 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 ( "Ancillary Armor Repairer", "Ancillary Shield Booster", "Capacitor Booster", "Ancillary Remote Armor Repairer", "Ancillary Remote Shield Booster", ): if "Armor" in itemGroup or "Shield" in itemGroup: boosted_attribute = "HP" reload_time = item.getAttribute("reloadTime", 0) / 1000 elif "Capacitor" in itemGroup: boosted_attribute = "Cap" reload_time = 10 else: boosted_attribute = "" reload_time = 0 cycles = max(stuff.numShots, 0) cycleTime = max(stuff.rawCycleTime, 0) # Get HP or boosted amount stuff_hp = max(stuff.hpBeforeReload, 0) armor_hp = stuff.getModifiedItemAttr("armorDamageAmount", 0) capacitor_hp = stuff.getModifiedChargeAttr("capacitorBonus", 0) shield_hp = stuff.getModifiedItemAttr("shieldBonus", 0) hp = max(stuff_hp, armor_hp * cycles, capacitor_hp * cycles, shield_hp * cycles, 0) if not hp or not cycleTime or not cycles: return "", None fit = Fit.getInstance().getFit(self.fittingView.getActiveFit()) ehpTotal = fit.ehp hpTotal = fit.hp useEhp = self.mainFrame.statsPane.nameViewMap[ "resistancesViewFull"].showEffective tooltip = "{0} restored over duration using charges (plus reload)".format( boosted_attribute) if useEhp and boosted_attribute == "HP" and "Remote" not in itemGroup: if "Ancillary Armor Repairer" in itemGroup: hpRatio = ehpTotal["armor"] / hpTotal["armor"] else: hpRatio = ehpTotal["shield"] / hpTotal["shield"] tooltip = "E{0}".format(tooltip) else: hpRatio = 1 if "Ancillary" in itemGroup and "Armor" in itemGroup: hpRatio *= stuff.getModifiedItemAttr( "chargedArmorDamageMultiplier", 1) ehp = hp * hpRatio duration = cycles * cycleTime / 1000 for number_of_cycles in {5, 10, 25}: tooltip = "{0}\n{1} charges lasts {2} seconds ({3} cycles)".format( tooltip, formatAmount(number_of_cycles * cycles, 3, 0, 3), formatAmount((duration + reload_time) * number_of_cycles, 3, 0, 3), formatAmount(number_of_cycles, 3, 0, 3)) text = "{0} / {1}s (+{2}s)".format( formatAmount(ehp, 3, 0, 9), formatAmount(duration, 3, 0, 3), formatAmount(reload_time, 3, 0, 3)) return text, tooltip elif itemGroup == "Armor Resistance Shift Hardener": itemArmorResistanceShiftHardenerEM = ( 1 - stuff.getModifiedItemAttr("armorEmDamageResonance")) * 100 itemArmorResistanceShiftHardenerTherm = ( 1 - stuff.getModifiedItemAttr("armorThermalDamageResonance")) * 100 itemArmorResistanceShiftHardenerKin = ( 1 - stuff.getModifiedItemAttr("armorKineticDamageResonance")) * 100 itemArmorResistanceShiftHardenerExp = ( 1 - stuff.getModifiedItemAttr("armorExplosiveDamageResonance") ) * 100 text = "{0}% | {1}% | {2}% | {3}%".format( formatAmount(itemArmorResistanceShiftHardenerEM, 3, 0, 3), formatAmount(itemArmorResistanceShiftHardenerTherm, 3, 0, 3), formatAmount(itemArmorResistanceShiftHardenerKin, 3, 0, 3), formatAmount(itemArmorResistanceShiftHardenerExp, 3, 0, 3), ) tooltip = "Resistances Shifted to Damage Profile:\n{0}% EM | {1}% Therm | {2}% Kin | {3}% Exp".format( formatAmount(itemArmorResistanceShiftHardenerEM, 3, 0, 3), formatAmount(itemArmorResistanceShiftHardenerTherm, 3, 0, 3), formatAmount(itemArmorResistanceShiftHardenerKin, 3, 0, 3), formatAmount(itemArmorResistanceShiftHardenerExp, 3, 0, 3), ) return text, tooltip elif stuff.charge is not None: chargeGroup = stuff.charge.group.name if chargeGroup.endswith("Rocket") or chargeGroup.endswith( "Missile") or chargeGroup.endswith("Torpedo"): cloudSize = stuff.getModifiedChargeAttr("aoeCloudSize") aoeVelocity = stuff.getModifiedChargeAttr("aoeVelocity") if not cloudSize or not aoeVelocity: return "", None text = "{0}{1} | {2}{3}".format( formatAmount(cloudSize, 3, 0, 3), "m", formatAmount(aoeVelocity, 3, 0, 3), "m/s") tooltip = "Explosion radius and explosion velocity" return text, tooltip elif chargeGroup == "Bomb": cloudSize = stuff.getModifiedChargeAttr("aoeCloudSize") if not cloudSize: return "", None text = "{0}{1}".format(formatAmount(cloudSize, 3, 0, 3), "m") tooltip = "Explosion radius" return text, tooltip elif chargeGroup in ("Scanner Probe", ): scanStr = stuff.getModifiedChargeAttr("baseSensorStrength") baseRange = stuff.getModifiedChargeAttr("baseScanRange") if not scanStr or not baseRange: return "", None strTwoAu = scanStr / (2.0 / baseRange) text = "{0}".format(formatAmount(strTwoAu, 3, 0, 3)) tooltip = "Scan strength with 2 AU scan range" return text, tooltip else: return "", None else: return "", None
def exportEfs(fit, typeNotFitFlag): sFit = Fit.getInstance() includeShipTypeData = typeNotFitFlag > 0 if includeShipTypeData: fitName = fit.name else: fitName = fit.ship.name + ": " + fit.name pyfalog.info("Creating Eve Fleet Simulator data for: " + fit.name) fitModAttr = fit.ship.getModifiedItemAttr propData = EfsPort.getPropData(fit, sFit) mwdPropSpeed = fit.maxSpeed if includeShipTypeData: mwdPropSpeed = EfsPort.getT2MwdSpeed(fit, sFit) projections = EfsPort.getOutgoingProjectionData(fit) modInfo = EfsPort.getModuleInfo(fit) moduleNames = modInfo["moduleNames"] modTypeIDs = modInfo["modTypeIDs"] weaponSystems = EfsPort.getWeaponSystemData(fit) turretSlots = fitModAttr("turretSlotsLeft") if fitModAttr( "turretSlotsLeft") is not None else 0 launcherSlots = fitModAttr("launcherSlotsLeft") if fitModAttr( "launcherSlotsLeft") is not None else 0 droneBandwidth = fitModAttr("droneBandwidth") if fitModAttr( "droneBandwidth") is not None else 0 weaponBonusMultipliers = EfsPort.getWeaponBonusMultipliers(fit) effectiveTurretSlots = round( turretSlots * weaponBonusMultipliers["turret"], 2) effectiveLauncherSlots = round( launcherSlots * weaponBonusMultipliers["launcher"], 2) effectiveDroneBandwidth = round( droneBandwidth * weaponBonusMultipliers["droneBandwidth"], 2) # Assume a T2 siege module for dreads if fit.ship.item.group.name == "Dreadnought": effectiveTurretSlots *= 9.4 effectiveLauncherSlots *= 15 hullResonance = { "exp": fitModAttr("explosiveDamageResonance"), "kin": fitModAttr("kineticDamageResonance"), "therm": fitModAttr("thermalDamageResonance"), "em": fitModAttr("emDamageResonance") } armorResonance = { "exp": fitModAttr("armorExplosiveDamageResonance"), "kin": fitModAttr("armorKineticDamageResonance"), "therm": fitModAttr("armorThermalDamageResonance"), "em": fitModAttr("armorEmDamageResonance") } shieldResonance = { "exp": fitModAttr("shieldExplosiveDamageResonance"), "kin": fitModAttr("shieldKineticDamageResonance"), "therm": fitModAttr("shieldThermalDamageResonance"), "em": fitModAttr("shieldEmDamageResonance") } resonance = { "hull": hullResonance, "armor": armorResonance, "shield": shieldResonance } shipSize = EfsPort.getShipSize(fit.ship.item.groupID) try: dataDict = { "name": fitName, "ehp": fit.ehp, "droneDPS": fit.droneDPS, "droneVolley": fit.droneVolley, "hp": fit.hp, "maxTargets": fit.maxTargets, "maxSpeed": fit.maxSpeed, "weaponVolley": fit.weaponVolley, "totalVolley": fit.totalVolley, "maxTargetRange": fit.maxTargetRange, "scanStrength": fit.scanStrength, "weaponDPS": fit.weaponDPS, "alignTime": fit.alignTime, "signatureRadius": fitModAttr("signatureRadius"), "weapons": weaponSystems, "scanRes": fitModAttr("scanResolution"), "capUsed": fit.capUsed, "capRecharge": fit.capRecharge, "rigSlots": fitModAttr("rigSlots"), "lowSlots": fitModAttr("lowSlots"), "midSlots": fitModAttr("medSlots"), "highSlots": fitModAttr("hiSlots"), "turretSlots": fitModAttr("turretSlotsLeft"), "launcherSlots": fitModAttr("launcherSlotsLeft"), "powerOutput": fitModAttr("powerOutput"), "cpuOutput": fitModAttr("cpuOutput"), "rigSize": fitModAttr("rigSize"), "effectiveTurrets": effectiveTurretSlots, "effectiveLaunchers": effectiveLauncherSlots, "effectiveDroneBandwidth": effectiveDroneBandwidth, "resonance": resonance, "typeID": fit.shipID, "groupID": fit.ship.item.groupID, "shipSize": shipSize, "droneControlRange": fitModAttr("droneControlRange"), "mass": fitModAttr("mass"), "unpropedSpeed": propData["unpropedSpeed"], "unpropedSig": propData["unpropedSig"], "usingMWD": propData["usingMWD"], "mwdPropSpeed": mwdPropSpeed, "projections": projections, "modTypeIDs": modTypeIDs, "moduleNames": moduleNames, "pyfaVersion": pyfaVersion, "efsExportVersion": EfsPort.version } except TypeError: pyfalog.error("Error parsing fit:" + str(fit)) pyfalog.error(TypeError) dataDict = {"name": fitName + "Fit could not be correctly parsed"} export = json.dumps(dataDict, skipkeys=True) return export
def OnFitRemoved(self, event): event.Skip() fitID = self.mainFrame.getActiveFit() fit = Fit.getInstance().getFit(fitID) self.refreshContents(fit)
def Do(self): fit = Fit.getInstance().getFit(self.fitID) srcMod = fit.modules[self.srcModPosition] if srcMod.isEmpty: return False srcModItemID = srcMod.itemID dstCargo = next( (c for c in fit.cargo if c.itemID == self.dstCargoItemID), None) success = False # Attempt to swap if we're moving our module onto a module in the cargo hold if not self.copy and dstCargo is not None and dstCargo.item.isModule: if srcModItemID == self.dstCargoItemID: return False srcModSlot = srcMod.slot newModInfo = ModuleInfo.fromModule(srcMod, unmutate=True) newModInfo.itemID = self.dstCargoItemID srcModChargeItemID = srcMod.chargeID srcModChargeAmount = srcMod.numCharges commands = [] commands.append( CalcRemoveCargoCommand(fitID=self.fitID, cargoInfo=CargoInfo( itemID=self.dstCargoItemID, amount=1), commit=False)) commands.append( CalcAddCargoCommand( fitID=self.fitID, # We cannot put mutated items to cargo, so use unmutated item ID cargoInfo=CargoInfo(itemID=ModuleInfo.fromModule( srcMod, unmutate=True).itemID, amount=1), commit=False)) cmdReplace = CalcReplaceLocalModuleCommand( fitID=self.fitID, position=self.srcModPosition, newModInfo=newModInfo, unloadInvalidCharges=True, commit=False) commands.append(cmdReplace) # Submit batch now because we need to have updated info on fit to keep going success = self.internalHistory.submitBatch(*commands) newMod = fit.modules[self.srcModPosition] # Process charge changes if module is moved to proper slot if newMod.slot == srcModSlot: # If we had to unload charge, add it to cargo if cmdReplace.unloadedCharge and srcModChargeItemID is not None: cmdAddCargoCharge = CalcAddCargoCommand( fitID=self.fitID, cargoInfo=CargoInfo(itemID=srcModChargeItemID, amount=srcModChargeAmount), commit=False) success = self.internalHistory.submit(cmdAddCargoCharge) # If we did not unload charge and there still was a charge, see if amount differs and process it elif not cmdReplace.unloadedCharge and srcModChargeItemID is not None: # How many extra charges do we need to take from cargo extraChargeAmount = newMod.numCharges - srcModChargeAmount if extraChargeAmount > 0: cmdRemoveCargoExtraCharge = CalcRemoveCargoCommand( fitID=self.fitID, cargoInfo=CargoInfo(itemID=srcModChargeItemID, amount=extraChargeAmount), commit=False) # Do not check if operation was successful or not, we're okay if we have no such # charges in cargo self.internalHistory.submit(cmdRemoveCargoExtraCharge) elif extraChargeAmount < 0: cmdAddCargoExtraCharge = CalcAddCargoCommand( fitID=self.fitID, cargoInfo=CargoInfo(itemID=srcModChargeItemID, amount=abs(extraChargeAmount)), commit=False) success = self.internalHistory.submit( cmdAddCargoExtraCharge) if success: # Store info to properly send events later self.removedModItemID = srcModItemID self.addedModItemID = self.dstCargoItemID # If drag happened to module which cannot be fit into current slot - consider it as failure else: success = False # And in case of any failures, cancel everything to try to do move instead if not success: self.internalHistory.undoAll() # Just dump module and its charges into cargo when copying or moving to cargo if not success: commands = [] commands.append( CalcAddCargoCommand(fitID=self.fitID, cargoInfo=CargoInfo( itemID=ModuleInfo.fromModule( srcMod, unmutate=True).itemID, amount=1), commit=False)) if srcMod.chargeID is not None: commands.append( CalcAddCargoCommand(fitID=self.fitID, cargoInfo=CargoInfo( itemID=srcMod.chargeID, amount=srcMod.numCharges), commit=False)) if not self.copy: commands.append( CalcRemoveLocalModulesCommand( fitID=self.fitID, positions=[self.srcModPosition], commit=False)) success = self.internalHistory.submitBatch(*commands) eos.db.commit() sFit = Fit.getInstance() sFit.recalc(self.fitID) self.savedRemovedDummies = sFit.fill(self.fitID) events = [] if self.removedModItemID is not None: events.append( GE.FitChanged(fitID=self.fitID, action='moddel', typeID=self.removedModItemID)) if self.addedModItemID is not None: events.append( GE.FitChanged(fitID=self.fitID, action='modadd', typeID=self.addedModItemID)) if not events: events.append(GE.FitChanged(fitID=self.fitID)) for event in events: wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), event) return success
def fetchPrices(cls, prices, fetchTimeout, validityOverride): """Fetch all prices passed to this method""" # Dictionary for our price objects priceMap = {} # Check all provided price objects, and add those we want to update to # dictionary for price in prices: if not price.isValid(validityOverride): priceMap[price.typeID] = price if not priceMap: return # Compose list of items we're going to request for typeID in tuple(priceMap): # Get item object item = db.getItem(typeID) # We're not going to request items only with market group, as our current market # sources do not provide any data for items not on the market if item is None: continue if not item.marketGroupID: priceMap[typeID].update(PriceStatus.notSupported) del priceMap[typeID] continue if not priceMap: return sFit = Fit.getInstance() if len(cls.sources.keys()) == 0: pyfalog.warn('No price source can be found') return # attempt to find user's selected price source, otherwise get first one sourceAll = list(cls.sources.keys()) sourcePrimary = sFit.serviceFittingOptions[ "priceSource"] if sFit.serviceFittingOptions[ "priceSource"] in sourceAll else sourceAll[0] # Format: {source name: timeout weight} sources = {sourcePrimary: len(sourceAll)} for source in sourceAll: if source == sourcePrimary: continue sources[source] = min(sources.values()) - 1 timeoutWeightMult = fetchTimeout / sum(sources.values()) # Record timeouts as it will affect our final decision timedOutSources = {} for source, timeoutWeight in sources.items(): pyfalog.info('Trying {}'.format(source)) timedOutSources[source] = False sourceFetchTimeout = timeoutWeight * timeoutWeightMult try: sourceCls = cls.sources.get(source) sourceCls( priceMap, cls.systemsList[sFit.serviceFittingOptions["priceSystem"]], sourceFetchTimeout) except TimeoutError: pyfalog.warning( "Price fetch timeout for source {}".format(source)) timedOutSources[source] = True except Exception as e: pyfalog.warn( 'Failed to fetch prices from price source {}: {}'.format( source, e)) # Sources remove price map items as they fetch info, if none remain then we're done if not priceMap: break # If we get to this point, then we've failed to get price with all our sources # If all sources failed due to timeouts, set one status if all(to is True for to in timedOutSources.values()): for typeID in priceMap.keys(): priceMap[typeID].update(PriceStatus.fetchTimeout) # If some sources failed due to any other reason, then it's definitely not network # timeout and we just set another status else: for typeID in priceMap.keys(): priceMap[typeID].update(PriceStatus.fetchFail)
def populatePanel(self, panel): self.mainFrame = gui.mainFrame.MainFrame.getInstance() mainSizer = wx.BoxSizer(wx.VERTICAL) helpCursor = wx.Cursor(wx.CURSOR_QUESTION_ARROW) self.engine_settings = EOSSettings.getInstance() self.stTitle = wx.StaticText(panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0) self.stTitle.Wrap(-1) self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) mainSizer.Add(self.stTitle, 0, wx.ALL, 5) self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) self.cbGlobalForceReload = wx.CheckBox( panel, wx.ID_ANY, "Factor in reload time when calculating capacitor usage, damage, and tank.", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbGlobalForceReload, 0, wx.ALL | wx.EXPAND, 5) self.cbStrictSkillLevels = wx.CheckBox( panel, wx.ID_ANY, "Enforce strict skill level requirements", wx.DefaultPosition, wx.DefaultSize, 0) self.cbStrictSkillLevels.SetCursor(helpCursor) self.cbStrictSkillLevels.SetToolTip( wx.ToolTip( 'When enabled, skills will check their dependencies\' requirements when their levels change and reset ' + 'skills that no longer meet the requirement.\neg: Setting Drones from level V to IV will reset the Heavy ' + 'Drone Operation skill, as that requires Drones V')) mainSizer.Add(self.cbStrictSkillLevels, 0, wx.ALL | wx.EXPAND, 5) self.cbUniversalAdaptiveArmorHardener = wx.CheckBox( panel, wx.ID_ANY, "When damage profile is Uniform, set Reactive Armor " + "Hardener to match (old behavior).", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbUniversalAdaptiveArmorHardener, 0, wx.ALL | wx.EXPAND, 5) spoolup_sizer = wx.BoxSizer(wx.HORIZONTAL) self.spool_up_label = wx.StaticText( panel, wx.ID_ANY, "Global Default Spoolup Percentage:", wx.DefaultPosition, wx.DefaultSize, 0) self.spool_up_label.Wrap(-1) self.spool_up_label.SetCursor(helpCursor) self.spool_up_label.SetToolTip( wx.ToolTip( 'The amount of spoolup to use by default on module which support it. Can be changed on a per-module basis' )) spoolup_sizer.Add(self.spool_up_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) self.spoolup_value = IntCtrl(panel, min=0, max=100, limited=True) spoolup_sizer.Add(self.spoolup_value, 0, wx.ALL, 5) mainSizer.Add(spoolup_sizer, 0, wx.ALL | wx.EXPAND, 0) # Future code once new cap sim is implemented ''' self.cbGlobalForceReactivationTimer = wx.CheckBox( panel, wx.ID_ANY, u"Factor in reactivation timer", wx.DefaultPosition, wx.DefaultSize, 0 ) mainSizer.Add( self.cbGlobalForceReactivationTimer, 0, wx.ALL|wx.EXPAND, 5 ) text = u" Ignores reactivation timer when calculating capacitor usage,\n damage, and tank." self.cbGlobalForceReactivationTimerText = wx.StaticText( panel, wx.ID_ANY, text, wx.DefaultPosition, wx.DefaultSize, 0 ) self.cbGlobalForceReactivationTimerText.Wrap( -1 ) self.cbGlobalForceReactivationTimerText.SetFont( wx.Font( 10, 70, 90, 90, False, wx.EmptyString ) ) mainSizer.Add( self.cbGlobalForceReactivationTimerText, 0, wx.ALL, 5 ) ''' # Future code for mining laser crystal ''' self.cbGlobalMiningSpecialtyCrystal = wx.CheckBox( panel, wx.ID_ANY, u"Factor in reactivation timer", wx.DefaultPosition, wx.DefaultSize, 0 ) mainSizer.Add( self.cbGlobalMiningSpecialtyCrystal, 0, wx.ALL|wx.EXPAND, 5 ) text = u" If enabled, displays the Specialty Crystal mining amount.\n This is the amount mined when using crystals and mining the matching asteroid." self.cbGlobalMiningSpecialtyCrystalText = wx.StaticText( panel, wx.ID_ANY, text, wx.DefaultPosition, wx.DefaultSize, 0 ) self.cbGlobalMiningSpecialtyCrystalText.Wrap( -1 ) self.cbGlobalMiningSpecialtyCrystalText.SetFont( wx.Font( 10, 70, 90, 90, False, wx.EmptyString ) ) mainSizer.Add( self.cbGlobalMiningSpecialtyCrystalText, 0, wx.ALL, 5 ) ''' self.sFit = Fit.getInstance() self.cbGlobalForceReload.SetValue( self.sFit.serviceFittingOptions["useGlobalForceReload"]) self.cbGlobalForceReload.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalForceReloadStateChange) self.cbStrictSkillLevels.SetValue( self.engine_settings.get("strictSkillLevels")) self.cbStrictSkillLevels.Bind(wx.EVT_CHECKBOX, self.OnCBStrictSkillLevelsChange) self.cbUniversalAdaptiveArmorHardener.SetValue( self.engine_settings.get("useStaticAdaptiveArmorHardener")) self.cbUniversalAdaptiveArmorHardener.Bind( wx.EVT_CHECKBOX, self.OnCBUniversalAdaptiveArmorHardenerChange) self.spoolup_value.SetValue( int( self.engine_settings.get("globalDefaultSpoolupPercentage") * 100)) self.spoolup_value.Bind(wx.lib.intctrl.EVT_INT, self.OnSpoolupChange) panel.SetSizer(mainSizer) panel.Layout()
def getSubMenu(self, context, selection, rootMenu, i, pitem): self.moduleLookup = {} sFit = Fit.getInstance() fit = sFit.getFit(self.mainFrame.getActiveFit()) def get_metalevel(x): if 'metaLevel' not in x.attributes: return 0 return x.attributes['metaLevel'].value def get_metagroup(x): # We want deadspace before officer mods remap = {5: 6, 6: 5} return remap.get(x.metaGroup.ID, x.metaGroup.ID) if x.metaGroup is not None else 0 def get_boosterrank(x): # If we're returning a lot of items, sort my name if len(self.variations) > 7: return x.name # Sort by booster chance to get some sort of pseudorank. elif 'boosterEffectChance1' in x.attributes: return x.attributes['boosterEffectChance1'].value # the "first" rank (Synth) doesn't have boosterEffectChance1. If we're not pulling back all boosters, return 0 for proper sorting else: return 0 m = wx.Menu() # If on Windows we need to bind out events into the root menu, on other # platforms they need to go to our sub menu if 'wxMSW' in wx.PlatformInfo: bindmenu = rootMenu else: bindmenu = m # Sort items by metalevel, and group within that metalevel items = list(self.variations) # Sort all items by name first items.sort(key=lambda x: x.name) # Do not do any extra sorting for implants if 'implantItem' in context: pass # Boosters don't have meta or anything concrete that we can rank by. Go by chance to inflict side effect elif 'boosterItem' in context: items.sort(key=get_boosterrank) else: # sort by group and meta level items.sort(key=get_metalevel) items.sort(key=get_metagroup) group = None for item in items: # Apparently no metaGroup for the Tech I variant: if 'subSystem' in item.effects: thisgroup = item.marketGroup.marketGroupName elif item.metaGroup is None: thisgroup = 'Tech I' else: thisgroup = item.metaGroup.name if thisgroup != group and context not in ('implantItem', 'boosterItem'): group = thisgroup id = ContextMenu.nextID() m.Append(id, '─ %s ─' % group) m.Enable(id, False) id = ContextMenu.nextID() mitem = wx.MenuItem(rootMenu, id, item.name) bindmenu.Bind(wx.EVT_MENU, self.handleModule, mitem) self.moduleLookup[id] = item, context m.Append(mitem) mitem.Enable(fit.canFit(item)) return m
def Do(self): cmd = CalcChangeProjectedModuleStateCommand(fitID=self.fitID, position=self.position, click=self.click) success = self.internalHistory.submit(cmd) Fit.getInstance().recalc(self.fitID) wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), GE.FitChanged(fitID=self.fitID)) return success
def populatePanel(self, panel): self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.dirtySettings = False self.openFitsSettings = SettingsProvider.getInstance().getSettings("pyfaPrevOpenFits", {"enabled": False, "pyfaOpenFits": []}) mainSizer = wx.BoxSizer(wx.VERTICAL) self.stTitle = wx.StaticText(panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0) self.stTitle.Wrap(-1) self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) helpCursor = wx.Cursor(wx.CURSOR_QUESTION_ARROW) mainSizer.Add(self.stTitle, 0, wx.ALL, 5) self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) self.cbGlobalChar = wx.CheckBox(panel, wx.ID_ANY, "Use global character", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbGlobalChar, 0, wx.ALL | wx.EXPAND, 5) self.cbDefaultCharImplants = wx.CheckBox(panel, wx.ID_ANY, "Use character implants by default for new fits", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbDefaultCharImplants, 0, wx.ALL | wx.EXPAND, 5) self.cbGlobalDmgPattern = wx.CheckBox(panel, wx.ID_ANY, "Use global damage pattern", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbGlobalDmgPattern, 0, wx.ALL | wx.EXPAND, 5) self.cbCompactSkills = wx.CheckBox(panel, wx.ID_ANY, "Compact skills needed tooltip", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbCompactSkills, 0, wx.ALL | wx.EXPAND, 5) self.cbFitColorSlots = wx.CheckBox(panel, wx.ID_ANY, "Color fitting view by slot", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbFitColorSlots, 0, wx.ALL | wx.EXPAND, 5) self.cbReopenFits = wx.CheckBox(panel, wx.ID_ANY, "Reopen previous fits on startup", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbReopenFits, 0, wx.ALL | wx.EXPAND, 5) self.cbRackSlots = wx.CheckBox(panel, wx.ID_ANY, "Separate Racks", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbRackSlots, 0, wx.ALL | wx.EXPAND, 5) labelSizer = wx.BoxSizer(wx.VERTICAL) self.cbRackLabels = wx.CheckBox(panel, wx.ID_ANY, "Show Rack Labels", wx.DefaultPosition, wx.DefaultSize, 0) labelSizer.Add(self.cbRackLabels, 0, wx.ALL | wx.EXPAND, 5) mainSizer.Add(labelSizer, 0, wx.LEFT | wx.EXPAND, 30) self.cbShowTooltip = wx.CheckBox(panel, wx.ID_ANY, "Show fitting tab tooltips", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbShowTooltip, 0, wx.ALL | wx.EXPAND, 5) self.cbGaugeAnimation = wx.CheckBox(panel, wx.ID_ANY, "Animate gauges", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbGaugeAnimation, 0, wx.ALL | wx.EXPAND, 5) self.cbOpenFitInNew = wx.CheckBox(panel, wx.ID_ANY, "Open fittings in a new page by default", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbOpenFitInNew, 0, wx.ALL | wx.EXPAND, 5) self.cbShowShipBrowserTooltip = wx.CheckBox(panel, wx.ID_ANY, "Show ship browser tooltip", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbShowShipBrowserTooltip, 0, wx.ALL | wx.EXPAND, 5) self.cbReloadAll = wx.CheckBox(panel, wx.ID_ANY, "Change charge in all modules of the same type", wx.DefaultPosition, wx.DefaultSize, 0) if "wxGTK" not in wx.PlatformInfo: self.cbReloadAll.SetCursor(helpCursor) self.cbReloadAll.SetToolTip(wx.ToolTip( 'When disabled, reloads charges just in selected modules. Action can be reversed by holding Ctrl or Alt key while changing charge.')) mainSizer.Add(self.cbReloadAll, 0, wx.ALL | wx.EXPAND, 5) self.sFit = Fit.getInstance() self.cbGlobalChar.SetValue(self.sFit.serviceFittingOptions["useGlobalCharacter"]) self.cbDefaultCharImplants.SetValue(self.sFit.serviceFittingOptions["useCharacterImplantsByDefault"]) self.cbGlobalDmgPattern.SetValue(self.sFit.serviceFittingOptions["useGlobalDamagePattern"]) self.cbFitColorSlots.SetValue(self.sFit.serviceFittingOptions["colorFitBySlot"] or False) self.cbRackSlots.SetValue(self.sFit.serviceFittingOptions["rackSlots"] or False) self.cbRackLabels.SetValue(self.sFit.serviceFittingOptions["rackLabels"] or False) self.cbCompactSkills.SetValue(self.sFit.serviceFittingOptions["compactSkills"] or False) self.cbReopenFits.SetValue(self.openFitsSettings["enabled"]) self.cbShowTooltip.SetValue(self.sFit.serviceFittingOptions["showTooltip"] or False) self.cbGaugeAnimation.SetValue(self.sFit.serviceFittingOptions["enableGaugeAnimation"]) self.cbOpenFitInNew.SetValue(self.sFit.serviceFittingOptions["openFitInNew"]) self.cbShowShipBrowserTooltip.SetValue(self.sFit.serviceFittingOptions["showShipBrowserTooltip"]) self.cbReloadAll.SetValue(self.sFit.serviceFittingOptions["ammoChangeAll"]) self.cbGlobalChar.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalCharStateChange) self.cbDefaultCharImplants.Bind(wx.EVT_CHECKBOX, self.OnCBDefaultCharImplantsStateChange) self.cbGlobalDmgPattern.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalDmgPatternStateChange) self.cbFitColorSlots.Bind(wx.EVT_CHECKBOX, self.onCBGlobalColorBySlot) self.cbRackSlots.Bind(wx.EVT_CHECKBOX, self.onCBGlobalRackSlots) self.cbRackLabels.Bind(wx.EVT_CHECKBOX, self.onCBGlobalRackLabels) self.cbCompactSkills.Bind(wx.EVT_CHECKBOX, self.onCBCompactSkills) self.cbReopenFits.Bind(wx.EVT_CHECKBOX, self.onCBReopenFits) self.cbShowTooltip.Bind(wx.EVT_CHECKBOX, self.onCBShowTooltip) self.cbGaugeAnimation.Bind(wx.EVT_CHECKBOX, self.onCBGaugeAnimation) self.cbOpenFitInNew.Bind(wx.EVT_CHECKBOX, self.onCBOpenFitInNew) self.cbShowShipBrowserTooltip.Bind(wx.EVT_CHECKBOX, self.onCBShowShipBrowserTooltip) self.cbReloadAll.Bind(wx.EVT_CHECKBOX, self.onCBReloadAll) self.cbRackLabels.Enable(self.sFit.serviceFittingOptions["rackSlots"] or False) panel.SetSizer(mainSizer) panel.Layout()
def __init__(self, parent): super().__init__(parent, id=wx.ID_ANY, title="Character Editor", resizeable=True, pos=wx.DefaultPosition, size=wx.Size(950, 650) if "wxGTK" in wx.PlatformInfo else wx.Size(850, 600)) i = wx.Icon(BitmapLoader.getBitmap("character_small", "gui")) self.SetIcon(i) self.mainFrame = parent # self.disableWin = wx.WindowDisabler(self) sFit = Fit.getInstance() mainSizer = wx.BoxSizer(wx.VERTICAL) self.entityEditor = CharacterEntityEditor(self) mainSizer.Add(self.entityEditor, 0, wx.ALL | wx.EXPAND, 2) # Default drop down to current fit's character self.entityEditor.setActiveEntity(sFit.character) self.viewsNBContainer = wx.Notebook(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0) self.sview = SkillTreeView(self.viewsNBContainer) self.iview = ImplantEditorView(self.viewsNBContainer, self) self.aview = APIView(self.viewsNBContainer) self.viewsNBContainer.AddPage(self.sview, "Skills") self.viewsNBContainer.AddPage(self.iview, "Implants") self.viewsNBContainer.AddPage(self.aview, "EVE SSO") mainSizer.Add(self.viewsNBContainer, 1, wx.EXPAND | wx.ALL, 5) bSizerButtons = wx.BoxSizer(wx.HORIZONTAL) self.btnSaveChar = wx.Button(self, wx.ID_ANY, "Save") self.btnSaveAs = wx.Button(self, wx.ID_ANY, "Save As...") self.btnRevert = wx.Button(self, wx.ID_ANY, "Revert") self.btnOK = wx.Button(self, wx.ID_OK) bSizerButtons.Add(self.btnSaveChar, 0, wx.ALL, 5) bSizerButtons.Add(self.btnSaveAs, 0, wx.ALL, 5) bSizerButtons.Add(self.btnRevert, 0, wx.ALL, 5) bSizerButtons.AddStretchSpacer() bSizerButtons.Add(self.btnOK, 0, wx.ALL, 5) self.btnSaveChar.Bind(wx.EVT_BUTTON, self.saveChar) self.btnSaveAs.Bind(wx.EVT_BUTTON, self.saveCharAs) self.btnRevert.Bind(wx.EVT_BUTTON, self.revertChar) self.btnOK.Bind(wx.EVT_BUTTON, self.editingFinished) mainSizer.Add(bSizerButtons, 0, wx.EXPAND, 5) self.btnRestrict() self.SetSizer(mainSizer) self.Layout() self.SetMinSize(self.GetSize()) self.Centre(wx.BOTH) self.Bind(wx.EVT_CLOSE, self.OnClose) self.Bind(wx.EVT_CHAR_HOOK, self.kbEvent) self.Bind(GE.CHAR_LIST_UPDATED, self.refreshCharacterList) self.entityEditor.Bind(wx.EVT_CHOICE, self.charChanged) self.charChanged(None)
def delaySearch(self, evt): sFit = Fit.getInstance() self.searchTimer.Stop() self.searchTimer.Start(sFit.serviceFittingOptions["marketSearchDelay"], True) # 150ms
def Do(self): cmd = CalcToggleFighterStateCommand(fitID=self.fitID, projected=False, position=self.position) success = self.internalHistory.submit(cmd) Fit.getInstance().recalc(self.fitID) wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), GE.FitChanged(fitID=self.fitID)) return success
def click(self, event): """ Handle click event on modules. This is only useful for the State column. If multiple items are selected, and we have clicked the State column, iterate through the selections and change State """ clickedRow, _, col = self.HitTestSubItem(event.Position) # only do State column and ignore invalid rows if clickedRow != -1 and clickedRow not in self.blanks and col == self.getColIndex(State): selectedRows = [] currentRow = self.GetFirstSelected() while currentRow != -1 and clickedRow not in self.blanks: selectedRows.append(currentRow) currentRow = self.GetNextSelected(currentRow) if clickedRow not in selectedRows: try: selectedMods = [self.mods[clickedRow]] except IndexError: return else: selectedMods = self.getSelectedMods() click = "ctrl" if event.GetModifiers() == wx.MOD_CONTROL or event.middleIsDown else "right" if event.GetButton() == 3 else "left" try: mainMod = self.mods[clickedRow] except IndexError: return if mainMod.isEmpty: return fitID = self.mainFrame.getActiveFit() fit = Fit.getInstance().getFit(fitID) if mainMod not in fit.modules: return mainPosition = fit.modules.index(mainMod) if event.GetModifiers() == wx.MOD_ALT: positions = getSimilarModPositions(fit.modules, mainMod) else: positions = [] for position, mod in enumerate(fit.modules): if mod in selectedMods: positions.append(position) self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleStatesCommand( fitID=fitID, mainPosition=mainPosition, positions=positions, click=click)) # update state tooltip tooltip = self.activeColumns[col].getToolTip(self.mods[clickedRow]) if tooltip: self.SetToolTip(tooltip) else: event.Skip()
def _merge(self, src, dst): sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() if sFit.mergeDrones(fitID, self.drones[src], self.drones[dst]): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))