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

fittingDogmaLocation.py (34796B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fittingScreen\fittingDogmaLocation.py
      2 import weakref
      3 import dbuff.common.registry
      4 import dogma.data as dogma_data
      5 import dynamicitemattributes
      6 import threadutils
      7 from carbon.common.lib import telemetry
      8 from dogma.attributes.limit import LimitAttributeOnItem
      9 from dogma.dogmaWrappers import WrappedMethod
     10 from dogma.effects.environment import Environment
     11 from dogma.items.baseDogmaItem import BaseDogmaItem
     12 from dogma.items.fighterDogmaItem import GhostFighterDogmaItem
     13 from dogma.items.structureDogmaItem import GhostStructureDogmaItem
     14 from dogma.items.structureModuleDogmaItem import GhostStructureModuleDogmaItem
     15 from eve.client.script.ui.shared.fitting.fittingUtil import GetSensorStrengthAttribute
     16 from eve.client.script.ui.shared.fitting.fighters_util import GetFighterNumByTypeIDsInTubes
     17 from eve.client.script.ui.shared.fittingScreen import FAKE_FLAGID
     18 from eve.client.script.ui.shared.fittingScreen.ghostFittingUtil import GhostFittingDataObject, GetOriganlItemIDFromItemKey
     19 from eve.client.script.ui.shared.fittingScreen.moduleStateUtil import GetTextForCurrentStateForDogmaItem
     20 from eve.common.script.dogma.baseDogmaLocation import BaseDogmaLocation
     21 from dogma.items.droneDogmaItem import GhostDroneDogmaItem
     22 from dogma.items.moduleDogmaItem import GhostModuleDogmaItem
     23 from dogma.items.shipDogmaItem import GhostShipDogmaItem
     24 from eveuniverse.security import securityClassZeroSec
     25 import inventorycommon.const as invConst
     26 from inventorycommon.util import IsShipFittable, IsStructureFittable, IsFighterTubeFlag
     27 from shipfitting.fittingDogmaLocationUtil import GetFittingItemDragData, GetTurretMissileAndAoeDps, CapacitorSimulator, GetAlphaStrike
     28 from shipfitting.droneUtil import GetOptimalDroneDamage, SelectedDroneTracker
     29 import uthread
     30 import log
     31 import blue
     32 from shipfitting.fittingStuff import IsRigSlot
     33 from utillib import KeyVal
     34 MAX_CARGO = 2000000000
     35 BURST_EFFECTS = [const.effectModuleBonusIndustrialInvulnerability,
     36  const.effectModuleTitanBurst,
     37  const.effectModuleBonusWarfareLinkArmor,
     38  const.effectModuleBonusWarfareLinkInfo,
     39  const.effectModuleBonusWarfareLinkMining,
     40  const.effectModuleBonusWarfareLinkShield,
     41  const.effectModuleBonusWarfareLinkSkirmish,
     42  const.effectChargeBonusWarfareCharge]
     43 SPEED_ATTRIBUTES_REQUIRING_MODULE_UPDATE = {const.attributeSpeedFactor}
     44 SPEED_CHANGING_EFFECTS = {const.effectModuleBonusAfterburner, const.effectModuleBonusMicrowarpdrive}
     45 
     46 class FittingDogmaLocation(BaseDogmaLocation):
     47     __notifyevents__ = ['OnServerBrainUpdated']
     48 
     49     def __init__(self, broker, charBrain = None):
     50         BaseDogmaLocation.__init__(self, broker)
     51         self.manualEffectCategories = {const.dgmEffActivation: True,
     52          const.dgmEffTarget: True,
     53          const.dgmEffArea: True}
     54         self.godma = sm.GetService('godma')
     55         self.scatterAttributeChanges = True
     56         self.dogmaStaticMgr = sm.GetService('clientDogmaStaticSvc')
     57         self.effectCompiler = sm.GetService('ghostFittingEffectCompiler')
     58         self.instanceFlagQuantityCache = {}
     59         self.effectRefreshInfo = []
     60         self.shipID = None
     61         self.SetEffectsNeedingRefreshDict()
     62         self.InitDbuffRegistry()
     63         self.brain = None
     64         self.shipIDBeingDisembarked = None
     65         if charBrain:
     66             self.SetBrainData(session.charid, charBrain)
     67         self.selectedDronesTracker = SelectedDroneTracker()
     68         self.locationName = 'FittingDogmaLocation'
     69         self.RegisterCallback(const.attributeActivationBlocked, self.OnActivationBlockedChanged)
     70         sm.RegisterNotify(self)
     71 
     72     def InitDbuffRegistry(self):
     73         modifierApplier = dbuff.common.registry.ModifierApplier(self)
     74         self.dbuffRegistry = dbuff.common.registry.BuffRegistry(modifierApplier, None, None)
     75 
     76     def SetEffectsNeedingRefreshDict(self):
     77         self.effectsNeedRefreshDict = {const.attributeMass: SPEED_CHANGING_EFFECTS}
     78 
     79     def SetBrainData(self, charID, brain):
     80         self.brain = brain
     81 
     82     def GetBrainData(self, charID):
     83         return self.brain
     84 
     85     def HasBrainData(self, charID):
     86         return self.brain is not None
     87 
     88     def GetCurrentShipID(self):
     89         return self.shipID
     90 
     91     def GetActiveShipID(self, characterID = None):
     92         return self.shipID
     93 
     94     def CheckApplyBrainEffects(self, shipID):
     95         return self.IsItemIdInDogmaItems(shipID)
     96 
     97     def IsItemIdInDogmaItems(self, itemID):
     98         return itemID in self.dogmaItems
     99 
    100     def OnServerBrainUpdated(self, brainData):
    101         self.LogInfo('FittingDogmaLocation:OnServerBrainUpdated received for character %s' % session.charid)
    102         shipID = self.GetCurrentShipID()
    103         if shipID is None:
    104             self.ProcessBrainData(session.charid, brainData)
    105             return
    106         with self.brainUpdate.Event(shipID):
    107             self.RemoveBrainEffects(shipID, session.charid, 'fittingDogmaLocation.OnServerBrainUpdated')
    108             self.ProcessBrainData(session.charid, brainData)
    109             self.ApplyBrainEffects(shipID, session.charid, 'fittingDogmaLocation.OnServerBrainUpdated')
    110 
    111     def CheckPowerCpuRequirementForOnlineModules(self, shipID):
    112         pass
    113 
    114     def LoadMyShip(self, typeID):
    115         myCharID = session.charid
    116         self.LoadItem(myCharID)
    117         s = GhostFittingDataObject(None, 0, typeID)
    118         itemKey = s.GetItemKey()
    119         self.LoadItem(itemKey, invItem=s)
    120         self.pilotsByShipID[itemKey] = myCharID
    121         shipDogmaItem = self.GetDogmaItem(itemKey)
    122         charDogmaItem = self.GetDogmaItem(myCharID)
    123         oldShipID = self.shipID
    124         self.shipIDBeingDisembarked = oldShipID
    125         self.ResetOldShip(oldShipID, itemKey)
    126         self.shipID = itemKey
    127         charDogmaItem.SetLocation(self.shipID, shipDogmaItem, const.flagPilot)
    128         self.MakeShipActive(self.shipID, oldShipID)
    129         return shipDogmaItem
    130 
    131     def ResetOldShip(self, oldShipID, newShipID):
    132         charID = session.charid
    133         oldShipItem = self.dogmaItems.get(oldShipID)
    134         if oldShipItem is None:
    135             return
    136         oldShipItem.isBeingDisembarked = True
    137         try:
    138             self.RemoveBrainEffects(oldShipID, charID, 'fittingDogmaLocation.ResetOldShip')
    139             self.UninstallPilotFromShipAndItems(oldShipID)
    140         finally:
    141             oldShipItem.isBeingDisembarked = False
    142 
    143         self.selectedDronesTracker.Clear()
    144         self._RemoveItemsFromHolds()
    145         oldShipItem.HandlePilotChange(None)
    146         self.UnfitItemFromLocation(oldShipID, charID)
    147         self.UnloadItem(oldShipID)
    148 
    149     def _RemoveItemsFromHolds(self):
    150         self.RemoveAllItemsFromHold(const.flagCargo)
    151         self.RemoveAllItemsFromHold(const.flagFighterBay)
    152         for eachHold in const.fighterTubeFlags:
    153             self.RemoveAllItemsFromHold(eachHold)
    154 
    155     def FitItemToLocation(self, locationID, itemID, flagID):
    156         if self._IsLocationIDInvalidForFitting(locationID):
    157             return
    158         wasItemLoaded = self.IsItemIdInDogmaItems(itemID)
    159         if not self.IsItemIdInDogmaItems(locationID):
    160             self.LoadItem(locationID)
    161             if not wasItemLoaded:
    162                 self.LogInfo('Neither location not item loaded, returning early', locationID, itemID)
    163                 return
    164         if not self.IsItemIdInDogmaItems(itemID):
    165             self.LoadItem(itemID)
    166             return
    167         locationDogmaItem = self.SafeGetDogmaItem(locationID)
    168         if locationDogmaItem is None:
    169             self.LogInfo('FitItemToLocation::Fitted to None item', itemID, locationID, flagID)
    170             return
    171         dogmaItem = self.GetDogmaItem(itemID)
    172         if getattr(dogmaItem, 'IsValidFittingLocation', None) and not dogmaItem.IsValidFittingLocation(locationDogmaItem):
    173             return
    174         dogmaItem.SetLocation(locationID, locationDogmaItem, flagID)
    175         if flagID in invConst.fittingFlags or itemID == self.shipID or flagID == invConst.flagHiddenModifers:
    176             startedEffects = self.StartPassiveEffects(itemID, dogmaItem.typeID)
    177         if self.IsCharge(dogmaItem):
    178             module = self.GetModuleFromShipFlag(flagID)
    179             if module:
    180                 typeEffectInfo = sm.GetService('ghostFittingSvc').GetDefaultAndOverheatEffect(module.typeID)
    181                 defaultEffectID = typeEffectInfo.defaultEffect.effectID
    182                 self.TryRestartBurstEffects(defaultEffectID, module.typeID)
    183         if flagID != FAKE_FLAGID:
    184             sm.GetService('ghostFittingSvc').SendOnStatsUpdatedEvent()
    185 
    186     def UnfitItemFromShip(self, itemID):
    187         self.selectedDronesTracker.UnregisterDroneFromActive(itemID)
    188         item = self.SafeGetDogmaItem(itemID)
    189         if not item:
    190             return
    191         if not self.IsCharge(item):
    192             chargeItem = self.GetChargeFromShipFlag(item.flagID)
    193             if chargeItem:
    194                 self.UnfitItemFromShip(chargeItem.itemID)
    195         self.UnfitItemFromLocation(self.shipID, itemID)
    196         self.UnloadItem(itemID)
    197 
    198     def GetQuantityFromCache(self, locationID, flagID):
    199         return 1
    200 
    201     def GetInstance(self, item):
    202         instanceRow = [item.itemID]
    203         for attributeID in self.GetAttributesByIndex().itervalues():
    204             v = getattr(item, dogma_data.get_attribute_name(attributeID), 0)
    205             instanceRow.append(v)
    206 
    207         return instanceRow
    208 
    209     def OnlineModule(self, itemKey):
    210         self.ChangeModuleStatus(itemKey, const.effectOnline)
    211 
    212     def ActivateModule(self, itemKey, moduleTypeID, flagID):
    213         if self.IsShipCloaked() and flagID not in const.rigSlotFlags:
    214             raise UserError('DeniedActivateCloaked')
    215         typeEffectInfo = sm.GetService('ghostFittingSvc').GetDefaultAndOverheatEffect(moduleTypeID)
    216         defaultEffectID = typeEffectInfo.defaultEffect.effectID
    217         self.ChangeModuleStatus(itemKey, defaultEffectID)
    218         self.TryStartPassiveEffects(itemKey, moduleTypeID, flagID)
    219 
    220     def TryStartPassiveEffects(self, itemID, moduleTypeID, flagID):
    221         if not IsRigSlot(flagID):
    222             return
    223         self.StartPassiveEffects(itemID, moduleTypeID)
    224 
    225     def ChangeModuleOverheatStatus(self, itemKey, moduleTypeID, flagID, start = True):
    226         typeEffectInfo = sm.GetService('ghostFittingSvc').GetDefaultAndOverheatEffect(moduleTypeID)
    227         if typeEffectInfo.overloadEffect:
    228             if start:
    229                 self.ChangeModuleStatus(itemKey, typeEffectInfo.overloadEffect.effectID)
    230             else:
    231                 self.StopEffectAndRestartBursts(typeEffectInfo.overloadEffect.effectID, itemKey)
    232             if typeEffectInfo.defaultEffect:
    233                 self.StopEffectAndRestartBursts(typeEffectInfo.defaultEffect.effectID, itemKey)
    234                 self.ActivateModule(itemKey, moduleTypeID, flagID)
    235 
    236     def OfflineSimulatedModule(self, itemKey, moduleTypeID, flagID):
    237         self.OfflineModule(itemKey)
    238         self.TryStopPassiveEffects(itemKey, moduleTypeID, flagID)
    239         self.DeactivateSimulatedModule(itemKey, moduleTypeID)
    240 
    241     def DeactivateSimulatedModule(self, itemKey, moduleTypeID):
    242         typeEffectInfo = sm.GetService('ghostFittingSvc').GetDefaultAndOverheatEffect(moduleTypeID)
    243         if typeEffectInfo.defaultEffect:
    244             self.StopEffectAndRestartBursts(typeEffectInfo.defaultEffect.effectID, itemKey)
    245         if typeEffectInfo.overloadEffect:
    246             self.StopEffectAndRestartBursts(typeEffectInfo.overloadEffect.effectID, itemKey)
    247 
    248     def StopEffectAndRestartBursts(self, effectID, itemKey, forced = False):
    249         self.StopEffect(effectID, itemKey, forced=forced)
    250         self.TryRestartBurstEffects(effectID, itemKey)
    251 
    252     def TryStopPassiveEffects(self, itemID, itemTypeID, flagID):
    253         if not IsRigSlot(flagID):
    254             return
    255         dogmaItem = self.SafeGetDogmaItem(itemID)
    256         if dogmaItem is None:
    257             return
    258         self.StopPassiveEffects(dogmaItem, itemID, itemTypeID)
    259 
    260     def GetItem(self, itemID):
    261         if itemID != session.charid:
    262             return self.dogmaItems.get(itemID)
    263         item = self.godma.GetItem(itemID)
    264         return item
    265 
    266     def GetCharacter(self, itemID, flush = False):
    267         return self.GetItem(itemID)
    268 
    269     def ShouldStartChanceBasedEffect(self, *args, **kwargs):
    270         return False
    271 
    272     def StartSystemEffect(self):
    273         pass
    274 
    275     def AddTargetEx(self, *args, **kwargs):
    276         return 1
    277 
    278     def ChangeModuleStatus(self, itemKey, effectID = None):
    279         dogmaItem = self.GetDogmaItem(itemKey)
    280         envInfo = dogmaItem.GetEnvironmentInfo()
    281         env = Environment(itemID=envInfo.itemID, charID=envInfo.charID, shipID=self.shipID, targetID=envInfo.targetID, otherID=envInfo.otherID, effectID=effectID, dogmaLM=weakref.proxy(self), expressionID=None, structureID=envInfo.structureID)
    282         self.StartEffect(effectID, itemKey, env, checksOnly=None)
    283 
    284     def CheckSkillRequirementsForType(self, typeID, *args):
    285         return self.GetMissingSkills(typeID)
    286 
    287     @telemetry.ZONE_METHOD
    288     def GetMissingSkills(self, typeID, skillSvc = None):
    289         if skillSvc is None:
    290             skillSvc = sm.GetService('skills')
    291         return super(FittingDogmaLocation, self).GetMissingSkills(typeID, skillSvc.GetSkills())
    292 
    293     def SetQuantity(self, itemKey, quantity):
    294         shipID, flagID, typeID = itemKey
    295         if self.IsItemLoaded(shipID):
    296             return self.SetAttributeValue(itemKey, const.attributeQuantity, quantity)
    297 
    298     def GetTurretAndMissileDps(self, shipID):
    299         return GetTurretMissileAndAoeDps(shipID, self)
    300 
    301     def GetAlphaStrike(self):
    302         return GetAlphaStrike(self)
    303 
    304     def GetOptimalDroneDamage(self, shipID, activeDrones):
    305         return GetOptimalDroneDamage(shipID, self, activeDrones)
    306 
    307     def GetOptimalDroneDamage2(self, shipID, activeDrones):
    308         return self.GetOptimalDroneDamage(shipID, activeDrones)
    309 
    310     def IsModuleIncludedInCalculation(self, module):
    311         dogmaItem = self.GetDogmaItem(module.itemID)
    312         return dogmaItem.IsActive()
    313 
    314     def GetDragData(self, itemID):
    315         return GetFittingItemDragData(itemID, self)
    316 
    317     def GetClassForItem(self, item):
    318         categoryID = item.categoryID
    319         if item.flagID in (const.flagCargo,) and categoryID in (const.categoryShip, const.categoryStructure):
    320             return BaseDogmaItem
    321         if categoryID == const.categoryShip:
    322             return GhostShipDogmaItem
    323         if item.categoryID == const.categoryStructure:
    324             return GhostStructureDogmaItem
    325         if IsStructureFittable(categoryID):
    326             return GhostStructureModuleDogmaItem
    327         if IsShipFittable(categoryID):
    328             return GhostModuleDogmaItem
    329         if item.categoryID == const.categoryDrone:
    330             return GhostDroneDogmaItem
    331         if item.categoryID == const.categoryFighter:
    332             return GhostFighterDogmaItem
    333         return BaseDogmaLocation.GetClassForItem(self, item)
    334 
    335     def GetShip(self):
    336         return self.GetShipItem()
    337 
    338     def GetShipItem(self):
    339         return self.SafeGetDogmaItem(self.shipID)
    340 
    341     def GetFittedItemsToShip(self):
    342         shipItem = self.GetShipItem()
    343         if shipItem:
    344             return shipItem.GetFittedItems()
    345         else:
    346             return {}
    347 
    348     def GetModuleFromShipFlag(self, flagID):
    349         return self.GetItemFromShipFlag(flagID, getCharge=False)
    350 
    351     def GetChargeFromShipFlag(self, flagID):
    352         return self.GetItemFromShipFlag(flagID, getCharge=True)
    353 
    354     def GetItemFromShipFlag(self, flagID, getCharge):
    355         fittedItems = self.GetFittedItemsToShip()
    356         for eachItem in fittedItems.itervalues():
    357             try:
    358                 if eachItem.flagID != flagID:
    359                     continue
    360                 if getCharge and self.IsCharge(eachItem) or not getCharge and not self.IsCharge(eachItem):
    361                     return eachItem
    362             except ReferenceError as e:
    363                 self.LogWarn(e)
    364 
    365     def IsCharge(self, fittedItem):
    366         if isinstance(fittedItem.itemID, tuple):
    367             return True
    368         if fittedItem.categoryID == const.categoryCharge:
    369             return True
    370         return False
    371 
    372     def GetChargeNonDB(self, shipID, flagID):
    373         for itemID, fittedItem in self.GetFittedItemsToShip().iteritems():
    374             if isinstance(itemID, tuple):
    375                 continue
    376             if fittedItem.flagID != flagID:
    377                 continue
    378             if fittedItem.categoryID == const.categoryCharge:
    379                 return fittedItem
    380 
    381     def GetSensorStrengthAttribute(self, shipID):
    382         return GetSensorStrengthAttribute(self, shipID)
    383 
    384     @WrappedMethod
    385     def MakeShipActive(self, shipID, oldShipID):
    386         myCharID = session.charid
    387         self.LoadItem(myCharID)
    388         shipDogmaItem = self.GetDogmaItem(shipID)
    389         shipDogmaItem.OnItemLoaded()
    390         uthread.Lock(self, 'makeShipActive')
    391         try:
    392             while not session.IsItSafe():
    393                 self.LogInfo('MakeShipActive - session is mutating. Sleeping for 250ms')
    394                 blue.pyos.synchro.SleepSim(250)
    395 
    396             if shipID is None:
    397                 log.LogTraceback('Unexpectedly got shipID = None')
    398                 return
    399             scatterValueBefore = self.scatterAttributeChanges
    400             self.SetScatterOnOrOff(scatterOn=False)
    401             try:
    402                 self.ApplyBrainEffects(shipID, myCharID)
    403             finally:
    404                 self.shipIDBeingDisembarked = None
    405                 self.SetScatterOnOrOff(scatterOn=scatterValueBefore)
    406 
    407         finally:
    408             uthread.UnLock(self, 'makeShipActive')
    409 
    410     def RemoveAllItemsFromHold(self, flagID):
    411         holdItems = self.GetHoldItems(flagID)
    412         for eachItemID in holdItems:
    413             self.UnloadItem(eachItemID)
    414 
    415     def GetCapacity(self, shipID, attributeID, flagID):
    416         keyVal = KeyVal(capacity=0, used=0)
    417         if flagID == const.flagDroneBay:
    418             keyVal.capacity = self.GetAttributeValue(shipID, const.attributeDroneCapacity)
    419             used = 0
    420             shipDogmaItem = self.GetDogmaItem(shipID)
    421             for droneID in shipDogmaItem.drones:
    422                 used += self.GetAttributeValue(droneID, const.attributeVolume)
    423 
    424             keyVal.used = used
    425         elif flagID == const.flagCargo:
    426             shipItem = self.SafeGetDogmaItem(shipID)
    427             if not shipItem:
    428                 return keyVal
    429             if shipItem.categoryID == const.categoryStructure:
    430                 keyVal.capacity = MAX_CARGO
    431             else:
    432                 keyVal.capacity = self.GetAttributeValue(shipID, const.attributeCapacity)
    433             used = 0
    434             for eachItemID, eachItem in self.GetHoldItems(const.flagCargo).iteritems():
    435                 qty = getattr(eachItem, 'stacksize', 1)
    436                 used += qty * self.GetAttributeValue(eachItemID, const.attributeVolume)
    437 
    438             keyVal.used = used
    439         elif flagID == const.flagFighterBay:
    440             keyVal.capacity = self.GetAttributeValue(shipID, const.attributeFighterCapacity)
    441             used = 0
    442             fightersInBay = self.GetHoldItems(const.flagFighterBay)
    443             for eachItemID, eachItem in fightersInBay.iteritems():
    444                 used += eachItem.stacksize * self.GetAttributeValue(eachItemID, const.attributeVolume)
    445 
    446             keyVal.used = used
    447         elif IsFighterTubeFlag(flagID):
    448             keyVal.capacity = self.GetAttributeValue(shipID, const.attributeFighterCapacity)
    449             used = 0
    450             fightersInTube = self.GetHoldItems(flagID)
    451             for eachItemID, eachItem in fightersInTube.iteritems():
    452                 used += eachItem.stacksize * self.GetAttributeValue(eachItemID, const.attributeVolume)
    453 
    454             keyVal.used = used
    455         return keyVal
    456 
    457     def CapacitorSimulator(self, shipID):
    458         return CapacitorSimulator(self, shipID)
    459 
    460     def _IsLocationIDInvalidForFitting(self, locationID):
    461         if locationID == self.shipIDBeingDisembarked:
    462             return True
    463         isLocationIDValidForFitting = locationID not in (self.GetCurrentShipID(), session.charid)
    464         return isLocationIDValidForFitting
    465 
    466     def OnAttributeChanged(self, attributeID, itemKey, value = None, oldValue = None):
    467         value = BaseDogmaLocation.OnAttributeChanged(self, attributeID, itemKey, value=value, oldValue=oldValue)
    468         self.RefreshEffectsOnShip(attributeID, itemKey)
    469         if self.scatterAttributeChanges:
    470             sm.ScatterEvent('OnDogmaAttributeChanged', self.shipID, itemKey, attributeID, value)
    471 
    472     def GetQuantity(self, itemID):
    473         return getattr(self.GetItem(itemID), 'stacksize', 1)
    474 
    475     def GetAccurateAttributeValue(self, itemID, attributeID, *args):
    476         return self.GetAttributeValue(itemID, attributeID)
    477 
    478     def DecreaseItemAttribute(self, itemKey, attributeID, itemKey2, attributeID2, limit = None, scaleFactor = 1):
    479         pass
    480 
    481     def AddLocationRequiredSkillModifierWithSource(self, operation, toLocationID, skillID, toAttribID, fromAttrib):
    482         if toLocationID is None:
    483             return
    484         BaseDogmaLocation.AddLocationRequiredSkillModifierWithSource(self, operation, toLocationID, skillID, toAttribID, fromAttrib)
    485 
    486     def IncreaseItemAttribute(self, itemKey, attributeID, itemKey2, attributeID2, limitAttributeID = None, scaleFactor = 1):
    487         value = scaleFactor * self.GetAttributeValue(itemKey2, attributeID2)
    488         if limitAttributeID:
    489             dogmaItem = self.dogmaItems.get(itemKey)
    490             value, _ = LimitAttributeOnItem(dogmaItem, blue.os.GetSimTime() / const.SEC, limitAttributeID, value)
    491         new, old = self.IncreaseItemAttributeEx(itemKey, attributeID, value, alsoReturnOldValue=True)
    492         if attributeID in (const.attributeShieldCharge, const.attributeCapacitorCharge) and new > old:
    493             actingItem = self.dogmaItems.get(itemKey2)
    494             if actingItem is None:
    495                 self.broker.LogWarn('No actingItem in IncreaseItemAttribute', itemKey, attributeID, itemKey2, attributeID2)
    496         return new
    497 
    498     def IncreaseItemAttributeEx(self, itemKey, attributeID, value, silently = 0, alsoReturnOldValue = False):
    499         dogmaItem = self.GetDogmaItem(itemKey)
    500         if not dogmaItem.CanAttributeBeModified():
    501             if alsoReturnOldValue:
    502                 return (0, 0)
    503             return 0
    504         attrib = dogmaItem.attributes[attributeID]
    505         oldValue = attrib.GetValue()
    506         attrib.SetBaseValue(oldValue + value)
    507         newValue = attrib.GetValue()
    508         if alsoReturnOldValue:
    509             return (newValue, oldValue)
    510         return newValue
    511 
    512     def DecreaseItemAttributeEx(self, itemKey, attributeID, reduction, silently = 0, alsoReturnOldValue = False):
    513         dogmaItem = self.dogmaItems.get(itemKey, None)
    514         if dogmaItem is None or not dogmaItem.CanAttributeBeModified():
    515             if alsoReturnOldValue:
    516                 return (0, 0)
    517             return 0
    518         oldValue = dogmaItem.attributes[attributeID].GetValue()
    519         if oldValue - reduction < 0:
    520             newValue = 0
    521         else:
    522             newValue = oldValue - reduction
    523         dogmaItem.attributes[attributeID].SetBaseValue(newValue)
    524         if alsoReturnOldValue:
    525             return (newValue, oldValue)
    526         return newValue
    527 
    528     def IsInWeaponBank(self, *args):
    529         return False
    530 
    531     def WaitForShip(self, *args):
    532         pass
    533 
    534     def CheckItemsMissingInAddModifier(self, toItemID, fromAttrib):
    535         if not fromAttrib:
    536             raise RuntimeError('Item missing from AddModifier')
    537 
    538     def GetSecurityClass(self):
    539         return securityClassZeroSec
    540 
    541     def StartEffect_PreChecks(self, effect, dogmaItem, environment, byUser):
    542         BaseDogmaLocation.StartEffect_PreChecks(self, effect, dogmaItem, environment, byUser)
    543         if effect.effectCategory in (const.dgmEffActivation, const.dgmEffTarget) and dogmaItem.IsOnline():
    544             self._CheckIfTooManyModulesInGroupAreActive(effect, dogmaItem, environment)
    545             if self.GetAttributeValue(dogmaItem.itemID, const.attributeActivationBlocked) != 0:
    546                 raise UserError('ModuleIsBlocked', {'moduleName': (const.UE_TYPEID, dogmaItem.typeID)})
    547 
    548     def _CheckIfTooManyModulesInGroupAreActive(self, effect, dogmaItem, environment):
    549         shipCategoryID = environment.shipCategoryID
    550         shipID = environment.shipID
    551         itemID = dogmaItem.itemID
    552         itemGroupID = dogmaItem.groupID
    553         if shipCategoryID != const.categoryShip:
    554             return
    555         if not self.IsShipLoaded(shipID):
    556             return
    557         maxGroupActive = self.GetAttributeValue(itemID, const.attributeMaxGroupActive)
    558         if itemGroupID == self.GetAttributeValue(shipID, const.attributeMaxShipGroupActiveID):
    559             maxGroupActive = max(self.GetAttributeValue(shipID, const.attributeMaxShipGroupActive), maxGroupActive)
    560         if maxGroupActive > 0:
    561             itemTypeID = dogmaItem.typeID
    562             shipDogmaItem = self.GetDogmaItem(shipID)
    563             modules = shipDogmaItem.GetFittedItems().itervalues()
    564             total = len([ item for item in modules if item.groupID == itemGroupID and item.IsActive() ])
    565             if total >= maxGroupActive:
    566                 raise UserError('EffectCrowdedOut', {'module': itemTypeID,
    567                  'count': total})
    568 
    569     def SetDroneActivityState(self, droneID, setActive, qty = 1):
    570         return self.selectedDronesTracker.SetDroneActivityState(self, droneID, setActive, qty=qty)
    571 
    572     def RegisterDroneAsActive(self, droneID, qty = 1, raiseError = True):
    573         return self.selectedDronesTracker.RegisterDroneAsActive(self, droneID, qty=qty, raiseError=raiseError)
    574 
    575     def UnregisterDroneFromActive(self, droneID, qty = 1):
    576         return self.selectedDronesTracker.UnregisterDroneFromActive(droneID, qty=qty)
    577 
    578     def GetActiveDrones(self):
    579         return self.selectedDronesTracker.GetSelectedDrones()
    580 
    581     @telemetry.ZONE_METHOD
    582     def GetSubSystemInFlag(self, shipID, flagID):
    583         dogmaItem = self.GetModuleFromShipFlag(flagID)
    584         return dogmaItem
    585 
    586     def GetActivityState(self, itemID):
    587         dogmaItem = self.SafeGetDogmaItem(itemID)
    588         if dogmaItem:
    589             return GetTextForCurrentStateForDogmaItem(dogmaItem)
    590         return (None, None, None)
    591 
    592     def GetHoldItems(self, flagID):
    593         cargoItems = {}
    594         for eachItemID, eachItem in self.dogmaItems.iteritems():
    595             if eachItem.flagID == flagID:
    596                 cargoItems[eachItemID] = eachItem
    597 
    598         return cargoItems
    599 
    600     def GetFightersInTubeInfo(self, flagID):
    601         fightersInHold = self.GetHoldItems(flagID)
    602         if len(fightersInHold) > 1:
    603             self.LogError('More than 1 fighter in tube, flagID = ', flagID)
    604         for eachItem in fightersInHold.itervalues():
    605             squadronSize = eachItem.squadronSize
    606             fighterTypeID = eachItem.typeID
    607             fighterID = eachItem.itemID
    608             return KeyVal(itemID=fighterID, typeID=fighterTypeID, squadronSize=squadronSize, fighters=eachItem)
    609 
    610     def SetScatterOnOrOff(self, scatterOn = True):
    611         self.scatterAttributeChanges = scatterOn
    612 
    613     def GetMaxActiveDrones(self):
    614         return max(5, self.GetAttributeValue(session.charid, const.attributeMaxActiveDrones))
    615 
    616     def RefreshEffectsOnShip(self, attributeID, itemKey, *args):
    617         self._TryRefreshOtherModuleEffectsOnChanges(attributeID, itemKey)
    618         if itemKey != self.shipID:
    619             return
    620         effectIDsToRefresh = self.effectsNeedRefreshDict.get(attributeID, [])
    621         if not effectIDsToRefresh:
    622             return
    623         effectInfoForRefresh = self.GetItemsAndEffectsToUpdate(effectIDsToRefresh, [])
    624         for effectClass, environment, eachItemKey in effectInfoForRefresh:
    625             effectClass.RefreshEffect(self, environment, eachItemKey, self.shipID)
    626 
    627     def _TryRefreshOtherModuleEffectsOnChanges(self, attributeID, itemKey):
    628         if attributeID in const.dbuffAttributeValueMappings:
    629             pass
    630         elif itemKey != self.shipID and attributeID in SPEED_ATTRIBUTES_REQUIRING_MODULE_UPDATE:
    631             pass
    632         else:
    633             return
    634         effectInfoForRefresh = self.GetItemsAndEffectsToUpdate(SPEED_CHANGING_EFFECTS, [])
    635         for eachEffectToRefresh in effectInfoForRefresh:
    636             if eachEffectToRefresh not in self.effectRefreshInfo:
    637                 self.effectRefreshInfo.append(eachEffectToRefresh)
    638 
    639         self.__RefreshEffect()
    640 
    641     @threadutils.throttled(0.05)
    642     def __RefreshEffect(self):
    643         while self.effectRefreshInfo:
    644             effectInfo = self.effectRefreshInfo.pop(0)
    645             effectClass, environment, eachItemKey = effectInfo
    646             if environment.shipID != self.shipID:
    647                 continue
    648             effectClass.RefreshEffect(self, environment, eachItemKey, self.shipID)
    649 
    650     def GetItemsAndEffectsToUpdate(self, effectIDsToRefresh, excludedItems):
    651         effectInfoForRefresh = []
    652         for eachDogmaItem in self.GetFittedItemsToShip().itervalues():
    653             if eachDogmaItem.itemID in excludedItems:
    654                 continue
    655             for eachEffectID, eachEffect in eachDogmaItem.activeEffects.iteritems():
    656                 if eachEffectID not in effectIDsToRefresh:
    657                     continue
    658                 environment = eachEffect[const.ACT_IDX_ENV]
    659                 effectClass = self.effectCompiler.effects.get(eachEffectID)
    660                 if effectClass is None:
    661                     continue
    662                 effectInfoForRefresh.append((effectClass, environment, eachDogmaItem.itemID))
    663 
    664         return effectInfoForRefresh
    665 
    666     def GetActivatedEffectsOnShip(self):
    667         activatedEffects = []
    668         for itemID, dogmaItem in self.GetFittedItemsToShip().iteritems():
    669             try:
    670                 for effectID, activationInfo in dogmaItem.activeEffects.iteritems():
    671                     effectCategory = self.dogmaStaticMgr.effects[effectID].effectCategory
    672                     if effectID != const.effectOnline and effectCategory in self.manualEffectCategories:
    673                         activatedEffects.append((effectID,
    674                          itemID,
    675                          activationInfo,
    676                          dogmaItem.typeID))
    677 
    678             except ReferenceError:
    679                 pass
    680 
    681         return activatedEffects
    682 
    683     def DeactivateActivatedEffectsOfShip(self, excludeEffectKey = None):
    684         for effectID, itemID, activationInfo, typeID in self.GetActivatedEffectsOnShip():
    685             if excludeEffectKey == (effectID, itemID):
    686                 continue
    687             try:
    688                 self.StopEffectAndRestartBursts(effectID, itemID, forced=True)
    689             except Exception as e:
    690                 pass
    691 
    692         sm.GetService('ghostFittingSvc').SendFittingSlotsChangedEvent()
    693         return 1
    694 
    695     def DeactivateBlockedActivatedEffectsOfShip(self):
    696         for effectID, itemID, activationInfo, typeID in self.GetActivatedEffectsOnShip():
    697             if not self.GetAttributeValue(itemID, const.attributeActivationBlocked):
    698                 continue
    699             try:
    700                 self.StopEffectAndRestartBursts(effectID, itemID, forced=True)
    701             except Exception as e:
    702                 pass
    703 
    704         sm.GetService('ghostFittingSvc').SendFittingSlotsChangedEvent()
    705         return 1
    706 
    707     def TryRestartBurstEffects(self, effectID, itemID):
    708         if effectID not in BURST_EFFECTS:
    709             return
    710         self.dbuffRegistry.RemoveBuffsFromItem(self.shipID)
    711         effectInfoForRefresh = self.GetItemsAndEffectsToUpdate(BURST_EFFECTS, [itemID])
    712         for effectClass, environment, eachItemKey in effectInfoForRefresh:
    713             effectClass.Start(environment, self, eachItemKey, environment.shipID, environment.charID, environment.otherID, environment.targetID)
    714 
    715         sm.GetService('ghostFittingSvc').SendOnStatsUpdatedEvent()
    716 
    717     def IsShipCloaked(self):
    718         cloakingDeviceList = [ x for x in self.GetFittedItemsToShip().itervalues() if x.groupID == const.groupCloakingDevice ]
    719         return any((x for x in cloakingDeviceList if x.IsActive()))
    720 
    721     def GetShipItemForFighter(self, itemID):
    722         currentShipID = self.GetCurrentShipID()
    723         if currentShipID:
    724             return self.SafeGetDogmaItem(currentShipID)
    725 
    726     def GetFightersForTube(self, eachTubeFlagID):
    727         fighterInfo = self.GetFightersInTubeInfo(eachTubeFlagID)
    728         if fighterInfo:
    729             return fighterInfo.fighters
    730 
    731     def GetFighterNumByTypeIDsInTubes(self):
    732         return GetFighterNumByTypeIDsInTubes(self)
    733 
    734     def GetCharacterSecurityStatus(self, charID):
    735         return sm.GetService('crimewatchSvc').GetMySecurityStatus()
    736 
    737     def GetAttributesForItem(self, itemID, typeID):
    738         if itemID and dynamicitemattributes.IsDynamicType(typeID):
    739             realItemID = GetOriganlItemIDFromItemKey(itemID)
    740             return sm.GetService('dynamicItemSvc').GetDynamicItemAttributes(realItemID)
    741         return BaseDogmaLocation.GetAttributesForItem(self, itemID, typeID)
    742 
    743     def GetAttributesForRealItemID(self, itemID, typeID):
    744         if itemID and dynamicitemattributes.IsDynamicType(typeID):
    745             return sm.GetService('dynamicItemSvc').GetDynamicItemAttributes(itemID)
    746         return BaseDogmaLocation.GetAttributesForItem(self, itemID, typeID)
    747 
    748     def OnActivationBlockedChanged(self, attributeID, itemID, newValue, oldValue = None):
    749         if not newValue:
    750             return
    751         dogmaItem = self.dogmaItems[itemID]
    752         for effectID in dogmaItem.activeEffects.keys():
    753             if effectID in self.onlineEffects:
    754                 continue
    755             effect = self.dogmaStaticMgr.effects[effectID]
    756             if effect.effectCategory not in [const.dgmEffActivation, const.dgmEffTarget]:
    757                 continue
    758             self.StopEffect(effectID, itemID, forced=True)
    759 
    760         sm.GetService('ghostFittingSvc').SendFittingSlotsChangedEvent()
    761 
    762     def ShouldMessageItemEvent(self, itemID, ownerID = None, locationID = None):
    763         dogmaItem = self.dogmaItems.get(itemID, None)
    764         if dogmaItem is None:
    765             return False
    766         if ownerID is None:
    767             ownerID = dogmaItem.ownerID
    768         if self.IsIgnoringOwnerEvents(ownerID):
    769             return False
    770         if locationID is None:
    771             locationID = dogmaItem.locationID
    772         if locationID in self.loadingItems and itemID in self.loadingItems:
    773             return False
    774         if locationID in self.unloadingItems and itemID in self.unloadingItems:
    775             return False
    776         return True
    777 
    778     def GetMaxDamageMultiplier(self, itemID):
    779         dmgMultiplier = 1.0
    780         dogmaItem = self.SafeGetDogmaItem(itemID)
    781         if not dogmaItem:
    782             return dmgMultiplier
    783         if self.ItemHasAttribute(itemID, const.attributeDamageMultiplierBonusMax):
    784             maxBonus = self.GetAttributeValue(itemID, const.attributeDamageMultiplierBonusMax)
    785             dmgMultiplier *= 1.0 + maxBonus
    786         return dmgMultiplier