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

invItemFunctions.py (25628B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\services\menuSvcExtras\invItemFunctions.py
      2 import collections
      3 from collections import defaultdict
      4 import blue
      5 from carbon.client.script.environment.AudioUtil import PlaySound
      6 from carbon.common.script.net.moniker import Moniker
      7 from carbon.common.script.util.linkUtil import GetShowInfoLink
      8 from carbonui import uiconst
      9 from carbonui.uicore import uicore
     10 import uthread2
     11 import destiny
     12 from cosmetics.client.shipSkinApplicationSvc import get_ship_skin_application_svc
     13 from eve.client.script.ui.shared.neocom.corporation.corp_ui_votes import VoteWizardDialog
     14 from eve.client.script.ui.shared.neocom.ownerSearch import OwnerSearchWindow
     15 from eve.client.script.ui.shared.shipNameDialog import prompt_rename_ship
     16 from eve.common.lib import appConst as const
     17 from eve.common.script.sys import eveCfg, idCheckers
     18 from eve.common.script.sys.eveCfg import IsControllingStructure
     19 from eve.common.script.util import notificationconst
     20 from eveexceptions import UserError
     21 from eveexceptions.const import UE_TYPEIDL
     22 import evetypes
     23 from inventorycommon.util import IsModularShip
     24 from inventoryrestrictions import is_trashable, CANNOT_TRASH_ERROR
     25 from inventoryutil.client.inventory import get_hangar_inventory
     26 import localization
     27 import logging
     28 from eve.client.script.ui.util import uix
     29 from corporation import voting
     30 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     31 from shipprogression.boarding_moment.boardingMomentSvc import GetBoardingMomentService
     32 logger = logging.getLogger(__name__)
     33 
     34 def LaunchSMAContents(invItem):
     35     _CheckIfValidStateToLaunchFromContainer()
     36     sm.GetService('gameui').GetShipAccess().LaunchFromContainer(invItem.locationID, invItem.itemID)
     37 
     38 
     39 def LaunchShipOrContainerFromWreckOrContainer(invItem):
     40     _CheckIfValidStateToLaunchFromContainer()
     41     sm.RemoteSvc('eject').LaunchShipOrContainerFromWreckOrContainer(invItem.locationID, invItem.itemID)
     42 
     43 
     44 def _CheckIfValidStateToLaunchFromContainer():
     45     bp = sm.GetService('michelle').GetBallpark()
     46     myShipBall = bp.GetBall(session.shipid)
     47     if myShipBall and myShipBall.mode == destiny.DSTBALL_WARP:
     48         raise UserError('ShipInWarp')
     49 
     50 
     51 def Jettison(invItems, showPrompt = True):
     52     if showPrompt and prompt_player_fsd_dialog('ConfirmJettison', {}, uiconst.YESNO, suppress=uiconst.ID_YES) != uiconst.ID_YES:
     53         return
     54     itemsByID = {invItem.itemID:invItem for invItem in invItems}
     55     ship = sm.StartService('gameui').GetShipAccess()
     56     if ship:
     57         itemIDs = itemsByID.keys()
     58         jettisonedToCanIDs, jettisonItemList = ship.Jettison(itemIDs)
     59         notJettisonedIDs = set(itemIDs) - set(jettisonedToCanIDs) - set(jettisonItemList)
     60         notJettisonedTypeIDs = set()
     61         for itemID in notJettisonedIDs:
     62             if itemID in itemsByID:
     63                 item = itemsByID[itemID]
     64                 notJettisonedTypeIDs.add(item.typeID)
     65 
     66         if notJettisonedTypeIDs:
     67             raise UserError('NotAllItemsWereJettisoned', {'itemList': (UE_TYPEIDL, notJettisonedTypeIDs)})
     68 
     69 
     70 def JettisonStructureFuel(invItems):
     71     if prompt_player_fsd_dialog('ConfirmJettison', {}, uiconst.YESNO, suppress=uiconst.ID_YES) != uiconst.ID_YES:
     72         return
     73     Moniker('structure', session.structureid).JettisonStructureFuel([ i.itemID for i in invItems ])
     74 
     75 
     76 def Reprocess(invItems):
     77     if not session.stationid and not session.structureid:
     78         return
     79     sm.StartService('reprocessing').ReprocessDlg(invItems)
     80 
     81 
     82 def TrainNow(invItems):
     83     if len(invItems) > 1:
     84         prompt_player_fsd_dialog('TrainMoreTheOne')
     85         return
     86     InjectSkillIntoBrain(invItems)
     87     blue.pyos.synchro.SleepWallclock(500)
     88     sm.GetService('skillqueue').TrainSkillNow(invItems[0].typeID, 1)
     89 
     90 
     91 def InjectSkillIntoBrain(invItems):
     92     sm.StartService('skills').InjectSkillIntoBrain(invItems)
     93 
     94 
     95 def PlugInImplant(invItems):
     96     if prompt_player_fsd_dialog('ConfirmPlugInImplant', {}, uiconst.OKCANCEL) != uiconst.ID_OK:
     97         return
     98     PlaySound(uiconst.SOUND_ADD_OR_USE)
     99     for invItem in invItems:
    100         sm.StartService('godma').GetDogmaLM().InjectImplant(invItem.itemID)
    101         sm.GetService('notificationSvc').MakeAndScatterNotification(notificationconst.notificationTypeImplantPluggedIn, {'typeID': invItem.typeID})
    102 
    103 
    104 def ConsumeBooster(invItems):
    105     if type(invItems) is not list:
    106         invItems = [invItems]
    107     for invItem in invItems:
    108         sm.StartService('godma').GetDogmaLM().UseBooster(invItem.itemID, invItem.locationID)
    109         sm.GetService('notificationSvc').MakeAndScatterNotification(notificationconst.notificationTypeBoosterConsumed, {'typeID': invItem.typeID})
    110 
    111 
    112 def ConsumeExpertSystem(invItem):
    113     sm.GetService('expertSystemSvc').ConsumeExpertSystem(invItem.itemID)
    114 
    115 
    116 def DeliverToStructure(items, invCacheSvc):
    117     if not session.structureid:
    118         return
    119     if not isinstance(items, collections.Iterable):
    120         items = [items]
    121     items = [ item for item in items if invCacheSvc.GetStationIDOfItem(item) == session.structureid ]
    122     if not items:
    123         return
    124 
    125     def Confirm(characterID):
    126         formatted = [ '<t>- %sx %s<br>' % (item.stacksize, GetShowInfoLink(item.typeID, evetypes.GetName(item.typeID), item.itemID)) for item in items ]
    127         data = {'items': ''.join(formatted),
    128          'character': characterID}
    129         if prompt_player_fsd_dialog('ConfirmDeliverItems', data, uiconst.YESNO) == uiconst.ID_YES:
    130             sm.RemoteSvc('structureDeliveries').Deliver(session.structureid, characterID, [ item.itemID for item in items ])
    131 
    132     def Deliver(results):
    133         for row in results():
    134             OwnerSearchWindow.CloseIfOpen(windowID='DeliverToStructure')
    135             return Confirm(row.charID)
    136 
    137     OwnerSearchWindow.CloseIfOpen(windowID='DeliverToStructure')
    138     OwnerSearchWindow.Open(windowID='DeliverToStructure', actionBtns=[(localization.GetByLabel('UI/Inventory/ItemActions/DeliverItems'), Deliver, True)], caption=localization.GetByLabel('UI/Inventory/ItemActions/DeliverItemsHeader'), input='', showContactList=True, multiSelect=False, ownerGroups=[const.groupCharacter])
    139 
    140 
    141 def AssembleShip(invItems):
    142     import stackless
    143     from eve.client.script.ui.station.assembleModularShip import prompt_assemble_modular_ship
    144     itemIDs = []
    145     subSystems = None
    146     invCache = sm.GetService('invCache')
    147     for item in invItems:
    148         lockInfo = invCache.IsItemLocked_NoLock(item.itemID)
    149         cfg.evelocations.RemoveFromKnowLuzers(item.itemID)
    150         if lockInfo[0] and lockInfo[7] != stackless.getcurrent():
    151             continue
    152         if IsModularShip(item.typeID):
    153             if not (eveCfg.IsDocked() or IsControllingStructure()):
    154                 prompt_player_fsd_dialog('CantAssembleModularShipInSpace')
    155                 return
    156             subSystems = prompt_assemble_modular_ship(item)
    157             if subSystems:
    158                 itemIDs = item.itemID
    159                 break
    160             else:
    161                 continue
    162         itemIDs.append(item.itemID)
    163 
    164     if itemIDs:
    165         singleItem = not isinstance(itemIDs, list) or len(itemIDs) == 1
    166         if singleItem and not settings.user.suppress.Get('suppress.ShipNameChangeOnAssemble', False):
    167             name = prompt_rename_ship(ship_type_id=item.typeID, show_suppress=True)
    168         else:
    169             name = None
    170         PlaySound('ship_goals_assemble_ship_play')
    171         bmSvc = GetBoardingMomentService()
    172         if not bmSvc.HasSeen(item.typeID):
    173             bmSvc.SetUnseen(item.typeID)
    174         item_id = sm.StartService('gameui').GetShipAccess().AssembleShip(itemIDs, name=name, subSystems=subSystems)
    175         try:
    176             if item_id is not None:
    177                 if isinstance(item_id, list):
    178                     for current_id in item_id:
    179                         type_id = sm.GetService('invCache').GetInventoryFromId(current_id).typeID
    180                         get_ship_skin_application_svc().apply_default_skin(current_id, type_id)
    181 
    182                 else:
    183                     type_id = sm.GetService('invCache').GetInventoryFromId(item_id).typeID
    184                     get_ship_skin_application_svc().apply_default_skin(item_id, type_id)
    185         except Exception as e:
    186             logger.error('Failed to apply default skin during ship assembly', e)
    187 
    188         return item_id
    189 
    190 
    191 def AssembleAndBoardShip(invItem):
    192     shipID = AssembleShip([invItem])
    193     if not shipID:
    194         return
    195     if isinstance(shipID, list):
    196         shipID = shipID[0]
    197     if session.stationid:
    198         ship = None
    199         if shipID != invItem.itemID:
    200             uthread2.Yield()
    201             inventory = get_hangar_inventory()
    202             for item in inventory.List():
    203                 if item.itemID == shipID:
    204                     ship = item
    205                     break
    206 
    207         else:
    208             ship = invItem
    209         if bool(ship):
    210             sm.GetService('station').TryActivateShip(ship)
    211     elif session.structureid:
    212         sm.GetService('structureDocking').ActivateShip(shipID)
    213     PlaySound('ship_goals_assemble_board_ship_play')
    214 
    215 
    216 def CheckItemsInSamePlace(invItems):
    217     if len(invItems) == 0:
    218         return
    219     locationID = invItems[0].locationID
    220     flag = invItems[0].flagID
    221     ownerID = invItems[0].ownerID
    222     for item in invItems:
    223         if item.locationID != locationID or item.flagID != flag or item.ownerID != ownerID:
    224             raise UserError('ItemsMustBeInSameHangar')
    225         locationID = item.locationID
    226         ownerID = item.ownerID
    227         flag = item.flagID
    228 
    229 
    230 def InSameStructureWithCorrectFlag(invItem, allowedFlags):
    231     currentStructureID = session.structureid
    232     if not currentStructureID:
    233         return False
    234     if invItem.locationID != currentStructureID:
    235         return False
    236     if invItem.flagID in allowedFlags:
    237         return True
    238     return False
    239 
    240 
    241 def CheckIfInPrimedOffice(invItem):
    242     office = sm.StartService('officeManager').GetCorpOfficeAtLocation()
    243     return office is not None and invItem.locationID == office.officeID
    244 
    245 
    246 def CheckSameStation(invItem):
    247     if session.stationid:
    248         if invItem.locationID == session.stationid:
    249             return 1
    250         if isinstance(invItem, blue.DBRow) and 'stationID' in invItem.__columns__ and invItem.stationID == session.stationid:
    251             return 1
    252         if CheckIfInPrimedOffice(invItem):
    253             return 1
    254         if idCheckers.IsPlayerItem(invItem.locationID) and sm.GetService('invCache').IsInventoryPrimedAndListed(invItem.locationID):
    255             return 1
    256     return 0
    257 
    258 
    259 def InvalidateItemLocation(ownerID, stationID, flag, invCacheSvc):
    260     if ownerID == session.corpid:
    261         which = 'offices'
    262         if flag == const.flagCorpDeliveries:
    263             which = 'deliveries'
    264         if flag == const.flagCapsuleerDeliveries:
    265             which = 'capsuleerdeliveries'
    266         sm.services['objectCaching'].InvalidateCachedMethodCall('corpmgr', 'GetAssetInventoryForLocation', session.corpid, stationID, which)
    267     else:
    268         sm.services['objectCaching'].InvalidateCachedMethodCall('stationSvc', 'GetStation', stationID)
    269         invCacheSvc.GetInventory(const.containerGlobal).InvalidateStationItemsCache(stationID)
    270 
    271 
    272 def DeliverToCorpHangarFolder(invItemAndFlagList, invCacheSvc):
    273     if len(invItemAndFlagList) == 0:
    274         return
    275     invItems = []
    276     itemIDs = []
    277     for item, flagID in invItemAndFlagList:
    278         invItems.append(item)
    279         itemIDs.append(item.itemID)
    280 
    281     CheckItemsInSamePlace(invItems)
    282     fromID = invItems[0].locationID
    283     doSplit = bool(uicore.uilib.Key(uiconst.VK_SHIFT) and len(invItemAndFlagList) == 1 and invItemAndFlagList[0][0].stacksize > 1)
    284     stationID = invCacheSvc.GetStationIDOfItem(invItems[0])
    285     if stationID is None:
    286         raise UserError('CanOnlyDoInStations')
    287     ownerID = invItems[0].ownerID
    288     flag = invItems[0].flagID
    289     deliverToFlag = invItemAndFlagList[0][1]
    290     qty = None
    291     if doSplit:
    292         invItem = invItems[0]
    293         caption = '%s: %s' % (localization.GetByLabel('UI/Inventory/ItemActions/DivideItemStack'), evetypes.GetName(invItem.typeID))
    294         ret = uix.QtyPopup(invItem.stacksize, 1, 1, None, caption)
    295         if ret is not None:
    296             qty = ret['qty']
    297     invCacheSvc.GetInventoryMgr().DeliverToCorpHangar(fromID, stationID, itemIDs, qty, ownerID, deliverToFlag)
    298     InvalidateItemLocation(ownerID, stationID, flag, invCacheSvc)
    299     if ownerID == session.corpid:
    300         sm.ScatterEvent('OnCorpAssetChange', invItems, stationID)
    301 
    302 
    303 def DeliverToCorpMember(invItems, invCacheSvc):
    304     if len(invItems) == 0:
    305         return
    306     CheckItemsInSamePlace(invItems)
    307     corpMemberIDs = sm.GetService('corp').GetMemberIDs()
    308     cfg.eveowners.Prime(corpMemberIDs)
    309     memberslist = []
    310     for memberID in corpMemberIDs:
    311         who = cfg.eveowners.Get(memberID)
    312         memberslist.append([who.ownerName, memberID, who.typeID])
    313 
    314     stationID = invCacheSvc.GetStationIDOfItem(invItems[0])
    315     if stationID is None:
    316         raise UserError('CanOnlyDoInStations')
    317     res = uix.ListWnd(memberslist, 'character', localization.GetByLabel('UI/Corporations/Common/SelectCorpMember'), localization.GetByLabel('UI/Corporations/Common/SelectCorpMemberToDeliverTo'), 1)
    318     if res:
    319         corporationMemberID = res[1]
    320         return _DeliverToCorpMemberID(corporationMemberID, invItems, invCacheSvc)
    321 
    322 
    323 def _DeliverToCorpMemberID(corporationMemberID, invItems, invCacheSvc):
    324     doSplit = uicore.uilib.Key(uiconst.VK_SHIFT) and len(invItems) == 1 and invItems[0].stacksize > 1
    325     stationID = invCacheSvc.GetStationIDOfItem(invItems[0])
    326     if stationID is None:
    327         raise UserError('CanOnlyDoInStations')
    328     ownerID = invItems[0].ownerID
    329     flagID = invItems[0].flagID
    330     itemIDs = [ item.itemID for item in invItems ]
    331     qty = None
    332     if doSplit:
    333         invItem = invItems[0]
    334         caption = '%s: %s' % (localization.GetByLabel('UI/Inventory/ItemActions/DivideItemStack'), evetypes.GetName(invItem.typeID))
    335         ret = uix.QtyPopup(invItem.stacksize, 1, 1, None, caption)
    336         if ret is not None:
    337             qty = ret['qty']
    338     invCacheSvc.GetInventoryMgr().DeliverToCorpMember(corporationMemberID, stationID, itemIDs, qty, ownerID, flagID)
    339     InvalidateItemLocation(ownerID, stationID, flagID, invCacheSvc)
    340     if ownerID == session.corpid:
    341         sm.ScatterEvent('OnCorpAssetChange', invItems, stationID)
    342 
    343 
    344 def DeliverToMyself(invItems, invCacheSvc):
    345     if len(invItems) == 0:
    346         return
    347     CheckItemsInSamePlace(invItems)
    348     _DeliverToCorpMemberID(session.charid, invItems, invCacheSvc)
    349 
    350 
    351 def SplitStack(invItems, invCacheSvc):
    352     if len(invItems) != 1:
    353         raise UserError('CannotPerformOnMultipleItems')
    354     invItem = invItems[0]
    355     caption = '%s: %s' % (localization.GetByLabel('UI/Inventory/ItemActions/DivideItemStack'), evetypes.GetName(invItem.typeID))
    356     ret = uix.QtyPopup(invItem.stacksize, 1, 1, None, caption)
    357     if ret is not None:
    358         qty = ret['qty']
    359         stationID = invCacheSvc.GetStationIDOfItem(invItem)
    360         if stationID is None:
    361             raise UserError('CanOnlyDoInStations')
    362         flag = invItem.flagID
    363         invCacheSvc.GetInventoryMgr().SplitStack(stationID, invItem.itemID, qty, invItem.ownerID)
    364         InvalidateItemLocation(invItem.ownerID, stationID, flag, invCacheSvc)
    365         if invItem.ownerID == session.corpid:
    366             invItem.quantity = invItem.quantity - qty
    367             sm.ScatterEvent('OnCorpAssetChange', [invItem], stationID)
    368 
    369 
    370 def LockDownBlueprint(invItem):
    371     try:
    372         stationID = {o.stationID for o in sm.StartService('officeManager').GetMyCorporationsOffices() if o.officeID == invItem.locationID}.pop()
    373     except KeyError:
    374         return
    375 
    376     blueprint = sm.GetService('blueprintSvc').GetBlueprintItem(invItem.itemID)
    377     description = localization.GetByLabel('UI/Corporations/Votes/ProposeLockdownDescription', blueprintLocation=stationID, efficiencyLevel=blueprint.materialEfficiency, productivityLevel=blueprint.timeEfficiency)
    378     formData = {'voteType': voting.voteItemLockdown,
    379      'voteTitle': localization.GetByLabel('UI/Corporations/Votes/LockdownItem', blueprint=invItem.typeID),
    380      'voteDescription': description,
    381      'voteDays': 1,
    382      'itemID': invItem.itemID,
    383      'typeID': invItem.typeID,
    384      'flagInput': invItem.flagID,
    385      'locationID': stationID}
    386     dlg = VoteWizardDialog.Open(**formData)
    387     dlg.GoToStep(len(dlg.steps))
    388     dlg.ShowModal()
    389 
    390 
    391 def UnlockBlueprint(invItem):
    392     dlg = VoteWizardDialog.Open()
    393     stationID = dlg.locationID
    394     blueprint = sm.GetService('blueprintSvc').GetBlueprintItem(invItem.itemID)
    395     description = localization.GetByLabel('UI/Corporations/Votes/ProposeLockdownDescription', blueprintLocation=stationID, efficiencyLevel=blueprint.materialEfficiency, productivityLevel=blueprint.timeEfficiency)
    396     dlg.voteType = voting.voteItemUnlock
    397     dlg.voteTitle = localization.GetByLabel('UI/Corporations/Votes/UnlockItem', blueprint=invItem.typeID)
    398     dlg.voteDescription = description or dlg.voteTitle
    399     dlg.voteDays = 1
    400     dlg.itemID = invItem.itemID
    401     dlg.typeID = invItem.typeID
    402     dlg.flagInput = invItem.flagID
    403     dlg.locationID = stationID
    404     dlg.GoToStep(len(dlg.steps))
    405     dlg.ShowModal()
    406 
    407 
    408 def ALSCLock(invItems, invCacheSvc):
    409     if len(invItems) < 1:
    410         return
    411     container = invCacheSvc.GetInventoryFromId(invItems[0].locationID)
    412     container.ALSCLockItems([ i.itemID for i in invItems ])
    413 
    414 
    415 def ALSCUnlock(invItems, invCacheSvc):
    416     if len(invItems) < 1:
    417         return
    418     container = invCacheSvc.GetInventoryFromId(invItems[0].locationID)
    419     container.ALSCUnlockItems([ i.itemID for i in invItems ])
    420 
    421 
    422 def GetContainerContents(containerItem, invCacheSvc, dockableID):
    423     dockableID = containerItem.locationID if dockableID is None else dockableID
    424     if not (idCheckers.IsStation(dockableID) or sm.GetService('structureDirectory').GetStructureInfo(dockableID)):
    425         raise RuntimeError('GetContainerContents: dockableID is neither structure nor station.')
    426     DoGetContainerContents(containerItem.itemID, dockableID, containerItem.typeID, invCacheSvc)
    427 
    428 
    429 def DoGetContainerContents(itemID, stationID, containerTypeID, invCacheSvc):
    430     from eve.client.script.ui.shared.inventory.containerContentWindow import ContainerContentWindow
    431     wnd = ContainerContentWindow.GetIfOpen()
    432     if not wnd or wnd.destroyed:
    433         wnd = ContainerContentWindow()
    434     wnd.LoadContent(itemID=itemID, stationID=stationID, containerTypeID=containerTypeID, invCacheSvc=invCacheSvc)
    435     wnd.Maximize()
    436 
    437 
    438 def CheckLocked(func, invItemsOrIDs, invCacheSvc):
    439     if not len(invItemsOrIDs):
    440         return
    441     if type(invItemsOrIDs[0]) == int or not hasattr(invItemsOrIDs[0], 'itemID'):
    442         ret = func(invItemsOrIDs)
    443     else:
    444         lockedItems = []
    445         try:
    446             for item in invItemsOrIDs:
    447                 if invCacheSvc.IsItemLocked(item.itemID):
    448                     continue
    449                 if invCacheSvc.TryLockItem(item.itemID):
    450                     lockedItems.append(item)
    451 
    452             if not len(lockedItems):
    453                 prompt_player_fsd_dialog('BusyItems')
    454                 return
    455             ret = func(lockedItems)
    456         finally:
    457             for invItem in lockedItems:
    458                 invCacheSvc.UnlockItem(invItem.itemID)
    459 
    460     return ret
    461 
    462 
    463 def CheckRepackageItems(invItems, warnAboutContainers):
    464     repackage = []
    465     if not invItems:
    466         return repackage
    467     insuranceQ_OK = 0
    468     containerQ_OK = -1
    469     insuranceContracts = None
    470     godma = sm.GetService('godma')
    471     for item in invItems:
    472         if item.typeID == const.typePlasticWrap:
    473             continue
    474         itemState = godma.GetItem(item.itemID)
    475         if itemState and (itemState.damage or item.categoryID in (const.categoryShip, const.categoryDrone) and itemState.armorDamage):
    476             prompt_player_fsd_dialog('CantRepackageDamagedItem')
    477             continue
    478         if item.categoryID == const.categoryShip:
    479             if insuranceContracts is None:
    480                 insuranceContracts = sm.StartService('insurance').GetContracts()
    481             if not insuranceQ_OK and item.itemID in insuranceContracts:
    482                 if prompt_player_fsd_dialog('RepairUnassembleVoidsContract', {}, uiconst.YESNO) != uiconst.ID_YES:
    483                     continue
    484                 insuranceQ_OK = 1
    485         containerGroups = (const.groupCargoContainer,
    486          const.groupSecureCargoContainer,
    487          const.groupAuditLogSecureContainer,
    488          const.groupFreightContainer)
    489         if warnAboutContainers and item.singleton and item.groupID in containerGroups:
    490             if not containerQ_OK:
    491                 continue
    492             if containerQ_OK == -1:
    493                 if sm.GetService('invCache').GetInventoryFromId(item.itemID).List():
    494                     if prompt_player_fsd_dialog('RepackageContainers', {}, uiconst.YESNO) != uiconst.ID_YES:
    495                         containerQ_OK = 0
    496                         continue
    497                     containerQ_OK = 1
    498         repackage.append(item)
    499 
    500     return repackage
    501 
    502 
    503 def RepackageItems(invItems):
    504     if any([ i.singleton for i in invItems ]):
    505         if prompt_player_fsd_dialog('ConfirmRepackageItem', {}, uiconst.YESNO) != uiconst.ID_YES:
    506             return
    507     invItems = CheckRepackageItems(invItems, len(invItems) > 1)
    508     if not invItems:
    509         return
    510     invCache = sm.GetService('invCache')
    511     itemsByStation = collections.defaultdict(list)
    512     for item in invItems:
    513         itemsByStation[invCache.GetStationIDOfItem(item) or item.locationID].append((item.itemID, item.locationID))
    514 
    515     itemsByStation = dict(itemsByStation)
    516     try:
    517         sm.RemoteSvc('repackagingSvc').RepackageItems(itemsByStation)
    518     except UserError as exception:
    519         if exception.msg == 'ConfirmRepackageSomethingWithUpgrades':
    520             if prompt_player_fsd_dialog(exception.msg, exception.dict, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES:
    521                 sm.RemoteSvc('repackagingSvc').RepackageItems(dict(itemsByStation), destroyable=True)
    522         elif exception.msg == 'ConfirmRepackageMultipleItemsWithUpgrades':
    523             failedItemIDs = exception.dict.get('itemIDs')
    524             itemStationTupleByItemID = {}
    525             for stationID, itemList in itemsByStation.iteritems():
    526                 for itemTuple in itemList:
    527                     itemStationTupleByItemID[itemTuple[0]] = (stationID, itemTuple)
    528 
    529             newItemsByStation = defaultdict(list)
    530             for eachItemID in failedItemIDs:
    531                 itemStationTuple = itemStationTupleByItemID.get(eachItemID, None)
    532                 if itemStationTuple:
    533                     stationID, itemTuple = itemStationTuple
    534                     newItemsByStation[stationID].append(itemTuple)
    535 
    536             if prompt_player_fsd_dialog(exception.msg, exception.dict, uiconst.YESNO) == uiconst.ID_YES:
    537                 sm.RemoteSvc('repackagingSvc').RepackageItems(dict(newItemsByStation), destroyable=True)
    538         else:
    539             raise
    540 
    541     PlaySound('ship_goals_repackage_ship_play')
    542 
    543 
    544 def Break(invItems, invCacheSvc):
    545     ok = 0
    546     validIDs = []
    547     for invItem in invItems:
    548         if ok or prompt_player_fsd_dialog('ConfirmBreakCourierPackage', {}, uiconst.OKCANCEL) == uiconst.ID_OK:
    549             validIDs.append(invItem.itemID)
    550             ok = 1
    551 
    552     for itemID in validIDs:
    553         invCacheSvc.GetInventoryFromId(itemID).BreakPlasticWrap()
    554 
    555 
    556 def TrashInvItems(invItems, invCacheSvc, showPrompt = True):
    557     if len(invItems) == 0:
    558         return
    559     CheckItemsInSamePlace(invItems)
    560     if showPrompt and not _IsTrashingAcceptedByUser(invItems[:]):
    561         return
    562     stationID = invCacheSvc.GetStationIDOfItem(invItems[0])
    563     itemsToTrash = []
    564     for item in invItems:
    565         if is_trashable(item.typeID):
    566             itemsToTrash.append(item.itemID)
    567         else:
    568             prompt_player_fsd_dialog(CANNOT_TRASH_ERROR)
    569             return
    570 
    571     locationID = stationID if stationID else invItems[0].locationID
    572     errors = invCacheSvc.GetInventoryMgr().TrashItems(itemsToTrash, locationID)
    573     if errors:
    574         for e in errors:
    575             prompt_player_fsd_dialog(e)
    576 
    577         return
    578     isCorp = invItems[0].ownerID == session.corpid
    579     InvalidateItemLocation(session.corpid if isCorp else session.charid, stationID, invItems[0].flagID, invCacheSvc)
    580     if isCorp:
    581         sm.ScatterEvent('OnCorpAssetChange', invItems, stationID)
    582 
    583 
    584 def _IsTrashingAcceptedByUser(invItems):
    585     if len(invItems) == 1:
    586         question = 'ConfirmTrashingSin'
    587         itemWithQuantity = cfg.FormatConvert(const.UE_TYPEIDANDQUANTITY, invItems[0].typeID, invItems[0].stacksize)
    588         args = {'itemWithQuantity': itemWithQuantity}
    589     else:
    590         question = 'ConfirmTrashingPlu'
    591         report = ''
    592         overflow_item_count = max(len(invItems) - 10, 0)
    593         if overflow_item_count > 0:
    594             invItems = invItems[:10]
    595         for item in invItems:
    596             report += '<t>- %s<br>' % cfg.FormatConvert(const.UE_TYPEIDANDQUANTITY, item.typeID, item.stacksize)
    597 
    598         if overflow_item_count > 0:
    599             report += u'<t>{}<br>'.format(localization.GetByLabel('UI/Inventory/TrashItemsOverflowCount', count=overflow_item_count))
    600         args = {'items': report}
    601     response = prompt_player_fsd_dialog(question, args, uiconst.YESNO)
    602     return response == uiconst.ID_YES
    603 
    604 
    605 def FindInPersonalAssets(typeID):
    606     from eve.client.script.ui.shared.assetsWindow import AssetsWindow
    607     wnd = AssetsWindow.GetIfOpen()
    608     if wnd and not wnd.destroyed:
    609         wnd.Maximize()
    610         wnd.SearchTypeID(typeID)
    611     else:
    612         wnd = AssetsWindow.Open(exactTypeID=typeID)
    613         wnd.tabGroup.SelectByID('search')