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