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

clientDogmaLocation.py (66019B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\dogma\clientDogmaLocation.py
      2 import itertools
      3 import sys
      4 import dogma.attributes.groups
      5 import utillib
      6 import weakref
      7 from collections import defaultdict
      8 import blue
      9 import dogma.data
     10 import evetypes
     11 import localization
     12 import log
     13 import telemetry
     14 import uthread
     15 from carbon.client.script.environment.AudioUtil import PlaySound
     16 from carbon.common.script.util.logUtil import LogNotice
     17 from carbonui import uiconst
     18 from carbonui.uicore import uicore
     19 from carbonui.util.bunch import Bunch
     20 from carbonui.util.various_unsorted import SortListOfTuples
     21 from dogma.ammoloadingUtils import IsChargeCompatibleWithLauncher, GetModuleCapacityForAmmoType
     22 from dogma.attributes.format import GetFormatAndValue
     23 from dogma.dogmaWrappers import WrappedMethod
     24 from dogma.effects.environment import Environment
     25 from eve.client.script.dogma.clientDogmaUtilFunc import WasLaunchingDrone, WasLaunchingFighter
     26 from eve.client.script.ui.util import uix
     27 from eve.common.lib import appConst as const
     28 from eve.common.script.dogma.baseDogmaLocation import BaseDogmaLocation
     29 from eve.common.script.net import eveMoniker
     30 from eve.common.script.sys import eveCfg
     31 from eve.common.script.sys.eveCfg import IsControllingStructure
     32 from eveexceptions import UserError
     33 from inventorycommon.util import IsFittingFlag, IsFittingModule, IsFighterTubeFlag, IsShipFittingFlag
     34 from itertoolsext import first
     35 from menu import MenuLabel
     36 from player_messaging.client.ui_message import prompt_player_fsd_dialog, prompt_player_fsd_dialog
     37 from shipfitting.droneUtil import GetOptimalDroneDamage
     38 from shipfitting.fittingDogmaLocationUtil import GetDamageFromItem, GetChanceToHit
     39 GROUPALL_THROTTLE_TIMER = 2 * const.SEC
     40 
     41 class DogmaLocation(BaseDogmaLocation):
     42     __notifyevents__ = ['OnModuleAttributeChanges',
     43      'OnWeaponBanksChanged',
     44      'OnWeaponGroupDestroyed',
     45      'OnServerBrainUpdated',
     46      'OnHeatAdded',
     47      'OnHeatRemoved',
     48      'OnDroneControlLost',
     49      'OnDroneStateChange2',
     50      'OnFighterRemovedFromControllerClient']
     51 
     52     def __init__(self, broker, charBrain = None):
     53         super(DogmaLocation, self).__init__(broker)
     54         self.instanceCache = {}
     55         self.scatterAttributeChanges = True
     56         self.dogmaStaticMgr = sm.GetService('clientDogmaStaticSvc')
     57         self.remoteDogmaLM = None
     58         self.godma = sm.GetService('godma')
     59         self.stateMgr = self.godma.GetStateManager()
     60         self.skillSvc = sm.GetService('skills')
     61         self.fakeInstanceRow = None
     62         self.items = {}
     63         self.nextItemID = 0
     64         self.effectCompiler = sm.GetService('clientEffectCompiler')
     65         self.brain = None
     66         if charBrain:
     67             initialBrain = (-1,) + charBrain[1:]
     68             self.SetBrainData(session.charid, initialBrain)
     69         self.lastGroupAllRequest = None
     70         self.lastUngroupAllRequest = None
     71         self.shipIDBeingDisembarked = None
     72         self.shipIDBeingEmbarked = None
     73         self.locationName = 'ClientDogmaLocation'
     74         sm.RegisterNotify(self)
     75 
     76     def SetBrainData(self, charID, brain):
     77         self.brain = brain
     78 
     79     def GetBrainData(self, charID):
     80         return self.brain
     81 
     82     def HasBrainData(self, charID):
     83         return self.brain is not None
     84 
     85     def GetCurrentShipID(self):
     86         return self.shipsByPilotID.get(session.charid, None)
     87 
     88     def GetActiveShipID(self, characterID = None):
     89         return session.shipid
     90 
     91     def CheckApplyBrainEffects(self, shipID):
     92         return shipID in self.dogmaItems
     93 
     94     def GetMatchingAmmo(self, shipID, itemID):
     95         ammoInfoByTypeID = defaultdict(lambda : utillib.KeyVal(singletons=[], nonSingletons=[]))
     96         dogmaItem = self.dogmaItems[itemID]
     97         for item in self.broker.invCache.GetInventoryFromId(shipID).List(const.flagCargo):
     98             if self.GetMissingSkills(item.typeID):
     99                 continue
    100             if IsChargeCompatibleWithLauncher(item.typeID, dogmaItem.typeID, self.dogmaStaticMgr):
    101                 if item.singleton:
    102                     ammoInfoByTypeID[item.typeID].singletons.append(item)
    103                 else:
    104                     ammoInfoByTypeID[item.typeID].nonSingletons.append(item)
    105 
    106         return ammoInfoByTypeID
    107 
    108     def AddToMenuFromAmmoInfo(self, itemID, chargeTypeID, ammoInfo, minimumAmmoNeeded, labels, numDamageTypes = None):
    109         menu = []
    110         menuClass = None
    111         if numDamageTypes >= 2:
    112             from eve.client.script.ui.control.eveMenu import AmmoMenuEntryView2
    113             menuClass = AmmoMenuEntryView2
    114         elif numDamageTypes == 1:
    115             from eve.client.script.ui.control.eveMenu import AmmoMenuEntryView
    116             menuClass = AmmoMenuEntryView
    117         if sum((item.stacksize for item in ammoInfo.singletons)) >= minimumAmmoNeeded:
    118             text = MenuLabel(labels[0], {'typeID': chargeTypeID})
    119             menu.append((text,
    120              self.LoadChargesToModule,
    121              (itemID, ammoInfo.singletons, ammoInfo.singletons[0].locationID),
    122              None,
    123              menuClass,
    124              None,
    125              chargeTypeID))
    126         noOfNonSingletons = sum((item.stacksize for item in ammoInfo.nonSingletons))
    127         if noOfNonSingletons >= minimumAmmoNeeded:
    128             text = MenuLabel(labels[1], {'typeID': chargeTypeID,
    129              'sumqty': noOfNonSingletons})
    130             menu.append((text,
    131              self.LoadChargesToModule,
    132              (itemID, ammoInfo.nonSingletons, ammoInfo.nonSingletons[0].locationID),
    133              None,
    134              menuClass,
    135              None,
    136              chargeTypeID))
    137         return menu
    138 
    139     def GetAmmoMenu(self, shipID, itemID, existingCharge, roomForReload):
    140         usedChargeType = self.godma.GetStateManager().GetAmmoTypeForModule(itemID)
    141         ammoInfoByTypeID = self.GetMatchingAmmo(shipID, itemID)
    142         sortedCharges = self.GetSortedCharges(itemID, ammoInfoByTypeID.keys(), existingCharge)
    143         numDamageTypes = self._FindNumDamageTypes(sortedCharges)
    144         try:
    145             minimumAmmoNeeded = len(self.GetModulesInBank(shipID, itemID))
    146         except TypeError:
    147             minimumAmmoNeeded = 1
    148 
    149         menu = []
    150         if usedChargeType in ammoInfoByTypeID and roomForReload:
    151             ammoInfo = ammoInfoByTypeID[usedChargeType]
    152             menuItems = self.AddToMenuFromAmmoInfo(itemID, usedChargeType, ammoInfo, minimumAmmoNeeded, ('UI/Inflight/ModuleRacks/ReloadUsed', 'UI/Inflight/ModuleRacks/Reload'), numDamageTypes)
    153             if menuItems:
    154                 menu.extend(menuItems)
    155                 menu.append((MenuLabel('UI/Inflight/ModuleRacks/ReloadAll'), uicore.cmd.GetCommandToExecute('CmdReloadAmmo')))
    156         if existingCharge and not self.godma.GetStateManager().IsModuleReloading(itemID):
    157             relevantOwner = session.charid
    158             label = 'UI/Inflight/ModuleRacks/UnloadToCargo'
    159             if IsControllingStructure() and shipID == session.structureid:
    160                 label = 'UI/Inflight/ModuleRacks/UnloadToAmmoHold'
    161                 relevantOwner = sm.GetService('structureDirectory').GetStructureInfo(shipID).ownerID
    162             shipItem = self.dogmaItems[shipID]
    163             flagID = const.flagCargo
    164             if shipItem.groupID == const.groupFlagCruiser:
    165                 flagID = const.flagSpecializedAmmoHold
    166                 label = 'UI/Inflight/ModuleRacks/UnloadToAmmoHold'
    167             menu.append((MenuLabel(label), self.UnloadAmmoToContainer, (shipID, existingCharge, (shipID, relevantOwner, flagID))))
    168         otherChargeMenu = []
    169         for chargeTypeID in sortedCharges:
    170             ammoInfo = ammoInfoByTypeID[chargeTypeID]
    171             if chargeTypeID == usedChargeType:
    172                 continue
    173             otherChargeMenu.extend(self.AddToMenuFromAmmoInfo(itemID, chargeTypeID, ammoInfo, minimumAmmoNeeded, ('UI/Inflight/ModuleRacks/AmmoTypeAndStatus', 'UI/Inflight/ModuleRacks/AmmoTypeAndQuantity'), numDamageTypes))
    174 
    175         menu.extend(otherChargeMenu)
    176         return menu
    177 
    178     def GetSortedCharges(self, moduleID, ammoTypeIDs, existingCharge):
    179         typeIDsWithRangeInfo = []
    180         rest = []
    181         weaponRangeForModule = self.GetAccurateAttributeValue(moduleID, const.attributeMaxRange)
    182         weaponFalloffForModule = self.GetAccurateAttributeValue(moduleID, const.attributeFalloff)
    183         if weaponRangeForModule and existingCharge:
    184             existingRangeMultiplier = self.GetAccurateAttributeValue(existingCharge.itemID, const.attributeWeaponRangeMultiplier)
    185             if existingRangeMultiplier:
    186                 weaponRangeForModule = weaponRangeForModule / existingRangeMultiplier
    187             existingFalloffMultiplier = self.GetAccurateAttributeValue(existingCharge.itemID, const.attributeFalloffMultiplier)
    188             if existingFalloffMultiplier:
    189                 weaponFalloffForModule = weaponFalloffForModule / existingFalloffMultiplier
    190         for eachTypeID in ammoTypeIDs:
    191             rangeForCharge = None
    192             rangeMultiplier = self.dogmaStaticMgr.GetTypeAttribute(eachTypeID, const.attributeWeaponRangeMultiplier)
    193             if rangeMultiplier:
    194                 falloffBonus = self.dogmaStaticMgr.GetTypeAttribute(eachTypeID, const.attributeFalloffMultiplier, 1.0)
    195                 rangeWithFalloff = falloffBonus * weaponFalloffForModule + rangeMultiplier * weaponRangeForModule
    196                 rangeForCharge = rangeWithFalloff
    197             else:
    198                 flightTime = self.dogmaStaticMgr.GetTypeAttribute(eachTypeID, const.attributeExplosionDelay)
    199                 if flightTime:
    200                     velocity = self.dogmaStaticMgr.GetTypeAttribute(eachTypeID, const.attributeMaxVelocity)
    201                     rangeForCharge = flightTime * velocity / 1000.0
    202             if rangeForCharge:
    203                 sortKey = (-rangeForCharge, evetypes.GetName(eachTypeID))
    204                 typeIDsWithRangeInfo.append((sortKey, eachTypeID))
    205             else:
    206                 rest.append(eachTypeID)
    207 
    208         sortedCharges = SortListOfTuples(typeIDsWithRangeInfo)
    209         rest = localization.util.Sort(rest, key=lambda x: evetypes.GetName(x))
    210         return sortedCharges + rest
    211 
    212     def _FindNumDamageTypes(self, sortedCharges):
    213         numDamageTypes = 0
    214         for eachTypeID in sortedCharges:
    215             numDamageTypes = 0
    216             for attrID in dogma.attributes.groups.damage_type_attribute_ids:
    217                 value = self.dogmaStaticMgr.GetTypeAttribute(eachTypeID, attrID)
    218                 if value:
    219                     numDamageTypes += 1
    220                 if numDamageTypes >= 2:
    221                     return numDamageTypes
    222 
    223         return numDamageTypes
    224 
    225     @WrappedMethod
    226     @telemetry.ZONE_METHOD
    227     def MakeShipActive(self, shipID, shipState = None):
    228         uthread.pool('MakeShipActive', self._MakeShipActive, shipID, shipState)
    229 
    230     @WrappedMethod
    231     @telemetry.ZONE_METHOD
    232     def _MakeShipActive(self, shipID, shipState):
    233         if shipID is None:
    234             log.LogTraceback('Unexpectedly got shipID = None')
    235             return
    236         if shipID == self.locationID:
    237             log.LogTraceback('ClientDogmaLocation is attempting to activate itself as a characters shipID!')
    238             return
    239         uthread.Lock(self, 'makeShipActive')
    240         try:
    241             self.shipIDBeingDisembarked = self.GetCurrentShipID()
    242             self.shipIDBeingEmbarked = shipID
    243             if self.GetCurrentShipID() == shipID:
    244                 self.shipIDBeingEmbarked = self.shipIDBeingDisembarked = None
    245                 return
    246             while not session.IsItSafe():
    247                 self.LogInfo('MakeShipActive - session is mutating. Sleeping for 250ms')
    248                 blue.pyos.synchro.SleepSim(250)
    249 
    250             self.UpdateRemoteDogmaLocation()
    251             oldShipID = self.GetCurrentShipID()
    252             if shipState is None:
    253                 sessionMgr = sm.GetService('sessionMgr')
    254                 shipState = sessionMgr.PerformSelectiveSessionChange('board', 'board', False, self.remoteShipMgr.Board, shipID, session.shipid)
    255             self.instanceCache, self.instanceFlagQuantityCache, self.wbData, heatStates = shipState
    256             if oldShipID and oldShipID in self.dogmaItems:
    257                 self.RemoveBrainEffects(oldShipID, session.charid, 'clientDogmaLocation._MakeShipActive')
    258             self.scatterAttributeChanges = False
    259             try:
    260                 LogNotice('_MakeShipActive: Calling LoadItem on new shipID=', shipID)
    261                 if oldShipID is not None:
    262                     LogNotice('_MakeShipActive: Unfitting oldShipID=', oldShipID)
    263                     self.UnfitItemFromLocation(oldShipID, session.charid)
    264                 if shipID is not None:
    265                     LogNotice('_MakeShipActive: Calling OnCharacterEmbarkation')
    266                     if not oldShipID:
    267                         self.LoadItem(session.charid)
    268                         self.SetWeaponBanks(shipID, self.wbData)
    269                     else:
    270                         if oldShipID and oldShipID in self.dogmaItems:
    271                             LogNotice('_MakeShipActive: Unloading oldShipID=', oldShipID)
    272                             self.UninstallPilotFromShipAndItems(oldShipID)
    273                             self.UnloadItem(oldShipID)
    274                         self.OnCharacterEmbarkation(session.charid, shipID, switching=oldShipID is not None)
    275                         LogNotice('_MakeShipActive: Calling SetWeaponBanks')
    276                         self.SetWeaponBanks(shipID, self.wbData)
    277                         self.LoadItemsInLocation(shipID)
    278                         sm.ChainEvent('ProcessActiveShipChanged', shipID, oldShipID)
    279             finally:
    280                 self.scatterAttributeChanges = True
    281 
    282             self.ClearInstanceCache()
    283         finally:
    284             self.shipIDBeingDisembarked = None
    285             self.shipIDBeingEmbarked = None
    286             uthread.UnLock(self, 'makeShipActive')
    287 
    288         LogNotice('_MakeShipActive: DONE')
    289 
    290     def WaitForShip(self):
    291         startTime = blue.os.GetWallclockTime()
    292         while self.IsSwitchingShips() and blue.os.TimeDiffInMs(startTime, blue.os.GetWallclockTime()) < 2000:
    293             blue.pyos.synchro.Sleep(100)
    294 
    295     def IsSwitchingShips(self):
    296         return self.shipIDBeingDisembarked is not None
    297 
    298     def ClearInstanceCache(self):
    299         self.instanceCache = {}
    300         self.instanceFlagQuantityCache = {}
    301         self.wbData = None
    302 
    303     @telemetry.ZONE_METHOD
    304     def UpdateRemoteDogmaLocation(self):
    305         if session.stationid is not None:
    306             self.remoteDogmaLM = eveMoniker.GetStationDogmaLocation()
    307             self.remoteShipMgr = eveMoniker.GetStationShipAccess()
    308             self.locationGroup = const.groupStation
    309             self.locationID = session.stationid
    310         else:
    311             self.remoteDogmaLM = eveMoniker.CharGetDogmaLocation()
    312             self.remoteShipMgr = eveMoniker.GetShipAccess()
    313             self.locationGroup = const.groupSolarSystem
    314             self.locationID = session.solarsystemid
    315 
    316     @telemetry.ZONE_METHOD
    317     def OnModuleAttributeChanges(self, changes):
    318         changes.sort(key=lambda change: change[4])
    319         for change in changes:
    320             try:
    321                 eventName, ownerID, itemID, attributeID, time, newValue, oldValue, _ = change
    322                 if attributeID == const.attributeQuantity:
    323                     if isinstance(itemID, tuple) and not self.IsItemLoaded(itemID[0]):
    324                         self.LogWarn("got an module attribute change and the item wasn't loaded", itemID)
    325                         continue
    326                     if newValue == 0:
    327                         self.SetAttributeValue(itemID, const.attributeQuantity, newValue)
    328                         self.UnfitAndUnloadItem(itemID[0], itemID)
    329                     else:
    330                         if itemID != self.GetSubLocation(itemID[0], itemID[1]):
    331                             self.FitItemToLocation(itemID[0], itemID, itemID[1])
    332                         self.dogmaItems[itemID].attributes[attributeID].SetBaseValue(newValue)
    333                 elif attributeID == const.attributeIsOnline:
    334                     if not self.IsItemLoaded(itemID):
    335                         continue
    336                     if newValue == self.GetAttributeValue(itemID, const.attributeIsOnline):
    337                         continue
    338                     if newValue == 0:
    339                         self.StopEffect(const.effectOnline, itemID)
    340                     else:
    341                         self.Activate(itemID, const.effectOnline)
    342                 elif self.IsItemLoaded(itemID) and attributeID in self.dogmaStaticMgr.damageStateAttributes:
    343                     dogmaItem = self.dogmaItems[itemID]
    344                     dogmaItem.attributes[attributeID].SetBaseValue(newValue)
    345                     sm.ScatterEvent('OnDamageStateChanged', itemID, attributeID, newValue, oldValue)
    346                 elif self.IsItemLoaded(itemID) and attributeID in const.heatAttributes:
    347                     dogmaItem = self.dogmaItems[itemID]
    348                     dogmaItem.attributes[attributeID].SetBaseValue(newValue)
    349             except Exception as e:
    350                 log.LogException('OnModuleAttributeChanges::Unexpected exception')
    351                 sys.exc_clear()
    352 
    353     def LoadItem(self, itemKey, **kwargs):
    354         if itemKey == session.locationid:
    355             return itemKey
    356         super(DogmaLocation, self).LoadItem(itemKey, **kwargs)
    357 
    358     @telemetry.ZONE_METHOD
    359     def FitItemToLocation(self, locationID, itemID, flagID):
    360         if self._IsLocationIDInvalidForFitting(locationID):
    361             return
    362         super(DogmaLocation, self).FitItemToLocation(locationID, itemID, flagID)
    363 
    364     @telemetry.ZONE_METHOD
    365     def UnfitItemFromLocation(self, locationID, itemID, flushEffects = False):
    366         super(DogmaLocation, self).UnfitItemFromLocation(locationID, itemID, flushEffects)
    367         self.ScheduleCheckPowerCpuRequirementForOnlineModules(locationID)
    368 
    369     @telemetry.ZONE_METHOD
    370     def GetChargeNonDB(self, shipID, flagID):
    371         for itemID, fittedItem in self.dogmaItems[shipID].GetFittedItems().iteritems():
    372             if isinstance(itemID, tuple):
    373                 continue
    374             if fittedItem.flagID != flagID:
    375                 continue
    376             if fittedItem.categoryID == const.categoryCharge:
    377                 return fittedItem
    378 
    379     @telemetry.ZONE_METHOD
    380     def GetSubSystemInFlag(self, shipID, flagID):
    381         fittedItems = self.GetFittedItemsToShip()
    382         itemsByFlagID = {x.flagID:x for x in fittedItems.itervalues()}
    383         return itemsByFlagID.get(flagID)
    384 
    385     @telemetry.ZONE_METHOD
    386     def GetItem(self, itemID):
    387         session.WaitUntilSafe()
    388         if itemID == self.GetCurrentShipID() or itemID == self.shipIDBeingEmbarked:
    389             return self.broker.invCache.GetInventoryFromId(itemID, locationID=session.stationid).GetItem()
    390         try:
    391             return self.items[itemID]
    392         except KeyError:
    393             sys.exc_clear()
    394 
    395         return self.godma.GetItem(itemID)
    396 
    397     @telemetry.ZONE_METHOD
    398     def GetCharacter(self, itemID, flush):
    399         return self.GetItem(itemID)
    400 
    401     @telemetry.ZONE_METHOD
    402     def Activate(self, itemID, effectID):
    403         dogmaItem = self.dogmaItems[itemID]
    404         envInfo = dogmaItem.GetEnvironmentInfo()
    405         env = Environment(envInfo.itemID, envInfo.charID, envInfo.shipID, envInfo.targetID, envInfo.otherID, effectID, weakref.proxy(self), None, envInfo.structureID)
    406         env.dogmaLM = self
    407         self.StartEffect(effectID, itemID, env)
    408 
    409     @telemetry.ZONE_METHOD
    410     def PostStopEffectAction(self, effectID, dogmaItem, activationInfo, *args):
    411         super(DogmaLocation, self).PostStopEffectAction(effectID, dogmaItem, activationInfo, *args)
    412         if effectID == const.effectOnline:
    413             self.ScheduleCheckPowerCpuRequirementForOnlineModules(dogmaItem.locationID)
    414 
    415     @telemetry.ZONE_METHOD
    416     def GetInstance(self, item):
    417         try:
    418             return self.instanceCache[item.itemID]
    419         except KeyError:
    420             sys.exc_clear()
    421 
    422         instanceRow = [item.itemID]
    423         godmaItem = self.broker.godma.GetItem(item.itemID)
    424         for attributeID in self.GetAttributesByIndex().itervalues():
    425             instanceRow.append(getattr(godmaItem, self.dogmaStaticMgr.attributes[attributeID].name, 0))
    426 
    427         return instanceRow
    428 
    429     def GetAccurateAttributeValue(self, itemID, attributeID, *args):
    430         godmaItem = self.godma.GetItem(itemID)
    431         isDocked = bool(session.stationid or session.structureid)
    432         if isDocked or godmaItem is None:
    433             return self.GetAttributeValue(itemID, attributeID)
    434         else:
    435             return self.GetGodmaAttributeValue(itemID, attributeID)
    436 
    437     @telemetry.ZONE_METHOD
    438     def GetMissingSkills(self, typeID, skillSvc = None):
    439         if skillSvc is None:
    440             skillSvc = sm.GetService('skills')
    441         return super(DogmaLocation, self).GetMissingSkills(typeID, skillSvc.GetSkills())
    442 
    443     @telemetry.ZONE_METHOD
    444     def CheckSkillRequirementsForType(self, _, typeID, errorMsgName):
    445         missingSkills = self.GetMissingSkills(typeID)
    446         if len(missingSkills) > 0:
    447             nameList = []
    448             for skillTypeID, requiredSkillLevel in missingSkills.iteritems():
    449                 nameList.append(localization.GetByLabel('UI/SkillQueue/Skills/SkillNameAndLevel', skill=skillTypeID, amount=requiredSkillLevel))
    450 
    451             raise UserError(errorMsgName, {'requiredSkills': localization.formatters.FormatGenericList(nameList),
    452              'item': typeID,
    453              'skillCount': len(nameList)})
    454         return missingSkills
    455 
    456     @telemetry.ZONE_METHOD
    457     def LoadItemsInLocation(self, itemID):
    458         if itemID in (session.charid, self.GetCurrentShipID(), self.shipIDBeingEmbarked):
    459             dogmaItem = self.dogmaItems[itemID]
    460             self.LogInfo('LoadItemsInLocation %s' % itemID)
    461             self.UpdateRemoteDogmaLocation()
    462             itemInv = self.broker.invCache.GetInventoryFromId(itemID, locationID=self.locationID)
    463             for item in sorted(itemInv.List(), key=lambda x: x.categoryID not in (const.categoryModule, const.categoryStructureModule)):
    464                 try:
    465                     if dogmaItem.ValidFittingFlag(item.flagID):
    466                         self.items[item.itemID] = item
    467                         self.LoadItem(item.itemID, invItem=item)
    468                 except Exception:
    469                     if item.itemID in self.items:
    470                         del self.items[item.itemID]
    471                     log.LogException('LoadItemsInLocation %s, %s' % (itemID, evetypes.GetName(item.typeID)))
    472                     sys.exc_clear()
    473 
    474     def UnloadItem(self, itemKey, item = None):
    475         super(DogmaLocation, self).UnloadItem(itemKey, item)
    476         if itemKey in self.items:
    477             del self.items[itemKey]
    478 
    479     def UnfitAndUnloadItem(self, locationID, itemID):
    480         self.UnfitItemFromLocation(locationID, itemID)
    481         self.UnloadItem(itemID)
    482 
    483     def UnloadItemsInLocation(self, locationID):
    484         if locationID in (session.charid, self.GetCurrentShipID(), self.shipIDBeingEmbarked):
    485             self.LogInfo('UnloadItemsInLocation %s' % locationID)
    486             self.UpdateRemoteDogmaLocation()
    487             itemInv = self.broker.invCache.GetInventoryFromId(locationID, locationID=self.locationID)
    488             for item in itemInv.List():
    489                 try:
    490                     self.UnfitItem(item.itemID)
    491                     self.UnloadItem(item.itemID, item)
    492                     if item.itemID in self.items:
    493                         del self.items[item.itemID]
    494                 except:
    495                     if item.itemID not in self.items:
    496                         self.items[item.itemID] = item
    497                     log.LogException('UnloadItemsInLocation %s, %s' % (locationID, evetypes.GetName(item.typeID)))
    498                     sys.exc_clear()
    499 
    500     def GetSensorStrengthAttribute(self, shipID):
    501         maxAttributeID = None
    502         maxValue = None
    503         for attributeID in (const.attributeScanGravimetricStrength,
    504          const.attributeScanLadarStrength,
    505          const.attributeScanMagnetometricStrength,
    506          const.attributeScanRadarStrength):
    507             val = self.GetAttributeValue(shipID, attributeID)
    508             if val > maxValue:
    509                 maxValue, maxAttributeID = val, attributeID
    510 
    511         return (maxAttributeID, maxValue)
    512 
    513     def UnfitItem(self, itemID):
    514         if itemID == session.charid:
    515             self.UnboardShip(session.charid)
    516         else:
    517             locationID = self.dogmaItems[itemID].locationID
    518             self.UnfitAndUnloadItem(locationID, itemID)
    519         if itemID in self.items:
    520             del self.items[itemID]
    521         if itemID in self.instanceCache:
    522             del self.instanceCache[itemID]
    523 
    524     def UnboardShip(self, charID):
    525         char = self.dogmaItems[charID]
    526         charItems = char.GetFittedItems()
    527         for implant in charItems.itervalues():
    528             for effectID in implant.activeEffects.keys():
    529                 self.StopEffect(effectID, implant.itemID)
    530 
    531         oldShipID = self.GetCurrentShipID()
    532         self.UnfitItemFromLocation(self.GetCurrentShipID(), charID)
    533 
    534     def FitItem(self, item):
    535         if self._IsLocationIDInvalidForFitting(item.locationID):
    536             return
    537         self.items[item.itemID] = item
    538         self.LoadItem(item.itemID)
    539         self.FitItemToLocation(item.locationID, item.itemID, item.flagID)
    540 
    541     def GetChanceToHit(self, shipID, targetID):
    542         trackingSpeed, falloff, maxRange, optimalSig = GetChanceToHit(shipID, self)
    543         bp = self.broker.michelle.GetBallpark()
    544         ball = bp.slimItems.get(targetID)
    545         if ball:
    546             targetSig = bp.slimItems.get(targetID).signatureRadius
    547             return (bp._parent_GetAccuracy(shipID, targetID, maxRange, falloff, trackingSpeed, targetSig, optimalSig)[0], (trackingSpeed,
    548               maxRange,
    549               falloff,
    550               optimalSig))
    551         raise RuntimeError('target not found')
    552 
    553     def OnItemChange(self, item, change, location):
    554         wasFitted = item.itemID in self.dogmaItems
    555         isFitted = self.IsFitted(item)
    556         wasLaunchingDrones = False
    557         wasLaunchingFighters = False
    558         if wasFitted and not isFitted and not isinstance(item.itemID, tuple):
    559             if item.categoryID == const.categoryDrone:
    560                 wasLaunchingDrones = self._WasLaunchingDrone(item, change)
    561                 if not wasLaunchingDrones:
    562                     self.LogNotice('Unfitting item as a result from item change', item, change)
    563                     self.UnfitAndUnloadItem(self.GetCurrentShipID(), item.itemID)
    564             elif item.categoryID == const.categoryFighter:
    565                 wasLaunchingFighters = self._WasLaunchingFighter(item, change)
    566                 if not wasLaunchingFighters:
    567                     self.LogNotice('Unfitting item as a result from item change', item, change)
    568                     self.UnfitAndUnloadItem(self.GetCurrentShipID(), item.itemID)
    569             else:
    570                 self.UnfitItem(item.itemID)
    571         if not wasFitted and isFitted and not isinstance(item.itemID, tuple):
    572             self.LogNotice('Fitting item as a result from item change', item, change)
    573             self.FitItem(item)
    574         if wasFitted and isFitted and const.ixFlag in change:
    575             self.dogmaItems[item.itemID].flagID = item.flagID
    576         if isFitted and const.ixStackSize in change:
    577             self.SetAttributeValue(item.itemID, const.attributeQuantity, item.stacksize)
    578         try:
    579             dogmaItem = self.dogmaItems[item.itemID]
    580         except KeyError:
    581             pass
    582         else:
    583             oldLocationID = item.locationID
    584             oldOwnerID = item.ownerID
    585             dogmaItem.invItem = item
    586             if const.ixOwnerID in change:
    587                 dogmaItem.HandleOwnerChange(oldOwnerID)
    588             if const.ixLocationID in change:
    589                 dogmaItem.HandleLocationChange(oldLocationID)
    590                 if wasLaunchingDrones or wasLaunchingFighters:
    591                     shipItem = self.GetShip()
    592                     if shipItem and dogmaItem:
    593                         shipItem.subItems.add(dogmaItem)
    594             if isFitted and not wasFitted:
    595                 self._OnlineModuleIfApplicable(item)
    596 
    597         if self.scatterAttributeChanges:
    598             sm.ScatterEvent('OnDogmaItemChange', item, change)
    599         self.items[item.itemID] = item
    600 
    601     def _WasLaunchingDrone(self, item, change):
    602         return WasLaunchingDrone(item, change, self.locationID)
    603 
    604     def _WasLaunchingFighter(self, item, change):
    605         return WasLaunchingFighter(item, change, self.locationID)
    606 
    607     def _OnlineModuleIfApplicable(self, item):
    608         if self.dogmaStaticMgr.TypeHasEffect(item.typeID, const.effectOnline):
    609             try:
    610                 self.OnlineModule(item.itemID)
    611             except UserError as e:
    612                 if e.msg != 'EffectAlreadyActive2':
    613                     uthread.pool('FitItem::RaiseUserError', prompt_player_fsd_dialog, *e.args)
    614             except Exception:
    615                 log.LogException('Raised during OnlineModule')
    616 
    617     def IsFitted(self, item):
    618         if self._IsLocationIDInvalidForFitting(item.locationID):
    619             return False
    620         if not IsFittingFlag(item.flagID) and not self.IsValidDroneOrFighterLocation(item.flagID):
    621             return False
    622         if item[const.ixStackSize] <= 0:
    623             return False
    624         return True
    625 
    626     def IsValidDroneOrFighterLocation(self, flagID):
    627         if flagID == const.flagDroneBay or IsFighterTubeFlag(flagID):
    628             return True
    629         return False
    630 
    631     def _IsLocationIDInvalidForFitting(self, locationID):
    632         if locationID == self.shipIDBeingDisembarked:
    633             self.LogNotice('Ignoring location because the ship is being disembarked', locationID)
    634             return True
    635         isLocationIDValidForFitting = locationID not in (self.GetCurrentShipID(), session.charid, self.shipIDBeingEmbarked)
    636         return isLocationIDValidForFitting
    637 
    638     def OnAttributeChanged(self, attributeID, itemKey, value = None, oldValue = None):
    639         value = super(DogmaLocation, self).OnAttributeChanged(attributeID, itemKey, value=value, oldValue=oldValue)
    640         if self.scatterAttributeChanges:
    641             sm.ScatterEvent('OnDogmaAttributeChanged', self.GetCurrentShipID(), itemKey, attributeID, value)
    642 
    643     def GetShip(self):
    644         return self.dogmaItems[self.GetCurrentShipID()]
    645 
    646     def GetShipItem(self):
    647         return self.SafeGetDogmaItem(self.GetCurrentShipID())
    648 
    649     def TryFit(self, item, flagID):
    650         shipID = eveCfg.GetActiveShip()
    651         shipInv = self.broker.invCache.GetInventoryFromId(shipID, locationID=session.stationid)
    652         shipInv.Add(item.itemID, item.locationID, qty=1, flag=flagID)
    653 
    654     def GetQuantity(self, itemID):
    655         if isinstance(itemID, tuple):
    656             return self.GetAttributeValue(itemID, const.attributeQuantity)
    657         return self.GetItem(itemID).stacksize
    658 
    659     def GetCapacity(self, shipID, attributeID, flagID):
    660         ret = self.broker.invCache.GetInventoryFromId(self.GetCurrentShipID(), locationID=session.stationid).GetCapacity(flagID)
    661         if const.flagLoSlot0 <= flagID <= const.flagHiSlot7:
    662             shipDogmaItem = self.dogmaItems[shipID]
    663             subLocation = shipDogmaItem.subLocations.get(flagID, None)
    664             if subLocation is None:
    665                 used = ret.used
    666             else:
    667                 used = self.GetAttributeValue(subLocation, const.attributeQuantity) * evetypes.GetVolume(subLocation[2])
    668             moduleID = self.GetSlotOther(shipID, flagID)
    669             if moduleID is None:
    670                 capacity = 0
    671             else:
    672                 capacity = self.GetAttributeValue(moduleID, const.attributeCapacity)
    673             return utillib.KeyVal(capacity=capacity, used=used)
    674         return ret
    675 
    676     def OnlineModule(self, moduleID):
    677         self.Activate(moduleID, const.effectOnline)
    678         dogmaItem = self.dogmaItems[moduleID]
    679         try:
    680             self.remoteDogmaLM.SetModuleOnline(dogmaItem.locationID, moduleID)
    681         except UserError as e:
    682             if e.msg != 'EffectAlreadyActive2':
    683                 self.StopEffect(const.effectOnline, moduleID)
    684                 raise
    685         except Exception:
    686             self.StopEffect(const.effectOnline, moduleID)
    687             raise
    688 
    689     def OfflineModule(self, moduleID):
    690         dogmaItem = self.dogmaItems[moduleID]
    691         if dogmaItem.locationID not in (self.shipIDBeingDisembarked, self.shipIDBeingEmbarked):
    692             try:
    693                 self.StopEffect(const.effectOnline, moduleID)
    694                 self.remoteDogmaLM.TakeModuleOffline(dogmaItem.locationID, moduleID)
    695             except Exception:
    696                 self.Activate(moduleID, const.effectOnline)
    697                 raise
    698 
    699     def GetDragData(self, itemID):
    700         if itemID in self.items:
    701             return [uix.GetItemData(self.items[itemID], 'icons')]
    702         dogmaItem = self.dogmaItems[itemID]
    703         data = Bunch()
    704         data.__guid__ = 'listentry.InvItem'
    705         data.item = utillib.KeyVal(itemID=dogmaItem.itemID, typeID=dogmaItem.typeID, groupID=dogmaItem.groupID, categoryID=dogmaItem.categoryID, flagID=dogmaItem.flagID, ownerID=dogmaItem.ownerID, locationID=dogmaItem.locationID, stacksize=self.GetAttributeValue(itemID, const.attributeQuantity))
    706         data.rec = data.item
    707         data.itemID = itemID
    708         data.viewMode = 'icons'
    709         return [data]
    710 
    711     def GetDisplayAttributes(self, itemID, attributes):
    712         ret = {}
    713         dogmaItem = self.dogmaItems[itemID]
    714         for attributeID in itertools.chain(dogmaItem.attributes, attributes):
    715             if attributeID == const.attributeVolume:
    716                 continue
    717             ret[attributeID] = self.GetAttributeValue(itemID, attributeID)
    718 
    719         return ret
    720 
    721     def GetCharacterSecurityStatus(self, charID):
    722         if charID != session.charid:
    723             return 0.0
    724         return sm.GetService('crimewatchSvc').GetMySecurityStatus()
    725 
    726     def LinkWeapons(self, shipID, toID, fromID, merge = True):
    727         if toID == fromID:
    728             return
    729         toItem = self.dogmaItems[toID]
    730         fromItem = self.dogmaItems[fromID]
    731         for item in (toItem, fromItem):
    732             if not item.IsOnline():
    733                 raise UserError('CantLinkModuleNotOnline')
    734 
    735         if toItem.typeID != fromItem.typeID:
    736             self.LogInfo('LinkWeapons::Modules not of same type', toItem, fromItem)
    737             return
    738         if toItem.groupID not in const.dgmGroupableGroupIDs:
    739             self.LogInfo('group not groupable', toItem, fromItem)
    740             return
    741         if shipID is None or shipID != fromItem.locationID:
    742             log.LogTraceback('LinkWeapons::Modules not located in the same place')
    743         masterID = self.GetMasterModuleID(shipID, toID)
    744         if not masterID:
    745             masterID = toID
    746         slaveID = self.IsInWeaponBank(shipID, fromID)
    747         if slaveID:
    748             if merge:
    749                 info = self.remoteDogmaLM.MergeModuleGroups(shipID, masterID, slaveID)
    750             else:
    751                 info = self.remoteDogmaLM.PeelAndLink(shipID, masterID, slaveID)
    752         else:
    753             info = self.remoteDogmaLM.LinkWeapons(shipID, masterID, fromID)
    754         self.OnWeaponBanksChanged(shipID, info)
    755 
    756     def UngroupModule(self, shipID, moduleID):
    757         slaveID = self.remoteDogmaLM.UnlinkModule(shipID, moduleID)
    758         self.slaveModulesByMasterModule[shipID][moduleID].remove(slaveID)
    759         if not self.slaveModulesByMasterModule[shipID][moduleID]:
    760             del self.slaveModulesByMasterModule[shipID][moduleID]
    761         self.SetGroupNumbers(shipID)
    762         sm.ScatterEvent('OnRefreshModuleBanks')
    763         return slaveID
    764 
    765     def UnlinkAllWeapons(self, shipID):
    766         self.remoteDogmaLM.UnlinkAllModules(shipID)
    767         self.OnWeaponBanksChanged(shipID, {})
    768         self.lastUngroupAllRequest = blue.os.GetSimTime()
    769 
    770     def LinkAllWeapons(self, shipID):
    771         info = self.remoteDogmaLM.LinkAllWeapons(shipID)
    772         self.OnWeaponBanksChanged(shipID, info)
    773         self.lastGroupAllRequest = blue.os.GetSimTime()
    774 
    775     def GetGroupAllOpacity(self, attributeName):
    776         lastRequest = getattr(self, attributeName)
    777         if lastRequest is None:
    778             return 1.0
    779         timeDiff = blue.os.GetSimTime() - lastRequest
    780         waitTime = min(GROUPALL_THROTTLE_TIMER, GROUPALL_THROTTLE_TIMER - timeDiff)
    781         opacity = max(0, 1 - float(waitTime) / GROUPALL_THROTTLE_TIMER)
    782         return opacity
    783 
    784     def IsInWeaponBank(self, shipID, itemID):
    785         slaveModulesByMasterModule = self.slaveModulesByMasterModule.get(shipID, {})
    786         if itemID in slaveModulesByMasterModule:
    787             return itemID
    788         masterID = self.GetMasterModuleID(shipID, itemID)
    789         if masterID is not None:
    790             return masterID
    791         return False
    792 
    793     def GetGroupableTypes(self, shipID):
    794         groupableTypes = defaultdict(lambda : 0)
    795         try:
    796             dogmaItem = self.dogmaItems[shipID]
    797         except KeyError:
    798             self.LogInfo('GetGroupableTypes - called before I was ready', shipID)
    799         else:
    800             for fittedItem in dogmaItem.GetFittedItems().itervalues():
    801                 if not const.flagHiSlot0 <= fittedItem.flagID <= const.flagHiSlot7:
    802                     continue
    803                 if fittedItem.groupID not in const.dgmGroupableGroupIDs:
    804                     continue
    805                 if not fittedItem.IsOnline():
    806                     continue
    807                 groupableTypes[fittedItem.typeID] += 1
    808 
    809         return groupableTypes
    810 
    811     def CanGroupAll(self, shipID):
    812         groupableTypes = self.GetGroupableTypes(shipID)
    813         groups = {}
    814         dogmaItem = self.dogmaItems[shipID]
    815         for fittedItem in dogmaItem.GetFittedItems().itervalues():
    816             if fittedItem.groupID not in const.dgmGroupableGroupIDs:
    817                 continue
    818             if not fittedItem.IsOnline():
    819                 continue
    820             if not self.IsInWeaponBank(shipID, fittedItem.itemID) and groupableTypes[fittedItem.typeID] > 1:
    821                 return True
    822             masterID = self.GetMasterModuleID(shipID, fittedItem.itemID)
    823             if masterID is None:
    824                 masterID = fittedItem.itemID
    825             if fittedItem.typeID not in groups:
    826                 groups[fittedItem.typeID] = masterID
    827             elif groups[fittedItem.typeID] != masterID:
    828                 return True
    829 
    830         return False
    831 
    832     def DestroyWeaponBank(self, shipID, itemID):
    833         self.remoteDogmaLM.DestroyWeaponBank(shipID, itemID)
    834         self.OnWeaponGroupDestroyed(shipID, itemID)
    835 
    836     def SetWeaponBanks(self, shipID, data):
    837         super(DogmaLocation, self).SetWeaponBanks(shipID, data)
    838         self.SetGroupNumbers(shipID)
    839 
    840     def OnWeaponBanksChanged(self, shipID, info):
    841         self.SetWeaponBanks(shipID, info)
    842         sm.ScatterEvent('OnRefreshModuleBanks')
    843 
    844     def OnWeaponGroupDestroyed(self, shipID, itemID):
    845         try:
    846             del self.slaveModulesByMasterModule[shipID][itemID]
    847         except KeyError:
    848             pass
    849 
    850         self.SetGroupNumbers(shipID)
    851         sm.ScatterEvent('OnRefreshModuleBanks')
    852 
    853     def SetGroupNumbers(self, shipID):
    854         allGroupsDict = settings.user.ui.Get('linkedWeapons_groupsDict', {})
    855         groupsDict = allGroupsDict.get(shipID, {})
    856         for masterID in groupsDict.keys():
    857             if masterID not in self.slaveModulesByMasterModule[shipID]:
    858                 del groupsDict[masterID]
    859 
    860         for masterID in self.slaveModulesByMasterModule[shipID]:
    861             if masterID in groupsDict:
    862                 continue
    863             for i in xrange(1, 9):
    864                 if i not in groupsDict.values():
    865                     groupsDict[masterID] = i
    866                     break
    867 
    868         settings.user.ui.Set('linkedWeapons_groupsDict', allGroupsDict)
    869 
    870     def GetModulesInBank(self, shipID, itemID):
    871         slaveModulesByMasterModule = self.slaveModulesByMasterModule.get(shipID, {})
    872         masterID = self.GetMasterModuleID(shipID, itemID)
    873         if masterID is None and itemID in slaveModulesByMasterModule:
    874             masterID = itemID
    875         elif masterID is None:
    876             return
    877         moduleIDs = self.GetSlaveModules(masterID, shipID)
    878         moduleIDs.add(masterID)
    879         return list(moduleIDs)
    880 
    881     def GetAllSlaveModulesByMasterModule(self, shipID):
    882         slaveModulesByMasterModule = self.slaveModulesByMasterModule.get(shipID, {})
    883         return slaveModulesByMasterModule
    884 
    885     def GetMasterModuleForFlag(self, shipID, flagID):
    886         moduleID = self.GetSlotOther(shipID, flagID)
    887         if moduleID is None:
    888             raise RuntimeError('GetMasterModuleForFlag, no module in the flag')
    889         masterID = self.GetMasterModuleID(shipID, moduleID)
    890         if masterID is not None:
    891             return masterID
    892         return moduleID
    893 
    894     def GetSubLocationsInBank(self, shipID, itemID):
    895         ret = []
    896         try:
    897             flagID = self.dogmaItems[itemID].flagID
    898         except KeyError:
    899             return []
    900 
    901         moduleID = self.GetSlotOther(shipID, flagID)
    902         if moduleID is None:
    903             return []
    904         moduleIDs = self.GetModulesInBank(shipID, moduleID)
    905         if not moduleIDs:
    906             return []
    907         shipDogmaItem = self.dogmaItems[shipID]
    908         for moduleID in moduleIDs:
    909             moduleDogmaItem = self.dogmaItems[moduleID]
    910             chargeID = shipDogmaItem.subLocations.get(moduleDogmaItem.flagID, None)
    911             if chargeID is not None:
    912                 ret.append(chargeID)
    913 
    914         return ret
    915 
    916     def GetCrystalsInBank(self, shipID, itemID):
    917         flagID = self.dogmaItems[itemID].flagID
    918         moduleID = self.GetSlotOther(shipID, flagID)
    919         if moduleID is None:
    920             return []
    921         moduleIDs = self.GetModulesInBank(shipID, moduleID)
    922         if not moduleIDs:
    923             return []
    924         crystals = []
    925         for moduleID in moduleIDs:
    926             moduleDogmaItem = self.dogmaItems[moduleID]
    927             crystal = self.GetChargeNonDB(shipID, moduleDogmaItem.flagID)
    928             if crystal is not None:
    929                 crystals.append(crystal.itemID)
    930 
    931         return crystals
    932 
    933     def LoadAmmoTypeToModule(self, moduleID, chargeTypeID):
    934         shipID = self.dogmaItems[moduleID].locationID
    935         shipInv = self.broker.invCache.GetInventoryFromId(shipID)
    936         chargeItems = [ ammoStack for ammoStack in shipInv.List(const.flagCargo) if ammoStack.typeID == chargeTypeID and not IsFittingFlag(ammoStack.flagID) ]
    937         self.LoadChargesToModule(moduleID, chargeItems, shipID)
    938 
    939     def LoadChargesToModule(self, moduleID, chargeItems, chargeLocationID):
    940         if not chargeItems:
    941             raise UserError('CannotLoadNotEnoughCharges')
    942         if not isinstance(chargeItems, (list, tuple)):
    943             chargeItems = [chargeItems]
    944         self.CheckSkillRequirementsForType(None, chargeItems[0].typeID, 'FittingHasSkillPrerequisites')
    945         moduleLocationID = self.dogmaItems[moduleID].locationID
    946         if self.IsModuleSlave(moduleID, moduleLocationID):
    947             moduleID = self.GetMasterModuleID(moduleLocationID, moduleID)
    948         PlaySound(uiconst.SOUND_ADD_OR_USE)
    949         self.remoteDogmaLM.LoadAmmo(moduleLocationID, moduleID, [ i.itemID for i in chargeItems ], chargeLocationID)
    950 
    951     def LoadAmmoToModules(self, shipID, moduleIDs, chargeItemIDs, ammoLocationID):
    952         PlaySound(uiconst.SOUND_ADD_OR_USE)
    953         self.remoteDogmaLM.LoadAmmo(shipID, moduleIDs, chargeItemIDs, ammoLocationID)
    954 
    955     def DropLoadChargeToModule(self, itemID, chargeTypeID, chargeItems):
    956         chargeLocationID = chargeItems[0].locationID
    957         chargeItems = filter(lambda i: i.locationID == chargeLocationID and i.typeID == chargeTypeID, chargeItems)
    958         if uicore.uilib.Key(uiconst.VK_SHIFT):
    959             maxQty = sum((i.stacksize for i in chargeItems))
    960             if maxQty == 0:
    961                 msg = localization.GetByLabel('UI/Common/NoMoreUnits')
    962             else:
    963                 msg = localization.GetByLabel('UI/Common/SetQuantity')
    964             ret = uix.QtyPopup(int(maxQty), 0, int(maxQty), msg)
    965             if ret is None:
    966                 return
    967             qty = ret['qty']
    968             if qty <= 0:
    969                 return
    970             containerInventory = self.broker.invCache.GetInventoryFromId(chargeLocationID)
    971             sortedCharges = sorted(chargeItems, key=lambda i: i.stacksize)
    972             chargeSum = 0
    973             chargeItems = []
    974             for chargeItem in sortedCharges:
    975                 if chargeSum + chargeItem.stacksize < qty:
    976                     chargeItems.append(chargeItem)
    977                     chargeSum += chargeItem.stacksize
    978                 elif chargeSum < qty:
    979                     newStackID = containerInventory.Add(chargeItem.itemID, chargeLocationID, qty=qty - chargeSum, flag=chargeItem.flagID)
    980                     chargeItems.append(utillib.KeyVal(itemID=newStackID, typeID=chargeItem.typeID))
    981                     break
    982 
    983         self.LoadChargesToModule(itemID, chargeItems, chargeLocationID)
    984 
    985     def LoadChargeToAllModules(self, invItem):
    986         chargeTypeID = invItem.typeID
    987         self.CheckSkillRequirementsForType(None, chargeTypeID, 'FittingHasSkillPrerequisites')
    988         availableRounds = invItem.stacksize
    989         fittedItems = self.GetFittedItemsToShip().values()
    990         suitableModules = []
    991         loadingModules = set()
    992         stateManager = self.godma.GetStateManager()
    993         for module in fittedItems:
    994             if not IsShipFittingFlag(module.flagID):
    995                 continue
    996             if not IsChargeCompatibleWithLauncher(chargeTypeID, module.typeID, self.dogmaStaticMgr):
    997                 continue
    998             if self.IsInWeaponBank(module.locationID, module.itemID) and self.IsModuleSlave(module.itemID, module.locationID):
    999                 continue
   1000             if stateManager.IsModuleReloading(module.itemID):
   1001                 continue
   1002             neededRounds = GetModuleCapacityForAmmoType(module.typeID, chargeTypeID, self.dogmaStaticMgr)
   1003             subLocation = self.GetSubLocation(session.shipid, module.flagID)
   1004             hasCharges = subLocation is not None
   1005             sameChargeType = False
   1006             if hasCharges and subLocation[2] == chargeTypeID:
   1007                 sameChargeType = True
   1008                 neededRounds -= self.GetQuantity(subLocation)
   1009             if neededRounds <= 0:
   1010                 continue
   1011             suitableModules.append((not module.IsOnline(),
   1012              hasCharges,
   1013              not sameChargeType,
   1014              neededRounds,
   1015              module.itemID))
   1016 
   1017         suitableModules.sort()
   1018         for suitableModule in suitableModules:
   1019             _, _, _, neededRounds, moduleItemID = suitableModule
   1020             loadingModules.add(moduleItemID)
   1021             availableRounds -= neededRounds
   1022             if availableRounds <= 0:
   1023                 break
   1024 
   1025         if loadingModules:
   1026             self.LoadAmmoToModules(session.shipid, loadingModules, [invItem.itemID], invItem.locationID)
   1027         else:
   1028             prompt_player_fsd_dialog('NoSuitableModules')
   1029 
   1030     def UnloadModuleToContainer(self, shipID, itemID, containerArgs, flag = None):
   1031         masterModuleID = None
   1032         if self.IsInWeaponBank(shipID, itemID):
   1033             ret = prompt_player_fsd_dialog('ClearGroupModule', {}, uiconst.YESNO, suppress=uiconst.ID_YES)
   1034             if ret != uiconst.ID_YES:
   1035                 return
   1036             masterModuleID = itemID
   1037             if self.IsModuleSlave(itemID, shipID):
   1038                 masterModuleID = self.GetMasterModuleID(shipID, itemID)
   1039             self.DestroyWeaponBank(shipID, masterModuleID)
   1040         containerInv = self.broker.invCache.GetInventoryFromId(*containerArgs)
   1041         containerItem = containerInv.GetItem()
   1042         if containerItem.groupID == const.groupAuditLogSecureContainer and flag is None:
   1043             flag = settings.user.ui.Get('defaultContainerLock_%s' % containerItem.itemID, None)
   1044             ownerID = session.charid
   1045             if containerItem.ownerID == session.corpid:
   1046                 ownerID = session.corpid
   1047             self.remoteDogmaLM.UnloadAmmo(shipID, masterModuleID or itemID, (containerItem.itemID, ownerID, flag))
   1048         else:
   1049             self.remoteDogmaLM.UnloadAmmo(shipID, masterModuleID or itemID, containerItem.itemID)
   1050         item = self.GetItem(itemID)
   1051         if containerArgs[0] == shipID:
   1052             containerInv.Add(itemID, item.locationID, qty=None, flag=flag)
   1053         elif flag is not None:
   1054             containerInv.Add(itemID, item.locationID, qty=None, flag=flag)
   1055         else:
   1056             containerInv.Add(itemID, item.locationID)
   1057 
   1058     def UnloadAmmoToContainer(self, shipID, ammoItem, destination, quantity = None):
   1059         moduleID = masterID = None
   1060         if self.IsItemSubLocation(ammoItem):
   1061             ship, sourceFlagID, _ = ammoItem
   1062             if shipID != ship:
   1063                 ammoItem = sm.StartService('godma').GetStateManager().GetItem(ammoItem)
   1064             ammoID = ammoItem
   1065         else:
   1066             sourceFlagID = ammoItem.flagID
   1067             ammoID = ammoItem.itemID
   1068         try:
   1069             moduleID = first(sm.GetService('invCache').GetInventoryFromId(shipID).List(flag=sourceFlagID), lambda i: i.itemID != ammoID).itemID
   1070         except (StopIteration, TypeError):
   1071             if self.IsItemSubLocation(ammoItem.itemID):
   1072                 shipID, sourceFlagID, _ = ammoItem.itemID
   1073                 ammoID = ammoItem.itemID
   1074                 moduleID = shipID
   1075 
   1076         if self.IsModuleSlave(moduleID, shipID):
   1077             masterID = moduleID = self.GetMasterModuleID(shipID, moduleID)
   1078         try:
   1079             return self.remoteDogmaLM.UnloadAmmo(shipID, moduleID, destination, quantity)
   1080         except UserError as e:
   1081             if e.msg == 'NotEnoughCargoSpace' and masterID is not None:
   1082                 prompt_player_fsd_dialog('NotEnoughCargoSpaceToUnloadBank')
   1083                 return
   1084             raise
   1085 
   1086     def UnloadAmmoFromModules(self, shipID, moduleIDs, destination):
   1087         if not isinstance(moduleIDs, (list, set, tuple)):
   1088             moduleIDs = [moduleIDs]
   1089         self.remoteDogmaLM.UnloadAmmo(shipID, moduleIDs, destination)
   1090 
   1091     def CheckCanFit(self, locationID, itemID, flagID, fromLocationID):
   1092         item = self.broker.invCache.FetchItem(itemID, fromLocationID)
   1093         if item is None:
   1094             self.LogInfo('ClientDogmaLocation::CheckCanFit - unable to fetch item', locationID, itemID, flagID, fromLocationID)
   1095             return
   1096         self.CheckCanFitByShipAndType(locationID, item.typeID)
   1097 
   1098     def CheckCanFitByShipAndType(self, locationID, typeID):
   1099         maxGroupFitted = self.dogmaStaticMgr.GetTypeAttribute(typeID, const.attributeMaxGroupFitted)
   1100         groupID = evetypes.GetGroupID(typeID)
   1101         if maxGroupFitted is not None:
   1102             modulesByGroup = self.GetModuleListByShipGroup(locationID, groupID)
   1103             if len(modulesByGroup) >= maxGroupFitted:
   1104                 shipItem = self.dogmaItems[locationID]
   1105                 raise UserError('CantFitTooManyByGroup', {'ship': shipItem.typeID,
   1106                  'module': typeID,
   1107                  'groupName': evetypes.GetGroupNameByGroup(groupID),
   1108                  'noOfModules': int(maxGroupFitted),
   1109                  'noOfModulesFitted': len(modulesByGroup)})
   1110         maxTypeFitted = self.dogmaStaticMgr.GetTypeAttribute(typeID, const.attributeMaxTypeFitted)
   1111         if maxTypeFitted is not None:
   1112             modulesByType = self.GetModuleListByShipType(locationID, typeID)
   1113             if len(modulesByType) >= maxTypeFitted:
   1114                 shipItem = self.dogmaItems[locationID]
   1115                 raise UserError('CantFitTooManyByType', {'ship': shipItem.typeID,
   1116                  'module': typeID,
   1117                  'noOfModules': int(maxTypeFitted),
   1118                  'noOfModulesFitted': len(modulesByType)})
   1119 
   1120     def GetOnlineModules(self, shipID):
   1121         return {module.flagID:moduleID for moduleID, module in self.dogmaItems[shipID].GetFittedItems().iteritems() if module.IsOnline()}
   1122 
   1123     def AreAllFittedModulesOnline(self, shipID):
   1124         for module in self.dogmaItems[shipID].GetFittedItems().values():
   1125             if IsFittingModule(module.categoryID) and IsFittingFlag(module.flagID) and not module.IsOnline():
   1126                 return False
   1127 
   1128         return True
   1129 
   1130     def ShouldStartChanceBasedEffect(self, effectID, itemID, chanceAttributeID):
   1131         dogmaItem = self.dogmaItems[itemID]
   1132         if dogmaItem.groupID == const.groupBooster:
   1133             godmaItem = self.godma.GetItem(itemID)
   1134             if godmaItem is None:
   1135                 return False
   1136             effectName = dogma.data.get_effect_name(effectID)
   1137             godmaEffect = godmaItem.effects.get(effectName, None)
   1138             if godmaEffect is None:
   1139                 return False
   1140             if godmaEffect.isActive:
   1141                 return True
   1142         return False
   1143 
   1144     def GetDogmaItemWithWait(self, itemID):
   1145         startTime = blue.os.GetWallclockTime()
   1146         while blue.os.TimeDiffInMs(startTime, blue.os.GetWallclockTime()) < 2000:
   1147             if itemID in self.dogmaItems:
   1148                 return self.dogmaItems[itemID]
   1149             self.LogInfo('GetDogmaItemWithWait::Item not ready, sleeping for 100ms')
   1150             blue.pyos.synchro.Sleep(100)
   1151 
   1152         self.LogError('Failed to get dogmaItem in time', itemID)
   1153 
   1154     def GetModifierString(self, itemID, attributeID):
   1155         dogmaItem = self.dogmaItems[itemID]
   1156         modifiers = self.GetModifiersOnAttribute(itemID, attributeID, dogmaItem.locationID, dogmaItem.groupID, dogmaItem.ownerID, dogmaItem.typeID)
   1157         baseValue = self.dogmaStaticMgr.GetTypeAttribute2(dogmaItem.typeID, attributeID)
   1158         ret = 'Base Value: %s\n' % GetFormatAndValue(dogma.data.get_attribute(attributeID), baseValue)
   1159         if modifiers:
   1160             ret += 'modified by\n'
   1161             for op, modifyingItemID, modifyingAttributeID in modifiers:
   1162                 value = self.GetAttributeValue(modifyingItemID, modifyingAttributeID)
   1163                 if op in (const.dgmAssPostMul,
   1164                  const.dgmAssPreMul,
   1165                  const.dgmAssPostDiv,
   1166                  const.dgmAssPreDiv) and value == 1.0:
   1167                     continue
   1168                 elif op in (const.dgmAssPostPercent, const.dgmAssModAdd, const.dgmAssModAdd) and value == 0.0:
   1169                     continue
   1170                 modifyingItem = self.dogmaItems[modifyingItemID]
   1171                 modifyingAttribute = dogma.data.get_attribute(modifyingAttributeID)
   1172                 value = GetFormatAndValue(modifyingAttribute, value)
   1173                 ret += '  %s: %s\n' % (evetypes.GetName(modifyingItem.typeID), value)
   1174 
   1175         return ret
   1176 
   1177     def GatherDroneInfo(self, shipDogmaItem):
   1178         dronesByTypeID = {}
   1179         for droneID in shipDogmaItem.GetDronesInBay():
   1180             damage = GetDamageFromItem(self, droneID)
   1181             if damage == 0:
   1182                 continue
   1183             damageMultiplier = self.GetAttributeValue(droneID, const.attributeDamageMultiplier)
   1184             if damageMultiplier == 0:
   1185                 continue
   1186             duration = self.GetAttributeValue(droneID, const.attributeRateOfFire)
   1187             droneDps = damage * damageMultiplier / duration
   1188             droneBandwidth = self.GetAttributeValue(droneID, const.attributeDroneBandwidthUsed)
   1189             droneDogmaItem = self.dogmaItems[droneID]
   1190             droneItem = self.GetItem(droneID)
   1191             if droneItem is None:
   1192                 continue
   1193             if droneDogmaItem.typeID not in dronesByTypeID:
   1194                 dronesByTypeID[droneItem.typeID] = [droneBandwidth, droneDps, droneItem.stacksize]
   1195             else:
   1196                 dronesByTypeID[droneItem.typeID][-1] += droneItem.stacksize
   1197 
   1198         drones = defaultdict(list)
   1199         for typeID, (bw, dps, qty) in dronesByTypeID.iteritems():
   1200             bw = int(bw)
   1201             drones[bw].append((typeID,
   1202              bw,
   1203              qty,
   1204              dps))
   1205 
   1206         for l in drones.itervalues():
   1207             l.sort(key=lambda vals: vals[-1], reverse=True)
   1208 
   1209         return drones
   1210 
   1211     def SimpleGetDroneDamageOutput(self, drones, bwLeft, dronesLeft):
   1212         dronesUsed = {}
   1213         totalDps = 0
   1214         for bw in sorted(drones.keys(), reverse=True):
   1215             if bw > bwLeft:
   1216                 continue
   1217             for typeID, bwNeeded, qty, dps in drones[bw]:
   1218                 noOfDrones = min(int(bwLeft) / int(bwNeeded), qty, dronesLeft)
   1219                 if noOfDrones == 0:
   1220                     break
   1221                 dronesUsed[typeID] = noOfDrones
   1222                 totalDps += dps * noOfDrones
   1223                 dronesLeft -= noOfDrones
   1224                 bwLeft -= noOfDrones * bwNeeded
   1225 
   1226         return (totalDps, dronesUsed)
   1227 
   1228     def GetOptimalDroneDamage(self, shipID, *args):
   1229         shipDogmaItem = self.dogmaItems[shipID]
   1230         drones = self.GatherDroneInfo(shipDogmaItem)
   1231         self.LogInfo('Gathered drone info and found', len(drones), 'types of drones')
   1232         bandwidth = self.GetAttributeValue(shipID, const.attributeDroneBandwidth)
   1233         if session.solarsystemid:
   1234             maxDrones = self.godma.GetItem(session.charid).maxActiveDrones
   1235         else:
   1236             maxDrones = self.GetAttributeValue(shipDogmaItem.ownerID, const.attributeMaxActiveDrones)
   1237         self.startedKnapsack = blue.os.GetWallclockTime()
   1238         dps, drones = self.SimpleGetDroneDamageOutput(drones, bandwidth, maxDrones)
   1239         return (dps * 1000, drones)
   1240 
   1241     def GetOptimalDroneDamage2(self, shipID, activeDrones):
   1242         return GetOptimalDroneDamage(shipID, self, activeDrones)
   1243 
   1244     def IsModuleIncludedInCalculation(self, module):
   1245         return module.IsOnline()
   1246 
   1247     def GetGodmaAttributeValue(self, itemID, attributeID):
   1248         attributeName = self.dogmaStaticMgr.attributes[attributeID].name
   1249         return self.godma.GetStateManager().GetAttribute(itemID, attributeName)
   1250 
   1251     def GetModulesLackingSkills(self):
   1252         ret = []
   1253         for moduleID, module in self.dogmaItems[self.GetCurrentShipID()].GetFittedItems().iteritems():
   1254             if IsFittingModule(module.categoryID) and IsFittingFlag(module.flagID) and not const.flagRigSlot0 <= module.flagID <= const.flagRigSlot7:
   1255                 if self.GetMissingSkills(module.typeID):
   1256                     ret.append(moduleID)
   1257 
   1258         return ret
   1259 
   1260     def OnServerBrainUpdated(self, brainData):
   1261         if self.brain and self.brain[0] >= brainData[0]:
   1262             LogNotice('OnServerBrainUpdated received for brain version %s, but we already have version %s. Update cancelled!' % (brainData[0], self.brain[0]))
   1263             return
   1264         self.LogNotice('OnServerBrainUpdated received for character %s, brain version %s' % (session.charid, brainData[0]))
   1265         shipID = self.shipsByPilotID.get(session.charid, None)
   1266         if shipID is None:
   1267             self.LogInfo('OnServerBrainUpdated:ClientDogmaLocation has not embarked character to anything. Nothing to do.')
   1268             self.ProcessBrainData(session.charid, brainData)
   1269             return
   1270         with self.brainUpdate.Event(shipID):
   1271             self.RemoveBrainEffects(shipID, session.charid, 'clientDogmaLocation.OnServerBrainUpdated')
   1272             self.ProcessBrainData(session.charid, brainData)
   1273             self.ApplyBrainEffects(shipID, session.charid, 'clientDogmaLocation.OnServerBrainUpdated')
   1274 
   1275     def GetModifiedTypeAttribute(self, typeID, attributeID):
   1276         return self.dogmaStaticMgr.GetTypeAttribute(typeID, attributeID)
   1277 
   1278     def GetCurrentShipHeatStates(self):
   1279         shipID = self.GetCurrentShipID()
   1280         shipHeatStates = {}
   1281         if shipID:
   1282             shipHeatStates = self.dogmaItems[shipID].GetHeatValues()
   1283         return shipHeatStates
   1284 
   1285     def OnHeatAdded(self, heatID, moduleID):
   1286         shipItem = self.dogmaItems[self.GetCurrentShipID()]
   1287         moduleItem = self.dogmaItems[moduleID]
   1288         sourceAttribute = moduleItem.attributes[const.attributeHeatAbsorbtionRateModifier]
   1289         heatAttribute = shipItem.attributes[heatID]
   1290         sourceAttribute.AddOutgoingModifier(const.dgmAssModAdd, heatAttribute.incomingHeat)
   1291         heatAttribute.AddIncomingModifier(const.dgmAssModAdd, sourceAttribute)
   1292 
   1293     def OnHeatRemoved(self, heatID, moduleID):
   1294         shipItem = self.dogmaItems[self.GetCurrentShipID()]
   1295         moduleItem = self.dogmaItems[moduleID]
   1296         sourceAttribute = moduleItem.attributes[const.attributeHeatAbsorbtionRateModifier]
   1297         heatAttribute = shipItem.attributes[heatID]
   1298         sourceAttribute.RemoveOutgoingModifier(const.dgmAssModAdd, heatAttribute.incomingHeat)
   1299         heatAttribute.RemoveIncomingModifier(const.dgmAssModAdd, sourceAttribute)
   1300 
   1301     def GetSecurityClass(self):
   1302         return sm.GetService('map').GetSecurityClass(session.solarsystemid2)
   1303 
   1304     def GetActiveDrones(self):
   1305         shipItem = self.GetShip()
   1306         drones = shipItem.GetDrones()
   1307         activeDrones = {}
   1308         for droneID, droneDogmaItem in drones.iteritems():
   1309             if droneDogmaItem.locationID == session.solarsystemid2:
   1310                 activeDrones[droneID] = 1
   1311 
   1312         if not activeDrones:
   1313             activeDrones = self._FindDronesInBayForActive(drones)
   1314         return activeDrones
   1315 
   1316     def _FindDronesInBayForActive(self, drones):
   1317         _, droneTypesToUSse = self.GetOptimalDroneDamage(self.GetCurrentShipID())
   1318         myDronesByTypeID = defaultdict(list)
   1319         for x in drones.itervalues():
   1320             myDronesByTypeID[x.typeID].append(x)
   1321 
   1322         activeDrones = {}
   1323         for droneTypeID, qtyNeeded in droneTypesToUSse.iteritems():
   1324             currentQty = 0
   1325             for eachDrone in myDronesByTypeID.get(droneTypeID, []):
   1326                 droneItem = self.GetItem(eachDrone.itemID)
   1327                 qtyFromDrone = min(qtyNeeded - currentQty, droneItem.stacksize)
   1328                 activeDrones[eachDrone.itemID] = qtyFromDrone
   1329                 currentQty += qtyFromDrone
   1330                 if currentQty >= qtyNeeded:
   1331                     break
   1332 
   1333         return activeDrones
   1334 
   1335     def OnDroneControlLost(self, droneID):
   1336         unloaded = self.UnloadDroneOrFighterOnDeath(droneID)
   1337         if unloaded:
   1338             sm.ScatterEvent('OnDogmaDronesChanged')
   1339 
   1340     def OnDroneStateChange2(self, droneID, oldState, newState):
   1341         if newState == -1:
   1342             return
   1343         if droneID in self.dogmaItems:
   1344             return
   1345         slimItem = sm.GetService('michelle').GetItem(droneID)
   1346         currentShipID = self.GetCurrentShipID()
   1347         if slimItem and slimItem.ownerID in (session.charid, currentShipID):
   1348             typeID = slimItem.typeID
   1349             item = blue.DBRow(self.godma.itemrd, [slimItem.itemID,
   1350              typeID,
   1351              slimItem.ownerID,
   1352              currentShipID,
   1353              const.flagDroneBay,
   1354              1,
   1355              evetypes.GetGroupID(typeID),
   1356              evetypes.GetCategoryID(typeID),
   1357              1])
   1358             self.FitItem(item)
   1359         sm.ScatterEvent('OnDogmaDronesChanged')
   1360 
   1361     def GetFittedItemsToShip(self):
   1362         shipItem = self.GetShip()
   1363         if shipItem:
   1364             return shipItem.GetFittedItems()
   1365         else:
   1366             return {}
   1367 
   1368     def GetActivityState(self, itemID):
   1369         return (None, None, None)
   1370 
   1371     def GetHoldItems(self, flagID):
   1372         shipInv = self.broker.invCache.GetInventoryFromId(self.GetCurrentShipID())
   1373         itemsInFlag = shipInv.List(flagID)
   1374         cargoItems = {}
   1375         for eachItem in itemsInFlag:
   1376             if eachItem.flagID == flagID:
   1377                 cargoItems[eachItem.itemID] = eachItem
   1378 
   1379         return cargoItems
   1380 
   1381     def GetMaxActiveDrones(self):
   1382         return self.GetAttributeValue(session.charid, const.attributeMaxActiveDrones)
   1383 
   1384     def GetShipItemForFighter(self, itemID):
   1385         currentShipID = self.GetCurrentShipID()
   1386         if currentShipID:
   1387             return self.SafeGetDogmaItem(currentShipID)
   1388 
   1389     def OnFighterRemovedFromControllerClient(self, fighterID):
   1390         self.UnloadDroneOrFighterOnDeath(fighterID)
   1391 
   1392     def UnloadDroneOrFighterOnDeath(self, entityID):
   1393         dogmaItem = self.SafeGetDogmaItem(entityID)
   1394         if not dogmaItem:
   1395             return False
   1396         if dogmaItem.locationID != self.GetCurrentShipID():
   1397             self.UnfitAndUnloadItem(self.GetCurrentShipID(), entityID)
   1398             return True
   1399         return False
   1400 
   1401     def GetFightersForTube(self, eachTubeFlagID):
   1402         from eve.client.script.ui.inflight.squadrons.shipFighterState import GetShipFighterState
   1403         shipFighterState = GetShipFighterState()
   1404         return shipFighterState.GetFightersForTubeID(eachTubeFlagID)
   1405 
   1406     def Overload(self, itemID, effectID):
   1407         if not self.__IsEffectActive(itemID, effectID):
   1408             self.Activate(itemID, effectID)
   1409 
   1410     def OverloadRack(self, moduleIDs):
   1411         for mID in moduleIDs:
   1412             effectID = self.__GetOverloadEffect(mID)
   1413             if effectID:
   1414                 self.Overload(mID, effectID)
   1415 
   1416     def StopOverloading(self, itemID, effectID):
   1417         self.StopEffect(effectID, itemID)
   1418 
   1419     def StopOverloadingRack(self, moduleIDs):
   1420         for mID in moduleIDs:
   1421             effectID = self.__GetOverloadEffect(mID)
   1422             if effectID:
   1423                 self.StopOverloading(mID, effectID)
   1424 
   1425     def __IsEffectActive(self, moduleID, effectID):
   1426         module = self.SafeGetDogmaItem(moduleID)
   1427         if module:
   1428             if effectID in module.activeEffects:
   1429                 return True
   1430         return False
   1431 
   1432     def __GetOverloadEffect(self, moduleID):
   1433         module = self.SafeGetDogmaItem(moduleID)
   1434         if not module:
   1435             return
   1436         for effectInfo in self.dogmaStaticMgr.TypeGetEffects(module.typeID).itervalues():
   1437             effectID = effectInfo.effectID
   1438             effect = self.dogmaStaticMgr.effects[effectID]
   1439             if effect.effectCategory == const.dgmEffOverload:
   1440                 return effectID
   1441 
   1442     def IsFullyCorrupted(self):
   1443         try:
   1444             if sm.GetService('corruptionSuppressionSvc').IsCurrentSystemFullyCorrupted():
   1445                 return True
   1446         except Exception:
   1447             log.LogTraceback('Failed to get IsFullyCorrupted on client')
   1448 
   1449         return False
   1450 
   1451     def GetMaxDamageMultiplier(self, itemID):
   1452         return 1.0