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

entity.py (7907B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\behaviors\entity.py
      2 from ballpark.helpers.aggression import get_kill_owner_id
      3 from ccpProfile import TimedFunction
      4 from collections import defaultdict
      5 import math
      6 import evetypes
      7 from ballpark.entities.entitywrapper import EntityWrapper
      8 from ballpark.messenger.const import MESSAGE_ON_BALL_MODE_CHANGED, MESSAGE_ON_ADDITIONAL_LOOT_REMOVED
      9 from ballpark.messenger.const import MESSAGE_ON_UNSPAWNED_WITH_ADDITIONAL_LOOT
     10 from ballpark.messenger.const import MESSAGE_ON_DROPPED_ADDITIONAL_LOOT
     11 from ballpark.warpDisruptionBalls import IsBallIntersectingAnyWarpDisruptionField
     12 from inventorycommon.const import groupSolarSystem, ownerUnknown
     13 import logging
     14 from ballpark.const import DESTINY_MODE_WARP
     15 from eveexceptions import UserError
     16 from inventorycommon.const import ownerNone
     17 from inventorycommon.util import IsNPC
     18 from dogma import const as dogmaConst
     19 from spacecomponents.common.helper import HasCargoBayComponent
     20 logger = logging.getLogger(__name__)
     21 INVULNERABLE_LABEL = 'BehaviorWarp'
     22 
     23 class NPCWarpError(Exception):
     24     pass
     25 
     26 
     27 class NpcWarpScrambledError(NPCWarpError):
     28     pass
     29 
     30 
     31 class NpcWarpBubbledError(NPCWarpError):
     32     pass
     33 
     34 
     35 class NpcWarpPathBubbledError(NPCWarpError):
     36     pass
     37 
     38 
     39 class BehaviorEntity(EntityWrapper):
     40     __destiny_ball_class_id__ = 58
     41 
     42     def DoSetup(self, entitySettings):
     43         self.additionalLoot = defaultdict(int)
     44         self.additionalLootTables = []
     45 
     46     def OnAddedToPark(self):
     47         pass
     48 
     49     @TimedFunction('behaviors::entity::BehaviorEntity::NPCWarpTo')
     50     def NPCWarpTo(self, destination, jitterRadius = 20000, warpAtRange = 0.0, warpSpeed = 6):
     51         if hasattr(self, 'ballpark') and self.ballpark is not None:
     52             if self.ballpark.IsWarpScrambled(self.id):
     53                 raise NpcWarpScrambledError('Warp Scrambled')
     54             if self.mode == DESTINY_MODE_WARP:
     55                 raise NPCWarpError('Already Warping')
     56             destination = self.ballpark.AdjustDstByJitter(destination, jitterRadius)
     57             if not self.ballpark.dogmaLM.GetAttributeValue(self.id, dogmaConst.attributeWarpBubbleImmune):
     58                 if IsBallIntersectingAnyWarpDisruptionField(self.ballpark, self.id):
     59                     raise NpcWarpBubbledError('Warp bubble disruptor')
     60                 try:
     61                     destination = self.ballpark.ApplyWarpDisruptors(self.id, self.GetPosition(), destination, warpAtRange)
     62                 except UserError:
     63                     raise NpcWarpPathBubbledError('Warp path too short due to bubble disruptor')
     64 
     65             self.ballpark.bubbleKeepAliveController.add_bubble_keep_alive_ball_at_coordinates(self.id, destination)
     66             self.ballpark.EntityWarpStart(self.id, pos=destination, makeItReal=True, notWarpingException=NPCWarpError, minRange=warpAtRange, warpSpeed=warpSpeed)
     67         else:
     68             raise NPCWarpError('No ballpark')
     69 
     70     @TimedFunction('behaviors::entity::BehaviorEntity::NPCEndWarp')
     71     def NPCEndWarp(self):
     72         if hasattr(self, 'ballpark') and self.ballpark is not None:
     73             self.ballpark.bubbleKeepAliveController.remove_bubble_keep_alive_ball(self.id)
     74         else:
     75             raise NPCWarpError()
     76 
     77     def _GetKillOwner(self):
     78         return get_kill_owner_id(self.ballpark, self.id)
     79 
     80     def _GetWreckID(self, item):
     81         return evetypes.GetWreckTypeIDOrNone(item.typeID)
     82 
     83     def _GetShipAccess(self, item):
     84         shipAccess = self.ballpark.broker.ship.GetShipAccessEx(item.locationID, groupSolarSystem)
     85         shipAccess.Bind()
     86         return shipAccess
     87 
     88     def OnExplode(self):
     89         item = self.ballpark.inventory2.GetItem(self.id)
     90         if HasCargoBayComponent(item.typeID):
     91             logger.debug('Entity %s of type %s has cargo bay component which is managing dropped loot.', self.id, item.typeID)
     92             return
     93         offenderOwnerID = self._GetKillOwner()
     94         wreckTypeID = self._GetWreckID(item)
     95         shipAccess = self._GetShipAccess(item)
     96         itemList = self.GetLootForEntity(item.typeID, item.ownerID)
     97         if wreckTypeID is not None:
     98             shipAccess.Jettison_DropWreck_Ex(offenderOwnerID, self.id, item.typeID, self.GetPosition(), wreckTypeID, itemList, npcLoot=True)
     99         super(BehaviorEntity, self).OnExplode()
    100 
    101     def OnUnspawn(self):
    102         additionalLoot = self.GetAdditionalLoot()
    103         if additionalLoot:
    104             self.SendMessage(self.id, MESSAGE_ON_UNSPAWNED_WITH_ADDITIONAL_LOOT, additionalLoot)
    105 
    106     def DoModeChange(self, oldMode, newMode):
    107         self.SendMessage(self.id, MESSAGE_ON_BALL_MODE_CHANGED, oldMode, newMode)
    108         if oldMode == DESTINY_MODE_WARP:
    109             self.NPCEndWarp()
    110 
    111     def _GetAdditionalLootForWreck(self):
    112         additionalLoot = []
    113         for lootTableId in self.additionalLootTables:
    114             additionalLoot.extend(self.ballpark.broker.lootSvc.GetLootFromTable(lootTableId))
    115 
    116         for typeId, amount in self.additionalLoot.iteritems():
    117             additionalLoot.append((typeId, amount, None))
    118 
    119         return additionalLoot
    120 
    121     def AddTypeAndAmountToAdditionalLoot(self, typeId, amount = 1, overload = True):
    122         if not overload:
    123             amount = self._GetAvailableAmountForTypeInAdditionalLoot(typeId, amount)
    124         self.additionalLoot[typeId] += amount
    125 
    126     def RemoveTypeFromAdditionalLoot(self, typeId):
    127         if typeId in self.additionalLoot:
    128             del self.additionalLoot[typeId]
    129 
    130     def HasTypeInAdditionalLoot(self, typeId):
    131         return typeId in self.additionalLoot
    132 
    133     def GetLootForEntity(self, typeId, ownerId):
    134         itemDict = self.ballpark.broker.lootSvc.GetLootForEntity(typeId, self.id, ownerId)
    135         itemList = []
    136         for typeID, pickList in itemDict.iteritems():
    137             for quantity, customInfo in pickList:
    138                 itemList.append((typeID, quantity, customInfo))
    139 
    140         additionalLoot = self._GetAdditionalLootForWreck()
    141         if additionalLoot:
    142             self.SendMessage(self.id, MESSAGE_ON_DROPPED_ADDITIONAL_LOOT, {(typeId, amount) for typeId, amount, _ in additionalLoot})
    143         itemList.extend(additionalLoot)
    144         return itemList
    145 
    146     def AddLootTableToAdditionalLoot(self, lootTableId):
    147         self.additionalLootTables.append(lootTableId)
    148 
    149     def HasLootTableInAdditionalLoot(self, lootTableId):
    150         return lootTableId in self.additionalLootTables
    151 
    152     def HasEnoughAdditionalCargoCapacityForType(self, typeId, quantity = 1):
    153         requiredCargoCapacity = evetypes.GetAttributeForType(typeId, 'volume') * quantity
    154         return self.GetAvailableAdditionalCargoCapacity() - requiredCargoCapacity >= 0
    155 
    156     def GetAvailableAdditionalCargoCapacity(self):
    157         selfTypeId = self.ballpark.inventory2.GetItem(self.id).typeID
    158         cargoCapacity = evetypes.GetAttributeForType(selfTypeId, 'capacity')
    159         usedCargoCapacity = self._GetUsedAdditionalCargoCapacity()
    160         return cargoCapacity - usedCargoCapacity
    161 
    162     def _GetUsedAdditionalCargoCapacity(self):
    163         usedCapacity = 0
    164         for typeId, amount in self.additionalLoot.iteritems():
    165             usedCapacity += evetypes.GetAttributeForType(typeId, 'volume') * amount
    166 
    167         return usedCapacity
    168 
    169     def _GetAvailableAmountForTypeInAdditionalLoot(self, typeId, amount):
    170         availabeCargoCapacity = self.GetAvailableAdditionalCargoCapacity()
    171         totalVolumeNeeded = evetypes.GetAttributeForType(typeId, 'volume') * amount
    172         if availabeCargoCapacity < totalVolumeNeeded:
    173             return math.floor(amount * (availabeCargoCapacity / totalVolumeNeeded))
    174         return amount
    175 
    176     def RemoveAdditionalLoot(self):
    177         additionalLoot = self.additionalLoot.copy()
    178         self.additionalLoot.clear()
    179         self.SendMessage(self.id, MESSAGE_ON_ADDITIONAL_LOOT_REMOVED)
    180         return additionalLoot
    181 
    182     def GetAdditionalLoot(self):
    183         return self.additionalLoot.copy()