fittingSlotController.py (12103B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fittingScreen\fittingSlotController.py 2 import carbonui.const as uiconst 3 import dogma.data as dogma_data 4 import eveicon 5 import evetypes 6 import uthread 7 from carbonui.control.contextMenu.menuEntryData import MenuEntryData 8 from carbonui.control.dragdrop.dragdata import TypeDragData 9 from menu import MenuLabel 10 from carbonui.uicore import uicore 11 from eve.client.script.ui.shared.fitting.fittingSlotController import FittingSlotController 12 from eve.client.script.ui.shared.fitting.fittingUtil import RigFittingCheck, IsCharge 13 from eve.client.script.ui.shared.fittingScreen import OFFLINE, ONLINE, ACTIVE, OVERHEATED, fittingSignals 14 from eve.client.script.ui.shared.fittingScreen.fittingUtil import GetOriginalItemID 15 from eve.common.script.sys.eveCfg import IsDocked 16 from localization import GetByLabel 17 from menu import MenuLabel 18 from player_messaging.client.ui_message import prompt_player_fsd_dialog 19 from shipfitting.errorConst import WRONG_SLOT 20 from shipfitting.fittingStuff import IsRightSlotForType, IsFittable 21 from utillib import KeyVal 22 23 class ShipFittingSlotController(FittingSlotController): 24 25 def __init__(self, flagID, parentController): 26 FittingSlotController.__init__(self, flagID, parentController) 27 28 def GetModule(self): 29 if self.IsModulePreviewModule(): 30 return None 31 return self.dogmaModuleItem 32 33 def GetModuleOrPreview(self): 34 return self.dogmaModuleItem 35 36 def IsModulePreviewModule(self): 37 if not self.dogmaModuleItem: 38 return False 39 if getattr(self.dogmaModuleItem, 'isPreviewItem', False): 40 return True 41 return False 42 43 def Add(self, item, sourceLocation = None): 44 if self.IsSimulated(): 45 return self.AddSimulatedItem(item) 46 else: 47 guid = getattr(item, '__guid__', None) 48 if guid is None and item.itemID or guid in ('listentry.InvItem', 'xtriui.InvItem'): 49 return self.AddRealItem(item) 50 sm.GetService('ghostFittingSvc').LoadCurrentShip() 51 return self.AddSimulatedItem(item) 52 53 def AddSimulatedItem(self, item): 54 ghostFittingSvc = sm.GetService('ghostFittingSvc') 55 if not IsRightSlotForType(self.dogmaLocation.dogmaStaticMgr, item.typeID, self.flagID): 56 ghostFittingSvc.SendOnFeedbackTextChanged(KeyVal(errorKey=WRONG_SLOT, extraInfo=None), timeout=True) 57 return 58 shipID = self.GetParentID() 59 wasUnfitted = self._TryUnfitModule(ghostFittingSvc, item) 60 originalItemID = GetOriginalItemID(item.itemID) 61 dogmaItem, errorInfo = ghostFittingSvc.FitModuleToShipAndChangeState(shipID, self.GetFlagID(), item.typeID, originalItemID=originalItemID) 62 if dogmaItem: 63 ghostFittingSvc.SendFittingSlotsChangedEvent() 64 else: 65 flagID = getattr(item, 'flagID', None) 66 if wasUnfitted and flagID: 67 ghostFittingSvc.FitModuleToShipAndChangeState(shipID, flagID, item.typeID, originalItemID=originalItemID) 68 ghostFittingSvc.SendOnFeedbackTextChanged(errorInfo, timeout=True) 69 70 def _TryUnfitModule(self, ghostFittingSvc, item): 71 itemID = getattr(item, 'itemID', None) 72 wasFitted = getattr(item, 'isFitted', False) 73 if wasFitted and itemID and not uicore.uilib.Key(uiconst.VK_SHIFT): 74 return sm.GetService('ghostFittingSvc').UnfitModule(itemID) 75 76 def AddRealItem(self, item): 77 if not getattr(item, 'typeID', None): 78 return 79 if not RigFittingCheck(item, self.parentController.GetTypeID()): 80 return 81 validFitting = False 82 shift = uicore.uilib.Key(uiconst.VK_SHIFT) 83 for effect in dogma_data.get_type_effects(item.typeID): 84 if not IsFittable(effect.effectID): 85 continue 86 validFitting = True 87 if effect.effectID == self.GetPowerType(): 88 isFitted = item.locationID == self.GetParentID() and item.flagID != const.flagCargo 89 if isFitted and shift and self.GetModule(): 90 if self.GetModule().typeID == item.typeID: 91 self.LinkWithWeapon(item) 92 return 93 else: 94 prompt_player_fsd_dialog('CustomNotify', {'notify': GetByLabel('UI/Fitting/GroupingIncompatible')}) 95 return 96 self.FitModule(item) 97 return 98 msgDict = {'item': evetypes.GetName(item.typeID), 99 'slotpower': dogma_data.get_effect_display_name(self.GetPowerType()), 100 'itempower': dogma_data.get_effect_display_name(effect.effectID)} 101 prompt_player_fsd_dialog('ItemDoesntFitPower', msgDict) 102 103 if not validFitting: 104 raise UserError('ItemNotHardware', {'itemname': item.typeID}) 105 106 def OnDropData(self, dragObj, nodes): 107 if self.GetModule() is not None and not self.SlotExists(): 108 return 109 items, fakeItems = self.GetDroppedItems(nodes) 110 allItems = items + fakeItems 111 chargeTypeID = None 112 chargeItems = [] 113 for item in allItems: 114 if not getattr(item, 'typeID', None): 115 return 116 if IsCharge(item.typeID): 117 if self.IsChargeable(): 118 if chargeTypeID is None: 119 chargeTypeID = item.typeID 120 if chargeTypeID == item.typeID: 121 chargeItems.append(item) 122 else: 123 uthread.new(self.Add, item) 124 125 if len(chargeItems): 126 if fakeItems and not self.IsSimulated(): 127 sm.GetService('ghostFittingSvc').LoadCurrentShip() 128 self.FitCharges(chargeItems) 129 130 def GetDroppedItems(self, nodes): 131 items = [] 132 fakeItems = [] 133 for node in nodes: 134 guid = getattr(node, '__guid__', None) 135 if guid in ('listentry.InvItem', 'xtriui.InvItem'): 136 invType = node.rec 137 if self.IsFittableType(invType.typeID): 138 items.append(invType) 139 elif guid in ('listentry.GenericMarketItem', 'listentry.Item', 'listentry.FittingModuleEntry') or isinstance(node, TypeDragData): 140 if self.IsFittableType(node.typeID): 141 fakeItems.append(KeyVal(typeID=node.typeID, itemID=getattr(node, 'itemID', None), isFitted=getattr(node, 'isFitted', False), flagID=getattr(node, 'flagID', None))) 142 143 return (items, fakeItems) 144 145 def GetMenu(self, slot): 146 m = [] 147 flagID = self.GetFlagID() 148 if flagID in const.moduleSlotFlags + const.rigSlotFlags: 149 m += [(MenuLabel('UI/Fitting/FittingWindow/SetFiltersForSlot'), sm.ScatterEvent, ('OnFittingFlagFilterSet', flagID))] 150 typeID = self.GetModuleTypeID() 151 if typeID and self.GetModuleID(): 152 m += [MenuEntryData(MenuLabel('UI/Fitting/FittingWindow/FindTypeInBrowser'), lambda : fittingSignals.on_find_type_in_browser(typeID), texturePath=eveicon.search)] 153 sm.GetService('marketutils').AddMarketDetailsMenuOption(m, typeID) 154 m += self.GetGroupMenu() 155 elif self.GetFailedTypeID(): 156 m += [(MenuLabel('UI/Fitting/FittingWindow/ClearSlot'), self.ClearFailedSlot, (slot,))] 157 return m 158 159 def ClearFailedSlot(self, slot): 160 self.SetFailedTypeID(None) 161 self.UpdateStatusDisplay(slot) 162 163 def _GetUnfitOption(self): 164 return [MenuEntryData(MenuLabel('UI/Fitting/Unfit'), self.Unfit, texturePath=eveicon.close)] 165 166 def GetGroupMenu(self, *args): 167 masterID = self.IsInWeaponBank() 168 if masterID: 169 return [(MenuLabel('UI/Fitting/ClearGroup'), self.DestroyWeaponBank, ())] 170 return [] 171 172 def OnClick(self, slot): 173 if self.GetModule() is None: 174 flagID = self.GetFlagID() 175 if flagID in const.moduleSlotFlags + const.rigSlotFlags: 176 sm.ScatterEvent('OnFittingFlagFilterSet', flagID) 177 return 178 if self.IsSimulated(): 179 return self.OnClickSimulated(slot) 180 if not self._ShouldContinueAfterOfflineWarning(): 181 return 182 self.ToggleOnlineModule() 183 184 def _ShouldContinueAfterOfflineWarning(self): 185 if not self.IsOnlineable(): 186 return False 187 if IsDocked(): 188 return True 189 if not self.IsOnline(): 190 return True 191 if prompt_player_fsd_dialog('PutOffline', {}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES: 192 return True 193 return False 194 195 def OnClickSimulated(self, slot): 196 if self.GetModule() is None: 197 return 198 typeID = self.GetModuleTypeID() 199 itemKey = self.GetModuleID() 200 flagID = self.GetFlagID() 201 ghostFittingSvc = sm.GetService('ghostFittingSvc') 202 if flagID not in const.rigSlotFlags and not self.IsOnlineable(): 203 if self.IsOnline(): 204 ghostFittingSvc.OfflineSlotList([flagID]) 205 else: 206 ghostFittingSvc.SwitchBetweenModes(itemKey, typeID, flagID) 207 self.UpdateStatusDisplay(slot) 208 209 def UpdateStatusDisplay(self, slot): 210 slot.SetIconNotAsPreview() 211 if not self.IsSimulated(): 212 slot.HideModuleSlotFill() 213 slot.ChangeWarningDisplay(False) 214 return 215 ghostFittingSvc = sm.GetService('ghostFittingSvc') 216 itemKey = self.GetModuleID() 217 typeID = self.GetModuleTypeID() 218 flagID = self.GetFlagID() 219 slot.ChangeWarningDisplay(bool(self.GetFailedTypeID())) 220 if itemKey is None or typeID is None: 221 slot.HideModuleSlotFill() 222 return 223 if self.IsModulePreviewModule(): 224 slot.SetIconAsPreview() 225 typeEffectInfo = ghostFittingSvc.GetDefaultAndOverheatEffect(typeID) 226 currentStatus = ghostFittingSvc.GetModuleStatus(itemKey, typeID, flagID) 227 if currentStatus is None: 228 return 229 if typeEffectInfo.defaultEffect and typeEffectInfo.isActivatable: 230 if currentStatus == OVERHEATED: 231 slot.SetTexturePathForOverheated() 232 else: 233 slot.SetTexurePathForActivatable() 234 else: 235 slot.SetTexturePathForPassive() 236 if currentStatus == OFFLINE: 237 slot.SetStatusDisplayOffline() 238 elif currentStatus == ONLINE: 239 slot.SetStatusDisplayOnline() 240 elif currentStatus == ACTIVE: 241 slot.SetStatusDisplayActive() 242 elif currentStatus == OVERHEATED: 243 slot.SetStatusDisplayOverheated() 244 245 def ShowChargeInfo(self, *args): 246 if self.GetCharge(): 247 sm.GetService('info').ShowInfo(self.GetCharge().typeID, self.GetCharge().itemID) 248 249 def UpdateGhostFittingIcons(self, slot, invItem): 250 if not self.IsSimulated() or not invItem: 251 slot.HideGhostFittingElement() 252 253 def GetCpuAndPowergridUsage(self): 254 if not self.GetModuleID() or self.parentController is None: 255 return 256 cpu = self.dogmaLocation.GetAttributeValue(self.GetModuleID(), const.attributeCpu) 257 powergrid = self.dogmaLocation.GetAttributeValue(self.GetModuleID(), const.attributePower) 258 calibration = self.dogmaLocation.GetAttributeValue(self.GetModuleID(), const.attributeUpgradeCost) 259 self.parentController.OnPreviewCPU(cpu, powergrid, calibration) 260 261 def HideCpuAndPowergridUsage(self): 262 if self.parentController: 263 self.parentController.OnPreviewCPU(0, 0, 0) 264 265 def ToggleOnlineModule(self): 266 if not self.IsSimulated(): 267 return FittingSlotController.ToggleOnlineModule(self) 268 if self.IsOnline(): 269 newState = OFFLINE 270 else: 271 newState = ONLINE 272 ghostFittingSvc = sm.GetService('ghostFittingSvc') 273 ghostFittingSvc.PerformActionAndSetNewState(newState, self.GetModuleID(), self.GetModuleTypeID(), self.GetFlagID()) 274 ghostFittingSvc.SendFittingSlotsChangedEvent()