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

fighterPickerMenu.py (15332B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fittingScreen\fighterPickerMenu.py
      2 import carbonui.const as uiconst
      3 import evetypes
      4 import fighters
      5 import gametime
      6 from carbonui.control.buttonIcon import ButtonIcon
      7 from carbonui.primitives.container import Container
      8 from carbonui.primitives.frame import Frame
      9 from carbonui.primitives.sprite import Sprite
     10 from carbonui.util.color import Color
     11 from collections import defaultdict
     12 from eve.client.script.ui.inflight.squadrons.fighterInvCont import SquadronLightContainer, SquadronSupportContainer, SquadronHeavyContainer
     13 from eve.client.script.ui.inflight.squadrons.squadronCont import SquadronContEmpty, SquadronCont
     14 from eve.client.script.ui.inflight.squadrons.squadronsUI import SQUADRON_WIDTH
     15 from eve.client.script.ui.shared.fitting.fittingUtil import EatSignalChangingErrors
     16 from eve.client.script.ui.shared.fittingScreen.itemPickerMenu import ItemPickerBase, BaseHoldItemPickerMenu
     17 from eve.client.script.ui.shared.fittingScreen.skillRequirements import GetMissingSkills_HighestLevelByTypeID
     18 from eve.client.script.ui.shared.fittingScreen.tryFit import FAKE_ITEM_GUID, FAKE_ITEM_LOCATION_GUID
     19 from eve.common.script.mgt.fighterConst import COLOR_OPEN
     20 from fighters import GetMaxSquadronSize
     21 from fighters.client import GetFighterTubesForShipAndDogmaLocation, GetLightSupportHeavySlotsForShipAndDogmaLocation, GetSquadronTypes
     22 from shipfitting.fittingDogmaLocationUtil import GetFittingItemDragData
     23 from shipfitting.fittingWarnings import GetColorForLevel
     24 from signals.signalUtil import ChangeSignalConnect
     25 
     26 class ItemFighterPicker(ItemPickerBase):
     27     __guid__ = 'listentry.ItemFighterPicker'
     28 
     29     def OnDblClick(self, *args):
     30         data = self.sr.node
     31         sm.GetService('ghostFittingSvc').FitFighterToEmptyTube(data.typeID)
     32 
     33     def OnDropData(self, dragObj, nodes):
     34         self.sr.node.onDroppedInListFunc(nodes)
     35 
     36 
     37 class FighterBayItemPickerMenu(BaseHoldItemPickerMenu):
     38     entryClass = ItemFighterPicker
     39     flagID = const.flagFighterBay
     40     emptyLabelPath = 'UI/Fitting/FittingWindow/NoFightersSimulated'
     41 
     42     def __init__(self, controller, menuParent):
     43         self.squadrons = []
     44         self.fightersAllowedCont = Container(name='fightersAllowedCont', parent=menuParent, align=uiconst.TOTOP, height=20, padTop=10)
     45         self.tubeCont = Container(name='tubeCont', parent=menuParent, align=uiconst.TOTOP, height=116, padLeft=4)
     46         BaseHoldItemPickerMenu.__init__(self, controller, menuParent)
     47         self.controller = controller
     48         self.AddTubeConts()
     49         self.LoadFighters()
     50         self.AddFighterAllowed()
     51         self.initDone = True
     52         self.UpdateSquadronTypes()
     53         self.ChangeSignalConnection(connect=True)
     54 
     55     def ChangeSignalConnection(self, connect = True):
     56         signalAndCallback = [(self.controller.on_stats_changed, self.UpdateNumbers), (self.controller.on_slots_updated, self.OnSlotsUpdated), (self.controller.on_warning_display_changed, self.HiliteProblematicEntries)]
     57         ChangeSignalConnect(signalAndCallback, connect)
     58 
     59     def DisconnectController(self):
     60         with EatSignalChangingErrors(errorMsg='FighterBayItemPickerMenu'):
     61             self.ChangeSignalConnection(connect=False)
     62         self.controller = False
     63 
     64     def GetExtraDataForType(self, itemIDs, activeItemsSet, typeID):
     65         return {'onDroppedInListFunc': self.OnDroppedInList}
     66 
     67     def GetNoItemDropFunc(self):
     68         return self.GetExtraDataForType(None, None, None)
     69 
     70     def OnDroppedInList(self, nodes):
     71         self._TryRemoveItemsFromTube(nodes)
     72         self._TryAddToFighterBay(nodes)
     73         self.ghostFittingSvc.SendFittingSlotsChangedEvent()
     74         self.ghostFittingSvc.SendOnStatsUpdatedEvent()
     75         self.LoadItemScroll()
     76 
     77     def _TryRemoveItemsFromTube(self, nodes):
     78         for eachNode in nodes:
     79             itemKey = getattr(eachNode, 'itemID', None)
     80             if itemKey is None:
     81                 continue
     82             currentFlag = getattr(eachNode, 'flagID', None)
     83             if currentFlag in const.fighterTubeFlags:
     84                 self.ghostFittingSvc.UnfitModule(itemKey, scatter=False)
     85 
     86     def _TryAddToFighterBay(self, nodes):
     87         qtyByTypeIDs = defaultdict(int)
     88         for eachNode in nodes:
     89             typeID = getattr(eachNode.rec, 'typeID', None)
     90             if typeID and evetypes.GetCategoryID(typeID) == const.categoryFighter:
     91                 stacksize = getattr(eachNode.rec, 'stacksize', 1)
     92                 qtyByTypeIDs[typeID] += stacksize
     93 
     94         if qtyByTypeIDs:
     95             self.ghostFittingSvc.TryFitItemsToFighterBay(qtyByTypeIDs)
     96 
     97     def OnSlotsUpdated(self):
     98         self.LoadFighters()
     99         self.LoadItemScroll()
    100 
    101     def UpdateNumbers(self):
    102         self.UpdateSquadronTypes()
    103 
    104     def AddFighterAllowed(self):
    105         self.lightSquadrons = SquadronLightContainer(parent=self.fightersAllowedCont, left=2)
    106         self.supportSquadrons = SquadronSupportContainer(parent=self.fightersAllowedCont, left=12)
    107         self.heavySquadrons = SquadronHeavyContainer(parent=self.fightersAllowedCont, left=12)
    108         self.ConstructSquadronTypes()
    109 
    110     def AddTubeConts(self):
    111         self.tubeCont.Flush()
    112         shipID = self.fittingDogmaLocation.GetCurrentShipID()
    113         numOfTubes = GetFighterTubesForShipAndDogmaLocation(shipID, self.fittingDogmaLocation)
    114         for i, tubeFlagID in enumerate(const.fighterTubeFlags):
    115             squadron = SingleTube(parent=self.tubeCont, tubeFlagID=tubeFlagID, dogmaLocation=self.fittingDogmaLocation, left=2)
    116             self.squadrons.append(squadron)
    117             if i >= numOfTubes:
    118                 squadron.SetAsDisabled()
    119 
    120     def LoadFighters(self):
    121         for eachSquadron in self.squadrons:
    122             eachSquadron.LoadFighterInfo()
    123 
    124         self.UpdateSquadronTypes()
    125 
    126     def GetEntryWidth(self, *args):
    127         return 454
    128 
    129     def ConstructSquadronTypes(self):
    130         light, support, heavy = GetLightSupportHeavySlotsForShipAndDogmaLocation(self.fittingDogmaLocation, self.fittingDogmaLocation.GetActiveShipID())
    131         contAndNumSlosts = [(self.heavySquadrons, heavy), (self.supportSquadrons, support), (self.lightSquadrons, light)]
    132         for cont, numSlots in contAndNumSlosts:
    133             cont.SetTotalSlots(numSlots)
    134             cont.display = bool(numSlots)
    135 
    136     def UpdateSquadronTypes(self):
    137         if getattr(self, 'initDone', False):
    138             heavy, support, light = GetSquadronTypes(self.fittingDogmaLocation.GetFighterNumByTypeIDsInTubes())
    139             self.heavySquadrons.SetUsedSlots(heavy)
    140             self.supportSquadrons.SetUsedSlots(support)
    141             self.lightSquadrons.SetUsedSlots(light)
    142 
    143     def RemoveAll(self, *args):
    144         BaseHoldItemPickerMenu.RemoveAll(self, *args)
    145         ghostFittingSvc = sm.GetService('ghostFittingSvc')
    146         for eachTubeID in const.fighterTubeFlags:
    147             fightersInfo = self.fittingDogmaLocation.GetFightersInTubeInfo(eachTubeID)
    148             if fightersInfo:
    149                 ghostFittingSvc.UnfitModule(fightersInfo.itemID, scatter=False)
    150 
    151         ghostFittingSvc.SendFittingSlotsChangedEvent()
    152         ghostFittingSvc.SendOnStatsUpdatedEvent()
    153         self.LoadItemScroll()
    154 
    155     def DoShowBtnWhenScollIsEmpty(self):
    156         heavy, support, light = GetSquadronTypes(self.fittingDogmaLocation.GetFighterNumByTypeIDsInTubes())
    157         return bool(heavy + support + light)
    158 
    159     def UpdateProblematicFigtersInTubes(self, warningSlotDict):
    160         allTypeIDsInTubes = {x.fighterTypeID for x in self.squadrons}
    161         _, typeIDsMissingSkills = GetMissingSkills_HighestLevelByTypeID(allTypeIDsInTubes)
    162         for eachFighter in self.squadrons:
    163             func = getattr(eachFighter, 'SetFittingWarningColor', None)
    164             if not func:
    165                 continue
    166             warningLevelForFighter = warningSlotDict.get(eachFighter.tubeFlagID)
    167             color = GetColorForLevel(warningLevelForFighter)
    168             if eachFighter.fighterTypeID in typeIDsMissingSkills:
    169                 func(color)
    170             else:
    171                 func(None)
    172 
    173     def HiliteProblematicEntries(self, warningSlotDict):
    174         self.UpdateProblematicFigtersInTubes(warningSlotDict)
    175         warningLevel = warningSlotDict.get(self.flagID, None)
    176         self.UpdateProblematicEntries(warningLevel)
    177 
    178 
    179 class SingleTube(Container):
    180     default_width = SQUADRON_WIDTH + 6
    181     default_height = 116
    182     default_name = 'singleTube'
    183     default_align = uiconst.TOLEFT
    184 
    185     def ApplyAttributes(self, attributes):
    186         Container.ApplyAttributes(self, attributes)
    187         self.tubeFlagID = attributes.tubeFlagID
    188         self.fittingWarning = None
    189         self.fighterTypeID = None
    190         self.fighterID = None
    191         self.fittingDogmaLocation = attributes.dogmaLocation
    192         tubeController = SimulatedSquadronController()
    193         self.squadronCont = SimulatedSquadronCont(parent=self, controller=tubeController, align=uiconst.TOPLEFT, tubeFlagID=self.tubeFlagID, state=uiconst.UI_NORMAL, doDamageUpdates=False)
    194         self.squadronCont.isDragObject = True
    195         self.squadronCont.GetDragData = self.GetSquadronDragData
    196         self.squadronCont.tooltipIdentifier = 'SimulatedFighterTooltip'
    197         self.squadronCont.GetMenu = self.GetSquadronMenu
    198         self.squadronContEmpty = SimulatedSquadronContEmpty(parent=self, controller=tubeController, fighterID=self.fighterID, fighterTypeID=self.fighterTypeID, align=uiconst.BOTTOMLEFT, tubeFlagID=self.tubeFlagID)
    199         self.squadronCont.OnDropData = self.OnDropDataOnTube
    200         self.squadronContEmpty.OnDropData = self.OnDropDataOnTube
    201         self.frame = Frame(parent=self, texturePath='res:/UI/Texture/classes/CarrierBay/simulateTube3.png')
    202         self.frame.SetRGBA(*COLOR_OPEN)
    203         self.btnCont = Container(name='btnCont', parent=self.squadronCont, align=uiconst.TOBOTTOM_NOPUSH, height=24, idx=0)
    204         self.addFighterBtn = ButtonIcon(name='removeFighterBtn', parent=self.btnCont, align=uiconst.CENTERTOP, pos=(-10, 0, 16, 16), iconSize=10, texturePath='res:/ui/texture/classes/shipui/minus.png', func=self.RemoveFighter)
    205         self.removeFighterBtn = ButtonIcon(name='addFighterBtn', parent=self.btnCont, align=uiconst.CENTERTOP, pos=(10, 0, 16, 16), iconSize=10, texturePath='res:/ui/texture/classes/shipui/plus.png', func=self.AddFighter)
    206 
    207     def SetFittingWarningColor(self, color):
    208         if color is None:
    209             if self.fittingWarning:
    210                 self.fittingWarning.display = False
    211         else:
    212             self.ConstructFittingWarning()
    213             self.fittingWarning.display = True
    214             self.fittingWarning.SetRGBA(*color)
    215 
    216     def ConstructFittingWarning(self):
    217         if self.fittingWarning and not self.fittingWarning.destroyed:
    218             return
    219         self.fittingWarning = Sprite(parent=self, name='fittingWarning', state=uiconst.UI_DISABLED, align=uiconst.BOTTOMLEFT, pos=(4, 40, 16, 16), texturePath='res:/UI/Texture/classes/Fitting/slotWarningIcon.png', idx=0)
    220 
    221     def GetSquadronMenu(self, *args):
    222         return sm.GetService('menu').GetMenuFromItemIDTypeID(self.fighterID, self.fighterTypeID, includeMarketDetails=True)
    223 
    224     def RemoveFighter(self, *args):
    225         return self.ChangeNumFighters(-1)
    226 
    227     def AddFighter(self, *args):
    228         return self.ChangeNumFighters(1)
    229 
    230     def ChangeNumFighters(self, change):
    231         fightersInfo = self.fittingDogmaLocation.GetFightersInTubeInfo(self.tubeFlagID)
    232         if not fightersInfo:
    233             return
    234         squadronSize = fightersInfo.squadronSize
    235         wanted = max(0, squadronSize + change)
    236         sm.GetService('ghostFittingSvc').ModifyFighterStackSize(fightersInfo.typeID, wanted, self.tubeFlagID)
    237         self.UpdateUI()
    238 
    239     def LoadFighterInfo(self):
    240         fightersInfo = self.fittingDogmaLocation.GetFightersInTubeInfo(self.tubeFlagID)
    241         if fightersInfo:
    242             squadronSize = fightersInfo.squadronSize
    243             self.fighterTypeID = fightersInfo.typeID
    244             self.fighterID = fightersInfo.itemID
    245             self.squadronCont.SetNewSquadron(self.fighterID, self.fighterTypeID, squadronSize)
    246             self.HideEmpty()
    247         else:
    248             self.fighterID = None
    249             self.fighterTypeID = None
    250             self.ShowEmpty()
    251 
    252     def ShowEmpty(self):
    253         self.squadronContEmpty.display = True
    254         self.squadronCont.display = False
    255 
    256     def HideEmpty(self):
    257         self.squadronContEmpty.display = False
    258         self.squadronCont.display = True
    259 
    260     def OnDropData(self, dragSource, nodes):
    261         return self.OnDropDataOnTube(dragSource, nodes)
    262 
    263     def GetSquadronDragData(self):
    264         return GetFittingItemDragData(self.fighterID, self.fittingDogmaLocation)
    265 
    266     def OnDropDataOnTube(self, dragSource, nodes):
    267         recs = []
    268         fakeRecs = []
    269         for node in nodes:
    270             if getattr(node, 'rec', None):
    271                 recs.append(node.rec)
    272             elif node.__guid__ in FAKE_ITEM_GUID:
    273                 fakeRecs.append(node)
    274             elif node.__guid__ in FAKE_ITEM_LOCATION_GUID and getattr(node, 'typeID', None):
    275                 if evetypes.GetCategoryID(node.typeID) == const.categoryStructure:
    276                     fakeRecs.append(node)
    277 
    278         for each in fakeRecs + recs:
    279             typeID = each.typeID
    280             sm.GetService('ghostFittingSvc').FitFighterToTube(typeID, self.tubeFlagID, qty=GetMaxSquadronSize(typeID))
    281 
    282         self.UpdateUI()
    283 
    284     def SetAsDisabled(self):
    285         self.squadronContEmpty.actionLabel.text = ''
    286         self.Disable()
    287         self.opacity = 0.3
    288 
    289     def UpdateUI(self):
    290         self.LoadFighterInfo()
    291 
    292 
    293 class SimulatedSquadronCont(SquadronCont):
    294 
    295     def ApplyAttributes(self, attributes):
    296         SquadronCont.ApplyAttributes(self, attributes)
    297         self.removeSquadronBtn = ButtonIcon(name='removeSquadronBtn', parent=self, align=uiconst.TOPRIGHT, pos=(2, 2, 16, 16), iconSize=16, texturePath='res:/UI/Texture/Icons/73_16_210.png', func=self.RemoveSquadron)
    298 
    299     def RemoveSquadron(self, *args):
    300         if self.fighterItemID:
    301             sm.GetService('ghostFittingSvc').UnfitModule(self.fighterItemID)
    302 
    303 
    304 class SimulatedSquadronContEmpty(SquadronContEmpty):
    305 
    306     def ApplyAttributes(self, attributes):
    307         SquadronContEmpty.ApplyAttributes(self, attributes)
    308         self.fighterCont.OnDropData = self.parent.OnDropData
    309 
    310 
    311 class SimulatedSquadronController(object):
    312 
    313     def __init__(self):
    314         pass
    315 
    316     def GetSquadronVelocity(self, tubeFlagID):
    317         return None
    318 
    319     def GetSquadronDistance(self, tubeFlagID):
    320         return None
    321 
    322     def GetSquadronBallInfo(self, tubeFlagID):
    323         return None
    324 
    325     def GetFightersBall(self, fightersItemID):
    326         return None
    327 
    328     def GetTimeNow(self):
    329         return gametime.GetSimTime()
    330 
    331     def GetFightersInSpaceItemID(self, tubeFlagID):
    332         return None
    333 
    334     def GetIsInSpace(self, tubeFlagID):
    335         return False
    336 
    337     def GetSquadronAction(self, tubeFlagID):
    338         stateText = 'UI/Fitting/FittingWindow/FightersSimulated'
    339         stateColor = Color(*COLOR_OPEN)
    340         stateColor.a = 0.8
    341         return (stateText, stateColor)
    342 
    343     def GetAbilities(self, fighterTypeID):
    344         if fighterTypeID:
    345             abilities = fighters.IterTypeAbilities(fighterTypeID)
    346             return abilities
    347 
    348     def GetIncomingEwarEffects(self, fighterID):
    349         return []