Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Use chance to hit when selecting targets for sentry drones, instead o…

…f distance

Autotargeter bug fixes
Factored out weapon helper chance to hit calculation into a reusable class in common.eve
  • Loading branch information...
commit a1850dd88cbb85e8cfa86408a9b23eb4fa4bab6c 1 parent 00ffec1
@kg authored
View
14 AutoTargeter/autotargeter.py
@@ -201,7 +201,7 @@ def updateTargets(self):
log("Locking %s", ", ".join(getNamesOfIDs(targetsToLock)))
for targetID in targetsToLock:
if targetID not in self.__lockedTargets:
- self.__lockedTargets.append(targetID)
+ self.__lockedTargets.add(targetID)
setItemColor(targetID, "Automatic Target")
uthread.pool(
@@ -225,7 +225,7 @@ def populateBalls(self):
targetSvc = sm.services.get('target', None)
if targetSvc:
- self.__lockedTargets = list(targetSvc.targets)
+ self.__lockedTargets = set(targetSvc.targets)
for id in self.__lockedTargets:
setItemColor(id, "Automatic Target")
@@ -252,6 +252,8 @@ def isEligible(self, cachedItem):
def _DoBallsAdded(self, lst):
for (ball, slimItem) in lst:
+ if not slimItem:
+ continue
if not slimItem.categoryID in TargetableCategories:
continue
if slimItem.itemID == eve.session.shipid:
@@ -291,8 +293,10 @@ def OnTargets(self, targets):
def OnTarget(self, what, tid=None, reason=None):
if (what == "lost"):
- if (reason == None) and (tid in self.__potentialTargets):
- self.__potentialTargets.remove(tid)
+ if (reason == None) and (tid in self.__balls):
+ ball = self.__balls[tid]
+ del self.__balls[tid]
+ self.__eligibleBalls.remove(ball)
if tid in self.__lockedTargets:
self.__lockedTargets.remove(tid)
setItemColor(tid, None)
@@ -301,7 +305,7 @@ def OnTarget(self, what, tid=None, reason=None):
for id in self.__lockedTargets:
setItemColor(id, None)
- self.__lockedTargets = []
+ self.__lockedTargets = set()
def initialize():
global serviceRunning, serviceInstance
View
150 Common/common.eve.py
@@ -75,6 +75,156 @@ def isBallTargetable(ball):
else:
return True
+class ChanceToHitCalculator(object):
+ def __init__(self, sourceID):
+ self.setSource(sourceID)
+
+ def setSource(self, sourceID):
+ from common.eve.state import getCachedItem
+ self.source = getCachedItem(sourceID)
+
+ def setDrone(self, id):
+ from common.eve.state import getCachedItem
+ self.source = getCachedItem(id)
+
+ si = self.source.slimItem
+ ball = self.source.ball
+ droneAttrs = getTypeAttributes(si.typeID, obj=ball)
+
+ self.baseDamage = float(
+ droneAttrs.get("kineticDamage", 0) +
+ droneAttrs.get("emDamage", 0) +
+ droneAttrs.get("explosiveDamage", 0) +
+ droneAttrs.get("thermalDamage", 0)
+ )
+
+ self.optimal = float(droneAttrs["maxRange"])
+ self.falloff = float(droneAttrs["falloff"])
+ self.tracking = float(droneAttrs["trackingSpeed"])
+ self.sigResolution = float(droneAttrs["optimalSigRadius"])
+
+ self.calculate = self.calculateTurret
+
+ def setModule(self, module):
+ godma = eve.LocalSvc("godma")
+
+ moduleAttrs = getModuleAttributes(module)
+ if getattr(module, "charge", None):
+ chargeObj = godma.GetItem(module.charge.itemID)
+ chargeAttrs = getTypeAttributes(module.charge.typeID, obj=chargeObj)
+ else:
+ chargeAttrs = {}
+
+ self.baseDamage = float(
+ chargeAttrs.get("kineticDamage", 0) +
+ chargeAttrs.get("emDamage", 0) +
+ chargeAttrs.get("explosiveDamage", 0) +
+ chargeAttrs.get("thermalDamage", 0)
+ )
+
+ if moduleAttrs.has_key("trackingSpeed"):
+ # Gun turret
+
+ self.optimal = float(moduleAttrs["maxRange"])
+ self.falloff = float(moduleAttrs["falloff"])
+ self.tracking = float(moduleAttrs["trackingSpeed"])
+ self.sigResolution = float(moduleAttrs["optimalSigRadius"])
+
+ self.calculate = self.calculateTurret
+
+ elif chargeAttrs.has_key("maxVelocity"):
+ # Missile launcher
+
+ self.maxVelocity = float(chargeAttrs["maxVelocity"])
+ self.flightTime = float(chargeAttrs["explosionDelay"]) / 1000.0
+ self.explosionRadius = max(float(chargeAttrs["aoeCloudSize"]), 0.00001)
+ self.explosionVelocity = float(chargeAttrs["aoeVelocity"])
+ self.damageReductionFactor = float(chargeAttrs["aoeDamageReductionFactor"])
+ self.maxRange = flightTime * maxVelocity
+
+ self.calculate = self.calculateLauncher
+
+ def calculateNone(self, targetID, **kwargs):
+ return 0.0
+
+ def calculateTurret(self, targetID, velocityModifier=1.0, radiusModifier=1.0):
+ import blue, foo
+ from common.eve.state import getCachedItem
+ target = getCachedItem(targetID)
+
+ ballpark = sm.services["michelle"].GetBallpark()
+ now = blue.os.GetTime()
+
+ shipVelocity = self.source.ball.GetVectorDotAt(now)
+ shipPos = foo.Vector3(
+ self.source.ball.x, self.source.ball.y, self.source.ball.z
+ )
+
+ distance = max(ballpark.DistanceBetween(eve.session.shipid, targetID), 0.00001)
+ distanceFactor = max(0.0, distance - self.optimal) / self.falloff
+
+ targetBall = target.ball
+ targetItem = target.slimItem
+ targetVelocity = targetBall.GetVectorDotAt(now) * velocityModifier
+ targetPos = foo.Vector3(targetBall.x, targetBall.y, targetBall.z)
+ targetRadius = target.radius * radiusModifier
+
+ combinedVelocity = foo.Vector3(
+ targetVelocity.x - shipVelocity.x,
+ targetVelocity.y - shipVelocity.y,
+ targetVelocity.z - shipVelocity.z
+ )
+
+ radialVector = targetPos - shipPos
+ if ((radialVector.x, radialVector.y, radialVector.z) != (0.0, 0.0, 0.0)):
+ radialVector = radialVector.Normalize()
+
+ radialVelocity = combinedVelocity * radialVector
+ transversalVelocity = (combinedVelocity - (radialVelocity * radialVector)).Length()
+
+ trackingFactor = transversalVelocity / distance * self.tracking
+
+ resolutionFactor = self.sigResolution / targetRadius
+
+ result = 0.5 ** (((trackingFactor * resolutionFactor) ** 2) + (distanceFactor ** 2))
+
+ return result
+
+ def calculateLauncher(self, targetID, velocityModifier=1.0, radiusModifier=1.0):
+ import blue, foo
+ from common.eve.state import getCachedItem
+ target = getCachedItem(targetID)
+ targetBall = target.ball
+ targetItem = target.slimItem
+
+ ballpark = sm.services["michelle"].GetBallpark()
+ now = blue.os.GetTime()
+
+ distance = max(ballpark.DistanceBetween(self.source.id, targetID), 0.00001)
+
+ targetVelocity = max(
+ targetBall.GetVectorDotAt(now).Length() * velocityModifier,
+ 0.00001
+ )
+ targetRadius = target.radius * radiusModifier
+
+ estimatedDamage = self.baseDamage * min(
+ min(
+ targetRadius / self.explosionRadius, 1
+ ), (
+ (self.explosionVelocity / self.explosionRadius * targetRadius / targetVelocity) **
+ (math.log(self.damageReductionFactor) / math.log(5.5))
+ )
+ )
+
+ if distance > self.maxRange:
+ return 0
+ else:
+ return estimatedDamage / self.baseDamage
+
+ def calculateSmartBomb(self, targetID, **kwargs):
+ return 0.0
+
def findModule(groupNames=None, groupIDs=None, typeNames=None, typeIDs=None):
modules = findModules(
count=1,
View
14 Common/common.eve.state.py
@@ -38,6 +38,18 @@ def slimItem(self):
return self._slimItem
+ @property
+ def radius(self):
+ r = None
+
+ if self.slimItem:
+ r = getattr(self.slimItem, "signatureRadius", None)
+
+ if ((r is None) or (r <= 0.0)) and (self.ball):
+ r = self.ball.radius
+
+ return r
+
def removedFromBallpark(self):
self._slimItem = None
self._ball = None
@@ -124,7 +136,7 @@ def OnStandingSet(self, fromID, toID, standing):
if ce:
ce.clearFlag()
- def OnStandingsModified(self):
+ def OnStandingsModified(self, modifications):
for obj in self.objectCache.values():
obj.clearFlag()
View
56 DroneHelper/dronehelper.py
@@ -1,6 +1,7 @@
import shootblues
from shootblues.common import log
-from shootblues.common.eve import SafeTimer, getFlagName, getNamesOfIDs
+from shootblues.common.eve import SafeTimer, getFlagName, getNamesOfIDs, ChanceToHitCalculator, getTypeAttributes
+from shootblues.common.eve.state import getCachedItem
from shootblues.common.service import forceStart, forceStop
import service
import uix
@@ -35,10 +36,16 @@ def notifyPrefsChanged(newPrefsJson):
class DroneInfo(object):
def __init__(self, droneID):
self.id = droneID
+ ci = getCachedItem(droneID)
+ self.ball = ci.ball
+ self.slimItem = ci.slimItem
self.target = None
self.actionTimestamp = self.timestamp = 0
self.shield = self.armor = self.structure = 1.0
self.state = None
+
+ attributes = getTypeAttributes(ci.slimItem.typeID, obj=ci.ball)
+ self.isSentry = float(attributes.get("entityCruiseSpeed", 0.0)) <= 0.0
def setState(self, newState, timestamp):
if timestamp > self.timestamp:
@@ -76,6 +83,7 @@ def __init__(self):
self.__lastAttackOrder = None
self.__recalledDrones = {}
self.__numFighters = 0
+ self.__numSentries = 0
self.disabled = False
self.checkUpdateTimer()
@@ -160,6 +168,39 @@ def getTargetSorter(self):
gp = Memoized(getPriority)
gd = Memoized(self.getDistance)
+ numDrones = len(self.__drones)
+ useChanceToHit = (self.__numSentries >= (numDrones / 2)) and (self.__numSentries > 0)
+
+ if useChanceToHit:
+ def getCalcForDrone(id):
+ cthc = ChanceToHitCalculator(id)
+ cthc.setDrone(id)
+ return Memoized(cthc.calculate)
+
+ calcs = [
+ getCalcForDrone(id) for id in self.__drones.iterkeys()
+ if self.__drones[id].isSentry
+ ]
+
+ def toHitSorter(lhs, rhs):
+ cthLhs = 0
+ cthRhs = 0
+
+ for calc in calcs:
+ cthLhs += calc(lhs)
+ cthRhs += calc(rhs)
+
+ cthLhs /= len(calcs)
+ cthRhs /= len(calcs)
+
+ return cmp(cthRhs, cthLhs)
+
+ else:
+ def toHitSorter(lhs, rhs):
+ distLhs = gd(lhs)
+ distRhs = gd(rhs)
+ return cmp(distLhs, distRhs)
+
def targetSorter(lhs, rhs):
# Highest priority first
priLhs = gp(lhs)
@@ -173,10 +214,8 @@ def targetSorter(lhs, rhs):
lhs is self.__lastAttackOrder
)
- if result == 0:
- distLhs = gd(lhs)
- distRhs = gd(rhs)
- result = cmp(distLhs, distRhs)
+ if result == 0:
+ result = toHitSorter(lhs, rhs)
return result
@@ -353,6 +392,11 @@ def updateDrones(self):
)):
self.__numFighters += 1
+ self.__numSentries = 0
+ for droneObj in self.__drones.itervalues():
+ if droneObj.isSentry:
+ self.__numSentries += 1
+
for (pendingID, psc) in list(self.__pendingStateChanges.items()):
if self.__pendingStateChanges.has_key(pendingID):
del self.__pendingStateChanges[pendingID]
@@ -387,7 +431,7 @@ def updateDrones(self):
commonTarget = self.getCommonTarget(filtered=False)
if commonTarget == eve.session.shipid:
return
-
+
oldPriority = getPriority(commonTarget)
newTarget = self.selectTarget()
newPriority = getPriority(newTarget)
View
3  EnemyPrioritizer/enemyprioritizer.py
@@ -20,6 +20,9 @@ def adjustPriority(targetID, delta=1):
def getPriority(id):
global priorities, priorityBoosts
+ if not id:
+ return -1
+
ci = getCachedItem(id)
if not ci.slimItem:
View
142 WeaponHelper/weaponhelper.py
@@ -1,6 +1,6 @@
import shootblues
from shootblues.common import log
-from shootblues.common.eve import SafeTimer, getFlagName, getNamesOfIDs, findModules, getModuleAttributes, getTypeAttributes, activateModule, canActivateModule
+from shootblues.common.eve import SafeTimer, getFlagName, getNamesOfIDs, findModules, getModuleAttributes, getTypeAttributes, activateModule, canActivateModule, ChanceToHitCalculator
from shootblues.common.service import forceStart, forceStop
import service
import json
@@ -51,136 +51,32 @@ def __init__(self):
self.__lastAttackOrder = None
def getTargetSorter(self, module):
- now = blue.os.GetTime(1)
godma = eve.LocalSvc("godma")
ballpark = eve.LocalSvc("michelle").GetBallpark()
gp = Memoized(getPriority)
- moduleAttrs = getModuleAttributes(module)
- if getattr(module, "charge", None):
- chargeObj = godma.GetItem(module.charge.itemID)
- chargeAttrs = getTypeAttributes(module.charge.typeID, obj=chargeObj)
- else:
- chargeAttrs = {}
-
- shipBall = ballpark.GetBall(eve.session.shipid)
- shipVelocity = shipBall.GetVectorDotAt(now)
- shipPos = foo.Vector3(shipBall.x, shipBall.y, shipBall.z)
+ cthc = ChanceToHitCalculator(eve.session.shipid)
+ cthc.setModule(module)
+ chanceToHitGetter = Memoized(cthc.calculate)
- if moduleAttrs.has_key("trackingSpeed"):
- # Gun turret
+ def targetSorter(lhs, rhs):
+ # Highest priority first
+ priLhs = gp(lhs)
+ priRhs = gp(rhs)
+ result = cmp(priRhs, priLhs)
- optimal = float(moduleAttrs["maxRange"])
- falloff = float(moduleAttrs["falloff"])
- tracking = float(moduleAttrs["trackingSpeed"])
- sigResolution = float(moduleAttrs["optimalSigRadius"])
+ if result == 0:
+ # Highest chance to hit first, but bias the chance to hit up for things we previously attacked
+ cthLhs = chanceToHitGetter(lhs)
+ if lhs is self.__lastAttackOrder:
+ cthLhs += ChanceToHitBias
+ cthRhs = chanceToHitGetter(rhs)
+ if rhs is self.__lastAttackOrder:
+ cthRhs += ChanceToHitBias
+ result = cmp(cthRhs, cthLhs)
- def _chanceToHitGetter(targetID):
- distance = max(ballpark.DistanceBetween(eve.session.shipid, targetID), 0.00001)
- distanceFactor = max(0.0, distance - optimal) / falloff
-
- targetBall = ballpark.GetBall(targetID)
- targetItem = ballpark.GetInvItem(targetID)
- targetVelocity = targetBall.GetVectorDotAt(now)
- targetPos = foo.Vector3(targetBall.x, targetBall.y, targetBall.z)
- targetRadius = getattr(
- targetItem, "signatureRadius", None
- )
- if (not targetRadius) or (targetRadius <= 0.0):
- targetRadius = targetBall.radius
-
- combinedVelocity = foo.Vector3(
- targetVelocity.x - shipVelocity.x,
- targetVelocity.y - shipVelocity.y,
- targetVelocity.z - shipVelocity.z
- )
-
- radialVector = targetPos - shipPos
- if ((radialVector.x, radialVector.y, radialVector.z) != (0.0, 0.0, 0.0)):
- radialVector = radialVector.Normalize()
-
- radialVelocity = combinedVelocity * radialVector
- transversalVelocity = (combinedVelocity - (radialVelocity * radialVector)).Length()
-
- trackingFactor = transversalVelocity / distance * tracking
-
- resolutionFactor = sigResolution / targetRadius
-
- result = 0.5 ** (((trackingFactor * resolutionFactor) ** 2) + (distanceFactor ** 2))
-
- return result
-
- chanceToHitGetter = Memoized(_chanceToHitGetter)
-
- elif chargeAttrs.has_key("maxVelocity"):
- # Missile launcher
-
- maxVelocity = float(chargeAttrs["maxVelocity"])
- flightTime = float(chargeAttrs["explosionDelay"]) / 1000.0
- explosionRadius = max(float(chargeAttrs["aoeCloudSize"]), 0.00001)
- explosionVelocity = float(chargeAttrs["aoeVelocity"])
- damageReductionFactor = float(chargeAttrs["aoeDamageReductionFactor"])
- maxRange = flightTime * maxVelocity
- baseDamage = float(
- chargeAttrs["kineticDamage"] + chargeAttrs["emDamage"] +
- chargeAttrs["explosiveDamage"] + chargeAttrs["thermalDamage"]
- )
-
- def _chanceToHitGetter(targetID):
- distance = max(ballpark.DistanceBetween(eve.session.shipid, targetID), 0.00001)
-
- targetBall = ballpark.GetBall(targetID)
- targetItem = ballpark.GetInvItem(targetID)
- targetVelocity = max(targetBall.GetVectorDotAt(now).Length(), 0.00001)
- targetRadius = getattr(
- targetItem, "signatureRadius", None
- )
- if (not targetRadius) or (targetRadius <= 0.0):
- targetRadius = targetBall.radius
-
- estimatedDamage = baseDamage * min(
- min(
- targetRadius / explosionRadius, 1
- ), (
- (explosionVelocity / explosionRadius * targetRadius / targetVelocity) **
- (math.log(damageReductionFactor) / math.log(5.5))
- )
- )
-
- if distance > maxRange:
- return 0
- else:
- return estimatedDamage / baseDamage
-
- chanceToHitGetter = Memoized(_chanceToHitGetter)
-
- if chanceToHitGetter:
- def targetSorter(lhs, rhs):
- # Highest priority first
- priLhs = gp(lhs)
- priRhs = gp(rhs)
- result = cmp(priRhs, priLhs)
-
- if result == 0:
- # Highest chance to hit first, but bias the chance to hit up for things we previously attacked
- cthLhs = chanceToHitGetter(lhs)
- if lhs is self.__lastAttackOrder:
- cthLhs += ChanceToHitBias
- cthRhs = chanceToHitGetter(rhs)
- if rhs is self.__lastAttackOrder:
- cthRhs += ChanceToHitBias
- result = cmp(cthRhs, cthLhs)
-
- return result
- else:
- # For some reason our weapon module has neither gun turret or missile attributes
- log("Warning: Weapon without chance-to-hit attributes.")
- def targetSorter(lhs, rhs):
- # Highest priority first
- priLhs = getPriority(lhs)
- priRhs = getPriority(rhs)
- result = cmp(priRhs, priLhs)
+ return result
return targetSorter
Please sign in to comment.
Something went wrong with that request. Please try again.