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

svc_invtools.py (23451B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\devtools\script\svc_invtools.py
      2 from __future__ import print_function
      3 import random
      4 import types
      5 import time
      6 import blue
      7 import evetypes
      8 from carbon.common.script.sys.service import Service
      9 from carbon.common.script.sys.serviceConst import ROLE_GML, ROLE_WORLDMOD, SERVICE_RUNNING, SERVICE_START_PENDING, SERVICE_STOP_PENDING, SERVICE_STOPPED
     10 from carbonui import uiconst
     11 from carbonui.control.combo import Combo
     12 from carbonui.control.singlelineedits.singleLineEditFloat import SingleLineEditFloat
     13 from carbonui.control.singlelineedits.singleLineEditInteger import SingleLineEditInteger
     14 from carbonui.primitives.container import Container
     15 from carbonui.primitives.frame import Frame
     16 from carbonui.primitives.line import Line
     17 from eve.client.script.ui.control import eveLabel
     18 from carbonui.button.group import ButtonGroup
     19 from carbonui.control.checkbox import Checkbox
     20 from carbonui.control.radioButton import RadioButton
     21 from carbonui.control.window import Window
     22 from eve.client.script.ui.util import uix
     23 from eve.common.lib import appConst as const
     24 from eve.common.script.sys import eveCfg
     25 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     26 MAX_VOLUME = 1000000000
     27 Progress = lambda title, text, current, total: sm.GetService('loading').ProgressWnd(title, text, current, total)
     28 
     29 class InvTools(Service):
     30     __module__ = __name__
     31     __exportedcalls__ = {}
     32     __notifyevents__ = []
     33     __dependencies__ = []
     34     __servicename__ = 'invtools'
     35     __displayname__ = 'invtools'
     36     __guid__ = 'svc.invtools'
     37 
     38     def __init__(self):
     39         Service.__init__(self)
     40         self.inv = sm.GetService('invCache').GetInventory
     41 
     42     def Run(self, memStream = None):
     43         self.state = SERVICE_START_PENDING
     44         Service.Run(self, memStream)
     45         self.wnd = None
     46         self.state = SERVICE_RUNNING
     47 
     48     def Stop(self, memStream = None):
     49         self.state = SERVICE_STOP_PENDING
     50         Service.Stop(self, memStream)
     51         self.state = SERVICE_STOPPED
     52 
     53     def Startup(self, *args):
     54         pass
     55 
     56     def GetShip(self, *args):
     57         if not hasattr(session, 'shipid'):
     58             return
     59         return self.inv(session.shipid)
     60 
     61     def GetSelf(self, *args):
     62         if not hasattr(session, 'charid'):
     63             return
     64         return self.inv(session.charid)
     65 
     66     def GetSpecial(self, loc = None, *args):
     67         if loc is None:
     68             return
     69         return self.inv(loc)
     70 
     71     def IsValid(self, typeID, onlyPublished, onlyUnpublished, volume):
     72         if evetypes.GetVolume(typeID) > volume:
     73             return False
     74         if onlyPublished and not evetypes.IsPublished(typeID):
     75             return False
     76         if onlyUnpublished and evetypes.IsPublished(typeID):
     77             return False
     78         if evetypes.IsDynamicType(typeID):
     79             return False
     80         return True
     81 
     82     def SpawnRandom(self, loc = None, flag = None, minQty = None, maxQty = None, iterations = None, categories = True, groups = False, want = None, onlyPublished = True, onlyUnpublished = False, useMultiMove = True, volume = None, *args):
     83         if loc is None:
     84             return
     85         if loc == eveCfg.GetActiveShip() and sm.GetService('clientDogmaIM').GetDogmaLocation().GetItem(loc).groupID == const.groupCapsule:
     86             prompt_player_fsd_dialog('CustomNotify', {'notify': 'You cannot spawn items into capsule.'})
     87             return
     88         if minQty is None:
     89             minQty = 1
     90         if maxQty is None:
     91             maxQty = 10
     92         if iterations is None:
     93             iterations = 10
     94         if minQty > maxQty:
     95             prompt_player_fsd_dialog('CustomNotify', {'notify': 'Min stack size is greater than max stack size.'})
     96             return
     97         if minQty > iterations:
     98             prompt_player_fsd_dialog('CustomNotify', {'notify': 'Min stack size is greater than number of items.'})
     99             return
    100         if want is None:
    101             categories = True
    102             want = [const.categoryCharge,
    103              const.categoryCommodity,
    104              const.categoryModule,
    105              const.categoryStructureModule]
    106         if type(want) is types.IntType:
    107             want = [want]
    108         if type(want) is not types.ListType:
    109             return
    110         selectedTypesAndQty = []
    111         mustMove = []
    112         possibleTypes = []
    113         if categories:
    114             for typeID in evetypes.GetTypeIDsByCategories(want):
    115                 if self.IsValid(typeID, onlyPublished, onlyUnpublished, volume):
    116                     possibleTypes.append(typeID)
    117 
    118         else:
    119             for typeID in evetypes.GetTypeIDsByGroups(want):
    120                 if self.IsValid(typeID, onlyPublished, onlyUnpublished, volume):
    121                     possibleTypes.append(typeID)
    122 
    123         if len(possibleTypes) == 0:
    124             return
    125         for i in xrange(1, iterations + 1):
    126             selectedTypesAndQty.append((random.choice(possibleTypes), random.choice(xrange(minQty, maxQty + 1))))
    127 
    128         title = 'Spawning...'
    129         idx = int()
    130         qty = len(selectedTypesAndQty)
    131         Progress(title, 'Processing', 0, qty)
    132         for t, q in selectedTypesAndQty:
    133             idx += 1
    134             msg = 'Processing %d of %d' % (idx, qty)
    135             Progress(title, msg, idx, qty)
    136             if q == 0:
    137                 q = 1
    138             try:
    139                 if session.role & ROLE_WORLDMOD:
    140                     itemID = sm.RemoteSvc('slash').SlashCmd('/createitem %d %d' % (t, q))
    141                 elif session.role & ROLE_GML:
    142                     itemID = sm.RemoteSvc('slash').SlashCmd('/load me %d %d' % (t, q))[0]
    143                 else:
    144                     return
    145                 mustMove.append(itemID)
    146             except Exception:
    147                 self.LogException('Failed to spawn item with typeID %s' % t)
    148 
    149         Progress(title, 'Complete', 1, 1)
    150         if session.stationid is not None and loc != const.containerHangar:
    151             self.MoveItems(items=mustMove, source=session.locationid, destination=loc, flag=flag, multi=useMultiMove, suppress=True)
    152 
    153     def GetFlags(self, *args):
    154         flagList = []
    155         for key in const.__dict__:
    156             if key.lower().startswith('flag'):
    157                 flagList.append(key)
    158 
    159         flagList.sort()
    160         return flagList
    161 
    162     def GetItemFromContainer(self, itemID = None, container = None, *args):
    163         if itemID is None:
    164             return
    165         if container is None:
    166             return
    167         inv = [ item for item in self.inv(container).List() ]
    168         for item in inv:
    169             if item.itemID == itemID:
    170                 return item
    171 
    172     def MoveItems(self, items = None, source = None, destination = None, flag = None, multi = True, suppress = False, **kwargs):
    173         if None in (items, source, destination):
    174             return
    175         if not suppress:
    176             destinationCargo = {}
    177             postDestinationCargo = {}
    178             sourceCargo = {}
    179             postSourceCargo = {}
    180             cargoDict = {}
    181             for rec in self.inv(destination).List():
    182                 destinationCargo[rec.itemID] = rec.stacksize
    183 
    184             for rec in self.inv(source).List():
    185                 sourceCargo[rec.itemID] = rec.stacksize
    186 
    187             for each in items:
    188                 cargoDict[each] = self.GetItemFromContainer(each, source).stacksize
    189 
    190         title = 'Moving...'
    191         Progress(title, 'Telling Scotty the docking manager what to do...', 0, 1)
    192         if multi:
    193             if flag is not None:
    194                 self.inv(destination).MultiAdd(items, source, flag=flag, **kwargs)
    195             else:
    196                 self.inv(destination).MultiAdd(items, source, **kwargs)
    197         else:
    198             idx = int()
    199             all = len(items)
    200             for itemID in items:
    201                 idx += 1
    202                 msg = 'Processing %d of %d' % (idx, all)
    203                 Progress(title, msg, idx, all)
    204                 self.inv(destination).Add(itemID, source, **kwargs)
    205 
    206         Progress(title, "All done, don't forget to pay the man!", 1, 1)
    207         if not suppress:
    208             blue.pyos.synchro.SleepWallclock(5000)
    209             for rec in self.inv(destination).List():
    210                 postDestinationCargo[rec.itemID] = rec.stacksize
    211 
    212             for rec in self.inv(source).List():
    213                 postSourceCargo[rec.itemID] = rec.stacksize
    214 
    215             for k in cargoDict.iterkeys():
    216                 if k in postDestinationCargo:
    217                     qtyCargo = cargoDict[k]
    218                     qtyDest = postDestinationCargo[k]
    219                     if qtyCargo == qtyDest:
    220                         pass
    221                     else:
    222                         print(k, ' is in destination and qty is different!')
    223                 else:
    224                     print('\t%s is not in destination', k)
    225                     print('\tsrc inv rec', self.GetItemFromContainer(k, source))
    226                     print('\tdest inv rec:', self.GetItemFromContainer(k, destination))
    227 
    228             postSourceCopy = postSourceCargo.copy()
    229             postSourceCopy.update(cargoDict)
    230             print('\tsrc ok?\t', ['No', 'Yes'][postSourceCopy == sourceCargo])
    231             destinationCopy = destinationCargo.copy()
    232             destinationCopy.update(cargoDict)
    233             print('\tdest ok?\t', ['No', 'Yes'][destinationCopy == postDestinationCargo])
    234 
    235     def InvMoveLoop(self, loop = None, noSpawn = True, *args):
    236         if loop is None:
    237             loop = 10
    238         _loop = loop
    239         if not noSpawn:
    240             self.SpawnRandom(session.shipid, iterations=10)
    241         items = self.GetShip().ListCargo()
    242         if len(items) == 0:
    243             return
    244         itemIDs = [ rec.itemID for rec in items ]
    245         moveCommands = [(session.shipid,
    246           const.containerHangar,
    247           const.flagHangar,
    248           False),
    249          (const.containerHangar,
    250           session.shipid,
    251           const.flagCargo,
    252           False),
    253          (session.shipid,
    254           const.containerHangar,
    255           const.flagHangar,
    256           True),
    257          (const.containerHangar,
    258           session.shipid,
    259           const.flagCargo,
    260           True)]
    261         lookup = {eveCfg.GetActiveShip(): 'Ship',
    262          const.containerHangar: 'Hangar Floor',
    263          const.flagCargo: 'Cargo Bay',
    264          const.flagCorpSAG1: 'Corp Hangar, Division 1',
    265          const.flagCorpSAG2: 'Corp Hangar, Division 2',
    266          const.flagCorpSAG3: 'Corp Hangar, Division 3',
    267          const.flagCorpSAG4: 'Corp Hangar, Division 4',
    268          const.flagCorpSAG5: 'Corp Hangar, Division 5',
    269          const.flagCorpSAG6: 'Corp Hangar, Division 6',
    270          const.flagCorpSAG7: 'Corp Hangar, Division 7',
    271          const.flagCorpGoalDeliveries: 'Corp Hangar, Goal Deliveries'}
    272         usecase = {True: 'multimove',
    273          False: 'single move'}
    274         office = sm.StartService('officeManager').GetCorpOfficeAtLocation()
    275         if office is not None:
    276             office = office.officeID
    277             moveCommands.extend([(session.shipid,
    278               office,
    279               const.flagCorpSAG1,
    280               False),
    281              (office,
    282               office,
    283               const.flagCorpSAG2,
    284               False),
    285              (office,
    286               office,
    287               const.flagCorpSAG3,
    288               False),
    289              (office,
    290               office,
    291               const.flagCorpSAG4,
    292               False),
    293              (office,
    294               office,
    295               const.flagCorpSAG5,
    296               False),
    297              (office,
    298               office,
    299               const.flagCorpSAG6,
    300               False),
    301              (office,
    302               office,
    303               const.flagCorpSAG7,
    304               False),
    305              (office,
    306               office,
    307               const.flagCorpGoalDeliveries,
    308               False),
    309              (office,
    310               session.shipid,
    311               const.flagCargo,
    312               False),
    313              (session.shipid,
    314               office,
    315               const.flagCorpSAG1,
    316               True),
    317              (office,
    318               office,
    319               const.flagCorpSAG2,
    320               True),
    321              (office,
    322               office,
    323               const.flagCorpSAG3,
    324               True),
    325              (office,
    326               office,
    327               const.flagCorpSAG4,
    328               True),
    329              (office,
    330               office,
    331               const.flagCorpSAG5,
    332               True),
    333              (office,
    334               office,
    335               const.flagCorpSAG6,
    336               True),
    337              (office,
    338               office,
    339               const.flagCorpSAG7,
    340               True),
    341              (office,
    342               office,
    343               const.flagCorpGoalDeliveries,
    344               True),
    345              (office,
    346               session.shipid,
    347               const.flagCargo,
    348               True)])
    349             lookup[office] = 'Office'
    350         start = time.time()
    351         while loop:
    352             for src, dest, f, m in moveCommands:
    353                 if f is not None:
    354                     print("Moving from %s to %s's %s using %s:" % (lookup[src],
    355                      lookup[dest],
    356                      lookup[f],
    357                      usecase[m]))
    358                 else:
    359                     print('Moving from %s to %s using %s:' % (lookup[src], lookup[dest], usecase[m]))
    360                 t = time.time()
    361                 self.MoveItems(itemIDs, src, dest, f, m)
    362                 duration = time.time() - t
    363                 print('Move took %d:%.2d to move %s items\n' % (duration / 60, duration % 60, len(items)))
    364 
    365             loop -= 1
    366 
    367         finish = time.time() - start
    368         print('Move test complete, total time: %d:%.2d for %s iteration(s)' % (finish / 60, finish % 60, _loop))
    369         print('%s items were moved %s times' % (len(items), len(moveCommands) * _loop))
    370 
    371 
    372 class InvToolsWnd(Window):
    373     __guid__ = 'form.invTools'
    374     __notifyevents__ = ['OnSessionChanged']
    375     RANDOM_COMBO = ('Random', 'random')
    376     PUBLISHED_LIST = ['<color=0xffff0000>Not Published<color=0xffffffff>', '<color=0xff00ff00>Published<color=0xffffffff>']
    377     default_windowID = 'InvTools'
    378 
    379     def ApplyAttributes(self, attributes):
    380         Window.ApplyAttributes(self, attributes)
    381         self.SetCaption('Inventory Tools')
    382         self.MakeUnResizeable()
    383         self.cats = None
    384         self.grps = None
    385         self.locs = None
    386         self.DoSetup()
    387         self.Begin()
    388 
    389     def OnSessionChanged(self, isRemote, session, change):
    390         self.location.entries = self.locs = self.GetLocations()
    391         self.location.SetValue('ship')
    392 
    393     def DoSetup(self):
    394         self.cats = [ ('%s [%s]' % (evetypes.GetCategoryNameByCategory(categoryID), self.PUBLISHED_LIST[evetypes.IsCategoryPublishedByCategory(categoryID)]), categoryID) for categoryID in evetypes.IterateCategories() if categoryID is not 0 ]
    395         self.cats.sort()
    396         self.cats.insert(0, self.RANDOM_COMBO)
    397         self.grps = [self.RANDOM_COMBO]
    398         self.default = {'categoryID': 'random',
    399          'groupID': 'random',
    400          'published': 1,
    401          'multimove': 1,
    402          'minQty': 1,
    403          'maxQty': 10,
    404          'number': 10,
    405          'volume': MAX_VOLUME,
    406          'location': 'ship'}
    407         self.config = self.default.copy()
    408         self.locs = self.GetLocations()
    409         self.spawnlocation = (eveCfg.GetActiveShip(), const.flagCargo)
    410         self.prepCorpHangar = False
    411 
    412     def Begin(self):
    413         margin = const.defaultPadding
    414         self.main = main = Container(name='main', parent=self.sr.main, padding=margin)
    415         Frame(parent=main, color=(1.0, 1.0, 1.0, 0.2))
    416         uix.GetContainerHeader('Random Item Spawn', main, bothlines=0)
    417         COMBOPADDING = 120
    418         self.categories = Combo(parent=main, options=self.cats, select=self.config['categoryID'], name='category', align=uiconst.TOTOP, callback=self.DoCategoryChange, padding=(COMBOPADDING,
    419          margin,
    420          margin,
    421          0))
    422         txt = eveLabel.Label(text='Category', parent=self.categories, align=uiconst.CENTERLEFT, left=-COMBOPADDING + margin, fontsize=10)
    423         self.groups = Combo(parent=main, options=self.grps, select=self.config['groupID'], name='group', align=uiconst.TOTOP, callback=self.DoGroupChange, padding=(COMBOPADDING,
    424          margin,
    425          margin,
    426          0))
    427         txt = eveLabel.Label(text='Group', parent=self.groups, align=uiconst.CENTERLEFT, left=-COMBOPADDING + margin, fontsize=10)
    428         self.pub = RadioButton(text='use only published items', parent=main, settingsKey='pub', retval=0, checked=bool(self.config['published'] == 1), groupname='published', align=uiconst.TOTOP, callback=self.DoPublishChange, padding=(margin,
    429          0,
    430          margin,
    431          0))
    432         Line(parent=main, align=uiconst.TOTOP)
    433         self.unpub = RadioButton(text='use only unpublished items', parent=main, settingsKey='unpub', retval=0, checked=bool(self.config['published'] == 0), groupname='published', align=uiconst.TOTOP, callback=self.DoPublishChange, padding=(margin,
    434          0,
    435          margin,
    436          0))
    437         self.all = RadioButton(text='use all items', parent=main, settingsKey='all', retval=0, checked=bool(self.config['published'] == -1), groupname='published', align=uiconst.TOTOP, callback=self.DoPublishChange, padding=(margin,
    438          0,
    439          margin,
    440          0))
    441         Line(parent=main, align=uiconst.TOTOP)
    442         self.multimove = Checkbox(text='use multimove', parent=main, settingsKey='multimove', checked=self.config['multimove'], groupname=None, align=uiconst.TOTOP, callback=self.DoMoveChange, padding=(margin,
    443          0,
    444          margin,
    445          0))
    446         Line(parent=main, align=uiconst.TOTOP)
    447         for checkbox in [self.pub,
    448          self.unpub,
    449          self.all,
    450          self.multimove]:
    451             checkbox.hint = 'Changing this is <color=0xffff0000>not advised<color=0xffffffff>.<br>Proceed with caution!'
    452 
    453         INPUTPADDING = 140
    454         self.min = SingleLineEditInteger(name='minQty', setvalue=str(self.config['minQty']), minValue=1, maxValue=100, parent=main, align=uiconst.TOTOP, padding=(INPUTPADDING,
    455          margin,
    456          margin,
    457          0))
    458         txt = eveLabel.Label(text='Minimum stack size', parent=self.min, align=uiconst.CENTERLEFT, left=-INPUTPADDING + margin, fontsize=10)
    459         self.max = SingleLineEditInteger(name='maxQty', setvalue=str(self.config['maxQty']), minValue=1, maxValue=100, parent=main, align=uiconst.TOTOP, padding=(INPUTPADDING,
    460          margin,
    461          margin,
    462          0))
    463         txt = eveLabel.Label(text='Maximum stack size', parent=self.max, align=uiconst.CENTERLEFT, left=-INPUTPADDING + margin, fontsize=10)
    464         self.number = SingleLineEditInteger(name='number', setvalue=str(self.config['number']), minValue=1, maxValue=1000, parent=main, align=uiconst.TOTOP, padding=(INPUTPADDING,
    465          margin,
    466          margin,
    467          0))
    468         txt = eveLabel.Label(text='Number of Items', parent=self.number, align=uiconst.CENTERLEFT, left=-INPUTPADDING + margin, fontsize=10)
    469         self.volume = SingleLineEditFloat(name='volume', setvalue=str(self.config['volume']), maxValue=MAX_VOLUME, parent=main, align=uiconst.TOTOP, padding=(INPUTPADDING,
    470          margin,
    471          margin,
    472          0))
    473         txt = eveLabel.Label(text='Maximum item volume', parent=self.volume, align=uiconst.CENTERLEFT, left=-INPUTPADDING + margin, fontsize=10)
    474         self.location = Combo(parent=main, options=self.locs, select=self.config['location'], name='location', align=uiconst.TOTOP, callback=self.DoLocationChange, padding=(COMBOPADDING,
    475          margin,
    476          margin,
    477          0))
    478         txt = eveLabel.Label(text='Location', parent=self.location, align=uiconst.CENTERLEFT, left=-COMBOPADDING + margin, fontsize=10)
    479         buttons = [['Spawn',
    480           self.DoFormSubmit,
    481           None,
    482           81]]
    483         btns = ButtonGroup(btns=buttons, line=1, parent=main, padTop=margin)
    484         btn = btns.GetChild('Spawn_Btn')
    485         if session.role & ROLE_WORLDMOD:
    486             btn.hint = 'Spawn using /createitem...'
    487         elif session.role & ROLE_GML:
    488             btn.hint = 'Spawn using /load...'
    489         else:
    490             btn.hint = 'No <b>WORLDMOD</b> or <b>GML</b> role present.'
    491         content_height = sum((each.height + each.padTop + each.padBottom + each.top for each in main.children)) + 16
    492         _, window_height = self.GetWindowSizeForContentSize(height=content_height)
    493         self.height = window_height
    494 
    495     def DoCategoryChange(self, combo, text, value):
    496         self.config['categoryID'] = value
    497         if value == 'random':
    498             self.grps = [self.RANDOM_COMBO]
    499         else:
    500             self.grps = [ ('%s [%s]' % (evetypes.GetGroupNameByGroup(groupID), self.PUBLISHED_LIST[evetypes.IsGroupPublishedByGroup(groupID)]), groupID) for groupID in evetypes.IterateGroups() if evetypes.GetCategoryIDByGroup(groupID) == value ]
    501             self.grps.sort()
    502             self.grps.insert(0, self.RANDOM_COMBO)
    503         self.groups.SetValue('random')
    504         self.config['groupID'] = 'random'
    505         self.groups.entries = self.grps
    506 
    507     def DoGroupChange(self, combo, text, value):
    508         self.config['groupID'] = value
    509 
    510     def DoLocationChange(self, combo, text, value):
    511         self.prepCorpHangar = False
    512         self.config['location'] = value
    513         if value == 'ship':
    514             self.spawnlocation = (eveCfg.GetActiveShip(), const.flagCargo)
    515         elif value == 'hangar':
    516             self.spawnlocation = const.containerHangar
    517 
    518     def DoPublishChange(self, cb):
    519         lookup = {'pub': 1,
    520          'unpub': 0,
    521          'all': -1}
    522         self.config['published'] = lookup[cb.name]
    523 
    524     def DoMoveChange(self, cb):
    525         self.config['multimove'] = cb.GetValue()
    526 
    527     def DoFormSubmit(self, *args):
    528         for formField in [self.min,
    529          self.max,
    530          self.number,
    531          self.volume]:
    532             configFieldName = formField.name
    533             self.config[configFieldName] = formField.GetValue()
    534 
    535         loc = self.spawnlocation
    536         if isinstance(loc, types.TupleType):
    537             loc, flag = loc
    538         else:
    539             flag = None
    540         if self.config['categoryID'] == 'random':
    541             ids = set([ evetypes.GetCategoryIDByGroup(groupID) for groupID in evetypes.IterateGroups() ])
    542             want = list(ids)
    543             categories = True
    544             groups = False
    545         elif self.config['groupID'] == 'random':
    546             ids = evetypes.GetGroupIDsByCategory(self.config['categoryID'])
    547             want = list(ids)
    548             categories = False
    549             groups = True
    550         else:
    551             want = [self.config['groupID']]
    552             categories = False
    553             groups = True
    554         publishedFlags = {0: (False, True),
    555          1: (True, False),
    556          -1: (False, False)}
    557         onlyPublished, onlyUnpublished = publishedFlags[self.config['published']]
    558         if self.prepCorpHangar is True:
    559             sm.GetService('window').OpenCorpHangar(None, None, 1)
    560         sm.StartService('invtools').SpawnRandom(loc=loc, flag=flag, minQty=self.config['minQty'], maxQty=self.config['maxQty'], iterations=self.config['number'], categories=categories, groups=groups, want=want, onlyPublished=onlyPublished, onlyUnpublished=onlyUnpublished, useMultiMove=self.config['multimove'], volume=self.config['volume'])
    561 
    562     def GetLocations(self):
    563         ret = [('Current Ship', 'ship')]
    564         if session.stationid or session.structureid:
    565             ret.append(('Hangar Floor', 'hangar'))
    566         return ret