NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

panelFitting.py (16717B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\info\panels\panelFitting.py
      2 import collections
      3 import itertools
      4 import carbonui.const as uiconst
      5 import dogma.data
      6 import evetypes
      7 import eveicon
      8 from carbon.common.script.util.format import FmtAmt
      9 from carbonui.control.scrollentries import SE_BaseClassCore
     10 from carbonui.primitives.container import Container
     11 from carbonui.primitives.sprite import Sprite
     12 from carbonui.util.various_unsorted import SortListOfTuples
     13 from dogma.attributes.format import GetFormattedAttributeAndValue
     14 from eve.client.script.ui.control.entries.item import Item
     15 from eve.client.script.ui.control.entries.label_text import LabelTextSides
     16 from eve.client.script.ui.control.entries.util import GetFromClass
     17 from eve.client.script.ui.control.eveScroll import Scroll
     18 from eve.client.script.ui.control.themeColored import FillThemeColored
     19 from eve.client.script.ui.shared.fittingScreen.tryFit import GetParentShipInfo
     20 from eve.common.lib import appConst as const
     21 from eve.common.script.sys import eveCfg, idCheckers
     22 from localization import GetByLabel, GetByMessageID
     23 FITTING_SLOT_INFO = [{'label': 'UI/InfoWindow/FittingHighPowerSlot',
     24   'attributeID': const.attributeHiSlots,
     25   'flags': const.hiSlotFlags,
     26   'effectID': const.effectHiPower},
     27  {'label': 'UI/InfoWindow/FittingMediumPowerSlots',
     28   'attributeID': const.attributeMedSlots,
     29   'flags': const.medSlotFlags,
     30   'effectID': const.effectMedPower},
     31  {'label': 'UI/InfoWindow/FittingLowPowerSlots',
     32   'attributeID': const.attributeLowSlots,
     33   'flags': const.loSlotFlags,
     34   'effectID': const.effectLoPower},
     35  {'label': 'UI/InfoWindow/FittingRigSlots',
     36   'attributeID': const.attributeUpgradeSlotsLeft,
     37   'flags': const.rigSlotFlags,
     38   'effectID': const.effectRigSlot},
     39  {'label': 'UI/InfoWindow/FittingServiceSlots',
     40   'attributeID': const.attributeServiceSlots,
     41   'flags': const.serviceSlotFlags,
     42   'effectID': const.effectServiceSlot},
     43  {'label': 'UI/InfoWindow/FittingSubsystemSlots',
     44   'attributeID': const.attributeSubSystemSlot,
     45   'flags': const.subsystemSlotFlags,
     46   'effectID': const.effectSubSystem}]
     47 
     48 class PanelFitting(Container):
     49 
     50     def ApplyAttributes(self, attributes):
     51         Container.ApplyAttributes(self, attributes)
     52         self.typeID = attributes.typeID
     53         self.item = attributes.get('item', None)
     54         self.itemID = attributes.get('itemID', None)
     55         if self.itemID is None and self.item is not None:
     56             self.itemID = self.item.itemID
     57         if self.item is None and self.itemID is not None:
     58             dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation()
     59             if dogmaLocation.IsItemLoaded(self.itemID):
     60                 self.item = dogmaLocation.GetItem(self.itemID)
     61 
     62     def Load(self):
     63         self.Flush()
     64         fittingScroll = Scroll(name='fittingScroll', parent=self, padding=const.defaultPadding)
     65         turretSlotsUsed = 0
     66         launcherSlotsUsed = 0
     67         entryList = []
     68         inventory = self.GetShipContents()
     69         for slotKey, slotInfo in enumerate(FITTING_SLOT_INFO):
     70             modulesByType = collections.defaultdict(list)
     71             chargesByFlag = collections.defaultdict(list)
     72             for item in filter(lambda item: item.flagID in slotInfo['flags'], inventory):
     73                 if IsCharge(item):
     74                     chargesByFlag[item.flagID].append(item)
     75                 else:
     76                     modulesByType[item.typeID].append(item)
     77 
     78             usedSlotCount = 0
     79             for typeID, items in modulesByType.iteritems():
     80                 if HasEffect(typeID, slotInfo['effectID']):
     81                     usedSlotCount += len(items)
     82                 if HasEffect(typeID, const.effectTurretFitted):
     83                     turretSlotsUsed += len(items)
     84                 if HasEffect(typeID, const.effectLauncherFitted):
     85                     launcherSlotsUsed += len(items)
     86                 lowestFlagID = min((item.flagID for item in items))
     87                 sortKey = (slotKey, lowestFlagID)
     88                 entry = self.GetFittingEntry(typeID, len(items))
     89                 entryList.append((sortKey, entry))
     90                 chargeQuantityByType = collections.defaultdict(int)
     91                 for charge in itertools.chain.from_iterable((chargesByFlag[item.flagID] for item in items)):
     92                     chargeQuantityByType[charge.typeID] += max(charge.quantity, 1)
     93 
     94                 for chargeType, chargeQuantity in chargeQuantityByType.iteritems():
     95                     sortKey = (slotKey, lowestFlagID, chargeType)
     96                     entry = self.GetFittingEntry(chargeType, chargeQuantity, isCharge=True)
     97                     entryList.append((sortKey, entry))
     98 
     99             sortKey = (slotKey,)
    100             entry = self.GetFittingSlotEntry(slotInfo, usedSlotCount)
    101             entryList.append((sortKey, entry))
    102 
    103         sortedEntryList = sm.GetService('info').GetAttributeScrollListForItem(itemID=self.itemID, typeID=self.typeID, attrList=[const.attributeCpuOutput, const.attributePowerOutput, const.attributeUpgradeCapacity])
    104         sortedEntryList.append(self.GetHardpointsEntry(turretSlotsUsed, launcherSlotsUsed))
    105         sortedEntryList.extend(SortListOfTuples(entryList))
    106         sortedEntryList.extend(self.GetDroneEntries(inventory))
    107         fittingScroll.Load(contentList=filter(None, sortedEntryList))
    108 
    109     def GetFittingSlotEntry(self, slotInfo, moduleCount):
    110         slotCount = self.GetTotalSlotCount(slotInfo)
    111         if slotCount <= 0 and moduleCount <= 0:
    112             return
    113         isMyActiveShip = self.itemID is not None and eveCfg.GetActiveShip() == self.itemID
    114         isOwnedByMe = self.item is not None and self.item.ownerID == session.charid
    115         if isMyActiveShip or isOwnedByMe:
    116             return GetFromClass(FittingSlotEntry, {'label': self.GetFittingSlotEntryLabel(slotInfo),
    117              'text': GetByLabel('UI/InfoWindow/FittingSlotsUsedAndTotal', usedSlots=moduleCount, slotCount=slotCount),
    118              'iconID': dogma.data.get_attribute_icon_id(slotInfo['attributeID']),
    119              'line': 1})
    120         else:
    121             return GetFromClass(LabelTextSides, {'label': self.GetFittingSlotEntryLabel(slotInfo),
    122              'text': FmtAmt(slotCount),
    123              'iconID': dogma.data.get_attribute_icon_id(slotInfo['attributeID']),
    124              'line': 1})
    125 
    126     def GetFittingEntry(self, typeID, quantity, isCharge = False):
    127         itemName = evetypes.GetName(typeID)
    128         if quantity > 1:
    129             label = GetByLabel('UI/InfoWindow/FittingItemLabelWithQuantity', quantity=quantity, itemName=itemName)
    130         else:
    131             label = itemName
    132         return GetFromClass(FittingItemEntry, {'typeID': typeID,
    133          'label': label,
    134          'getIcon': True,
    135          'indentLevel': 2 if isCharge else 1})
    136 
    137     def GetHardpointsEntry(self, turretSlotsUsed, launcherSlotsUsed):
    138         turretSlotCount = self.GetAttributeValue(const.attributeTurretSlotsLeft)
    139         launcherSlotCount = self.GetAttributeValue(const.attributeLauncherSlotsLeft)
    140         if self.itemID == eveCfg.GetActiveShip():
    141             turretSlotCount += turretSlotsUsed
    142             launcherSlotCount += launcherSlotsUsed
    143         if turretSlotCount <= 0 and launcherSlotCount <= 0:
    144             return None
    145         return GetFromClass(TurretAndLauncherSlotEntry, {'turretSlotsUsed': turretSlotsUsed,
    146          'turretSlotCount': turretSlotCount,
    147          'launcherSlotsUsed': launcherSlotsUsed,
    148          'launcherSlotCount': launcherSlotCount})
    149 
    150     def GetDroneEntries(self, items):
    151         if not idCheckers.IsShipType(self.typeID):
    152             return []
    153         totalDroneCapacity = dogma.data.get_type_attribute(self.typeID, const.attributeDroneCapacity)
    154         if not totalDroneCapacity:
    155             return []
    156         dronesByType = collections.defaultdict(int)
    157         for item in items:
    158             if item.flagID == const.flagDroneBay:
    159                 dronesByType[item.typeID] += item.stacksize
    160 
    161         usedCapacity = sum([ evetypes.GetVolume(typeID) * amount for typeID, amount in dronesByType.iteritems() ])
    162         isMyActiveShip = self.itemID is not None and eveCfg.GetActiveShip() == self.itemID
    163         isOwnedByMe = self.item is not None and self.item.ownerID == session.charid
    164         if isMyActiveShip or isOwnedByMe:
    165             headerClass = FittingSlotEntry
    166             headerText = GetByLabel('UI/Inventory/ContainerQuantityAndCapacity', quantity=usedCapacity, capacity=totalDroneCapacity)
    167         else:
    168             headerClass = LabelTextSides
    169             headerText = GetByLabel('UI/Inventory/ContainerCapacity', capacity=totalDroneCapacity)
    170         dronesHeaderEntry = GetFromClass(headerClass, {'label': GetByLabel('UI/Drones/Drones'),
    171          'text': headerText,
    172          'iconID': eveicon.drones,
    173          'line': 1})
    174         result = [dronesHeaderEntry]
    175         result.extend([ self.GetFittingEntry(typeID, quantity) for typeID, quantity in sorted(dronesByType.items(), key=lambda d: evetypes.GetName(d[0])) ])
    176         return result
    177 
    178     def GetTotalSlotCount(self, slotInfo):
    179         if slotInfo['attributeID'] == const.attributeUpgradeSlotsLeft:
    180             return self.GetTypeAttributeValue(slotInfo['attributeID'])
    181         else:
    182             return self.GetAttributeValue(slotInfo['attributeID'])
    183 
    184     def GetFittingSlotEntryLabel(self, slotInfo):
    185         if slotInfo['attributeID'] == const.attributeUpgradeSlotsLeft:
    186             rigSize = self.GetAttributeValue(const.attributeRigSize)
    187             formattedRigSize = GetFormattedAttributeAndValue(const.attributeRigSize, rigSize)
    188             return GetByLabel(slotInfo['label'], rigSize=getattr(formattedRigSize, 'value', ''))
    189         return GetByLabel(slotInfo['label'])
    190 
    191     def GetShipContents(self):
    192         if self.itemID is None:
    193             return []
    194         if session.shipid == self.itemID:
    195             shipinfo = sm.GetService('godma').GetItem(self.itemID)
    196             if shipinfo is not None and getattr(shipinfo, 'inventory', None) is not None:
    197                 return shipinfo.inventory.List()
    198         if sm.GetService('info').IsItemSimulated(self.itemID):
    199             return self.GetSimulatedShipContents()
    200         if self.item is None:
    201             return []
    202         if not self.item.singleton:
    203             return []
    204         if self.item.ownerID == session.charid and self.item.locationID:
    205             dockableLocationID = self.item.locationID
    206             solarSystemID = None
    207             if self.item.flagID in (const.flagCargo, const.flagShipHangar):
    208                 parentShipInfo = GetParentShipInfo(self.item)
    209                 if parentShipInfo:
    210                     dockableLocationID, solarSystemID = parentShipInfo
    211             inventoryMgr = sm.GetService('invCache').GetInventoryMgr()
    212             try:
    213                 return inventoryMgr.GetContainerContents(self.item.itemID, dockableLocationID, solarSystemID)
    214             except AttributeError:
    215                 pass
    216 
    217         return []
    218 
    219     def GetSimulatedShipContents(self):
    220         dogmaLocation = sm.GetService('clientDogmaIM').GetFittingDogmaLocation()
    221         fittedItems = dogmaLocation.GetFittedItemsToShip()
    222         return fittedItems.values()
    223 
    224     def GetAttributeValue(self, attributeID):
    225         dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation()
    226         if dogmaLocation.IsItemLoaded(self.itemID):
    227             return dogmaLocation.GetAccurateAttributeValue(self.itemID, attributeID)
    228         return self.GetTypeAttributeValue(attributeID)
    229 
    230     def GetTypeAttributeValue(self, attributeID):
    231         info = sm.GetService('godma').GetStateManager().GetShipType(self.typeID)
    232         return getattr(info, dogma.data.get_attribute_name(attributeID))
    233 
    234 
    235 def IsCharge(item):
    236     return item.categoryID == const.categoryCharge
    237 
    238 
    239 def HasEffect(typeID, effectID):
    240     return sm.GetService('clientDogmaStaticSvc').TypeHasEffect(typeID, effectID)
    241 
    242 
    243 class FittingItemEntry(Item):
    244 
    245     def Load(self, node):
    246         Item.Load(self, node)
    247         indentLevel = node.get('indentLevel', 0)
    248         if indentLevel > 0:
    249             self.sr.icon.left = 16 * indentLevel
    250             self.sr.label.left = 16 * indentLevel + self.sr.icon.width + 4
    251 
    252 
    253 class FittingSlotEntry(LabelTextSides):
    254 
    255     def Startup(self, *args):
    256         super(FittingSlotEntry, self).Startup(*args)
    257         FillThemeColored(bgParent=self, colorType=uiconst.COLORTYPE_UIHILIGHT)
    258 
    259 
    260 class TurretAndLauncherSlotEntry(SE_BaseClassCore):
    261 
    262     def Startup(self, *args):
    263         turretTopContainer = Container(parent=self, align=uiconst.TOLEFT_PROP, width=0.5, state=uiconst.UI_NORMAL)
    264         turretTopContainer.LoadTooltipPanel = self.LoadTooltipPanelForTurret
    265         Sprite(name='turretHardpointsIcon', texturePath='res:/UI/Texture/Icons/26_64_1.png', parent=turretTopContainer, align=uiconst.TOPLEFT, pos=(1, 2, 24, 24), ignoreSize=True, state=uiconst.UI_DISABLED)
    266         self.sr.turretBubbles = []
    267         for i in range(8):
    268             x = i * 14 + 26
    269             bubble = Sprite(parent=turretTopContainer, pos=(x,
    270              7,
    271              14,
    272              16), useSizeFromTexture=True, align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED)
    273             self.sr.turretBubbles.append(bubble)
    274 
    275         launcherTopContainer = Container(parent=self, align=uiconst.TOLEFT_PROP, width=0.5, state=uiconst.UI_NORMAL)
    276         launcherTopContainer.LoadTooltipPanel = self.LoadTooltipPanelForLauncher
    277         Sprite(name='launcherHardpointsIcon', texturePath='res:/UI/Texture/Icons/81_64_16.png', parent=launcherTopContainer, align=uiconst.TOPRIGHT, pos=(1, 2, 24, 24), ignoreSize=True, state=uiconst.UI_DISABLED)
    278         self.sr.launcherBubbles = []
    279         for i in range(8):
    280             x = i * 14 + 26
    281             bubble = Sprite(parent=launcherTopContainer, pos=(x,
    282              7,
    283              14,
    284              16), useSizeFromTexture=True, align=uiconst.TOPRIGHT, state=uiconst.UI_DISABLED)
    285             self.sr.launcherBubbles.append(bubble)
    286 
    287     def Load(self, node):
    288         self.sr.node = node
    289         self.FillBubbles(self.sr.turretBubbles, node.get('turretSlotsUsed', 0), node.get('turretSlotCount', 0))
    290         self.FillBubbles(self.sr.launcherBubbles, node.get('launcherSlotsUsed', 0), node.get('launcherSlotCount', 0))
    291 
    292     def FillBubbles(self, bubbles, slotsUsed, slotCount):
    293         for i, bubble in enumerate(bubbles):
    294             if i < slotsUsed:
    295                 bubble.display = True
    296                 bubble.texturePath = 'res:/UI/Texture/classes/Fitting/slotTaken.png'
    297             elif i < slotCount:
    298                 bubble.display = True
    299                 bubble.texturePath = 'res:/UI/Texture/classes/Fitting/slotLeft.png'
    300             else:
    301                 bubble.display = False
    302 
    303     def GetHeight(self, *args):
    304         node, width = args
    305         node.height = 30
    306         return 30
    307 
    308     def LoadTooltipPanelForTurret(self, tooltipPanel, *args):
    309         turretsFitted = int(self.sr.node.get('turretSlotsUsed', 0))
    310         turretSlotsCount = int(self.sr.node.get('turretSlotCount', 0))
    311         counterText = GetByLabel('Tooltips/FittingWindow/TurretHardPointBubbles_description', hardpointsUsed=turretsFitted, hardpointsTotal=turretSlotsCount)
    312         return self.LoadTooltipPanelForTurretsAndLaunchers(tooltipPanel, const.attributeTurretSlotsLeft, counterText)
    313 
    314     def LoadTooltipPanelForLauncher(self, tooltipPanel, *args):
    315         turretsFitted = int(self.sr.node.get('launcherSlotsUsed', 0))
    316         turretSlotsCount = int(self.sr.node.get('launcherSlotCount', 0))
    317         counterText = GetByLabel('Tooltips/FittingWindow/LauncherHardPointBubbles_description', hardpointsUsed=turretsFitted, hardpointsTotal=turretSlotsCount)
    318         return self.LoadTooltipPanelForTurretsAndLaunchers(tooltipPanel, const.attributeLauncherSlotsLeft, counterText)
    319 
    320     def LoadTooltipPanelForTurretsAndLaunchers(self, tooltipPanel, attributeID, counterText):
    321         attribute = dogma.data.get_attribute(attributeID)
    322         headerText = GetByMessageID(attribute.tooltipTitleID)
    323         descriptionText = GetByMessageID(attribute.tooltipDescriptionID)
    324         tooltipPanel.LoadGeneric2ColumnTemplate()
    325         tooltipPanel.AddLabelMedium(text=headerText, bold=True)
    326         tooltipPanel.AddLabelMedium(text=counterText, bold=True, align=uiconst.TOPRIGHT, cellPadding=(20, 0, 0, 0))
    327         tooltipPanel.AddLabelMedium(text=descriptionText, wrapWidth=200, colSpan=tooltipPanel.columns, color=(0.6, 0.6, 0.6, 1))
    328 
    329     @classmethod
    330     def GetCopyData(cls, node):
    331         return '%s\t%s\n%s\t%s' % (dogma.data.get_attribute_display_name(const.attributeTurretSlotsLeft),
    332          node.get('turretSlotCount', 0),
    333          dogma.data.get_attribute_display_name(const.attributeLauncherSlotsLeft),
    334          node.get('launcherSlotCount', 0))