tryFit.py (11964B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fittingScreen\tryFit.py 2 from itertools import groupby 3 import blue 4 import evetypes 5 import log 6 from carbon.client.script.environment.AudioUtil import PlaySound 7 from carbonui import uiconst 8 from collections import defaultdict 9 from dogma.ammoloadingUtils import GetModuleCapacityForAmmoType 10 from eve.client.script.environment import invControllers as invCtrl 11 from eve.client.script.ui.shared.fitting.fittingUtil import RigFittingCheck 12 from eve.common.script.sys.idCheckers import IsStation, IsSolarSystem, flagCorpSAGs 13 from inventorycommon.const import flagFrigateEscapeBay 14 from inventorycommon.util import IsFittingModule, IsShipFittingFlag 15 from player_messaging.client.ui_message import prompt_player_fsd_dialog 16 from shipfitting.fittingStuff import GetSlotTypeForType 17 from utillib import KeyVal 18 FAKE_ITEM_GUID = ['listentry.GenericMarketItem', 19 'listentry.Item', 20 'uicls.GenericDraggableForTypeID', 21 'listentry.QuickbarItem', 22 'listentry.ContractItemSelect', 23 'listentry.FittingModuleEntry', 24 'listentry.KillItems'] 25 FAKE_ITEM_LOCATION_GUID = ['xtriui.ListSurroundingsBtn'] 26 27 class TryFitter(object): 28 29 def __init__(self): 30 self.ghostFittingSvc = sm.GetService('ghostFittingSvc') 31 32 def TryFit(self, realInvItems, fakeInvItems, controller, shipID = None): 33 if not shipID: 34 shipID = session.shipid 35 if not shipID: 36 return 37 invItems = realInvItems + fakeInvItems 38 dogmaLocation = controller.GetDogmaLocation() 39 charges, drones, fakeFighters, newInvItems = self.GetInvItemsToFit(invItems, controller) 40 if len(newInvItems) == 1: 41 invItem = invItems[0] 42 if self.IsShipOrStructure(invItem): 43 return GhostFitShip(invItem) 44 if not controller.IsSimulated() and not realInvItems and fakeInvItems: 45 self.ghostFittingSvc.LoadCurrentShip() 46 if len(newInvItems) > 0: 47 sourceID = getattr(newInvItems[0], 'locationID', None) 48 self.FitModule(shipID, sourceID, newInvItems, controller) 49 if drones: 50 self.AddDrones(drones, shipID, controller) 51 if fakeFighters: 52 self.AddSimulatedFighters(fakeFighters, shipID, controller) 53 if charges: 54 self.TryFitCharges(dogmaLocation, shipID, controller, charges) 55 56 def IsModuleSuitable(self, dogmaLocation, usedWith, module): 57 if not IsShipFittingFlag(module.flagID): 58 return False 59 if module.typeID not in usedWith: 60 return False 61 if self.IsWeaponBankSlave(dogmaLocation, module): 62 return False 63 if self.IsCharge(module): 64 return False 65 return True 66 67 def IsCharge(self, row): 68 return row.categoryID == const.categoryCharge 69 70 def IsWeaponBankSlave(self, dogmaLocation, row): 71 return dogmaLocation.IsInWeaponBank(row.locationID, row.itemID) and dogmaLocation.IsModuleSlave(row.itemID, row.locationID) 72 73 def IsShipOrStructure(self, invItem): 74 categoryID = evetypes.GetCategoryID(invItem.typeID) 75 if categoryID in (const.categoryShip, const.categoryStructure): 76 return True 77 78 def GetInvItemsToFit(self, invItems, controller): 79 isSimulated = controller.IsSimulated() 80 if isSimulated: 81 useRigs = True 82 else: 83 useRigs = None 84 charges = [] 85 drones = [] 86 fakeFighters = [] 87 newInvItems = [] 88 subSystemGroupIDs = set() 89 for eachInvItem in invItems[:]: 90 categoryID = evetypes.GetCategoryID(eachInvItem.typeID) 91 if IsFittingModule(categoryID): 92 slotEffect = GetSlotTypeForType(eachInvItem.typeID) 93 if slotEffect == const.effectRigSlot: 94 if useRigs is None: 95 useRigs = RigFittingCheck(eachInvItem, controller.GetTypeID()) 96 if useRigs: 97 newInvItems.append(eachInvItem) 98 continue 99 if categoryID == const.categorySubSystem: 100 if eachInvItem.groupID not in subSystemGroupIDs: 101 subSystemGroupIDs.add(eachInvItem.groupID) 102 newInvItems.append(eachInvItem) 103 continue 104 elif categoryID == const.categoryCharge: 105 charges.append(eachInvItem) 106 continue 107 elif categoryID == const.categoryDrone: 108 drones.append(eachInvItem) 109 continue 110 elif isSimulated and categoryID == const.categoryFighter: 111 fakeFighters.append(eachInvItem) 112 continue 113 newInvItems.append(eachInvItem) 114 115 return (charges, 116 drones, 117 fakeFighters, 118 newInvItems) 119 120 def FitModule(self, shipID, sourceID, invItems, controller): 121 PlaySound(uiconst.SOUND_ADD_OR_USE) 122 if controller.IsSimulated(): 123 sortedInvItems = sorted(invItems, key=lambda x: x.typeID) 124 for each in sortedInvItems: 125 self.ghostFittingSvc.TryFitModuleToOneSlot(each.typeID, feedbackTimeOut=True, originalItemID=getattr(each, 'itemID', None)) 126 127 else: 128 itemIDs = [ invItem.itemID for invItem in invItems ] 129 shipInv = sm.GetService('invCache').GetInventoryFromId(shipID, locationID=session.stationid) 130 shipInv.moniker.MultiAdd(itemIDs, sourceID, flag=const.flagAutoFit) 131 132 def TryFitCharges(self, dogmaLocation, shipID, controller, charges): 133 if controller.IsSimulated(): 134 return self.TryFitGhostCharges(charges) 135 loadResults = None 136 infoSvc = sm.GetService('info') 137 sortKey = lambda charge: charge.typeID 138 loadedModules = set() 139 for chargeTypeID, chargeItems in groupby(sorted(charges, key=sortKey), sortKey): 140 usedWith = infoSvc.GetUsedWithTypeIDs(chargeTypeID) 141 if usedWith is None: 142 continue 143 try: 144 dogmaLocation.CheckSkillRequirementsForType(None, chargeTypeID, 'FittingHasSkillPrerequisites') 145 except UserError as e: 146 loadResults = e 147 continue 148 149 chargeItems = list(chargeItems) 150 availableRounds = sum((c.stacksize for c in chargeItems)) 151 isCrystalOrScript = evetypes.GetGroupID(chargeTypeID) in cfg.GetCrystalGroups() 152 fittedItems = dogmaLocation.GetFittedItemsToShip().values() 153 fittedItems = sorted(fittedItems, key=lambda x: getattr(x, 'flagID', None)) 154 suitableModules = set() 155 for moduleItem in fittedItems: 156 if availableRounds <= 0: 157 break 158 if moduleItem.itemID in loadedModules: 159 continue 160 if not self.IsModuleSuitable(dogmaLocation, usedWith, moduleItem): 161 continue 162 if isCrystalOrScript: 163 if len([ i for i in fittedItems if i.flagID == moduleItem.flagID if i.itemID != moduleItem.itemID ]): 164 continue 165 availableRounds -= 1 166 else: 167 subLocation = dogmaLocation.GetSubLocation(shipID, moduleItem.flagID) 168 if subLocation is not None and subLocation[2] != chargeTypeID: 169 continue 170 neededRounds = GetModuleCapacityForAmmoType(moduleItem.typeID, chargeTypeID, dogmaLocation.dogmaStaticMgr) 171 if subLocation is not None: 172 neededRounds -= dogmaLocation.GetQuantity(subLocation) 173 if neededRounds <= 0: 174 continue 175 availableRounds -= neededRounds 176 suitableModules.add(moduleItem.itemID) 177 178 if len(suitableModules): 179 try: 180 dogmaLocation.LoadAmmoToModules(shipID, suitableModules, [ c.itemID for c in chargeItems ], chargeItems[0].locationID) 181 loadResults = True 182 loadedModules.update(suitableModules) 183 except Exception as e: 184 loadResults = e 185 186 blue.pyos.synchro.SleepSim(50) 187 188 if isinstance(loadResults, UserError): 189 raise loadResults 190 elif not loadedModules: 191 prompt_player_fsd_dialog('NoSuitableModules') 192 193 def TryFitGhostCharges(self, charges): 194 chargeTypeIDs = {x.typeID for x in charges} 195 self.ghostFittingSvc.TryFitFakeAmmoToAllModulesFitted(chargeTypeIDs) 196 197 def AddDrones(self, drones, shipID, controller): 198 if controller.IsSimulated(): 199 qtyByTypeAndItemID = defaultdict(int) 200 for eachDrone in drones: 201 qtyByTypeAndItemID[eachDrone.typeID, eachDrone.itemID] += 1 202 203 self.ghostFittingSvc.TryFitDronesToDroneBay(qtyByTypeAndItemID) 204 else: 205 invCtrl.ShipDroneBay(shipID).AddItems(drones) 206 207 def AddSimulatedFighters(self, fighters, shipID, controller): 208 if not controller.IsSimulated(): 209 return 210 qtyByTypeID = defaultdict(int) 211 for eachFighter in fighters: 212 qtyByTypeID[eachFighter.typeID] += getattr(eachFighter, 'stacksize', None) or 1 213 214 self.ghostFittingSvc.TryFitFightersToTubeOrBay(qtyByTypeID) 215 216 217 def GhostFitShip(invItem): 218 shipTypeID = invItem.typeID 219 fitData = [] 220 oringalItemIDByFlagAndTypeID = {} 221 itemID = getattr(invItem, 'itemID', None) 222 if itemID: 223 dockableLocationID, solarSystemID, ownerID = _GetOwnerAndLocationID(invItem) 224 if (dockableLocationID or solarSystemID) and ownerID in (session.charid, session.corpid): 225 try: 226 fitData, oringalItemIDByFlagAndTypeID = sm.GetService('fittingSvc').FittingDictForRemoteShip(itemID, putModuleAmmoInCargo=True, dockableLocationID=dockableLocationID, solarSystemID=solarSystemID) 227 except Exception as e: 228 if isinstance(e, UserError) and e.msg == 'InventoryStopSpamming': 229 raise 230 log.LogWarn('Tryfit - failed to get fitdata, e = ', e) 231 232 fitting = KeyVal(shipTypeID=shipTypeID, fittingID=None, ownerID=None, fitData=fitData) 233 sm.GetService('ghostFittingSvc').SimulateFitting(fitting, oringalItemIDByFlagAndTypeID) 234 235 236 def _GetOwnerAndLocationID(invItem): 237 dockableLocationID = getattr(invItem, 'locationID', None) 238 solarSystemID = None 239 ownerID = getattr(invItem, 'ownerID', None) 240 item = getattr(invItem, 'item', invItem) 241 if ownerID is None and item: 242 ownerID = getattr(item, 'ownerID', None) 243 if dockableLocationID is None and item: 244 dockableLocationID = getattr(item, 'locationID', None) 245 if item and item.flagID in (const.flagCargo, const.flagShipHangar, flagFrigateEscapeBay): 246 parentShipInfo = GetParentShipInfo(item) 247 if parentShipInfo: 248 dockableLocationID, solarSystemID = parentShipInfo 249 elif ownerID == session.corpid and item and item.flagID in flagCorpSAGs: 250 for office in sm.GetService('officeManager').GetMyCorporationsOffices(): 251 if office.officeID == dockableLocationID: 252 dockableLocationID = office.stationID 253 break 254 255 return (dockableLocationID, solarSystemID, ownerID) 256 257 258 def GetParentShipInfo(item): 259 parentShip = sm.GetService('invCache').GetInventoryFromId(item.locationID).GetItem() 260 if not parentShip: 261 return 262 dockableLocationID = solarSystemID = None 263 itemLocation = parentShip.locationID 264 if IsStation(itemLocation): 265 dockableLocationID = itemLocation 266 elif IsSolarSystem(itemLocation): 267 dockableLocationID = None 268 solarSystemID = itemLocation 269 elif sm.GetService('structureDirectory').GetStructureInfo(itemLocation) is not None: 270 dockableLocationID = itemLocation 271 return (dockableLocationID, solarSystemID)