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

combat.py (16747B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\behaviors\monitors\combat.py
      2 import logging
      3 import ballpark.messenger.const as messages
      4 import evetypes
      5 from behaviors.blackboards import BlackboardDeletedError
      6 from behaviors.groups.mixin import GroupTaskMixin
      7 from behaviors.tasks import Task
      8 from behaviors.utility.ballparks import get_ball_position
      9 from behaviors.utility.owner import get_owner_id
     10 from ccpProfile import TimedFunction
     11 from crimewatch.util import GetAggressorId
     12 from eveexceptions.exceptionEater import ExceptionEater
     13 from eve.common.script.sys import idCheckers
     14 logger = logging.getLogger(__name__)
     15 
     16 class WaitForAggressiveAct(Task):
     17 
     18     @TimedFunction('behaviors::monitors::combat::WaitForAggressiveAct::OnEnter')
     19     def OnEnter(self):
     20         self.SubscribeItem(self.context.myItemId, messages.MESSAGE_CRIMEWATCH_EVENT_STARTED, self._OnCrimewatchEventStarted)
     21         self.SubscribeItem(self.context.myItemId, messages.MESSAGE_INDIRECT_OFFENSE_EVENT, self._OnIndirectOffenseEvent)
     22         self.SetStatusToSuccess()
     23 
     24     def CleanUp(self):
     25         super(WaitForAggressiveAct, self).CleanUp()
     26         self.UnsubscribeItem(self.context.myItemId, messages.MESSAGE_CRIMEWATCH_EVENT_STARTED, self._OnCrimewatchEventStarted)
     27         self.UnsubscribeItem(self.context.myItemId, messages.MESSAGE_INDIRECT_OFFENSE_EVENT, self._OnIndirectOffenseEvent)
     28 
     29     def AddAggressorAndResetTree(self, aggressorID, targetTypeID):
     30         try:
     31             combatSet = self.GetLastBlackboardValue(self.attributes.combatTargetsAddress) or set()
     32         except BlackboardDeletedError:
     33             logger.debug(u'WaitForAggressiveAct:::Combat target address references deleted blackboard: %s', unicode(self.attributes.combatTargetsAddress))
     34             return
     35 
     36         if aggressorID not in combatSet:
     37             logger.debug('Entity aggressed: %s', aggressorID)
     38             combatSet.add(aggressorID)
     39             self.SendBlackboardValue(self.attributes.combatTargetsAddress, combatSet)
     40             self.behaviorTree.RequestReset(requestedBy=self)
     41             self._LogAggression(aggressorID, targetTypeID)
     42             self.OnNewAggressorDetected()
     43 
     44     def AddAggressorsAndResetTree(self, categoryID, sourceOwnerID, aggressorID, targetTypeID):
     45         aggressorID = GetAggressorId(categoryID, sourceOwnerID, aggressorID)
     46         self.AddAggressorAndResetTree(aggressorID, targetTypeID)
     47 
     48     @TimedFunction('behaviors::monitors::combat::WaitForAggressiveAct::_OnCrimewatchEventStarted')
     49     def _OnCrimewatchEventStarted(self, effectKey, effectInfo):
     50         if self.IsInvalid():
     51             return
     52         if effectInfo.isAssistance:
     53             return
     54         aggressorID = effectKey.shipID
     55         categoryID = evetypes.GetCategoryID(effectInfo.moduleTypeID)
     56         if self.IsValidAggressor(aggressorID):
     57             self.AddAggressorsAndResetTree(categoryID, effectInfo.sourceOwnerID, aggressorID, effectInfo.targetTypeID)
     58 
     59     @TimedFunction('behaviors::monitors::combat::WaitForAggressiveAct::_OnIndirectOffenseEvent')
     60     def _OnIndirectOffenseEvent(self, sourceOwnerId, targetItem):
     61         if self.IsInvalid():
     62             return
     63         try:
     64             offendingOwner = self.context.ballpark.inventory2.GetItem(sourceOwnerId)
     65         except RuntimeError:
     66             pass
     67         else:
     68             if offendingOwner:
     69                 offendingShipID = offendingOwner.locationID
     70                 offendingItem = self.context.ballpark.inventory2.GetItem(offendingShipID)
     71                 if self.IsValidAggressor(offendingShipID):
     72                     self.AddAggressorsAndResetTree(offendingItem.categoryID, sourceOwnerId, offendingShipID, targetItem.typeID)
     73 
     74     def _LogAggression(self, aggressorID, targetTypeID):
     75         with ExceptionEater('WaitForAggressiveAct.LogAggression'):
     76             entity_group = self.context.entityLocation.GetBehaviorEntityGroup(self.context.myEntityGroupId)
     77             self.context.eventLogger.log_behavior_aggressed(get_owner_id(self), self.behaviorTree.GetBehaviorId(), self._GetGroupBehaviorId(entity_group), targetTypeID, aggressorID)
     78 
     79     def OnNewAggressorDetected(self):
     80         pass
     81 
     82     def _GetGroupBehaviorId(self, entity_group):
     83         if entity_group is not None:
     84             return entity_group.GetBehaviorId()
     85         return self.behaviorTree.GetBehaviorId()
     86 
     87     def IsValidAggressor(self, aggressorID):
     88         if not aggressorID:
     89             return False
     90         ballpark = self.context.ballpark
     91         ball = ballpark.GetBallOrNone(aggressorID)
     92         if ball is None:
     93             return False
     94         return all((filterfunction(ballpark, ball) for filterfunction in self._GetFilterFunctions()))
     95 
     96     def _GetFilterFunctions(self):
     97         return [self._PlayerAggressorFilter]
     98 
     99     def _PlayerAggressorFilter(self, ballpark, ball):
    100         if getattr(self.attributes, 'onlyPlayerAggressors', False):
    101             slimItem = ballpark.GetSlimItem(ball.id)
    102             if not slimItem or slimItem.ownerID is None:
    103                 return False
    104             if not idCheckers.IsPlayerOwner(slimItem.ownerID):
    105                 return False
    106         return True
    107 
    108 
    109 class SetFlagAndResetWhenAggressed(WaitForAggressiveAct):
    110 
    111     def AddAggressorsAndResetTree(self, categoryID, sourceOwnerID, aggressorID, targetTypeID):
    112         self.SendBlackboardValue(self.attributes.flagAddress, True)
    113         self.behaviorTree.RequestReset(requestedBy=self)
    114 
    115 
    116 class FlagAggressionAndReportMyPosition(WaitForAggressiveAct):
    117 
    118     def OnNewAggressorDetected(self):
    119         my_position = get_ball_position(self, self.context.myItemId)
    120         self.SendBlackboardValue(self.attributes.flagAddress, True)
    121         self.SendBlackboardValue(self.attributes.myPositionAddress, my_position)
    122 
    123 
    124 class ClearValueAndResetIfTargetCloaks(Task):
    125 
    126     @TimedFunction('behaviors::monitors::combat::ClearValueAndResetIfTargetCloaks::OnEnter')
    127     def OnEnter(self):
    128         self.targetId = self.GetLastBlackboardValue(self.attributes.targetAddress)
    129         if self.targetId is not None:
    130             self.SubscribeToCloakChanged()
    131             self.SetStatusToSuccess()
    132         else:
    133             self.SetStatusToFailed()
    134 
    135     def CleanUp(self):
    136         if not self.IsInvalid():
    137             self.UnsubscribeFromCloakChanged()
    138             self.targetId = None
    139             self.SetStatusToInvalid()
    140 
    141     def SubscribeToCloakChanged(self):
    142         self.SubscribeItem(self.targetId, messages.MESSAGE_ON_CLOAK_BALL, self._OnCloakBall)
    143 
    144     def UnsubscribeFromCloakChanged(self):
    145         self.UnsubscribeItem(self.targetId, messages.MESSAGE_ON_CLOAK_BALL, self._OnCloakBall)
    146 
    147     @TimedFunction('behaviors::monitors::combat::ClearValueAndResetIfTargetCloaks::_OnCloakChanged')
    148     def _OnCloakBall(self, itemId):
    149         self.SendBlackboardValue(self.attributes.valueAddress, None)
    150         self.behaviorTree.RequestReset(requestedBy=self)
    151 
    152 
    153 class MaxLockedTargetsChangedMonitor(Task):
    154 
    155     @TimedFunction('behaviors::monitors::combat::MaxLockedTargetsChangedMonitor::OnEnter')
    156     def OnEnter(self):
    157         self.SubscribeItem(self.context.myItemId, messages.MESSAGE_MAX_LOCKED_TARGETS_CHANGED, self._OnMaxLockedTargetsChanged)
    158         self.SetStatusToSuccess()
    159 
    160     def CleanUp(self):
    161         if not self.IsInvalid():
    162             self.UnsubscribeItem(self.context.myItemId, messages.MESSAGE_MAX_LOCKED_TARGETS_CHANGED, self._OnMaxLockedTargetsChanged)
    163         super(MaxLockedTargetsChangedMonitor, self).CleanUp()
    164 
    165     @TimedFunction('behaviors::monitors::combat::MaxLockedTargetsChangedMonitor::_OnMaxLockedTargetsChanged')
    166     def _OnMaxLockedTargetsChanged(self):
    167         if not self.IsInvalid():
    168             self.behaviorTree.RequestReset(requestedBy=self)
    169 
    170 
    171 class MonitorAssistanceToTargets(WaitForAggressiveAct):
    172 
    173     @TimedFunction('behaviors::monitors::combat::MonitorAssistanceToTargets::OnEnter')
    174     def OnEnter(self):
    175         combatTargetIds = self.GetLastBlackboardValue(self.attributes.combatTargetsAddress)
    176         self.SubscribeToTargetsInBubble(combatTargetIds, self.context.myBall.newBubbleId)
    177         self.SetStatusToSuccess()
    178 
    179     def SubscribeToTargetsInBubble(self, combatTargetIds, bubbleId):
    180         if not combatTargetIds:
    181             return
    182         monitoredTargetSet = self.GetMonitoredTargets()
    183         destinyBalls = self.context.ballpark.balls
    184         for combatTargetId in combatTargetIds:
    185             ball = destinyBalls.get(combatTargetId)
    186             if ball and ball.newBubbleId == bubbleId:
    187                 monitoredTargetSet.add(combatTargetId)
    188                 self.SubscribeItem(combatTargetId, messages.MESSAGE_CRIMEWATCH_EVENT_STARTED, self._OnCrimewatchEventStarted)
    189 
    190     def CleanUp(self):
    191         if not self.IsInvalid():
    192             self.UnsubscribeFromMonitoredTargets()
    193             self.SetStatusToInvalid()
    194 
    195     def UnsubscribeFromMonitoredTargets(self):
    196         monitoredTargetSet = self.GetMonitoredTargets()
    197         if not monitoredTargetSet:
    198             return
    199         for monitoredTargetId in monitoredTargetSet:
    200             self.UnsubscribeItem(monitoredTargetId, messages.MESSAGE_CRIMEWATCH_EVENT_STARTED, self._OnCrimewatchEventStarted)
    201 
    202         self.SetMonitoredTargets(None)
    203 
    204     @TimedFunction('behaviors::monitors::combat::MonitorAssistanceToTargets::_OnCrimewatchEventStarted')
    205     def _OnCrimewatchEventStarted(self, effectKey, effectInfo):
    206         if self.IsInvalid():
    207             return
    208         if not effectInfo.isAssistance:
    209             return
    210         aggressorID = effectKey.shipID
    211         categoryID = evetypes.GetCategoryID(effectInfo.moduleTypeID)
    212         self.AddAggressorsAndResetTree(categoryID, effectInfo.sourceOwnerID, aggressorID, effectInfo.targetTypeID)
    213 
    214     def GetMonitoredTargets(self):
    215         if not self.HasContextValue('monitoredTargetSet'):
    216             return set()
    217         return self.GetContextValue('monitoredTargetSet')
    218 
    219     def SetMonitoredTargets(self, monitoredTargetSet):
    220         self.SetContextValue('monitoredTargetSet', monitoredTargetSet)
    221 
    222 
    223 class MonitorAssistanceToGroupTargets(MonitorAssistanceToTargets, GroupTaskMixin):
    224 
    225     def OnEnter(self):
    226         combatTargetIds = self.GetLastBlackboardValue(self.attributes.combatTargetsAddress)
    227         for bubbleId in self.GetMemberBubbleSet():
    228             self.SubscribeToTargetsInBubble(combatTargetIds, bubbleId)
    229 
    230         self.SetStatusToSuccess()
    231 
    232 
    233 class MonitorAggressionTowardsTargets(WaitForAggressiveAct):
    234 
    235     @TimedFunction('behaviors::monitors::combat::MonitorAggressionTowardsTargets::OnEnter')
    236     def OnEnter(self):
    237         monitoredTargetIds = self.GetLastBlackboardValue(self.attributes.monitoredTargetsAddress)
    238         self.SubscribeToTargetsInBubble(monitoredTargetIds, self.context.myBall.newBubbleId)
    239         self.SetStatusToSuccess()
    240 
    241     def SubscribeToTargetsInBubble(self, monitoredTargetIds, bubbleId):
    242         if not monitoredTargetIds:
    243             return
    244         monitoredTargetSet = self.GetMonitoredTargets()
    245         destinyBalls = self.context.ballpark.balls
    246         for targetId in monitoredTargetIds:
    247             ball = destinyBalls.get(targetId)
    248             if ball and ball.newBubbleId == bubbleId:
    249                 monitoredTargetSet.add(targetId)
    250                 self.SubscribeItem(targetId, messages.MESSAGE_CRIMEWATCH_EVENT_STARTED, self._OnCrimewatchEventStarted)
    251                 self.SubscribeItem(targetId, messages.MESSAGE_INDIRECT_OFFENSE_EVENT, self._OnIndirectOffenseEvent)
    252 
    253     def CleanUp(self):
    254         if not self.IsInvalid():
    255             self.UnsubscribeFromMonitoredTargets()
    256             self.SetStatusToInvalid()
    257 
    258     def UnsubscribeFromMonitoredTargets(self):
    259         monitoredTargetSet = self.GetMonitoredTargets()
    260         if not monitoredTargetSet:
    261             return
    262         for monitoredTargetId in monitoredTargetSet:
    263             self.UnsubscribeItem(monitoredTargetId, messages.MESSAGE_CRIMEWATCH_EVENT_STARTED, self._OnCrimewatchEventStarted)
    264             self.UnsubscribeItem(self.context.myItemId, messages.MESSAGE_INDIRECT_OFFENSE_EVENT, self._OnIndirectOffenseEvent)
    265 
    266         self.SetMonitoredTargets(None)
    267 
    268     @TimedFunction('behaviors::monitors::combat::MonitorAggressionTowardsTargets::_OnCrimewatchEventStarted')
    269     def _OnCrimewatchEventStarted(self, effectKey, effectInfo):
    270         if self.IsInvalid():
    271             return
    272         if not effectInfo.isOffensive:
    273             return
    274         aggressorID = effectKey.shipID
    275         categoryID = evetypes.GetCategoryID(effectInfo.moduleTypeID)
    276         self.AddAggressorsAndResetTree(categoryID, effectInfo.sourceOwnerID, aggressorID, effectInfo.targetTypeID)
    277 
    278     def GetMonitoredTargets(self):
    279         if not self.HasContextValue('monitoredTargetSet'):
    280             return set()
    281         return self.GetContextValue('monitoredTargetSet')
    282 
    283     def SetMonitoredTargets(self, monitoredTargetSet):
    284         self.SetContextValue('monitoredTargetSet', monitoredTargetSet)
    285 
    286     @TimedFunction('behaviors::monitors::combat::MonitorAggressionTowardsTargets::_OnIndirectOffenseEvent')
    287     def _OnIndirectOffenseEvent(self, sourceOwnerId, targetItem):
    288         if self.IsInvalid():
    289             return
    290         try:
    291             offendingOwner = self.context.ballpark.inventory2.GetItem(sourceOwnerId)
    292         except RuntimeError:
    293             pass
    294         else:
    295             if offendingOwner:
    296                 offendingShipID = offendingOwner.locationID
    297                 offendingItem = self.context.ballpark.inventory2.GetItem(offendingShipID)
    298                 self.AddAggressorsAndResetTree(offendingItem.categoryID, sourceOwnerId, offendingShipID, targetItem.typeID)
    299 
    300     def _LogAggression(self, aggressorID, targetTypeID):
    301         with ExceptionEater('MonitorAggressionTowardsTargets.LogAggression'):
    302             entity_group = self.context.entityLocation.GetBehaviorEntityGroup(self.context.myEntityGroupId)
    303             self.context.eventLogger.log_monitored_target_aggressed(get_owner_id(self), self.behaviorTree.GetBehaviorId(), self._GetGroupBehaviorId(entity_group), targetTypeID, aggressorID)
    304 
    305 
    306 class MonitorAggressionTowardsGroupTargets(MonitorAggressionTowardsTargets, GroupTaskMixin):
    307 
    308     def OnEnter(self):
    309         monitoredTargetIds = self.GetLastBlackboardValue(self.attributes.monitoredTargetsAddress)
    310         for bubbleId in self.GetMemberBubbleSet():
    311             self.SubscribeToTargetsInBubble(monitoredTargetIds, bubbleId)
    312 
    313         self.SetStatusToSuccess()
    314 
    315 
    316 class MonitorSecurityStatusLoss(Task):
    317 
    318     def GetServiceManager(self):
    319         return sm
    320 
    321     def __init__(self, attributes = None):
    322         super(MonitorSecurityStatusLoss, self).__init__(attributes)
    323         self._solarSystemID = None
    324 
    325     @TimedFunction('behaviors::monitors::combat::MonitorSecurityStatusLoss::OnEnter')
    326     def OnEnter(self):
    327         if self.context.ballpark:
    328             self._solarSystemID = self.context.ballpark.solarsystemID
    329             self.SubscribeItem(self._solarSystemID, messages.MESSAGE_SEC_STATUS_LOST_EVENT, self.OnSecStatusLost)
    330         self.SetStatusToSuccess()
    331 
    332     def _GetBubbleID(self):
    333         return self.context.myBall.newBubbleId
    334 
    335     def CleanUp(self):
    336         super(MonitorSecurityStatusLoss, self).CleanUp()
    337         if self._solarSystemID:
    338             self.UnsubscribeItem(self._solarSystemID, messages.MESSAGE_CRIMEWATCH_EVENT_STARTED, self.OnSecStatusLost)
    339 
    340     @TimedFunction('behaviors::monitors::combat::MonitorSecurityStatusLoss::OnSecStatusLost')
    341     def OnSecStatusLost(self, ownerID, shipID):
    342         if self.IsInvalid() or shipID is None:
    343             return
    344         ballpark = self.context.ballpark
    345         if not ballpark:
    346             return
    347         ball = ballpark.GetBallOrNone(shipID)
    348         if not ball:
    349             return
    350         if not self._IsInSameBubble(ball):
    351             return
    352         if self.attributes.maxDistance is not None:
    353             try:
    354                 distance = ballpark.DistanceBetween(self.context.myItemId, shipID)
    355                 if distance > self.attributes.maxDistance:
    356                     return
    357             except Exception:
    358                 pass
    359 
    360         self.AddBallAsTargetAndResetTree(shipID)
    361 
    362     def _IsInSameBubble(self, ball):
    363         return ball.newBubbleId == self._GetBubbleID()
    364 
    365     def AddBallAsTargetAndResetTree(self, ballID):
    366         try:
    367             combatSet = self.GetLastBlackboardValue(self.attributes.combatTargetsAddress) or set()
    368         except BlackboardDeletedError:
    369             logger.debug(u'MonitorSecurityStatusLoss:::Combat target address references deleted blackboard: %s', unicode(self.attributes.combatTargetsAddress))
    370             return
    371 
    372         if ballID not in combatSet:
    373             combatSet.add(ballID)
    374             self.SendBlackboardValue(self.attributes.combatTargetsAddress, combatSet)
    375             self.behaviorTree.RequestReset(requestedBy=self)