combatnavigation.py (6971B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\behaviors\actions\combatnavigation.py 2 import random 3 import math 4 from behaviors.const.behaviorroles import ROLE_COMMANDER, ROLE_DPS, ROLE_TACKLER 5 from behaviors.exceptions import BehaviorAuthoringException 6 from behaviors.tasks import Task 7 from behaviors.utility.dogmatic import get_my_attribute_value 8 from ccpProfile import TimedFunction 9 import logging 10 from dogma.const import attributeBehaviorCombatOrbitRange 11 logger = logging.getLogger(__name__) 12 DEFAULT_COMBAT_ORBIT_RANGE = 10000.0 13 DEFAULT_COMBAT_ATTACK_RANGE = 30000.0 14 COMBAT_ATTACK_RANGE_FACTOR = 3.0 15 DEFAULT_MAXIMUM_ORBIT_RANGE = 100000.0 16 FALLOFF_ORBIT_DISTANCE_FACTOR = 0.25 17 MISSILE_RANGE_ORBIT_DISTANCE_FACTOR = 0.75 18 OPTIMAL_ORBIT_DISTANCE_FACTOR = 0.75 19 COMBAT_WARP_AT_DISTANCE_FACTOR = 50000.0 20 DEFAULT_ANCHOR_ORBIT_RANGE = (1000.0, 4000.0) 21 FLEET_NAVIGATION_BY_ROLE = {ROLE_DPS: {'orbitTarget': ROLE_COMMANDER, 22 'orbitRange': DEFAULT_ANCHOR_ORBIT_RANGE}, 23 ROLE_TACKLER: {'orbitTarget': 'target'}} 24 25 class GetCombatOrbitAndAttackRange(Task): 26 27 @TimedFunction('behaviors::actions::combatnavigation::GetCombatOrbitRange::OnEnter') 28 def OnEnter(self): 29 self.SetStatusToSuccess() 30 if not self._should_calculate_orbit_and_attack_range(): 31 return 32 orbit_range, attack_range = self._get_desired_orbit_and_attack_range() 33 if orbit_range > attack_range: 34 raise BehaviorAuthoringException('Behavior=%s for entity_type=%s has less attack range than orbit range', self.behaviorTree.GetBehaviorId(), self.context.mySlimItem.typeID) 35 self.SendBlackboardValue(self.attributes.orbitRangeAddress, orbit_range) 36 self.SendBlackboardValue(self.attributes.attackRangeAddress, attack_range) 37 38 def _should_calculate_orbit_and_attack_range(self): 39 return self.GetLastBlackboardValue(self.attributes.orbitRangeAddress) is None 40 41 def _get_desired_orbit_and_attack_range(self): 42 behavior_orbit_range = getattr(self.attributes, 'orbitRange', 0) 43 attack_range = getattr(self.attributes, 'attackRange', 0) 44 if behavior_orbit_range and attack_range: 45 return (behavior_orbit_range, attack_range) 46 calculated_orbit_range, calculated_attack_range = self._calculate_orbit_and_attack_range() 47 if not calculated_orbit_range and not behavior_orbit_range: 48 raise BehaviorAuthoringException('Behavior=%s for entity_type=%s missing orbitRange or optimalRange from address, might be missing task=GetMyMinOptimalAndFalloff', self.behaviorTree.GetBehaviorId(), self.context.mySlimItem.typeID) 49 orbit_range = behavior_orbit_range or min(calculated_orbit_range, DEFAULT_MAXIMUM_ORBIT_RANGE) 50 dogma_orbit_range = get_my_attribute_value(self, attributeBehaviorCombatOrbitRange) 51 if dogma_orbit_range > 0: 52 orbit_range = min(orbit_range, dogma_orbit_range) 53 return (orbit_range, attack_range or calculated_attack_range) 54 55 def _calculate_orbit_and_attack_range(self): 56 min_optimal, min_falloff = self._get_min_optimal_and_falloff_from_addresses() 57 if not min_falloff: 58 orbit_range = min_optimal * OPTIMAL_ORBIT_DISTANCE_FACTOR 59 attack_range = min_optimal 60 else: 61 orbit_range = min_optimal + min_falloff * FALLOFF_ORBIT_DISTANCE_FACTOR 62 attack_range = min_optimal + min_falloff * COMBAT_ATTACK_RANGE_FACTOR 63 return (orbit_range or DEFAULT_COMBAT_ORBIT_RANGE, attack_range or DEFAULT_COMBAT_ATTACK_RANGE) 64 65 def _get_min_optimal_and_falloff_from_addresses(self): 66 min_optimal = min_falloff = 0.0 67 if self.HasAttribute('minOptimalAddress'): 68 min_optimal = self.GetLastBlackboardValue(self.attributes.minOptimalAddress) 69 if self.HasAttribute('minFalloffAddress'): 70 min_falloff = self.GetLastBlackboardValue(self.attributes.minFalloffAddress) 71 return (min_optimal, min_falloff) 72 73 74 class GetTargetToOrbit(Task): 75 76 @TimedFunction('behaviors::actions::combatnavigation::GetTargetToOrbit::OnEnter') 77 def OnEnter(self): 78 self.SetStatusToSuccess() 79 commanderId = self.GetLastBlackboardValue(self.attributes.commanderAddress) 80 if self._ShouldOrbitCommander(commanderId): 81 self.SendBlackboardValue(self.attributes.orbitTargetAddress, commanderId) 82 else: 83 combatTargetId = self.GetLastBlackboardValue(self.attributes.combatTargetAddress) 84 self.SendBlackboardValue(self.attributes.orbitTargetAddress, combatTargetId) 85 86 def _ShouldOrbitCommander(self, commanderId): 87 if commanderId is None: 88 return False 89 if self.context.myItemId == commanderId: 90 return False 91 role = self.GetLastBlackboardValue(self.attributes.roleAddress) 92 if not role: 93 return False 94 if role not in FLEET_NAVIGATION_BY_ROLE or FLEET_NAVIGATION_BY_ROLE[role]['orbitTarget'] != ROLE_COMMANDER: 95 return False 96 return True 97 98 99 class GetFleetCombatOrbitRangeByRole(Task): 100 101 @TimedFunction('behaviors::actions::combatnavigation::GetFleetCombatOrbitAndAttackRangeByRole::OnEnter') 102 def OnEnter(self): 103 self.SetStatusToSuccess() 104 orbitRange = self._GetCommanderOrbitRangeByRole() 105 self.SendBlackboardValue(self.attributes.orbitRangeAddress, orbitRange) 106 107 def _GetCommanderOrbitRangeByRole(self): 108 role = self.GetLastBlackboardValue(self.attributes.roleAddress) 109 if role in FLEET_NAVIGATION_BY_ROLE: 110 minOrbitRange, maxOrbitRange = FLEET_NAVIGATION_BY_ROLE[role]['orbitRange'] 111 else: 112 minOrbitRange, maxOrbitRange = DEFAULT_ANCHOR_ORBIT_RANGE 113 return random.randrange(minOrbitRange, maxOrbitRange) 114 115 116 class GetCombatWarpAtDistance(Task): 117 118 @TimedFunction('behaviors::actions::combatnavigation::GetCombatWarpAtDistance::OnEnter') 119 def OnEnter(self): 120 self.SetStatusToSuccess() 121 if self._already_has_combat_warp_at_distance(): 122 return 123 combat_warp_at_distance = self._get_combat_warp_at_distance() 124 self.SendBlackboardValue(self.attributes.combatWarpAtDistanceAddress, combat_warp_at_distance) 125 126 def _already_has_combat_warp_at_distance(self): 127 return self.GetLastBlackboardValue(self.attributes.combatWarpAtDistanceAddress) is not None 128 129 def _get_combat_warp_at_distance(self): 130 combat_orbit_range = self._get_combat_orbit_range() 131 if not combat_orbit_range: 132 raise BehaviorAuthoringException('Behavior=%s for entity=%s has no combat_orbit_range for GetCombatWarpAtDistance' % (self.behaviorTree.GetBehaviorId(), self.context.myItemId)) 133 factor = 1.0 - 1.0 / math.exp((combat_orbit_range / COMBAT_WARP_AT_DISTANCE_FACTOR) ** 2.0) 134 return factor * combat_orbit_range 135 136 def _get_combat_orbit_range(self): 137 return self.GetLastBlackboardValue(self.attributes.combatOrbitRangeAddress)