attempted cleanup of previous test fire condition; division of turret callbacks between generic targets and vehicle targets; facility turret stops automatic fire when being mounted and resumes automatic mode when being dismounted

This commit is contained in:
Fate-JH 2024-01-12 02:03:46 -05:00
parent 20b5de34ab
commit 3ffb817f4a
8 changed files with 192 additions and 76 deletions

View file

@ -435,9 +435,14 @@ private[support] class WeaponAndProjectileOperations(
def handleAIDamage(pkt: AIDamage): Unit = { def handleAIDamage(pkt: AIDamage): Unit = {
val AIDamage(targetGuid, attackerGuid, projectileTypeId, _, _) = pkt val AIDamage(targetGuid, attackerGuid, projectileTypeId, _, _) = pkt
(continent.GUID(player.VehicleSeated) match { (continent.GUID(player.VehicleSeated) match {
case Some(tobj: PlanetSideServerObject with FactionAffinity with Vitality) if tobj.GUID == targetGuid => Some(tobj) case Some(tobj: PlanetSideServerObject with FactionAffinity with Vitality with OwnableByPlayer)
case _ if player.GUID == targetGuid => Some(player) if tobj.GUID == targetGuid && tobj.OwnerGuid.contains(player.GUID) =>
case _ => None Some(tobj)
case _
if player.GUID == targetGuid =>
Some(player)
case _ =>
None
}).foreach { target => }).foreach { target =>
sessionData.validObject(attackerGuid, decorator = "AIDamage/Attacker") sessionData.validObject(attackerGuid, decorator = "AIDamage/Attacker")
.collect { .collect {

View file

@ -10057,7 +10057,8 @@ object GlobalDefinitions {
targetValidation = List(EffectTarget.Validation.MaxOnRadar, EffectTarget.Validation.VehiclesOnRadar), targetValidation = List(EffectTarget.Validation.MaxOnRadar, EffectTarget.Validation.VehiclesOnRadar),
retaliatoryDuration = 8000L, retaliatoryDuration = 8000L,
cylindricalCheck = true, cylindricalCheck = true,
cylindricalHeight = 25f cylindricalHeight = 25f,
detectionSpeed = 2.seconds
) )
manned_turret.innateDamage = new DamageWithPosition { manned_turret.innateDamage = new DamageWithPosition {
CausesDamageType = DamageType.One CausesDamageType = DamageType.One

View file

@ -109,8 +109,8 @@ class TurretControl(turret: TurretDeployable)
attacker => attacker =>
val channel = zone.id val channel = zone.id
val guid = AutomatedTurretObject.GUID val guid = AutomatedTurretObject.GUID
AutomatedTurretBehavior.startTrackingTargets(zone, channel, guid, List(attacker.GUID)) AutomatedTurretBehavior.startTracking(attacker, channel, guid, List(attacker.GUID))
AutomatedTurretBehavior.stopTrackingTargets(zone, channel, guid) //TODO delay by a few milliseconds? AutomatedTurretBehavior.stopTracking(attacker, channel, guid) //TODO delay by a few milliseconds?
} }
} }
} }

View file

@ -26,9 +26,9 @@ class InteractWithTurrets()
def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit = { def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit = {
target match { target match {
case clarifiedTarget: AutomatedTurret.Target => case clarifiedTarget: AutomatedTurret.Target =>
val posxy = clarifiedTarget.Position.xy val pos = clarifiedTarget.Position
val unique = SourceEntry(clarifiedTarget).unique val unique = SourceEntry(clarifiedTarget).unique
val targets = getTurretTargets(sector, posxy).filter { turret => turret.Definition.AutoFire.nonEmpty && turret.Detected(unique).isEmpty } val targets = getTurretTargets(sector, pos).filter { turret => turret.Definition.AutoFire.nonEmpty && turret.Detected(unique).isEmpty }
targets.foreach { t => t.Actor ! AutomatedTurretBehavior.Alert(clarifiedTarget) } targets.foreach { t => t.Actor ! AutomatedTurretBehavior.Alert(clarifiedTarget) }
case _ => () case _ => ()
} }
@ -72,7 +72,7 @@ class InteractWithTurrets()
} }
object InteractWithTurrets { object InteractWithTurrets {
private val Range: Float = { private lazy val Range: Float = {
Seq( Seq(
GlobalDefinitions.spitfire_turret, GlobalDefinitions.spitfire_turret,
GlobalDefinitions.spitfire_cloaked, GlobalDefinitions.spitfire_cloaked,

View file

@ -212,7 +212,8 @@ object EffectTarget {
!target.Destroyed && (target match { !target.Destroyed && (target match {
case v: Vehicle => case v: Vehicle =>
val vdef = v.Definition val vdef = v.Definition
!(v.Cloaked || !(v.MountedIn.nonEmpty ||
v.Cloaked ||
GlobalDefinitions.isAtvVehicle(vdef) || GlobalDefinitions.isAtvVehicle(vdef) ||
vdef == GlobalDefinitions.two_man_assault_buggy || vdef == GlobalDefinitions.two_man_assault_buggy ||
vdef == GlobalDefinitions.skyguard) vdef == GlobalDefinitions.skyguard)

View file

@ -1,7 +1,7 @@
// Copyright (c) 2023 PSForever // Copyright (c) 2023 PSForever
package net.psforever.objects.serverobject.turret package net.psforever.objects.serverobject.turret
import akka.actor.{Actor, Cancellable} import akka.actor.{Actor, ActorRef, Cancellable}
import net.psforever.objects.definition.ObjectDefinition import net.psforever.objects.definition.ObjectDefinition
import net.psforever.objects.{Default, Player, Vehicle} import net.psforever.objects.{Default, Player, Vehicle}
import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.PlanetSideServerObject
@ -10,8 +10,11 @@ import net.psforever.objects.sourcing.{SourceEntry, SourceUniqueness}
import net.psforever.objects.vital.Vitality import net.psforever.objects.vital.Vitality
import net.psforever.objects.vital.interaction.DamageResult import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.zones.{InteractsWithZone, Zone} import net.psforever.objects.zones.{InteractsWithZone, Zone}
import net.psforever.packet.PlanetSideGamePacket
import net.psforever.packet.game.{ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ObjectDetectedMessage} import net.psforever.packet.game.{ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ObjectDetectedMessage}
import net.psforever.services.Service
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.local.{LocalAction, LocalServiceMessage}
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import net.psforever.types.{PlanetSideGUID, Vector3} import net.psforever.types.{PlanetSideGUID, Vector3}
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
@ -85,6 +88,8 @@ trait AutomatedTurretBehavior {
private lazy val autoStats: Option[Automation] = AutomatedTurretObject.Definition.AutoFire private lazy val autoStats: Option[Automation] = AutomatedTurretObject.Definition.AutoFire
private var previousTestedTargets: Set[Target] = Set()
def AutomatedTurretObject: AutomatedTurret def AutomatedTurretObject: AutomatedTurret
val automatedTurretBehavior: Actor.Receive = if (autoStats.isDefined) { val automatedTurretBehavior: Actor.Receive = if (autoStats.isDefined) {
@ -127,6 +132,13 @@ trait AutomatedTurretBehavior {
protected def AutomaticOperationFunctionalityChecks: Boolean protected def AutomaticOperationFunctionalityChecks: Boolean
protected def CurrentTargetLastShotReported: Long = currentTargetLastShotReported
protected def CurrentTargetLastShotReported_=(value: Long): Long = {
currentTargetLastShotReported = value
CurrentTargetLastShotReported
}
private def bringAttentionToTarget(target: Target): Unit = { private def bringAttentionToTarget(target: Target): Unit = {
val targets = AutomatedTurretObject.Targets val targets = AutomatedTurretObject.Targets
val size = targets.size val size = targets.size
@ -140,12 +152,12 @@ trait AutomatedTurretBehavior {
private def confirmShot(target: Target): Unit = { private def confirmShot(target: Target): Unit = {
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
if (currentTargetToken.isEmpty || now - currentTargetLastShotReported > autoStats.map { _.targetSelectCooldown }.get) { if (currentTargetToken.isEmpty) {
currentTargetLastShotReported = now currentTargetLastShotReported = now
engageNewDetectedTarget(target) engageNewDetectedTarget(target)
} else if ( } else if (
currentTargetToken.contains(SourceEntry(target).unique) && currentTargetToken.contains(SourceEntry(target).unique) &&
now - currentTargetLastShotReported < autoStats.map { _.missedShotCooldown }.get) { now - currentTargetLastShotReported < autoStats.map(_.missedShotCooldown).getOrElse(0L)) {
currentTargetLastShotReported = now currentTargetLastShotReported = now
} }
} }
@ -165,27 +177,24 @@ trait AutomatedTurretBehavior {
} }
private def resetAlerts(): Unit = { private def resetAlerts(): Unit = {
AutomatedTurretObject.Target.foreach { noLongerEngageDetectedTarget } AutomatedTurretObject.Target.foreach(noLongerEngageDetectedTarget)
AutomatedTurretObject.Target = None
AutomatedTurretObject.Clear() AutomatedTurretObject.Clear()
testTargetListQualifications(beforeSize = 1) testTargetListQualifications(beforeSize = 1)
} previousTestedTargets.foreach(noLongerEngageTestedTarget)
previousTestedTargets = Set()
private def testNewDetectedTarget(target: Target, channel: String): Unit = { currentTargetToken = None
val zone = target.Zone
AutomatedTurretBehavior.startTrackingTargets(zone, channel, AutomatedTurretObject.GUID, List(target.GUID))
AutomatedTurretBehavior.startShooting(zone, channel, AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID)
context.system.scheduler.scheduleOnce(100.milliseconds, (() => {
AutomatedTurretBehavior.stopShooting(zone, channel, AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID)
}).asInstanceOf[Runnable])
} }
protected def engageNewDetectedTarget(target: Target): Unit = { protected def engageNewDetectedTarget(target: Target): Unit = {
val zone = target.Zone val zone = target.Zone
val zoneid = zone.id val zoneid = zone.id
AutomatedTurretObject.Target = target previousTestedTargets.filterNot(_ == target).foreach(noLongerEngageTestedTarget)
previousTestedTargets = Set(target)
currentTargetToken = Some(SourceEntry(target).unique) currentTargetToken = Some(SourceEntry(target).unique)
AutomatedTurretBehavior.startTrackingTargets(zone, zoneid, AutomatedTurretObject.GUID, List(target.GUID)) AutomatedTurretObject.Target = target
AutomatedTurretBehavior.startShooting(zone, zoneid, AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID) AutomatedTurretBehavior.startTracking(target, zoneid, AutomatedTurretObject.GUID, List(target.GUID))
AutomatedTurretBehavior.startShooting(target, zoneid, AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID)
} }
protected def noLongerDetectTargetIfCurrent(target: Target): Option[Target] = { protected def noLongerDetectTargetIfCurrent(target: Target): Option[Target] = {
@ -197,22 +206,30 @@ trait AutomatedTurretBehavior {
} }
protected def noLongerEngageDetectedTarget(target: Target): Option[Target] = { protected def noLongerEngageDetectedTarget(target: Target): Option[Target] = {
val zone = target.Zone
val zoneid = zone.id
AutomatedTurretObject.Target = None AutomatedTurretObject.Target = None
currentTargetToken = None currentTargetToken = None
AutomatedTurretBehavior.stopTrackingTargets(zone, zoneid, AutomatedTurretObject.GUID) noLongerEngageTestedTarget(target)
AutomatedTurretBehavior.stopShooting(zone, zoneid, AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID) None
}
private def noLongerEngageTestedTarget(target: Target): Option[Target] = {
val zone = target.Zone
val zoneid = zone.id
AutomatedTurretBehavior.stopTracking(target, zoneid, AutomatedTurretObject.GUID)
AutomatedTurretBehavior.stopShooting(target, zoneid, AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID)
None None
} }
protected def trySelectNewTarget(): Option[Target] = { protected def trySelectNewTarget(): Option[Target] = {
AutomatedTurretObject.Target.orElse { AutomatedTurretObject.Target.orElse {
val turretPosition = AutomatedTurretObject.Position val turretPosition = AutomatedTurretObject.Position
val turretGuid = AutomatedTurretObject.GUID
val weaponGuid = AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID
val radius = autoStats.get.targetTriggerRange val radius = autoStats.get.targetTriggerRange
val validation = autoStats.get.targetValidation val validation = autoStats.get.targetValidation
val faction = AutomatedTurretObject.Faction val faction = AutomatedTurretObject.Faction
AutomatedTurretObject //noinspection CollectHeadOption
val (targets, forValidation) = AutomatedTurretObject
.Targets .Targets
.collect { case target .collect { case target
if /*target.Faction != faction &&*/ if /*target.Faction != faction &&*/
@ -221,18 +238,29 @@ trait AutomatedTurretBehavior {
target target
} }
.sortBy(target => Vector3.DistanceSquared(target.Position, turretPosition)) .sortBy(target => Vector3.DistanceSquared(target.Position, turretPosition))
.collectFirst { .collect {
case target: Player => case target: Player =>
testNewDetectedTarget(target, target.Name) AutomatedTurretBehavior.Generic.testNewDetected(target, target.Name, turretGuid, weaponGuid)
target Seq((target, target))
case target: Vehicle => case target: Vehicle =>
target.Seats.values target.Seats.values
.flatMap(_.occupants) .flatMap(_.occupants)
.foreach { target => .collectFirst { passenger =>
testNewDetectedTarget(target, target.Name) AutomatedTurretBehavior.Generic.testNewDetected(passenger, passenger.Name, turretGuid, weaponGuid)
(target, passenger)
} }
target
} }
.flatten
.unzip
//call an explicit stop for these targets
(for {
a <- forValidation
b <- previousTestedTargets
if SourceEntry(a).unique != SourceEntry(b).unique
} yield b)
.foreach(noLongerEngageTestedTarget)
previousTestedTargets = forValidation.toSet
targets.headOption
} }
} }
@ -274,7 +302,7 @@ trait AutomatedTurretBehavior {
} }
.orElse { .orElse {
//no target; unless we are deactivated or have any unfinished delays, search for new target //no target; unless we are deactivated or have any unfinished delays, search for new target
if (automaticOperation && now - currentTargetLastShotReported >= selectDelay) { if (automaticOperation && now - currentTargetLastShotReported >= 0) {
trySelectNewTarget() trySelectNewTarget()
} }
None None
@ -291,17 +319,17 @@ trait AutomatedTurretBehavior {
if (target.Destroyed) { if (target.Destroyed) {
//if the target died while we were shooting at it //if the target died while we were shooting at it
noLongerEngageDetectedTarget(target) noLongerEngageDetectedTarget(target)
currentTargetLastShotReported = now - eliminationDelay currentTargetLastShotReported = now + eliminationDelay
None None
} else if (AutomatedTurretBehavior.shapedDistanceCheckAgainstValue(autoStats, target.Position, AutomatedTurretObject.Position, escapeRange)) { } else if (AutomatedTurretBehavior.shapedDistanceCheckAgainstValue(autoStats, target.Position, AutomatedTurretObject.Position, escapeRange)) {
//if the target made sufficient distance from the turret //if the target made sufficient distance from the turret
noLongerEngageDetectedTarget(target) noLongerEngageDetectedTarget(target)
currentTargetLastShotReported = now - cooldownDelay currentTargetLastShotReported = now + cooldownDelay
None None
} else if (now - currentTargetLastShotReported >= cooldownDelay) { } else if (now - currentTargetLastShotReported >= cooldownDelay) {
//if the target goes mia through lack of response //if the target goes mia through lack of response
noLongerEngageDetectedTarget(target) noLongerEngageDetectedTarget(target)
currentTargetLastShotReported = now - selectDelay currentTargetLastShotReported = now + selectDelay
None None
} else { } else {
//continue shooting //continue shooting
@ -377,32 +405,105 @@ object AutomatedTurretBehavior {
private case object PeriodicCheck private case object PeriodicCheck
def startTrackingTargets(zone: Zone, channel: String, guid: PlanetSideGUID, list: List[PlanetSideGUID]): Unit = { trait AutomatedTurretDispatch {
zone.LocalEvents ! LocalServiceMessage( private val noTargets :List[PlanetSideGUID] = List(Service.defaultPlayerGUID)
channel,
LocalAction.SendResponse(ObjectDetectedMessage(guid, guid, 0, list)) def getEventBus(target: Target): ActorRef
)
def composeMessageEnvelope(channel: String, msg: PlanetSideGamePacket): Any
def startTracking(target: Target, channel: String, turretGuid: PlanetSideGUID, list: List[PlanetSideGUID]): Unit = {
getEventBus(target) ! composeMessageEnvelope(channel, startTrackingMsg(turretGuid, list))
}
def stopTracking(target: Target, channel: String, turretGuid: PlanetSideGUID): Unit = {
getEventBus(target) ! composeMessageEnvelope(channel, stopTrackingMsg(turretGuid))
}
def startShooting(target: Target, channel: String, weaponGuid: PlanetSideGUID): Unit = {
getEventBus(target) ! composeMessageEnvelope(channel, startShootingMsg(weaponGuid))
}
def stopShooting(target: Target, channel: String, weaponGuid: PlanetSideGUID): Unit = {
getEventBus(target) ! composeMessageEnvelope(channel, stopShootingMsg(weaponGuid))
}
def testNewDetected(target: Target, channel: String, turretGuid: PlanetSideGUID, weaponGuid: PlanetSideGUID): Unit = {
startTracking(target, channel, turretGuid, List(target.GUID))
startShooting(target, channel, weaponGuid)
stopShooting(target, channel, weaponGuid)
}
private def startTrackingMsg(guid: PlanetSideGUID, list: List[PlanetSideGUID]): PlanetSideGamePacket = {
ObjectDetectedMessage(guid, guid, 0, list)
}
private def stopTrackingMsg(turretGuid: PlanetSideGUID): PlanetSideGamePacket = {
ObjectDetectedMessage(turretGuid, turretGuid, 0, noTargets)
}
private def startShootingMsg(weaponGuid: PlanetSideGUID): PlanetSideGamePacket = {
ChangeFireStateMessage_Start(weaponGuid)
}
private def stopShootingMsg(weaponGuid: PlanetSideGUID): PlanetSideGamePacket = {
ChangeFireStateMessage_Stop(weaponGuid)
}
} }
def stopTrackingTargets(zone: Zone, channel: String, guid: PlanetSideGUID): Unit = { object Generic extends AutomatedTurretDispatch {
zone.LocalEvents ! LocalServiceMessage( def getEventBus(target: Target): ActorRef = {
channel, target.Zone.LocalEvents
LocalAction.SendResponse(ObjectDetectedMessage(guid, guid, 0, List(PlanetSideGUID(0)))) }
)
def composeMessageEnvelope(channel: String, msg: PlanetSideGamePacket): Any = {
LocalServiceMessage(channel, LocalAction.SendResponse(msg))
}
} }
private def startShooting(zone: Zone, channel: String, weaponGuid: PlanetSideGUID): Unit = { object Vehicle extends AutomatedTurretDispatch {
zone.LocalEvents ! LocalServiceMessage( def getEventBus(target: Target): ActorRef = {
channel, target.Zone.VehicleEvents
LocalAction.SendResponse(ChangeFireStateMessage_Start(weaponGuid)) }
)
def composeMessageEnvelope(channel: String, msg: PlanetSideGamePacket): Any = {
VehicleServiceMessage(channel, VehicleAction.SendResponse(Service.defaultPlayerGUID, msg))
}
} }
private def stopShooting(zone: Zone, channel: String, weaponGuid: PlanetSideGUID): Unit = { def startTracking(target: Target, channel: String, turretGuid: PlanetSideGUID, list: List[PlanetSideGUID]): Unit = {
zone.LocalEvents ! LocalServiceMessage( target match {
channel, case v: Vehicle => Vehicle.startTracking(v, channel, turretGuid, list)
LocalAction.SendResponse(ChangeFireStateMessage_Stop(weaponGuid)) case _ => Generic.startTracking(target, channel, turretGuid, list)
) }
}
def stopTracking(target: Target, channel: String, turretGuid: PlanetSideGUID): Unit = {
target match {
case v: Vehicle => Vehicle.stopTracking(v, channel, turretGuid)
case _ => Generic.stopTracking(target, channel, turretGuid)
}
}
def startShooting(target: Target, channel: String, weaponGuid: PlanetSideGUID): Unit = {
target match {
case v: Vehicle => Vehicle.startShooting(v, channel, weaponGuid)
case _ => Generic.startShooting(target, channel, weaponGuid)
}
}
def stopShooting(target: Target, channel: String, weaponGuid: PlanetSideGUID): Unit = {
target match {
case v: Vehicle => Vehicle.stopShooting(v, channel, weaponGuid)
case _ => Generic.stopShooting(target, channel, weaponGuid)
}
}
def testNewDetected(target: Target, channel: String, turretGuid: PlanetSideGUID, weaponGuid: PlanetSideGUID): Unit = {
target match {
case v: Vehicle => Vehicle.testNewDetected(v, channel, turretGuid, weaponGuid)
case _ => Generic.testNewDetected(target, channel, turretGuid, weaponGuid)
}
} }
def getAttackerFromCause(zone: Zone, cause: DamageResult): Option[PlanetSideServerObject with Vitality] = { def getAttackerFromCause(zone: Zone, cause: DamageResult): Option[PlanetSideServerObject with Vitality] = {
@ -445,7 +546,7 @@ object AutomatedTurretBehavior {
position: Vector3, position: Vector3,
testPosition: Vector3, testPosition: Vector3,
testRange: Float, testRange: Float,
result: Int = 1 //by default, calculation > testRange^2 result: Int = 1 //by default, calculation > input
): Boolean = { ): Boolean = {
val testRangeSq = testRange * testRange val testRangeSq = testRange * testRange
if (stats.exists(_.cylindricalCheck)) { if (stats.exists(_.cylindricalCheck)) {

View file

@ -92,19 +92,24 @@ class FacilityTurretControl(turret: FacilityTurret)
} }
override protected def tryMount(obj: PlanetSideServerObject with Mountable, seatNumber: Int, player: Player): Boolean = { override protected def tryMount(obj: PlanetSideServerObject with Mountable, seatNumber: Int, player: Player): Boolean = {
val result = super.tryMount(obj, seatNumber, player) AutomaticOperation = false //turn off
if (result) { if (!super.tryMount(obj, seatNumber, player)) {
AutomaticOperation = false AutomaticOperation = AutomaticOperationFunctionalityChecks //revert?
false
} else {
true
} }
result
} }
override protected def tryDismount(obj: Mountable, seatNumber: Int, player: Player, bailType: BailType.Value): Boolean = { override protected def tryDismount(obj: Mountable, seatNumber: Int, player: Player, bailType: BailType.Value): Boolean = {
val result = super.tryDismount(obj, seatNumber, player, bailType) AutomaticOperation = AutomaticOperationFunctionalityChecksExceptMounting //turn on, if can turn on
if (result) { if (!super.tryDismount(obj, seatNumber, player, bailType)) {
AutomaticOperation = AutomaticOperationFunctionalityChecks AutomaticOperation = false //revert
false
} else {
CurrentTargetLastShotReported = System.currentTimeMillis() + 4000L
true
} }
result
} }
override protected def DamageAwareness(target: Damageable.Target, cause: DamageResult, amount: Any) : Unit = { override protected def DamageAwareness(target: Damageable.Target, cause: DamageResult, amount: Any) : Unit = {
@ -173,10 +178,13 @@ class FacilityTurretControl(turret: FacilityTurret)
} }
protected def AutomaticOperationFunctionalityChecks: Boolean = { protected def AutomaticOperationFunctionalityChecks: Boolean = {
AutomaticOperationFunctionalityChecksExceptMounting && !TurretObject.Seats.values.exists(_.isOccupied)
}
protected def AutomaticOperationFunctionalityChecksExceptMounting: Boolean = {
isPowered && isPowered &&
!JammableObject.Jammed && !JammableObject.Jammed &&
TurretObject.Health > TurretObject.Definition.DamageDisablesAt && TurretObject.Health > TurretObject.Definition.DamageDisablesAt
!TurretObject.Seats.values.exists(_.isOccupied)
} }
private def primaryWeaponFireModeOnly(): Unit = { private def primaryWeaponFireModeOnly(): Unit = {
@ -224,8 +232,8 @@ class FacilityTurretControl(turret: FacilityTurret)
attacker => attacker =>
val channel = zone.id val channel = zone.id
val guid = AutomatedTurretObject.GUID val guid = AutomatedTurretObject.GUID
AutomatedTurretBehavior.startTrackingTargets(zone, channel, guid, List(attacker.GUID)) AutomatedTurretBehavior.startTracking(attacker, channel, guid, List(attacker.GUID))
AutomatedTurretBehavior.stopTrackingTargets(zone, channel, guid) //TODO delay by a few milliseconds? AutomatedTurretBehavior.stopTracking(attacker, channel, guid) //TODO delay by a few milliseconds?
} }
} }
} }

View file

@ -26,7 +26,7 @@ final case class Automation(
targetEliminationCooldown: Long = 0L, //ms targetEliminationCooldown: Long = 0L, //ms
revertToDefaultFireMode: Boolean = true revertToDefaultFireMode: Boolean = true
) { ) {
assert(targetDetectionRange > targetTriggerRange, "trigger range must be less or equal to detection range") assert(targetDetectionRange > targetTriggerRange, "trigger range must be less than detection range")
} }
/** /**