tanking.py (7114B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\behaviors\actions\tanking.py 2 from ballpark.messenger.const import MESSAGE_ON_EFFECT_STARTED, MESSAGE_ON_DAMAGE_CHANGED 3 from behaviors.tasks import Task 4 from ccpProfile import TimedFunction 5 from dogma.attributes.health import GetCurrentArmorRatio, GetCurrentShieldRatio 6 from dogma.const import effectEntityArmorRepairingLarge, effectEntityArmorRepairingMedium, effectEntityArmorRepairingSmall 7 from dogma.const import effectEntityShieldBoostingLarge, effectEntityShieldBoostingMedium, effectEntityShieldBoostingSmall 8 from dogma.const import effectNpcBehaviorArmorRepairer, effectNpcBehaviorShieldBooster 9 from eveexceptions import UserError 10 from eveexceptions.exceptionEater import ExceptionEater 11 import logging 12 logger = logging.getLogger(__name__) 13 ARMOR_TANK_EFFECT_IDS = {effectEntityArmorRepairingLarge, 14 effectEntityArmorRepairingMedium, 15 effectEntityArmorRepairingSmall, 16 effectNpcBehaviorArmorRepairer} 17 SHIELD_TANK_EFFECT_IDS = {effectEntityShieldBoostingLarge, 18 effectEntityShieldBoostingMedium, 19 effectEntityShieldBoostingSmall, 20 effectNpcBehaviorShieldBooster} 21 22 class ActiveTank(Task): 23 24 def __init__(self, attributes = None): 25 super(ActiveTank, self).__init__(attributes) 26 self.armorTank = EntityArmorTank() 27 self.shieldTank = EntityShieldTank() 28 29 @TimedFunction('behaviors::actions::tanking::ActiveTank::OnEnter') 30 def OnEnter(self): 31 self._InitTanks() 32 try: 33 self.ActivateTanks() 34 self._SubscribeDamageChangesIfNotTanking() 35 except RuntimeError: 36 pass 37 38 self.SetStatusToFailed() 39 40 def CleanUp(self): 41 if not self.IsInvalid(): 42 self.UnsubscribeItem(self.context.myItemId, MESSAGE_ON_DAMAGE_CHANGED, self._OnDamageReceived) 43 super(ActiveTank, self).CleanUp() 44 45 def _SubscribeDamageChangesIfNotTanking(self): 46 if all((not tank.IsTanking() for tank in self._IterTanks())): 47 self.SubscribeItem(self.context.myItemId, MESSAGE_ON_DAMAGE_CHANGED, self._OnDamageReceived) 48 49 @TimedFunction('behaviors::actions::tanking::ActiveTank::ActivateTanks') 50 def ActivateTanks(self): 51 for tank in self._IterTanks(): 52 tank.ActivateTankIfDamaged() 53 54 @TimedFunction('behaviors::actions::tanking::ActiveTank::_InitTanks') 55 def _InitTanks(self): 56 for tank in self._IterTanks(): 57 self._InitEntityTank(tank) 58 59 def _InitEntityTank(self, entityTank): 60 if not entityTank.IsInitialized(self.context.myItemId): 61 entityTank.Initialized(self.context.myItemId, self.context.mySlimItem.typeID, self.context.mySlimItem.ownerID, self.context.dogmaLM, self.context.ballpark.eventMessenger) 62 63 def _OnDamageReceived(self, *args): 64 for tank in self._IterTanks(): 65 if tank.CanActiveTank() and not tank.IsTanking() and not tank.IsAtFullHealth(): 66 self.behaviorTree.RequestReset(requestedBy=self) 67 68 def _IterTanks(self): 69 for tank in (self.shieldTank, self.armorTank): 70 yield tank 71 72 73 class EffectStillActivatingError(Exception): 74 pass 75 76 77 class EntityArmorTank(object): 78 __validTankEffects__ = ARMOR_TANK_EFFECT_IDS 79 80 def __init__(self): 81 self.isTanking = False 82 self.effectId = None 83 self.itemId = None 84 self.typeId = None 85 self.ownerId = None 86 self.dogmaLM = None 87 self.eventMessenger = None 88 89 def Initialized(self, itemId, typeId, ownerId, dogmaLM, eventMessenger): 90 self.itemId = itemId 91 self.typeId = typeId 92 self.ownerId = ownerId 93 self.dogmaLM = dogmaLM 94 self.eventMessenger = eventMessenger 95 self._DetermineValidTankEffect() 96 97 def IsInitialized(self, itemId): 98 return self.itemId is not None and self.itemId == itemId 99 100 def ActivateTankIfDamaged(self): 101 if not self.CanActiveTank(): 102 return 103 if not self.IsAtFullHealth(): 104 self._StartTanking() 105 106 def CanActiveTank(self): 107 return self.effectId is not None and not self._IsExploding() 108 109 def _IsExploding(self): 110 return self.dogmaLM.ballpark.IsExploding(self.itemId) 111 112 def IsTanking(self): 113 return self.isTanking 114 115 def IsAtFullHealth(self): 116 return self.GetTankStatus() >= 1.0 117 118 def _StartTanking(self): 119 self.isTanking = True 120 self.eventMessenger.SubscribeItem(self.itemId, (MESSAGE_ON_EFFECT_STARTED, self.effectId), self._OnTankRepaired) 121 self._StartEffects() 122 logger.debug('%s starting tanking with effectId %s', self.itemId, self.effectId) 123 124 def _StopTanking(self): 125 self._StopEffects() 126 self.isTanking = False 127 self.eventMessenger.UnsubscribeItem(self.itemId, (MESSAGE_ON_EFFECT_STARTED, self.effectId), self._OnTankRepaired) 128 logger.debug('%s stopping tanking with effectId %s', self.itemId, self.effectId) 129 130 def _OnTankRepaired(self, *args): 131 if not self.IsTanking(): 132 return 133 if self.IsAtFullHealth(): 134 self.TryStopTanking() 135 136 def TryStopTanking(self): 137 with ExceptionEater('Failed to stop active tanking'): 138 try: 139 self._StopTanking() 140 except EffectStillActivatingError: 141 pass 142 143 @TimedFunction('behaviors::actions::tanking::EntityArmorTank::_IsTankEffectActive') 144 def _IsTankEffectActive(self): 145 return self.dogmaLM.GetActiveEffectData(self.itemId, self.effectId) is not None 146 147 @TimedFunction('behaviors::actions::tanking::EntityArmorTank::_StartEffects') 148 def _StartEffects(self): 149 with ExceptionEater('Activating entity active tank'): 150 if self._IsTankEffectActive(): 151 return 152 self.dogmaLM.ActivateWithContext(self.ownerId, self.itemId, self.effectId, repeat=100) 153 logger.debug('Item %s started tank effect %s', self.itemId, self.effectId) 154 155 @TimedFunction('behaviors::actions::tanking::EntityArmorTank::_StopEffects') 156 def _StopEffects(self): 157 try: 158 self.dogmaLM.StopEffect(self.effectId, self.itemId) 159 logger.debug('Item %s stopped tank effect %s', self.itemId, self.effectId) 160 except UserError as e: 161 if e.msg == 'EffectStillActivating': 162 raise EffectStillActivatingError() 163 raise 164 except: 165 raise 166 167 def _DetermineValidTankEffect(self): 168 self.effectId = None 169 for effectId in self.__validTankEffects__: 170 if self.dogmaLM.dogmaStaticMgr.TypeHasEffect(self.typeId, effectId): 171 self.effectId = effectId 172 break 173 174 @TimedFunction('behaviors::actions::tanking::EntityArmorTank::GetTankStatus') 175 def GetTankStatus(self): 176 return GetCurrentArmorRatio(self.dogmaLM, self.itemId) 177 178 179 class EntityShieldTank(EntityArmorTank): 180 __validTankEffects__ = SHIELD_TANK_EFFECT_IDS 181 182 @TimedFunction('behaviors::actions::tanking::EntityShieldTank::GetTankStatus') 183 def GetTankStatus(self): 184 return GetCurrentShieldRatio(self.dogmaLM, self.itemId)