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 []