mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-07-16 08:55:18 +00:00
separated overworld facility turrets from cavern facility turrets, called vanu sentry turrets; tightened functionality inheritance between turret deployables and facility turrets; corrected issue where recharging vehicle weapons didn't work
This commit is contained in:
parent
18c3162dfe
commit
fc2ce70aae
10 changed files with 389 additions and 180 deletions
|
|
@ -208,6 +208,7 @@ class SessionLocalHandlers(
|
||||||
continent.GUID(vehicleGuid)
|
continent.GUID(vehicleGuid)
|
||||||
.collect { case vehicle: MountableWeapons => (vehicle, vehicle.PassengerInSeat(player)) }
|
.collect { case vehicle: MountableWeapons => (vehicle, vehicle.PassengerInSeat(player)) }
|
||||||
.collect { case (vehicle, Some(seat_num)) => vehicle.WeaponControlledFromSeat(seat_num) }
|
.collect { case (vehicle, Some(seat_num)) => vehicle.WeaponControlledFromSeat(seat_num) }
|
||||||
|
.getOrElse(Set.empty)
|
||||||
.collect { case weapon: Tool if weapon.GUID == weaponGuid =>
|
.collect { case weapon: Tool if weapon.GUID == weaponGuid =>
|
||||||
sendResponse(InventoryStateMessage(weapon.AmmoSlot.Box.GUID, weapon.GUID, weapon.Magazine))
|
sendResponse(InventoryStateMessage(weapon.AmmoSlot.Box.GUID, weapon.GUID, weapon.Magazine))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.actors.session.support
|
||||||
|
|
||||||
import akka.actor.{ActorContext, typed}
|
import akka.actor.{ActorContext, typed}
|
||||||
import net.psforever.objects.zones.Zoning
|
import net.psforever.objects.zones.Zoning
|
||||||
import net.psforever.objects.serverobject.turret.{AutomatedTurret, AutomatedTurretBehavior}
|
import net.psforever.objects.serverobject.turret.{AutomatedTurret, AutomatedTurretBehavior, VanuSentry}
|
||||||
import net.psforever.objects.zones.exp.ToDatabase
|
import net.psforever.objects.zones.exp.ToDatabase
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
@ -52,8 +52,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
private[support] var shotsWhileDead: Int = 0
|
private[support] var shotsWhileDead: Int = 0
|
||||||
private val projectiles: Array[Option[Projectile]] =
|
private val projectiles: Array[Option[Projectile]] =
|
||||||
Array.fill[Option[Projectile]](Projectile.rangeUID - Projectile.baseUID)(None)
|
Array.fill[Option[Projectile]](Projectile.rangeUID - Projectile.baseUID)(None)
|
||||||
private var zoningOpt: Option[ZoningOperations] = None
|
|
||||||
def zoning: ZoningOperations = zoningOpt.orNull
|
|
||||||
/* packets */
|
/* packets */
|
||||||
|
|
||||||
def handleWeaponFire(pkt: WeaponFireMessage): Unit = {
|
def handleWeaponFire(pkt: WeaponFireMessage): Unit = {
|
||||||
|
|
@ -569,11 +568,6 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
)
|
)
|
||||||
continent.Projectile ! ZoneProjectile.Add(player.GUID, qualityprojectile)
|
continent.Projectile ! ZoneProjectile.Add(player.GUID, qualityprojectile)
|
||||||
}
|
}
|
||||||
obj match {
|
|
||||||
case turret: FacilityTurret if turret.Definition == GlobalDefinitions.vanu_sentry_turret =>
|
|
||||||
turret.Actor ! FacilityTurret.WeaponDischarged()
|
|
||||||
case _ => ()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
log.warn(
|
log.warn(
|
||||||
s"WeaponFireMessage: ${player.Name}'s ${tool.Definition.Name} projectile is too far from owner position at time of discharge ($distanceToOwner > $acceptableDistanceToOwner); suspect"
|
s"WeaponFireMessage: ${player.Name}'s ${tool.Definition.Name} projectile is too far from owner position at time of discharge ($distanceToOwner > $acceptableDistanceToOwner); suspect"
|
||||||
|
|
@ -1224,6 +1218,10 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
}
|
}
|
||||||
|
|
||||||
private def fireStateStartMountedMessages(itemGuid: PlanetSideGUID): Unit = {
|
private def fireStateStartMountedMessages(itemGuid: PlanetSideGUID): Unit = {
|
||||||
|
sessionData.findContainedEquipment()._1.collect {
|
||||||
|
case turret: FacilityTurret if continent.map.cavern =>
|
||||||
|
turret.Actor ! VanuSentry.ChangeFireStart
|
||||||
|
}
|
||||||
continent.VehicleEvents ! VehicleServiceMessage(
|
continent.VehicleEvents ! VehicleServiceMessage(
|
||||||
continent.id,
|
continent.id,
|
||||||
VehicleAction.ChangeFireState_Start(player.GUID, itemGuid)
|
VehicleAction.ChangeFireState_Start(player.GUID, itemGuid)
|
||||||
|
|
@ -1286,6 +1284,10 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
}
|
}
|
||||||
|
|
||||||
private def fireStateStopMountedMessages(itemGuid: PlanetSideGUID): Unit = {
|
private def fireStateStopMountedMessages(itemGuid: PlanetSideGUID): Unit = {
|
||||||
|
sessionData.findContainedEquipment()._1.collect {
|
||||||
|
case turret: FacilityTurret if continent.map.cavern =>
|
||||||
|
turret.Actor ! VanuSentry.ChangeFireStop
|
||||||
|
}
|
||||||
continent.VehicleEvents ! VehicleServiceMessage(
|
continent.VehicleEvents ! VehicleServiceMessage(
|
||||||
continent.id,
|
continent.id,
|
||||||
VehicleAction.ChangeFireState_Stop(player.GUID, itemGuid)
|
VehicleAction.ChangeFireState_Stop(player.GUID, itemGuid)
|
||||||
|
|
@ -1416,6 +1418,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
addShotsToMap(shotsFired, weaponId, shots)
|
addShotsToMap(shotsFired, weaponId, shots)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection SameParameterValue
|
||||||
private def addShotsLanded(weaponId: Int, shots: Int): Unit = {
|
private def addShotsLanded(weaponId: Int, shots: Int): Unit = {
|
||||||
addShotsToMap(shotsLanded, weaponId, shots)
|
addShotsToMap(shotsLanded, weaponId, shots)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,17 @@ import akka.actor.{Actor, ActorContext, ActorRef, Props}
|
||||||
import net.psforever.objects.ce.{Deployable, DeployableBehavior, DeployedItem}
|
import net.psforever.objects.ce.{Deployable, DeployableBehavior, DeployedItem}
|
||||||
import net.psforever.objects.definition.DeployableDefinition
|
import net.psforever.objects.definition.DeployableDefinition
|
||||||
import net.psforever.objects.definition.converter.SmallTurretConverter
|
import net.psforever.objects.definition.converter.SmallTurretConverter
|
||||||
import net.psforever.objects.equipment.{JammableMountedWeapons, JammableUnit}
|
import net.psforever.objects.equipment.JammableUnit
|
||||||
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
||||||
import net.psforever.objects.serverobject.damage.Damageable.Target
|
import net.psforever.objects.serverobject.damage.Damageable.Target
|
||||||
import net.psforever.objects.serverobject.damage.DamageableWeaponTurret
|
|
||||||
import net.psforever.objects.serverobject.hackable.Hackable
|
import net.psforever.objects.serverobject.hackable.Hackable
|
||||||
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
import net.psforever.objects.serverobject.repair.RepairableWeaponTurret
|
import net.psforever.objects.serverobject.turret.{AutomatedTurret, AutomatedTurretBehavior, MountableTurretControl, TurretDefinition, WeaponTurret}
|
||||||
import net.psforever.objects.serverobject.turret.{AutomatedTurret, AutomatedTurretBehavior, TurretDefinition, WeaponTurret}
|
|
||||||
import net.psforever.objects.vital.damage.DamageCalculations
|
import net.psforever.objects.vital.damage.DamageCalculations
|
||||||
import net.psforever.objects.vital.interaction.DamageResult
|
import net.psforever.objects.vital.interaction.DamageResult
|
||||||
import net.psforever.objects.vital.{SimpleResolutions, StandardVehicleResistance, Vitality}
|
import net.psforever.objects.vital.{SimpleResolutions, StandardVehicleResistance}
|
||||||
import net.psforever.objects.zones.Zone
|
|
||||||
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
|
||||||
import scala.concurrent.duration.FiniteDuration
|
import scala.concurrent.duration.FiniteDuration
|
||||||
|
|
@ -65,11 +62,9 @@ class TurretControl(turret: TurretDeployable)
|
||||||
extends Actor
|
extends Actor
|
||||||
with DeployableBehavior
|
with DeployableBehavior
|
||||||
with FactionAffinityBehavior.Check
|
with FactionAffinityBehavior.Check
|
||||||
with JammableMountedWeapons //note: jammable status is reported as vehicle events, not local events
|
with MountableTurretControl
|
||||||
with MountableBehavior
|
|
||||||
with DamageableWeaponTurret
|
|
||||||
with RepairableWeaponTurret
|
|
||||||
with AutomatedTurretBehavior {
|
with AutomatedTurretBehavior {
|
||||||
|
def TurretObject: TurretDeployable = turret
|
||||||
def DeployableObject: TurretDeployable = turret
|
def DeployableObject: TurretDeployable = turret
|
||||||
def MountableObject: TurretDeployable = turret
|
def MountableObject: TurretDeployable = turret
|
||||||
def JammableObject: TurretDeployable = turret
|
def JammableObject: TurretDeployable = turret
|
||||||
|
|
@ -81,18 +76,14 @@ class TurretControl(turret: TurretDeployable)
|
||||||
override def postStop(): Unit = {
|
override def postStop(): Unit = {
|
||||||
super.postStop()
|
super.postStop()
|
||||||
deployableBehaviorPostStop()
|
deployableBehaviorPostStop()
|
||||||
damageableWeaponTurretPostStop()
|
|
||||||
automaticTurretPostStop()
|
automaticTurretPostStop()
|
||||||
}
|
}
|
||||||
|
|
||||||
def receive: Receive =
|
def receive: Receive =
|
||||||
deployableBehavior
|
commonBehavior
|
||||||
|
.orElse(deployableBehavior)
|
||||||
.orElse(checkBehavior)
|
.orElse(checkBehavior)
|
||||||
.orElse(jammableBehavior)
|
|
||||||
.orElse(mountBehavior)
|
.orElse(mountBehavior)
|
||||||
.orElse(dismountBehavior)
|
|
||||||
.orElse(takesDamage)
|
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
|
||||||
.orElse(automatedTurretBehavior)
|
.orElse(automatedTurretBehavior)
|
||||||
.orElse {
|
.orElse {
|
||||||
case _ => ()
|
case _ => ()
|
||||||
|
|
@ -112,7 +103,7 @@ class TurretControl(turret: TurretDeployable)
|
||||||
AutomaticOperation = false
|
AutomaticOperation = false
|
||||||
//look in direction of cause of jamming
|
//look in direction of cause of jamming
|
||||||
val zone = JammableObject.Zone
|
val zone = JammableObject.Zone
|
||||||
TurretControl.getAttackerFromCause(zone, cause).foreach {
|
AutomatedTurretBehavior.getAttackerFromCause(zone, cause).foreach {
|
||||||
attacker =>
|
attacker =>
|
||||||
val channel = zone.id
|
val channel = zone.id
|
||||||
val guid = AutomatedTurretObject.GUID
|
val guid = AutomatedTurretObject.GUID
|
||||||
|
|
@ -131,7 +122,7 @@ class TurretControl(turret: TurretDeployable)
|
||||||
override protected def DamageAwareness(target: Target, cause: DamageResult, amount: Any): Unit = {
|
override protected def DamageAwareness(target: Target, cause: DamageResult, amount: Any): Unit = {
|
||||||
if (AutomaticOperation && AutomatedTurretObject.Definition.AutoFire.exists(_.retaliatoryDuration > 0)) {
|
if (AutomaticOperation && AutomatedTurretObject.Definition.AutoFire.exists(_.retaliatoryDuration > 0)) {
|
||||||
//turret retribution
|
//turret retribution
|
||||||
TurretControl.getAttackerFromCause(target.Zone, cause).collect {
|
AutomatedTurretBehavior.getAttackerFromCause(target.Zone, cause).collect {
|
||||||
case attacker if attacker.Faction != target.Faction =>
|
case attacker if attacker.Faction != target.Faction =>
|
||||||
engageNewDetectedTarget(attacker)
|
engageNewDetectedTarget(attacker)
|
||||||
}
|
}
|
||||||
|
|
@ -141,7 +132,7 @@ class TurretControl(turret: TurretDeployable)
|
||||||
|
|
||||||
override protected def DestructionAwareness(target: Target, cause: DamageResult): Unit = {
|
override protected def DestructionAwareness(target: Target, cause: DamageResult): Unit = {
|
||||||
AutomaticOperation = false
|
AutomaticOperation = false
|
||||||
super.DestructionAwareness(target, cause)
|
//super.DestructionAwareness(target, cause)
|
||||||
CancelJammeredSound(target)
|
CancelJammeredSound(target)
|
||||||
CancelJammeredStatus(target)
|
CancelJammeredStatus(target)
|
||||||
Deployables.AnnounceDestroyDeployable(turret, None)
|
Deployables.AnnounceDestroyDeployable(turret, None)
|
||||||
|
|
@ -184,40 +175,3 @@ class TurretControl(turret: TurretDeployable)
|
||||||
TaskWorkflow.execute(GUIDTask.unregisterDeployableTurret(zone.GUID, turret))
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.damage.DamageableEntity
|
import net.psforever.objects.serverobject.damage.DamageableEntity
|
||||||
import net.psforever.objects.sourcing.{SourceEntry, SourceUniqueness}
|
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.zones.{InteractsWithZone, Zone}
|
import net.psforever.objects.zones.{InteractsWithZone, Zone}
|
||||||
import net.psforever.packet.game.{ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ObjectDetectedMessage}
|
import net.psforever.packet.game.{ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ObjectDetectedMessage}
|
||||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
|
@ -206,7 +207,7 @@ trait AutomatedTurretBehavior {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
private def trySelectNewTarget(): Option[Target] = {
|
protected def trySelectNewTarget(): Option[Target] = {
|
||||||
currentTarget.orElse {
|
currentTarget.orElse {
|
||||||
val turretPosition = AutomatedTurretObject.Position
|
val turretPosition = AutomatedTurretObject.Position
|
||||||
val radiusSquared = autoStats.get.targetingRange * autoStats.get.targetingRange
|
val radiusSquared = autoStats.get.targetingRange * autoStats.get.targetingRange
|
||||||
|
|
@ -358,4 +359,39 @@ object AutomatedTurretBehavior {
|
||||||
LocalAction.SendResponse(ChangeFireStateMessage_Stop(weaponGuid))
|
LocalAction.SendResponse(ChangeFireStateMessage_Stop(weaponGuid))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,25 @@
|
||||||
package net.psforever.objects.serverobject.turret
|
package net.psforever.objects.serverobject.turret
|
||||||
|
|
||||||
import net.psforever.objects.equipment.JammableUnit
|
import net.psforever.objects.equipment.JammableUnit
|
||||||
import net.psforever.objects.serverobject.structures.Amenity
|
import net.psforever.objects.serverobject.structures.{Amenity, AmenityOwner, Building}
|
||||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAware
|
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAware
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
|
|
||||||
class FacilityTurret(tDef: FacilityTurretDefinition)
|
class FacilityTurret(tDef: FacilityTurretDefinition)
|
||||||
extends Amenity
|
extends Amenity
|
||||||
with WeaponTurret
|
with AutomatedTurret
|
||||||
with JammableUnit
|
with JammableUnit
|
||||||
with CaptureTerminalAware {
|
with CaptureTerminalAware {
|
||||||
WeaponTurret.LoadDefinition(this)
|
WeaponTurret.LoadDefinition(this)
|
||||||
|
|
||||||
|
override def Owner: AmenityOwner = {
|
||||||
|
if (Zone.map.cavern) {
|
||||||
|
Building.NoBuilding
|
||||||
|
} else {
|
||||||
|
super.Owner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def Definition: FacilityTurretDefinition = tDef
|
def Definition: FacilityTurretDefinition = tDef
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,9 +35,6 @@ object FacilityTurret {
|
||||||
new FacilityTurret(tDef)
|
new FacilityTurret(tDef)
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class RechargeAmmo()
|
|
||||||
final case class WeaponDischarged()
|
|
||||||
|
|
||||||
import akka.actor.ActorContext
|
import akka.actor.ActorContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,21 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.turret
|
package net.psforever.objects.serverobject.turret
|
||||||
|
|
||||||
import akka.actor.Cancellable
|
import net.psforever.objects.entity.WorldEntity
|
||||||
import net.psforever.objects.{Default, GlobalDefinitions, Player, Tool}
|
import net.psforever.objects.{GlobalDefinitions, Player, Tool}
|
||||||
import net.psforever.objects.equipment.{Ammo, JammableMountedWeapons}
|
import net.psforever.objects.equipment.Ammo
|
||||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||||
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
import net.psforever.objects.serverobject.damage.Damageable
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
|
||||||
import net.psforever.objects.serverobject.damage.{Damageable, DamageableWeaponTurret}
|
|
||||||
import net.psforever.objects.serverobject.hackable.GenericHackables
|
import net.psforever.objects.serverobject.hackable.GenericHackables
|
||||||
import net.psforever.objects.serverobject.hackable.GenericHackables.getTurretUpgradeTime
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableWeaponTurret}
|
import net.psforever.objects.serverobject.repair.AmenityAutoRepair
|
||||||
import net.psforever.objects.serverobject.structures.PoweredAmenityControl
|
import net.psforever.objects.serverobject.structures.PoweredAmenityControl
|
||||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAwareBehavior
|
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAwareBehavior
|
||||||
import net.psforever.objects.vital.interaction.DamageResult
|
import net.psforever.objects.vital.interaction.DamageResult
|
||||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
import net.psforever.packet.game.ChangeFireModeMessage
|
||||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
import net.psforever.services.Service
|
||||||
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
|
||||||
import scala.concurrent.duration._
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An `Actor` that handles messages being dispatched to a specific `MannedTurret`.<br>
|
* An `Actor` that handles messages being dispatched to a specific `MannedTurret`.<br>
|
||||||
* <br>
|
* <br>
|
||||||
|
|
@ -31,133 +26,106 @@ import scala.concurrent.duration._
|
||||||
* @param turret the `MannedTurret` object being governed
|
* @param turret the `MannedTurret` object being governed
|
||||||
*/
|
*/
|
||||||
class FacilityTurretControl(turret: FacilityTurret)
|
class FacilityTurretControl(turret: FacilityTurret)
|
||||||
extends PoweredAmenityControl
|
extends PoweredAmenityControl
|
||||||
with FactionAffinityBehavior.Check
|
|
||||||
with MountableBehavior
|
|
||||||
with DamageableWeaponTurret
|
|
||||||
with RepairableWeaponTurret
|
|
||||||
with AmenityAutoRepair
|
with AmenityAutoRepair
|
||||||
with JammableMountedWeapons
|
with MountableTurretControl
|
||||||
|
with AutomatedTurretBehavior
|
||||||
with CaptureTerminalAwareBehavior {
|
with CaptureTerminalAwareBehavior {
|
||||||
|
def TurretObject: FacilityTurret = turret
|
||||||
def FactionObject: FacilityTurret = turret
|
def FactionObject: FacilityTurret = turret
|
||||||
def MountableObject: FacilityTurret = turret
|
def MountableObject: FacilityTurret = turret
|
||||||
def JammableObject: FacilityTurret = turret
|
def JammableObject: FacilityTurret = turret
|
||||||
def DamageableObject: FacilityTurret = turret
|
def DamageableObject: FacilityTurret = turret
|
||||||
def RepairableObject: FacilityTurret = turret
|
def RepairableObject: FacilityTurret = turret
|
||||||
def AutoRepairObject: FacilityTurret = turret
|
def AutoRepairObject: FacilityTurret = turret
|
||||||
|
def AutomatedTurretObject: FacilityTurret = turret
|
||||||
def CaptureTerminalAwareObject: FacilityTurret = turret
|
def CaptureTerminalAwareObject: FacilityTurret = turret
|
||||||
|
|
||||||
// Used for timing ammo recharge for vanu turrets in caves
|
private var testToResetToDefaultFireMode: Boolean = false
|
||||||
var weaponAmmoRechargeTimer: Cancellable = Default.Cancellable
|
|
||||||
|
|
||||||
override def postStop(): Unit = {
|
override def postStop(): Unit = {
|
||||||
super.postStop()
|
super.postStop()
|
||||||
damageableWeaponTurretPostStop()
|
damageableWeaponTurretPostStop()
|
||||||
|
automaticTurretPostStop()
|
||||||
stopAutoRepair()
|
stopAutoRepair()
|
||||||
}
|
}
|
||||||
|
|
||||||
def commonBehavior: Receive =
|
private val upgradeableTurret: Receive = {
|
||||||
checkBehavior
|
case CommonMessages.Use(player, Some((item: Tool, upgradeValue: Int)))
|
||||||
.orElse(jammableBehavior)
|
if player.Faction == TurretObject.Faction &&
|
||||||
.orElse(dismountBehavior)
|
item.Definition == GlobalDefinitions.nano_dispenser && item.AmmoType == Ammo.upgrade_canister &&
|
||||||
.orElse(takesDamage)
|
item.Magazine > 0 && TurretObject.Seats.values.forall(!_.isOccupied) =>
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
TurretUpgrade.values.find(_.id == upgradeValue).foreach {
|
||||||
.orElse(autoRepairBehavior)
|
case upgrade
|
||||||
.orElse(captureTerminalAwareBehaviour)
|
if TurretObject.Upgrade != upgrade && TurretObject.Definition.WeaponPaths.values
|
||||||
|
.flatMap(_.keySet)
|
||||||
|
.exists(_ == upgrade) =>
|
||||||
|
TurretObject.setMiddleOfUpgrade(true)
|
||||||
|
sender() ! CommonMessages.Progress(
|
||||||
|
1.25f,
|
||||||
|
WeaponTurrets.FinishUpgradingMannedTurret(TurretObject, player, item, upgrade),
|
||||||
|
GenericHackables.TurretUpgradingTickAction(progressType = 2, player, TurretObject, item.GUID)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def poweredStateLogic: Receive =
|
override def commonBehavior: Receive = super.commonBehavior
|
||||||
|
.orElse(automatedTurretBehavior)
|
||||||
|
.orElse(captureTerminalAwareBehaviour)
|
||||||
|
|
||||||
|
override def poweredStateLogic: Receive =
|
||||||
commonBehavior
|
commonBehavior
|
||||||
.orElse(mountBehavior)
|
.orElse(mountBehavior)
|
||||||
|
.orElse(upgradeableTurret)
|
||||||
.orElse {
|
.orElse {
|
||||||
case CommonMessages.Use(player, Some((item: Tool, upgradeValue: Int)))
|
case _ => ()
|
||||||
if player.Faction == turret.Faction &&
|
|
||||||
item.Definition == GlobalDefinitions.nano_dispenser && item.AmmoType == Ammo.upgrade_canister &&
|
|
||||||
item.Magazine > 0 && turret.Seats.values.forall(!_.isOccupied) =>
|
|
||||||
TurretUpgrade.values.find(_.id == upgradeValue) match {
|
|
||||||
case Some(upgrade)
|
|
||||||
if turret.Upgrade != upgrade && turret.Definition.WeaponPaths.values
|
|
||||||
.flatMap(_.keySet)
|
|
||||||
.exists(_ == upgrade) =>
|
|
||||||
turret.setMiddleOfUpgrade(true)
|
|
||||||
sender() ! CommonMessages.Progress(
|
|
||||||
1.25f,
|
|
||||||
WeaponTurrets.FinishUpgradingMannedTurret(turret, player, item, upgrade),
|
|
||||||
GenericHackables.TurretUpgradingTickAction(progressType = 2, player, turret, item.GUID)
|
|
||||||
)
|
|
||||||
case _ => ;
|
|
||||||
}
|
|
||||||
|
|
||||||
case FacilityTurret.WeaponDischarged() =>
|
|
||||||
if (weaponAmmoRechargeTimer != Default.Cancellable) {
|
|
||||||
weaponAmmoRechargeTimer.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
weaponAmmoRechargeTimer = context.system.scheduler.scheduleWithFixedDelay(
|
|
||||||
3 seconds,
|
|
||||||
200 milliseconds,
|
|
||||||
self,
|
|
||||||
FacilityTurret.RechargeAmmo()
|
|
||||||
)
|
|
||||||
|
|
||||||
case FacilityTurret.RechargeAmmo() =>
|
|
||||||
turret.ControlledWeapon(wepNumber = 1).foreach {
|
|
||||||
case weapon: Tool =>
|
|
||||||
// recharge when last shot fired 3s delay, +1, 200ms interval
|
|
||||||
if (weapon.Magazine < weapon.MaxMagazine && System.currentTimeMillis() - weapon.LastDischarge > 3000L) {
|
|
||||||
weapon.Magazine += 1
|
|
||||||
val seat = turret.Seat(0).get
|
|
||||||
seat.occupant match {
|
|
||||||
case Some(player : Player) =>
|
|
||||||
turret.Zone.LocalEvents ! LocalServiceMessage(
|
|
||||||
turret.Zone.id,
|
|
||||||
LocalAction.RechargeVehicleWeapon(player.GUID, turret.GUID, weapon.GUID)
|
|
||||||
)
|
|
||||||
case _ => ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (weapon.Magazine == weapon.MaxMagazine && weaponAmmoRechargeTimer != Default.Cancellable) {
|
|
||||||
weaponAmmoRechargeTimer.cancel()
|
|
||||||
weaponAmmoRechargeTimer = Default.Cancellable
|
|
||||||
}
|
|
||||||
case _ => ;
|
|
||||||
}
|
|
||||||
|
|
||||||
case _ => ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def unpoweredStateLogic: Receive =
|
override def unpoweredStateLogic: Receive =
|
||||||
commonBehavior
|
commonBehavior
|
||||||
.orElse {
|
.orElse {
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected def mountTest(
|
override protected def mountTest(
|
||||||
obj: PlanetSideServerObject with Mountable,
|
obj: PlanetSideServerObject with Mountable,
|
||||||
seatNumber: Int,
|
seatNumber: Int,
|
||||||
player: Player): Boolean = {
|
player: Player): Boolean = {
|
||||||
(!turret.Definition.FactionLocked || player.Faction == obj.Faction) && !obj.Destroyed && !turret.isUpgrading ||
|
super.mountTest(obj, seatNumber, player) &&
|
||||||
System.currentTimeMillis() - getTurretUpgradeTime >= 1500L
|
(!TurretObject.isUpgrading || System.currentTimeMillis() - GenericHackables.getTurretUpgradeTime >= 1500L) &&
|
||||||
|
AutomaticOperation_=(state = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected def dismountTest(obj: Mountable with WorldEntity, seatNumber: Int, user: Player): Boolean = {
|
||||||
|
super.dismountTest(obj, seatNumber, user) &&
|
||||||
|
AutomaticOperation_=(autoTurretFunctionalityChecks)
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected def DamageAwareness(target: Damageable.Target, cause: DamageResult, amount: Any) : Unit = {
|
override protected def DamageAwareness(target: Damageable.Target, cause: DamageResult, amount: Any) : Unit = {
|
||||||
tryAutoRepair()
|
tryAutoRepair()
|
||||||
|
if (AutomaticOperation) {
|
||||||
|
if (TurretObject.Health < TurretObject.Definition.DamageDisablesAt) {
|
||||||
|
AutomaticOperation = false
|
||||||
|
} else if (AutomatedTurretObject.Definition.AutoFire.exists(_.retaliatoryDuration > 0)) {
|
||||||
|
//turret retribution
|
||||||
|
AutomatedTurretBehavior.getAttackerFromCause(target.Zone, cause).collect {
|
||||||
|
case attacker if attacker.Faction != target.Faction =>
|
||||||
|
engageNewDetectedTarget(attacker)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
super.DamageAwareness(target, cause, amount)
|
super.DamageAwareness(target, cause, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected def DestructionAwareness(target: Damageable.Target, cause: DamageResult): Unit = {
|
override protected def DestructionAwareness(target: Damageable.Target, cause: DamageResult): Unit = {
|
||||||
tryAutoRepair()
|
|
||||||
super.DestructionAwareness(target, cause)
|
super.DestructionAwareness(target, cause)
|
||||||
val zone = target.Zone
|
tryAutoRepair()
|
||||||
val zoneId = zone.id
|
AutomaticOperation = false
|
||||||
val events = zone.AvatarEvents
|
|
||||||
val tguid = target.GUID
|
|
||||||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 50, 1))
|
|
||||||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 51, 1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override def PerformRepairs(target : Damageable.Target, amount : Int) : Int = {
|
override def PerformRepairs(target : Damageable.Target, amount : Int) : Int = {
|
||||||
val newHealth = super.PerformRepairs(target, amount)
|
val newHealth = super.PerformRepairs(target, amount)
|
||||||
if(newHealth == target.Definition.MaxHealth) {
|
if (newHealth == target.Definition.MaxHealth) {
|
||||||
stopAutoRepair()
|
stopAutoRepair()
|
||||||
}
|
}
|
||||||
newHealth
|
newHealth
|
||||||
|
|
@ -165,12 +133,7 @@ class FacilityTurretControl(turret: FacilityTurret)
|
||||||
|
|
||||||
override def Restoration(obj: Damageable.Target): Unit = {
|
override def Restoration(obj: Damageable.Target): Unit = {
|
||||||
super.Restoration(obj)
|
super.Restoration(obj)
|
||||||
val zone = turret.Zone
|
AutomaticOperation = autoTurretFunctionalityChecks
|
||||||
val zoneId = zone.id
|
|
||||||
val events = zone.AvatarEvents
|
|
||||||
val tguid = turret.GUID
|
|
||||||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 50, 0))
|
|
||||||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 51, 0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override def tryAutoRepair() : Boolean = {
|
override def tryAutoRepair() : Boolean = {
|
||||||
|
|
@ -179,12 +142,13 @@ class FacilityTurretControl(turret: FacilityTurret)
|
||||||
|
|
||||||
def powerTurnOffCallback(): Unit = {
|
def powerTurnOffCallback(): Unit = {
|
||||||
stopAutoRepair()
|
stopAutoRepair()
|
||||||
|
AutomaticOperation = false
|
||||||
//kick all occupants
|
//kick all occupants
|
||||||
val guid = turret.GUID
|
val guid = TurretObject.GUID
|
||||||
val zone = turret.Zone
|
val zone = TurretObject.Zone
|
||||||
val zoneId = zone.id
|
val zoneId = zone.id
|
||||||
val events = zone.VehicleEvents
|
val events = zone.VehicleEvents
|
||||||
turret.Seats.values.foreach(seat =>
|
TurretObject.Seats.values.foreach(seat =>
|
||||||
seat.occupant match {
|
seat.occupant match {
|
||||||
case Some(player) =>
|
case Some(player) =>
|
||||||
seat.unmount(player)
|
seat.unmount(player)
|
||||||
|
|
@ -192,12 +156,83 @@ class FacilityTurretControl(turret: FacilityTurret)
|
||||||
if (player.HasGUID) {
|
if (player.HasGUID) {
|
||||||
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2=false, guid))
|
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2=false, guid))
|
||||||
}
|
}
|
||||||
case None => ;
|
case None => ()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def powerTurnOnCallback(): Unit = {
|
def powerTurnOnCallback(): Unit = {
|
||||||
tryAutoRepair()
|
tryAutoRepair()
|
||||||
|
AutomaticOperation = autoTurretFunctionalityChecks
|
||||||
|
}
|
||||||
|
|
||||||
|
override def AutomaticOperation_=(state: Boolean): Boolean = {
|
||||||
|
val result = super.AutomaticOperation_=(state)
|
||||||
|
testToResetToDefaultFireMode = result && TurretObject.Definition.AutoFire.exists(_.revertToDefaultFireMode)
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
private def autoTurretFunctionalityChecks: Boolean = {
|
||||||
|
isPowered &&
|
||||||
|
!JammableObject.Jammed &&
|
||||||
|
TurretObject.Health > TurretObject.Definition.DamageDisablesAt &&
|
||||||
|
!TurretObject.Seats.values.exists(_.isOccupied)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def primaryWeaponFireModeOnly(): Unit = {
|
||||||
|
if (testToResetToDefaultFireMode) {
|
||||||
|
val zone = TurretObject.Zone
|
||||||
|
val zoneid = zone.id
|
||||||
|
val events = zone.VehicleEvents
|
||||||
|
TurretObject.Weapons.values
|
||||||
|
.flatMap(_.Equipment)
|
||||||
|
.collect { case weapon: Tool if weapon.FireModeIndex > 0 =>
|
||||||
|
weapon.FireModeIndex = 0
|
||||||
|
events ! VehicleServiceMessage(
|
||||||
|
zoneid,
|
||||||
|
VehicleAction.SendResponse(Service.defaultPlayerGUID, ChangeFireModeMessage(weapon.GUID, 0))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testToResetToDefaultFireMode = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected def trySelectNewTarget(): Option[AutomatedTurret.Target] = {
|
||||||
|
if (autoTurretFunctionalityChecks) {
|
||||||
|
primaryWeaponFireModeOnly()
|
||||||
|
super.trySelectNewTarget()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override def engageNewDetectedTarget(target: AutomatedTurret.Target): Unit = {
|
||||||
|
if (autoTurretFunctionalityChecks) {
|
||||||
|
primaryWeaponFireModeOnly()
|
||||||
|
super.engageNewDetectedTarget(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override def TryJammerEffectActivate(target: Any, cause: DamageResult): Unit = {
|
||||||
|
val startsUnjammed = !JammableObject.Jammed
|
||||||
|
super.TryJammerEffectActivate(target, cause)
|
||||||
|
if (startsUnjammed && JammableObject.Jammed && AutomatedTurretObject.Definition.AutoFire.exists(_.retaliatoryDuration > 0)) {
|
||||||
|
AutomaticOperation = false
|
||||||
|
//look in direction of cause of jamming
|
||||||
|
val zone = JammableObject.Zone
|
||||||
|
AutomatedTurretBehavior.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_=(autoTurretFunctionalityChecks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright (c) 2023 PSForever
|
||||||
|
package net.psforever.objects.serverobject.turret
|
||||||
|
|
||||||
|
import akka.actor.Actor
|
||||||
|
import net.psforever.objects.Player
|
||||||
|
import net.psforever.objects.equipment.JammableMountedWeapons
|
||||||
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
||||||
|
import net.psforever.objects.serverobject.damage.{Damageable, DamageableWeaponTurret}
|
||||||
|
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
||||||
|
import net.psforever.objects.serverobject.repair.RepairableWeaponTurret
|
||||||
|
import net.psforever.objects.vital.interaction.DamageResult
|
||||||
|
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
|
||||||
|
trait MountableTurretControl
|
||||||
|
extends FactionAffinityBehavior.Check
|
||||||
|
with MountableBehavior
|
||||||
|
with DamageableWeaponTurret
|
||||||
|
with RepairableWeaponTurret
|
||||||
|
with JammableMountedWeapons
|
||||||
|
with Actor { /* note: jammable status is reported as vehicle events, not local events */
|
||||||
|
def TurretObject: PlanetSideServerObject with WeaponTurret
|
||||||
|
|
||||||
|
override def postStop(): Unit = {
|
||||||
|
super.postStop()
|
||||||
|
damageableWeaponTurretPostStop()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** commonBehavior does not implement mountingBehavior; please do so when implementing */
|
||||||
|
def commonBehavior: Receive =
|
||||||
|
checkBehavior
|
||||||
|
.orElse(jammableBehavior)
|
||||||
|
.orElse(dismountBehavior)
|
||||||
|
.orElse(takesDamage)
|
||||||
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
|
|
||||||
|
override protected def mountTest(
|
||||||
|
obj: PlanetSideServerObject with Mountable,
|
||||||
|
seatNumber: Int,
|
||||||
|
player: Player): Boolean = {
|
||||||
|
(!TurretObject.Definition.FactionLocked || player.Faction == obj.Faction) && !obj.Destroyed
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An override for `Restoration`, best for facility turrets.
|
||||||
|
* @param obj the entity being restored
|
||||||
|
*/
|
||||||
|
override def Restoration(obj: Damageable.Target): Unit = {
|
||||||
|
super.Restoration(obj)
|
||||||
|
val zone = TurretObject.Zone
|
||||||
|
val zoneId = zone.id
|
||||||
|
val events = zone.AvatarEvents
|
||||||
|
val tguid = TurretObject.GUID
|
||||||
|
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 50, 0))
|
||||||
|
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 51, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An override for `DamageAwareness`, best for facility turrets.
|
||||||
|
* @param target the entity being destroyed
|
||||||
|
* @param cause historical information about the damage
|
||||||
|
*/
|
||||||
|
override protected def DestructionAwareness(target: Damageable.Target, cause: DamageResult): Unit = {
|
||||||
|
super.DestructionAwareness(target, cause)
|
||||||
|
val zone = target.Zone
|
||||||
|
val zoneId = zone.id
|
||||||
|
val events = zone.AvatarEvents
|
||||||
|
val tguid = target.GUID
|
||||||
|
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 50, 1))
|
||||||
|
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 51, 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,7 +18,8 @@ final case class Automation(
|
||||||
detectionSpeed: FiniteDuration = 1.seconds,
|
detectionSpeed: FiniteDuration = 1.seconds,
|
||||||
targetSelectCooldown: Long = 1500L, //ms
|
targetSelectCooldown: Long = 1500L, //ms
|
||||||
missedShotCooldown: Long = 3000L, //ms
|
missedShotCooldown: Long = 3000L, //ms
|
||||||
targetEliminationCooldown: Long = 0L //ms
|
targetEliminationCooldown: Long = 0L, //ms
|
||||||
|
revertToDefaultFireMode: Boolean = true
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
// Copyright (c) 2023 PSForever
|
||||||
|
package net.psforever.objects.serverobject.turret
|
||||||
|
|
||||||
|
import akka.actor.Cancellable
|
||||||
|
import net.psforever.objects.serverobject.ServerObjectControl
|
||||||
|
import net.psforever.objects.{Default, Player, Tool}
|
||||||
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
import net.psforever.types.Vector3
|
||||||
|
|
||||||
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
class VanuSentryControl(turret: FacilityTurret)
|
||||||
|
extends ServerObjectControl
|
||||||
|
with MountableTurretControl {
|
||||||
|
def TurretObject: FacilityTurret = turret
|
||||||
|
def FactionObject: FacilityTurret = turret
|
||||||
|
def MountableObject: FacilityTurret = turret
|
||||||
|
def JammableObject: FacilityTurret = turret
|
||||||
|
def DamageableObject: FacilityTurret = turret
|
||||||
|
def RepairableObject: FacilityTurret = turret
|
||||||
|
|
||||||
|
// Used for timing ammo recharge for vanu turrets in caves
|
||||||
|
private var weaponAmmoRechargeTimer: Cancellable = Default.Cancellable
|
||||||
|
|
||||||
|
private val weaponAmmoRecharge: Receive = {
|
||||||
|
case VanuSentry.ChangeFireStart =>
|
||||||
|
weaponAmmoRechargeTimer.cancel()
|
||||||
|
weaponAmmoRechargeTimer = Default.Cancellable
|
||||||
|
|
||||||
|
case VanuSentry.ChangeFireStop =>
|
||||||
|
weaponAmmoRechargeTimer.cancel()
|
||||||
|
weaponAmmoRechargeTimer = context.system.scheduler.scheduleWithFixedDelay(
|
||||||
|
3 seconds,
|
||||||
|
200 milliseconds,
|
||||||
|
self,
|
||||||
|
VanuSentry.RechargeAmmo
|
||||||
|
)
|
||||||
|
|
||||||
|
case VanuSentry.RechargeAmmo =>
|
||||||
|
TurretObject.ControlledWeapon(wepNumber = 1).collect {
|
||||||
|
case weapon: Tool =>
|
||||||
|
// recharge when last shot fired 3s delay, +1, 200ms interval
|
||||||
|
if (weapon.Magazine < weapon.MaxMagazine && System.currentTimeMillis() - weapon.LastDischarge > 3000L) {
|
||||||
|
weapon.Magazine += 1
|
||||||
|
val seat = TurretObject.Seat(0).get
|
||||||
|
seat.occupant.collect {
|
||||||
|
case player: Player =>
|
||||||
|
TurretObject.Zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
TurretObject.Zone.id,
|
||||||
|
LocalAction.RechargeVehicleWeapon(player.GUID, TurretObject.GUID, weapon.GUID)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (weapon.Magazine == weapon.MaxMagazine && weaponAmmoRechargeTimer != Default.Cancellable) {
|
||||||
|
weaponAmmoRechargeTimer.cancel()
|
||||||
|
weaponAmmoRechargeTimer = Default.Cancellable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override def postStop(): Unit = {
|
||||||
|
super.postStop()
|
||||||
|
weaponAmmoRechargeTimer.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
def receive: Receive =
|
||||||
|
commonBehavior
|
||||||
|
.orElse(mountBehavior)
|
||||||
|
.orElse(weaponAmmoRecharge)
|
||||||
|
.orElse {
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
override def parseAttribute(attribute: Int, value: Long, other: Option[Any]): Unit = { /*intentionally blank*/ }
|
||||||
|
}
|
||||||
|
|
||||||
|
object VanuSentry {
|
||||||
|
final case object RechargeAmmo
|
||||||
|
final case object ChangeFireStart
|
||||||
|
final case object ChangeFireStop
|
||||||
|
|
||||||
|
import akka.actor.ActorContext
|
||||||
|
def Constructor(pos: Vector3, tdef: FacilityTurretDefinition)(id: Int, context: ActorContext): FacilityTurret = {
|
||||||
|
import akka.actor.Props
|
||||||
|
val obj = FacilityTurret(tdef)
|
||||||
|
obj.Position = pos
|
||||||
|
obj.Actor = context.actorOf(Props(classOf[VanuSentryControl], obj), s"${tdef.Name}_$id")
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,7 @@ import net.psforever.objects.serverobject.structures.{Building, BuildingDefiniti
|
||||||
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalDefinition}
|
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalDefinition}
|
||||||
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
|
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
|
||||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||||
import net.psforever.objects.serverobject.turret.{FacilityTurret, FacilityTurretDefinition}
|
import net.psforever.objects.serverobject.turret.{FacilityTurret, FacilityTurretDefinition, VanuSentry}
|
||||||
import net.psforever.objects.serverobject.zipline.ZipLinePath
|
import net.psforever.objects.serverobject.zipline.ZipLinePath
|
||||||
import net.psforever.objects.sourcing.{DeployableSource, PlayerSource, TurretSource, VehicleSource}
|
import net.psforever.objects.sourcing.{DeployableSource, PlayerSource, TurretSource, VehicleSource}
|
||||||
import net.psforever.objects.zones.{MapInfo, Zone, ZoneInfo, ZoneMap}
|
import net.psforever.objects.zones.{MapInfo, Zone, ZoneInfo, ZoneMap}
|
||||||
|
|
@ -585,7 +585,7 @@ object Zones {
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "manned_turret" | "vanu_sentry_turret" =>
|
case "manned_turret" =>
|
||||||
zoneMap.addLocalObject(
|
zoneMap.addLocalObject(
|
||||||
obj.guid,
|
obj.guid,
|
||||||
FacilityTurret.Constructor(
|
FacilityTurret.Constructor(
|
||||||
|
|
@ -596,6 +596,17 @@ object Zones {
|
||||||
)
|
)
|
||||||
zoneMap.linkTurretToWeapon(obj.guid, turretWeaponGuid.getAndIncrement())
|
zoneMap.linkTurretToWeapon(obj.guid, turretWeaponGuid.getAndIncrement())
|
||||||
|
|
||||||
|
case "vanu_sentry_turret" =>
|
||||||
|
zoneMap.addLocalObject(
|
||||||
|
obj.guid,
|
||||||
|
VanuSentry.Constructor(
|
||||||
|
obj.position,
|
||||||
|
obj.objectDefinition.asInstanceOf[FacilityTurretDefinition]
|
||||||
|
),
|
||||||
|
owningBuildingGuid = ownerGuid
|
||||||
|
)
|
||||||
|
zoneMap.linkTurretToWeapon(obj.guid, turretWeaponGuid.getAndIncrement())
|
||||||
|
|
||||||
case "implant_terminal_mech" =>
|
case "implant_terminal_mech" =>
|
||||||
zoneMap.addLocalObject(
|
zoneMap.addLocalObject(
|
||||||
obj.guid,
|
obj.guid,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue