mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-03-17 11:20:40 +00:00
thoroughly reorganized code in behavior; added code for turret-specific interactions for deployable construction, deployable destruction, jamming, and for weaponfire retribution; killing is currently disable for testing turnaround
This commit is contained in:
parent
41462ce540
commit
2e84b33a47
5 changed files with 359 additions and 151 deletions
|
|
@ -3,7 +3,7 @@ package net.psforever.actors.session.support
|
|||
|
||||
import akka.actor.{ActorContext, typed}
|
||||
import net.psforever.objects.zones.Zoning
|
||||
import net.psforever.objects.serverobject.turret.AutomatedTurret
|
||||
import net.psforever.objects.serverobject.turret.{AutomatedTurret, AutomatedTurretBehavior}
|
||||
import net.psforever.objects.zones.exp.ToDatabase
|
||||
|
||||
import scala.collection.mutable
|
||||
|
|
@ -432,44 +432,52 @@ private[support] class WeaponAndProjectileOperations(
|
|||
}
|
||||
|
||||
def handleAIDamage(pkt: AIDamage): Unit = {
|
||||
val AIDamage(_, attackerGuid, projectileTypeId, _, _) = pkt
|
||||
sessionData.validObject(attackerGuid, decorator = "AIDamage/Entity")
|
||||
.collect {
|
||||
case turret: AutomatedTurret with OwnableByPlayer =>
|
||||
val owner = sessionData.validObject(turret.OwnerGuid, decorator = "AIDamage/Owner")
|
||||
.collect { case obj: PlanetSideGameObject with FactionAffinity => SourceEntry(obj) }
|
||||
.getOrElse { SourceEntry.None }
|
||||
turret.Weapons
|
||||
.values
|
||||
.flatMap { _.Equipment }
|
||||
.collect { case weapon: Tool => (turret, weapon, owner, weapon.Projectile) }
|
||||
.find { case (_, _, _, p) => p.ObjectId == projectileTypeId }
|
||||
val AIDamage(targetGuid, attackerGuid, projectileTypeId, _, _) = pkt
|
||||
(continent.GUID(player.VehicleSeated) match {
|
||||
case Some(tobj: PlanetSideServerObject with FactionAffinity with Vitality) if tobj.GUID == targetGuid => Some(tobj)
|
||||
case _ if player.GUID == targetGuid => Some(player)
|
||||
case _ => None
|
||||
}).foreach { target =>
|
||||
sessionData.validObject(attackerGuid, decorator = "AIDamage/Attacker")
|
||||
.collect {
|
||||
case turret: AutomatedTurret if turret.Target.isEmpty =>
|
||||
turret.Actor ! AutomatedTurretBehavior.ConfirmShot(target)
|
||||
None
|
||||
|
||||
}
|
||||
.collect {
|
||||
case Some((obj, tool, owner, projectileInfo)) =>
|
||||
val target = sessionData.validObject(player.VehicleSeated, decorator = "AIDamage/Entity") match {
|
||||
case Some(tobj: PlanetSideGameObject with FactionAffinity with Vitality) => tobj
|
||||
case _ => player
|
||||
}
|
||||
val angle = Vector3.Unit(target.Position - obj.Position)
|
||||
val proj = new Projectile(
|
||||
projectileInfo,
|
||||
tool.Definition,
|
||||
tool.FireMode,
|
||||
None,
|
||||
owner,
|
||||
obj.Definition.ObjectId,
|
||||
obj.Position + Vector3.z(value = 1f),
|
||||
angle,
|
||||
Some(angle * projectileInfo.FinalVelocity)
|
||||
)
|
||||
val hitPos = target.Position + Vector3.z(value = 1f)
|
||||
ResolveProjectileInteraction(proj, DamageResolution.Hit, target, hitPos).collect { resprojectile =>
|
||||
addShotsLanded(resprojectile.cause.attribution, shots = 1)
|
||||
sessionData.handleDealingDamage(target, resprojectile)
|
||||
}
|
||||
}
|
||||
case turret: AutomatedTurret with OwnableByPlayer =>
|
||||
turret.Actor ! AutomatedTurretBehavior.ConfirmShot(target)
|
||||
val owner = continent.GUID(turret.OwnerGuid)
|
||||
.collect { case obj: PlanetSideGameObject with FactionAffinity => SourceEntry(obj) }
|
||||
.getOrElse { SourceEntry.None }
|
||||
turret.Weapons
|
||||
.values
|
||||
.flatMap { _.Equipment }
|
||||
.collect { case weapon: Tool => (turret, weapon, owner, weapon.Projectile) }
|
||||
.find { case (_, _, _, p) => p.ObjectId == projectileTypeId }
|
||||
|
||||
}
|
||||
.collect {
|
||||
case Some((obj, tool, owner, projectileInfo)) =>
|
||||
|
||||
val angle = Vector3.Unit(target.Position - obj.Position)
|
||||
val proj = new Projectile(
|
||||
projectileInfo,
|
||||
tool.Definition,
|
||||
tool.FireMode,
|
||||
None,
|
||||
owner,
|
||||
obj.Definition.ObjectId,
|
||||
obj.Position + Vector3.z(value = 1f),
|
||||
angle,
|
||||
Some(angle * projectileInfo.FinalVelocity)
|
||||
)
|
||||
val hitPos = target.Position + Vector3.z(value = 1f)
|
||||
ResolveProjectileInteraction(proj, DamageResolution.Hit, target, hitPos).collect { resprojectile =>
|
||||
addShotsLanded(resprojectile.cause.attribution, shots = 1)
|
||||
//sessionData.handleDealingDamage(target, resprojectile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* support code */
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects
|
||||
|
||||
import akka.actor.{Actor, ActorContext, Props}
|
||||
import akka.actor.{Actor, ActorContext, ActorRef, Props}
|
||||
import net.psforever.objects.ce.{Deployable, DeployableBehavior, DeployedItem}
|
||||
import net.psforever.objects.definition.DeployableDefinition
|
||||
import net.psforever.objects.definition.converter.SmallTurretConverter
|
||||
|
|
@ -17,7 +17,8 @@ import net.psforever.objects.serverobject.repair.RepairableWeaponTurret
|
|||
import net.psforever.objects.serverobject.turret.{AutomatedTurret, AutomatedTurretBehavior, TurretDefinition, WeaponTurret}
|
||||
import net.psforever.objects.vital.damage.DamageCalculations
|
||||
import net.psforever.objects.vital.interaction.DamageResult
|
||||
import net.psforever.objects.vital.{SimpleResolutions, StandardVehicleResistance}
|
||||
import net.psforever.objects.vital.{SimpleResolutions, StandardVehicleResistance, Vitality}
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
|
@ -28,7 +29,7 @@ class TurretDeployable(tdef: TurretDeployableDefinition)
|
|||
with JammableUnit
|
||||
with Hackable
|
||||
with AutomatedTurret {
|
||||
WeaponTurret.LoadDefinition(this)
|
||||
WeaponTurret.LoadDefinition(turret = this)
|
||||
|
||||
override def Definition: TurretDeployableDefinition = tdef
|
||||
}
|
||||
|
|
@ -81,6 +82,7 @@ class TurretControl(turret: TurretDeployable)
|
|||
super.postStop()
|
||||
deployableBehaviorPostStop()
|
||||
damageableWeaponTurretPostStop()
|
||||
automaticTurretPostStop()
|
||||
}
|
||||
|
||||
def receive: Receive =
|
||||
|
|
@ -103,7 +105,42 @@ class TurretControl(turret: TurretDeployable)
|
|||
(!turret.Definition.FactionLocked || player.Faction == obj.Faction) && !obj.Destroyed
|
||||
}
|
||||
|
||||
override def TryJammerEffectActivate(target: Any, cause: DamageResult): Unit = {
|
||||
val startsUnjammed = !JammableObject.Jammed
|
||||
super.TryJammerEffectActivate(target, cause)
|
||||
if (startsUnjammed && JammableObject.Jammed) {
|
||||
AutomaticOperation = false
|
||||
//look in direction of source of jamming
|
||||
val zone = JammableObject.Zone
|
||||
TurretControl.getAttackerFromCause(zone, cause).foreach {
|
||||
attacker =>
|
||||
val channel = zone.id
|
||||
val guid = AutomatedTurretObject.GUID
|
||||
AutomatedTurretBehavior.startTrackingTargets(zone, channel, guid, List(attacker.GUID))
|
||||
AutomatedTurretBehavior.stopTrackingTargets(zone, channel, guid) //TODO delay by a few milliseconds?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def CancelJammeredStatus(target: Any): Unit = {
|
||||
val startsJammed = JammableObject.Jammed
|
||||
super.CancelJammeredStatus(target)
|
||||
startsJammed && AutomaticOperation_=(state = true)
|
||||
}
|
||||
|
||||
override protected def DamageAwareness(target: Target, cause: DamageResult, amount: Any): Unit = {
|
||||
//turret retribution
|
||||
if (AutomaticOperation) {
|
||||
TurretControl.getAttackerFromCause(target.Zone, cause).foreach {
|
||||
attacker =>
|
||||
engageNewDetectedTarget(attacker)
|
||||
}
|
||||
}
|
||||
super.DamageAwareness(target, cause, amount)
|
||||
}
|
||||
|
||||
override protected def DestructionAwareness(target: Target, cause: DamageResult): Unit = {
|
||||
AutomaticOperation = false
|
||||
super.DestructionAwareness(target, cause)
|
||||
CancelJammeredSound(target)
|
||||
CancelJammeredStatus(target)
|
||||
|
|
@ -111,6 +148,7 @@ class TurretControl(turret: TurretDeployable)
|
|||
}
|
||||
|
||||
override def deconstructDeployable(time: Option[FiniteDuration]) : Unit = {
|
||||
AutomaticOperation = false
|
||||
val zone = turret.Zone
|
||||
val seats = turret.Seats.values
|
||||
//either we have no seats or no one gets to sit
|
||||
|
|
@ -136,8 +174,50 @@ class TurretControl(turret: TurretDeployable)
|
|||
super.deconstructDeployable(retime)
|
||||
}
|
||||
|
||||
override def finalizeDeployable(callback: ActorRef): Unit = {
|
||||
super.finalizeDeployable(callback)
|
||||
AutomaticOperation = true
|
||||
}
|
||||
|
||||
override def unregisterDeployable(obj: Deployable): Unit = {
|
||||
val zone = obj.Zone
|
||||
TaskWorkflow.execute(GUIDTask.unregisterDeployableTurret(zone.GUID, turret))
|
||||
}
|
||||
}
|
||||
|
||||
object TurretControl {
|
||||
private def getAttackerFromCause(zone: Zone, cause: DamageResult): Option[PlanetSideServerObject with Vitality] = {
|
||||
import net.psforever.objects.sourcing._
|
||||
cause
|
||||
.interaction
|
||||
.adversarial
|
||||
.collect { adversarial =>
|
||||
adversarial.attacker match {
|
||||
case p: PlayerSource =>
|
||||
p.seatedIn
|
||||
.map { _._1.unique }
|
||||
.collect {
|
||||
case v: UniqueVehicle => zone.Vehicles.find(SourceEntry(_).unique == v)
|
||||
case a: UniqueAmenity => zone.GUID(a.guid)
|
||||
case d: UniqueDeployable => zone.DeployableList.find(SourceEntry(_).unique == d)
|
||||
}
|
||||
.flatten
|
||||
.orElse {
|
||||
val name = p.Name
|
||||
zone.LivePlayers.find(_.Name.equals(name))
|
||||
}
|
||||
case o =>
|
||||
o.unique match {
|
||||
case v: UniqueVehicle => zone.Vehicles.find(SourceEntry(_).unique == v)
|
||||
case a: UniqueAmenity => zone.GUID(a.guid)
|
||||
case d: UniqueDeployable => zone.DeployableList.find(SourceEntry(_).unique == d)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
.flatten
|
||||
.collect {
|
||||
case out: PlanetSideServerObject with Vitality => out
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class InteractWithTurrets(val range: Float)
|
|||
target.getInteractionSector(),
|
||||
target.Position.xy
|
||||
).foreach { turret =>
|
||||
turret.Actor ! AutomatedTurretBehavior.ResetAlerts
|
||||
turret.Actor ! AutomatedTurretBehavior.Reset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ trait JammableBehavior {
|
|||
* @param target the objects to be determined if affected by the source's jammering
|
||||
* @param cause the source of the "jammered" status
|
||||
*/
|
||||
def TryJammerEffectActivate(target: Any, cause: DamageResult): Unit =
|
||||
def TryJammerEffectActivate(target: Any, cause: DamageResult): Unit = {
|
||||
target match {
|
||||
case obj: PlanetSideServerObject =>
|
||||
val interaction = cause.interaction
|
||||
|
|
@ -157,8 +157,9 @@ trait JammableBehavior {
|
|||
}
|
||||
case None =>
|
||||
}
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate a distinctive buzzing sound effect.
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ import akka.actor.{Actor, Cancellable}
|
|||
import net.psforever.objects.definition.ObjectDefinition
|
||||
import net.psforever.objects.{Default, Player}
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.serverobject.damage.DamageableEntity
|
||||
import net.psforever.objects.sourcing.{SourceEntry, SourceUniqueness}
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.{ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ObjectDetectedMessage}
|
||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||
import net.psforever.types.{PlanetSideGUID, Vector3}
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
||||
|
|
@ -20,8 +20,23 @@ trait AutomatedTurret
|
|||
extends PlanetSideServerObject
|
||||
with WeaponTurret {
|
||||
import AutomatedTurret.Target
|
||||
private var currentTarget: Option[Target] = None
|
||||
|
||||
private var targets: List[Target] = List[Target]()
|
||||
|
||||
def Target: Option[Target] = currentTarget
|
||||
|
||||
def Target_=(newTarget: Target): Option[Target] = {
|
||||
Target_=(Some(newTarget))
|
||||
}
|
||||
|
||||
def Target_=(newTarget: Option[Target]): Option[Target] = {
|
||||
if (newTarget.isDefined != currentTarget.isDefined) {
|
||||
currentTarget = newTarget
|
||||
}
|
||||
currentTarget
|
||||
}
|
||||
|
||||
def Targets: List[Target] = targets
|
||||
|
||||
def Detected(target: Target): Option[Target] = {
|
||||
|
|
@ -56,125 +71,212 @@ object AutomatedTurret {
|
|||
}
|
||||
|
||||
trait AutomatedTurretBehavior {
|
||||
_: Actor =>
|
||||
_: Actor with DamageableEntity =>
|
||||
import AutomatedTurret.Target
|
||||
import AutomatedTurretBehavior.TurretTargetEntry
|
||||
|
||||
private val targets: mutable.HashMap[SourceUniqueness, TurretTargetEntry] =
|
||||
mutable.HashMap[SourceUniqueness, TurretTargetEntry]()
|
||||
private var automaticOperation: Boolean = false
|
||||
|
||||
private var targetDistanceCheck: Cancellable = Default.Cancellable
|
||||
private var currentTargetToken: Option[SourceUniqueness] = None
|
||||
|
||||
private var currentTarget: Option[Target] = None
|
||||
|
||||
private var currentTargetLastShotReported: Long = 0L
|
||||
|
||||
private var periodicValidationTest: Cancellable = Default.Cancellable
|
||||
|
||||
def AutomatedTurretObject: AutomatedTurret
|
||||
|
||||
val automatedTurretBehavior: Actor.Receive = {
|
||||
case AutomatedTurretBehavior.Alert(target) =>
|
||||
val targets = AutomatedTurretObject.Targets
|
||||
val size = targets.size
|
||||
AutomatedTurretObject.Detected(target)
|
||||
.orElse {
|
||||
AutomatedTurretObject.AddTarget(target)
|
||||
retimeDistanceCheck(size)
|
||||
Some(target)
|
||||
}
|
||||
.foreach { newDetectedTarget }
|
||||
bringAttentionToTarget(target)
|
||||
|
||||
case AutomatedTurretBehavior.ConfirmShot(target) =>
|
||||
confirmShot(target)
|
||||
|
||||
case AutomatedTurretBehavior.Unalert(target) =>
|
||||
val targets = AutomatedTurretObject.Targets
|
||||
val size = targets.size
|
||||
AutomatedTurretObject.Detected(target)
|
||||
.collect { out =>
|
||||
AutomatedTurretObject.RemoveTarget(target)
|
||||
testDistanceCheckQualifications(size)
|
||||
out
|
||||
disregardTarget(target)
|
||||
|
||||
case AutomatedTurretBehavior.Reset =>
|
||||
resetAlerts()
|
||||
|
||||
case AutomatedTurretBehavior.PeriodicCheck =>
|
||||
performPeriodicTargetValidation()
|
||||
}
|
||||
|
||||
def AutomaticOperation: Boolean = automaticOperation
|
||||
|
||||
def AutomaticOperation_=(state: Boolean): Boolean = {
|
||||
val previousState = automaticOperation
|
||||
automaticOperation = state
|
||||
if (!previousState && state) {
|
||||
trySelectNewTarget()
|
||||
} else if (previousState && !state) {
|
||||
currentTarget.foreach { noLongerEngageDetectedTarget }
|
||||
}
|
||||
state
|
||||
}
|
||||
|
||||
private def bringAttentionToTarget(target: Target): Unit = {
|
||||
val targets = AutomatedTurretObject.Targets
|
||||
val size = targets.size
|
||||
AutomatedTurretObject.Detected(target)
|
||||
.orElse {
|
||||
AutomatedTurretObject.AddTarget(target)
|
||||
retimePeriodicTargetChecks(size)
|
||||
Some(target)
|
||||
}
|
||||
}
|
||||
|
||||
private def confirmShot(target: Target): Unit = {
|
||||
val now = System.currentTimeMillis()
|
||||
if (currentTargetToken.isEmpty || now - currentTargetLastShotReported > 1500L) {
|
||||
currentTargetLastShotReported = now
|
||||
engageNewDetectedTarget(target)
|
||||
} else if (currentTargetToken.contains(SourceEntry(target).unique) && now - currentTargetLastShotReported < 3000L) {
|
||||
currentTargetLastShotReported = now
|
||||
}
|
||||
}
|
||||
|
||||
private def disregardTarget(target: Target): Unit = {
|
||||
val targets = AutomatedTurretObject.Targets
|
||||
val size = targets.size
|
||||
AutomatedTurretObject.Detected(target)
|
||||
.collect { out =>
|
||||
AutomatedTurretObject.RemoveTarget(target)
|
||||
testTargetListQualifications(size)
|
||||
out
|
||||
}
|
||||
.flatMap {
|
||||
noLongerDetectTargetIfCurrent
|
||||
}
|
||||
}
|
||||
|
||||
private def resetAlerts(): Unit = {
|
||||
currentTarget.foreach { noLongerEngageDetectedTarget }
|
||||
AutomatedTurretObject.Clear()
|
||||
testTargetListQualifications(beforeSize = 1)
|
||||
}
|
||||
|
||||
private def testNewDetectedTarget(target: Target, channel: String): Unit = {
|
||||
val zone = target.Zone
|
||||
AutomatedTurretBehavior.startTrackingTargets(zone, channel, AutomatedTurretObject.GUID, List(target.GUID))
|
||||
AutomatedTurretBehavior.startShooting(zone, channel, AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID)
|
||||
AutomatedTurretBehavior.stopShooting(zone, channel, AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID)
|
||||
}
|
||||
|
||||
protected def engageNewDetectedTarget(target: Target): Unit = {
|
||||
val zone = target.Zone
|
||||
val zoneid = zone.id
|
||||
AutomatedTurretObject.Target = target
|
||||
currentTarget = Some(target)
|
||||
currentTargetToken = Some(SourceEntry(target).unique)
|
||||
AutomatedTurretBehavior.startTrackingTargets(zone, zoneid, AutomatedTurretObject.GUID, List(target.GUID))
|
||||
AutomatedTurretBehavior.startShooting(zone, zoneid, AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID)
|
||||
}
|
||||
|
||||
protected def noLongerDetectTargetIfCurrent(target: Target): Option[Target] = {
|
||||
if (currentTargetToken.contains(SourceEntry(target).unique)) {
|
||||
noLongerEngageDetectedTarget(target)
|
||||
} else {
|
||||
currentTarget
|
||||
}
|
||||
}
|
||||
|
||||
protected def noLongerEngageDetectedTarget(target: Target): Option[Target] = {
|
||||
val zone = target.Zone
|
||||
val zoneid = zone.id
|
||||
AutomatedTurretObject.Target = None
|
||||
currentTarget = None
|
||||
currentTargetToken = None
|
||||
AutomatedTurretBehavior.stopTrackingTargets(zone, zoneid, AutomatedTurretObject.GUID)
|
||||
AutomatedTurretBehavior.stopShooting(zone, zoneid, AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID)
|
||||
None
|
||||
}
|
||||
|
||||
private def trySelectNewTarget(): Option[Target] = {
|
||||
currentTarget.orElse {
|
||||
val turretPosition = AutomatedTurretObject.Position
|
||||
AutomatedTurretObject.Targets
|
||||
.filter { target =>
|
||||
!target.Destroyed && (target match {
|
||||
case p: Player => validTargetCheck(p)
|
||||
case _ => false
|
||||
})
|
||||
}
|
||||
.foreach { noLongerDetectedTarget }
|
||||
|
||||
case AutomatedTurretBehavior.ResetAlerts =>
|
||||
AutomatedTurretObject.Clear().foreach { noLongerDetectedTarget }
|
||||
testDistanceCheckQualifications(beforeSize = 1)
|
||||
|
||||
case AutomatedTurretBehavior.PeriodicDistanceCheck =>
|
||||
performPeriodicDistanceCheck()
|
||||
}
|
||||
|
||||
private def newDetectedTarget(target: Target): Unit = {
|
||||
target match {
|
||||
case target: Player =>
|
||||
startTrackingTargets(target.Zone, target.Name, List(target.GUID))
|
||||
startShooting(target.Zone, target.Name, AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID)
|
||||
case _ => ()
|
||||
.sortBy {
|
||||
target => Vector3.DistanceSquared(target.Position, turretPosition)
|
||||
}
|
||||
.flatMap { case target: Player =>
|
||||
testNewDetectedTarget(target, target.Name)
|
||||
Some(target)
|
||||
}
|
||||
.headOption
|
||||
}
|
||||
}
|
||||
|
||||
private def noLongerDetectedTarget(target: Target): Unit = {
|
||||
target match {
|
||||
case target: Player =>
|
||||
stopTrackingTargets(target.Zone, target.Name)
|
||||
stopShooting(target.Zone, target.Name, AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID)
|
||||
case _ => ()
|
||||
}
|
||||
private def validTargetCheck(target: Target): Boolean = {
|
||||
!target.Destroyed && (target match {
|
||||
case p: Player =>
|
||||
if (p.Cloaked) false
|
||||
else if (p.Crouching) false
|
||||
else p.isMoving(test = 3f)
|
||||
case _ => false
|
||||
})
|
||||
}
|
||||
|
||||
def startTrackingTargets(zone: Zone, channel: String, list: List[PlanetSideGUID]): Unit = {
|
||||
zone.AvatarEvents ! AvatarServiceMessage(
|
||||
channel,
|
||||
AvatarAction.SendResponse(PlanetSideGUID(0), ObjectDetectedMessage(AutomatedTurretObject.GUID, AutomatedTurretObject.GUID, 0, list))
|
||||
)
|
||||
private def performPeriodicTargetValidation(): List[Target] = {
|
||||
val size = AutomatedTurretObject.Targets.size
|
||||
val list = performDistanceCheck()
|
||||
performCurrentTargetDecayCheck()
|
||||
testTargetListQualifications(size)
|
||||
list
|
||||
}
|
||||
|
||||
def stopTrackingTargets(zone: Zone, channel: String): Unit = {
|
||||
zone.AvatarEvents ! AvatarServiceMessage(
|
||||
channel,
|
||||
AvatarAction.SendResponse(PlanetSideGUID(0), ObjectDetectedMessage(AutomatedTurretObject.GUID, AutomatedTurretObject.GUID, 0, List(PlanetSideGUID(0))))
|
||||
)
|
||||
}
|
||||
|
||||
def startShooting(zone: Zone, channel: String, weaponGuid: PlanetSideGUID): Unit = {
|
||||
zone.AvatarEvents ! AvatarServiceMessage(
|
||||
channel,
|
||||
AvatarAction.SendResponse(PlanetSideGUID(0), ChangeFireStateMessage_Start(weaponGuid))
|
||||
)
|
||||
}
|
||||
|
||||
def stopShooting(zone: Zone, channel: String, weaponGuid: PlanetSideGUID): Unit = {
|
||||
zone.AvatarEvents ! AvatarServiceMessage(
|
||||
channel,
|
||||
AvatarAction.SendResponse(PlanetSideGUID(0), ChangeFireStateMessage_Stop(weaponGuid))
|
||||
)
|
||||
}
|
||||
|
||||
private def testDistanceCheckQualifications(beforeSize: Int): Unit = {
|
||||
if (beforeSize > 0 && AutomatedTurretObject.Targets.isEmpty) {
|
||||
targetDistanceCheck.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
private def retimeDistanceCheck(beforeSize: Int): Unit = {
|
||||
if (beforeSize == 0 && AutomatedTurretObject.Targets.nonEmpty) {
|
||||
targetDistanceCheck = context.system.scheduler.scheduleAtFixedRate(
|
||||
1.second,
|
||||
1.second,
|
||||
self,
|
||||
AutomatedTurretBehavior.PeriodicDistanceCheck
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private def performPeriodicDistanceCheck(): List[Target] = {
|
||||
private def performDistanceCheck(): List[Target] = {
|
||||
//cull targets
|
||||
val pos = AutomatedTurretObject.Position
|
||||
val earlyTargets = AutomatedTurretObject.Targets
|
||||
val earlySize = earlyTargets.size
|
||||
val removedTargets = earlyTargets
|
||||
val removedTargets = AutomatedTurretObject.Targets
|
||||
.collect {
|
||||
case t if Vector3.DistanceSquared(t.Position, pos) > 625 =>
|
||||
case t if t.Destroyed || Vector3.DistanceSquared(t.Position, pos) > 625 =>
|
||||
AutomatedTurretObject.RemoveTarget(t)
|
||||
t
|
||||
}
|
||||
removedTargets.foreach { noLongerDetectedTarget }
|
||||
testDistanceCheckQualifications(earlySize)
|
||||
removedTargets
|
||||
}
|
||||
|
||||
private def testTargetListQualifications(beforeSize: Int): Boolean = {
|
||||
beforeSize > 0 && AutomatedTurretObject.Targets.isEmpty && periodicValidationTest.cancel()
|
||||
}
|
||||
|
||||
private def retimePeriodicTargetChecks(beforeSize: Int): Boolean = {
|
||||
if (beforeSize == 0 && AutomatedTurretObject.Targets.nonEmpty) {
|
||||
periodicValidationTest = context.system.scheduler.scheduleWithFixedDelay(
|
||||
Duration.Zero,
|
||||
1.second,
|
||||
self,
|
||||
AutomatedTurretBehavior.PeriodicCheck
|
||||
)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private def performCurrentTargetDecayCheck(): Unit = {
|
||||
//complete culling and/or check the current selected target
|
||||
if (System.currentTimeMillis() - currentTargetLastShotReported > 3000L) {
|
||||
currentTarget.foreach { noLongerEngageDetectedTarget }
|
||||
if (automaticOperation) {
|
||||
//trySelectNewTarget()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def automaticTurretPostStop(): Unit = {
|
||||
periodicValidationTest.cancel()
|
||||
currentTarget.foreach { noLongerEngageDetectedTarget }
|
||||
AutomatedTurretObject.Targets.foreach { AutomatedTurretObject.RemoveTarget }
|
||||
}
|
||||
}
|
||||
|
||||
object AutomatedTurretBehavior {
|
||||
|
|
@ -183,20 +285,37 @@ object AutomatedTurretBehavior {
|
|||
|
||||
final case class Unalert(target: Target)
|
||||
|
||||
final case object ResetAlerts
|
||||
final case class ConfirmShot(target: Target)
|
||||
|
||||
private case object PeriodicDistanceCheck
|
||||
final case object Reset
|
||||
|
||||
final case class TurretTargetEntry(target: Target, regard: RegardTargetAs.TurretOpinion)
|
||||
private case object PeriodicCheck
|
||||
|
||||
object RegardTargetAs {
|
||||
trait TurretOpinion
|
||||
def startTrackingTargets(zone: Zone, channel: String, guid: PlanetSideGUID, list: List[PlanetSideGUID]): Unit = {
|
||||
zone.LocalEvents ! LocalServiceMessage(
|
||||
channel,
|
||||
LocalAction.SendResponse(ObjectDetectedMessage(guid, guid, 0, list))
|
||||
)
|
||||
}
|
||||
|
||||
final case object Friendly extends TurretOpinion
|
||||
final case object Testing extends TurretOpinion
|
||||
final case object Unreachable extends TurretOpinion
|
||||
final case object Blocked extends TurretOpinion
|
||||
final case object Invalid extends TurretOpinion
|
||||
final case object Attack extends TurretOpinion
|
||||
def stopTrackingTargets(zone: Zone, channel: String, guid: PlanetSideGUID): Unit = {
|
||||
zone.LocalEvents ! LocalServiceMessage(
|
||||
channel,
|
||||
LocalAction.SendResponse(ObjectDetectedMessage(guid, guid, 0, List(PlanetSideGUID(0))))
|
||||
)
|
||||
}
|
||||
|
||||
private def startShooting(zone: Zone, channel: String, weaponGuid: PlanetSideGUID): Unit = {
|
||||
zone.LocalEvents ! LocalServiceMessage(
|
||||
channel,
|
||||
LocalAction.SendResponse(ChangeFireStateMessage_Start(weaponGuid))
|
||||
)
|
||||
}
|
||||
|
||||
private def stopShooting(zone: Zone, channel: String, weaponGuid: PlanetSideGUID): Unit = {
|
||||
zone.LocalEvents ! LocalServiceMessage(
|
||||
channel,
|
||||
LocalAction.SendResponse(ChangeFireStateMessage_Stop(weaponGuid))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue