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

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)