breaking up classes related to different kinds of turret deployables

This commit is contained in:
Fate-JH 2024-06-19 00:43:16 -04:00
parent 9070f396d0
commit 700059e86a
8 changed files with 355 additions and 256 deletions

View file

@ -0,0 +1,89 @@
// Copyright (c) 2024 PSForever
package net.psforever.objects
import akka.actor.{ActorContext, Props}
import net.psforever.objects.ce.{Deployable, DeployedItem}
import net.psforever.objects.definition.WithShields
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.hackable.GenericHackables
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
import net.psforever.objects.serverobject.turret.{MountableTurret, WeaponTurrets}
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.sourcing.SourceEntry
import net.psforever.objects.vital.{InGameActivity, ShieldCharge}
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import net.psforever.types.PlanetSideGUID
/** definition */
class FieldTurretDeployableDefinition(private val objectId: Int)
extends TurretDeployableDefinition(objectId) {
override def Initialize(obj: Deployable, context: ActorContext): Unit = {
obj.Actor = context.actorOf(Props(classOf[FieldTurretControl], obj), PlanetSideServerObject.UniqueActorName(obj))
}
}
object FieldTurretDeployableDefinition {
def apply(dtype: DeployedItem.Value): FieldTurretDeployableDefinition = {
new FieldTurretDeployableDefinition(dtype.id)
}
}
/** control actor */
class FieldTurretControl(turret: TurretDeployable)
extends TurretDeployableControl
with MountableBehavior {
def TurretObject: TurretDeployable = turret
def DeployableObject: TurretDeployable = turret
def JammableObject: TurretDeployable = turret
def FactionObject: TurretDeployable = turret
def DamageableObject: TurretDeployable = turret
def RepairableObject: TurretDeployable = turret
def AffectedObject: TurretDeployable = turret
def MountableObject: TurretDeployable = turret
def receive: Receive =
commonBehavior
.orElse(mountBehavior)
.orElse(dismountBehavior)
.orElse {
case CommonMessages.Use(player, Some(item: SimpleItem))
if item.Definition == GlobalDefinitions.remote_electronics_kit &&
turret.Faction != player.Faction =>
sender() ! CommonMessages.Progress(
GenericHackables.GetHackSpeed(player, turret),
WeaponTurrets.FinishHackingTurretDeployable(turret, player),
GenericHackables.HackingTickAction(progressType = 1, player, turret, item.GUID)
)
case CommonMessages.ChargeShields(amount, motivator) =>
chargeShields(amount, motivator.collect { case o: PlanetSideGameObject with FactionAffinity => SourceEntry(o) })
case _ => ()
}
override protected def mountTest(
obj: PlanetSideServerObject with Mountable,
seatNumber: Int,
player: Player
): Boolean = MountableTurret.MountTest(TurretObject, player)
//make certain vehicles don't charge shields too quickly
private def canChargeShields: Boolean = {
val func: InGameActivity => Boolean = WithShields.LastShieldChargeOrDamage(System.currentTimeMillis(), turret.Definition)
turret.Health > 0 && turret.Shields < turret.MaxShields &&
turret.History.findLast(func).isEmpty
}
private def chargeShields(amount: Int, motivator: Option[SourceEntry]): Unit = {
if (canChargeShields) {
turret.LogActivity(ShieldCharge(amount, motivator))
turret.Shields = turret.Shields + amount
turret.Zone.VehicleEvents ! VehicleServiceMessage(
s"${turret.Actor}",
VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), turret.GUID, turret.Definition.shieldUiAttribute, turret.Shields)
)
}
}
}

View file

@ -1023,11 +1023,11 @@ object GlobalDefinitions {
val jammer_mine: ExplosiveDeployableDefinition = ExplosiveDeployableDefinition(DeployedItem.jammer_mine) val jammer_mine: ExplosiveDeployableDefinition = ExplosiveDeployableDefinition(DeployedItem.jammer_mine)
val spitfire_turret: TurretDeployableDefinition = TurretDeployableDefinition(DeployedItem.spitfire_turret) val spitfire_turret: TurretDeployableDefinition = SmallTurretDeployableDefinition(DeployedItem.spitfire_turret)
val spitfire_cloaked: TurretDeployableDefinition = TurretDeployableDefinition(DeployedItem.spitfire_cloaked) val spitfire_cloaked: TurretDeployableDefinition = SmallTurretDeployableDefinition(DeployedItem.spitfire_cloaked)
val spitfire_aa: TurretDeployableDefinition = TurretDeployableDefinition(DeployedItem.spitfire_aa) val spitfire_aa: TurretDeployableDefinition = SmallTurretDeployableDefinition(DeployedItem.spitfire_aa)
val motionalarmsensor: SensorDeployableDefinition = SensorDeployableDefinition(DeployedItem.motionalarmsensor) val motionalarmsensor: SensorDeployableDefinition = SensorDeployableDefinition(DeployedItem.motionalarmsensor)
@ -1035,13 +1035,13 @@ object GlobalDefinitions {
val tank_traps: TrapDeployableDefinition = TrapDeployableDefinition(DeployedItem.tank_traps) val tank_traps: TrapDeployableDefinition = TrapDeployableDefinition(DeployedItem.tank_traps)
val portable_manned_turret: TurretDeployableDefinition = TurretDeployableDefinition(DeployedItem.portable_manned_turret) val portable_manned_turret: TurretDeployableDefinition = FieldTurretDeployableDefinition(DeployedItem.portable_manned_turret)
val portable_manned_turret_nc: TurretDeployableDefinition = TurretDeployableDefinition(DeployedItem.portable_manned_turret_nc) val portable_manned_turret_nc: TurretDeployableDefinition = FieldTurretDeployableDefinition(DeployedItem.portable_manned_turret_nc)
val portable_manned_turret_tr: TurretDeployableDefinition = TurretDeployableDefinition(DeployedItem.portable_manned_turret_tr) val portable_manned_turret_tr: TurretDeployableDefinition = FieldTurretDeployableDefinition(DeployedItem.portable_manned_turret_tr)
val portable_manned_turret_vs: TurretDeployableDefinition = TurretDeployableDefinition(DeployedItem.portable_manned_turret_vs) val portable_manned_turret_vs: TurretDeployableDefinition = FieldTurretDeployableDefinition(DeployedItem.portable_manned_turret_vs)
val deployable_shield_generator = new ShieldGeneratorDefinition val deployable_shield_generator = new ShieldGeneratorDefinition

View file

@ -0,0 +1,158 @@
// Copyright (c) 2024 PSForever
package net.psforever.objects
import akka.actor.{ActorContext, ActorRef, Props}
import net.psforever.objects.ce.{Deployable, DeployedItem}
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.damage.Damageable
import net.psforever.objects.serverobject.turret.auto.AutomatedTurret.Target
import net.psforever.objects.serverobject.turret.auto.{AutomatedTurret, AutomatedTurretBehavior}
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.types.PlanetSideGUID
import scala.concurrent.duration.FiniteDuration
/** definition */
class SmallTurretDeployableDefinition(private val objectId: Int)
extends TurretDeployableDefinition(objectId) {
override def Initialize(obj: Deployable, context: ActorContext): Unit = {
obj.Actor = context.actorOf(Props(classOf[SmallTurretControl], obj), PlanetSideServerObject.UniqueActorName(obj))
}
}
object SmallTurretDeployableDefinition {
def apply(dtype: DeployedItem.Value): SmallTurretDeployableDefinition = {
new SmallTurretDeployableDefinition(dtype.id)
}
}
/** control actor */
class SmallTurretControl(turret: TurretDeployable)
extends TurretDeployableControl
with AutomatedTurretBehavior {
def TurretObject: TurretDeployable = turret
def DeployableObject: TurretDeployable = turret
def JammableObject: TurretDeployable = turret
def FactionObject: TurretDeployable = turret
def DamageableObject: TurretDeployable = turret
def RepairableObject: TurretDeployable = turret
def AffectedObject: TurretDeployable = turret
def AutomatedTurretObject: TurretDeployable = turret
override def postStop(): Unit = {
super.postStop()
selfReportingDatabaseUpdate()
automaticTurretPostStop()
}
def receive: Receive =
commonBehavior
.orElse(automatedTurretBehavior)
.orElse {
case _ => ()
}
protected def engageNewDetectedTarget(
target: AutomatedTurret.Target,
channel: String,
turretGuid: PlanetSideGUID,
weaponGuid: PlanetSideGUID
): Unit = {
val zone = target.Zone
AutomatedTurretBehavior.startTracking(zone, channel, turretGuid, List(target.GUID))
AutomatedTurretBehavior.startShooting(zone, channel, weaponGuid)
}
protected def noLongerEngageTarget(
target: AutomatedTurret.Target,
channel: String,
turretGuid: PlanetSideGUID,
weaponGuid: PlanetSideGUID
): Option[AutomatedTurret.Target] = {
val zone = target.Zone
AutomatedTurretBehavior.stopTracking(zone, channel, turretGuid)
AutomatedTurretBehavior.stopShooting(zone, channel, weaponGuid)
None
}
protected def testNewDetected(
target: AutomatedTurret.Target,
channel: String,
turretGuid: PlanetSideGUID,
weaponGuid: PlanetSideGUID
): Unit = {
val zone = target.Zone
AutomatedTurretBehavior.startTracking(zone, channel, turretGuid, List(target.GUID))
AutomatedTurretBehavior.startShooting(zone, channel, weaponGuid)
AutomatedTurretBehavior.stopShooting(zone, channel, weaponGuid)
}
protected def testKnownDetected(
target: AutomatedTurret.Target,
channel: String,
turretGuid: PlanetSideGUID,
weaponGuid: PlanetSideGUID
): Unit = {
val zone = target.Zone
AutomatedTurretBehavior.startShooting(zone, channel, weaponGuid)
AutomatedTurretBehavior.stopShooting(zone, channel, weaponGuid)
}
override protected def suspendTargetTesting(
target: Target,
channel: String,
turretGuid: PlanetSideGUID,
weaponGuid: PlanetSideGUID
): Unit = {
AutomatedTurretBehavior.stopTracking(target.Zone, channel, turretGuid)
}
override def TryJammerEffectActivate(target: Any, cause: DamageResult): Unit = {
val startsUnjammed = !JammableObject.Jammed
super.TryJammerEffectActivate(target, cause)
if (JammableObject.Jammed && AutomatedTurretObject.Definition.AutoFire.exists(_.retaliatoryDelay > 0)) {
if (startsUnjammed) {
AutomaticOperation = false
}
//look in direction of cause of jamming
val zone = JammableObject.Zone
AutomatedTurretBehavior.getAttackVectorFromCause(zone, cause).foreach { attacker =>
AutomatedTurretBehavior.startTracking(zone, zone.id, AutomatedTurretObject.GUID, List(attacker.GUID))
}
}
}
override def CancelJammeredStatus(target: Any): Unit = {
val startsJammed = JammableObject.Jammed
super.CancelJammeredStatus(target)
if (startsJammed && AutomaticOperation_=(state = true)) {
val zone = TurretObject.Zone
AutomatedTurretBehavior.stopTracking(zone, zone.id, TurretObject.GUID)
}
}
override protected def DamageAwareness(target: Damageable.Target, cause: DamageResult, amount: Any): Unit = {
amount match {
case 0 => ()
case _ => attemptRetaliation(target, cause)
}
super.DamageAwareness(target, cause, amount)
}
override protected def DestructionAwareness(target: Damageable.Target, cause: DamageResult): Unit = {
AutomaticOperation = false
super.DestructionAwareness(target, cause)
}
override def deconstructDeployable(time: Option[FiniteDuration]) : Unit = {
AutomaticOperation = false
super.deconstructDeployable(time)
}
override def finalizeDeployable(callback: ActorRef): Unit = {
super.finalizeDeployable(callback)
AutomaticOperation = true
}
}

View file

@ -1,29 +1,26 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever.objects package net.psforever.objects
import akka.actor.{Actor, ActorContext, ActorRef, Props} import akka.actor.Actor
import net.psforever.objects.ce.{Deployable, DeployableBehavior, DeployableCategory, DeployedItem, InteractWithTurrets} import net.psforever.objects.ce.{Deployable, DeployableBehavior, InteractWithTurrets}
import net.psforever.objects.definition.{DeployableDefinition, WithShields} 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.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.{CommonMessages, PlanetSideServerObject} import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.damage.Damageable import net.psforever.objects.serverobject.damage.Damageable
import net.psforever.objects.serverobject.hackable.{GenericHackables, Hackable} import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.mount.{InteractWithRadiationCloudsSeatedInEntity, Mountable} import net.psforever.objects.serverobject.mount.InteractWithRadiationCloudsSeatedInEntity
import net.psforever.objects.serverobject.turret.auto.AutomatedTurret.Target import net.psforever.objects.serverobject.turret.auto.{AffectedByAutomaticTurretFire, AutomatedTurret}
import net.psforever.objects.serverobject.turret.auto.{AffectedByAutomaticTurretFire, AutomatedTurret, AutomatedTurretBehavior} import net.psforever.objects.serverobject.turret.{TurretControl, TurretDefinition, WeaponTurret}
import net.psforever.objects.serverobject.turret.{MountableTurretControl, TurretDefinition, WeaponTurret, WeaponTurrets}
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry} import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
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.resistance.StandardResistanceProfile import net.psforever.objects.vital.resistance.StandardResistanceProfile
import net.psforever.objects.vital.{InGameActivity, ShieldCharge, SimpleResolutions, StandardVehicleResistance} import net.psforever.objects.vital.{SimpleResolutions, StandardVehicleResistance}
import net.psforever.objects.zones.InteractsWithZone import net.psforever.objects.zones.InteractsWithZone
import net.psforever.packet.game.TriggeredSound import net.psforever.packet.game.TriggeredSound
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import net.psforever.types.PlanetSideGUID
import scala.concurrent.duration.FiniteDuration import scala.concurrent.duration.FiniteDuration
@ -54,14 +51,12 @@ class TurretDeployable(tdef: TurretDeployableDefinition)
.getOrElse(SourceEntry(this)) .getOrElse(SourceEntry(this))
} }
override def MaxShields: Int = { override def MaxShields: Int = Definition.MaxShields
Definition.MaxShields
}
override def Definition: TurretDeployableDefinition = tdef override def Definition: TurretDeployableDefinition = tdef
} }
class TurretDeployableDefinition(private val objectId: Int) abstract class TurretDeployableDefinition(private val objectId: Int)
extends DeployableDefinition(objectId) extends DeployableDefinition(objectId)
with TurretDefinition { with TurretDefinition {
Name = "turret_deployable" Name = "turret_deployable"
@ -74,175 +69,36 @@ class TurretDeployableDefinition(private val objectId: Int)
override def MaxHealth: Int = super[DeployableDefinition].MaxHealth override def MaxHealth: Int = super[DeployableDefinition].MaxHealth
//override to clarify inheritance conflict //override to clarify inheritance conflict
override def MaxHealth_=(max: Int): Int = super[DeployableDefinition].MaxHealth_=(max) override def MaxHealth_=(max: Int): Int = super[DeployableDefinition].MaxHealth_=(max)
override def Initialize(obj: Deployable, context: ActorContext): Unit = {
obj.Actor = context.actorOf(Props(classOf[TurretControl], obj), PlanetSideServerObject.UniqueActorName(obj))
}
}
object TurretDeployableDefinition {
def apply(dtype: DeployedItem.Value): TurretDeployableDefinition = {
new TurretDeployableDefinition(dtype.id)
}
} }
/** control actors */ /** control actors */
class TurretControl(turret: TurretDeployable) abstract class TurretDeployableControl
extends Actor extends Actor
with DeployableBehavior with DeployableBehavior
with FactionAffinityBehavior.Check with FactionAffinityBehavior.Check
with MountableTurretControl with TurretControl
with AutomatedTurretBehavior
with AffectedByAutomaticTurretFire { with AffectedByAutomaticTurretFire {
def TurretObject: TurretDeployable = turret
def DeployableObject: TurretDeployable = turret
def MountableObject: TurretDeployable = turret
def JammableObject: TurretDeployable = turret
def FactionObject: TurretDeployable = turret
def DamageableObject: TurretDeployable = turret
def RepairableObject: TurretDeployable = turret
def AutomatedTurretObject: TurretDeployable = turret
def AffectedObject: TurretDeployable = turret
override def postStop(): Unit = { override def postStop(): Unit = {
super.postStop() super.postStop()
deployableBehaviorPostStop() deployableBehaviorPostStop()
selfReportingDatabaseUpdate()
automaticTurretPostStop()
} }
def receive: Receive = override def commonBehavior: Receive =
commonBehavior super.commonBehavior
.orElse(deployableBehavior) .orElse(deployableBehavior)
.orElse(checkBehavior) .orElse(checkBehavior)
.orElse(mountBehavior)
.orElse(automatedTurretBehavior)
.orElse(takeAutomatedDamage) .orElse(takeAutomatedDamage)
.orElse {
case CommonMessages.Use(player, Some(item: SimpleItem))
if item.Definition == GlobalDefinitions.remote_electronics_kit &&
turret.Definition.DeployCategory == DeployableCategory.FieldTurrets &&
turret.Faction != player.Faction =>
sender() ! CommonMessages.Progress(
GenericHackables.GetHackSpeed(player, turret),
WeaponTurrets.FinishHackingTurretDeployable(turret, player),
GenericHackables.HackingTickAction(progressType = 1, player, turret, item.GUID)
)
case CommonMessages.ChargeShields(amount, motivator)
if turret.Definition.DeployCategory == DeployableCategory.FieldTurrets=>
chargeShields(amount, motivator.collect { case o: PlanetSideGameObject with FactionAffinity => SourceEntry(o) })
case _ => ()
}
protected def engageNewDetectedTarget(
target: AutomatedTurret.Target,
channel: String,
turretGuid: PlanetSideGUID,
weaponGuid: PlanetSideGUID
): Unit = {
val zone = target.Zone
AutomatedTurretBehavior.startTracking(zone, channel, turretGuid, List(target.GUID))
AutomatedTurretBehavior.startShooting(zone, channel, weaponGuid)
}
protected def noLongerEngageTarget(
target: AutomatedTurret.Target,
channel: String,
turretGuid: PlanetSideGUID,
weaponGuid: PlanetSideGUID
): Option[AutomatedTurret.Target] = {
val zone = target.Zone
AutomatedTurretBehavior.stopTracking(zone, channel, turretGuid)
AutomatedTurretBehavior.stopShooting(zone, channel, weaponGuid)
None
}
protected def testNewDetected(
target: AutomatedTurret.Target,
channel: String,
turretGuid: PlanetSideGUID,
weaponGuid: PlanetSideGUID
): Unit = {
val zone = target.Zone
AutomatedTurretBehavior.startTracking(zone, channel, turretGuid, List(target.GUID))
AutomatedTurretBehavior.startShooting(zone, channel, weaponGuid)
AutomatedTurretBehavior.stopShooting(zone, channel, weaponGuid)
}
protected def testKnownDetected(
target: AutomatedTurret.Target,
channel: String,
turretGuid: PlanetSideGUID,
weaponGuid: PlanetSideGUID
): Unit = {
val zone = target.Zone
AutomatedTurretBehavior.startShooting(zone, channel, weaponGuid)
AutomatedTurretBehavior.stopShooting(zone, channel, weaponGuid)
}
override protected def suspendTargetTesting(
target: Target,
channel: String,
turretGuid: PlanetSideGUID,
weaponGuid: PlanetSideGUID
): Unit = {
AutomatedTurretBehavior.stopTracking(target.Zone, channel, turretGuid)
}
override protected def mountTest(
obj: PlanetSideServerObject with Mountable,
seatNumber: Int,
player: Player): Boolean = {
(!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 (JammableObject.Jammed && AutomatedTurretObject.Definition.AutoFire.exists(_.retaliatoryDelay > 0)) {
if (startsUnjammed) {
AutomaticOperation = false
}
//look in direction of cause of jamming
val zone = JammableObject.Zone
AutomatedTurretBehavior.getAttackVectorFromCause(zone, cause).foreach { attacker =>
AutomatedTurretBehavior.startTracking(zone, zone.id, AutomatedTurretObject.GUID, List(attacker.GUID))
}
}
}
override def CancelJammeredStatus(target: Any): Unit = {
val startsJammed = JammableObject.Jammed
super.CancelJammeredStatus(target)
if (startsJammed && AutomaticOperation_=(state = true)) {
val zone = TurretObject.Zone
AutomatedTurretBehavior.stopTracking(zone, zone.id, TurretObject.GUID)
}
}
override protected def DamageAwareness(target: Damageable.Target, cause: DamageResult, amount: Any): Unit = {
amount match {
case 0 => ()
case _ => attemptRetaliation(target, cause)
}
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 = {
AutomaticOperation = false
super.DestructionAwareness(target, cause) super.DestructionAwareness(target, cause)
CancelJammeredSound(target) Deployables.AnnounceDestroyDeployable(DeployableObject, None)
CancelJammeredStatus(target)
Deployables.AnnounceDestroyDeployable(turret, None)
} }
override def deconstructDeployable(time: Option[FiniteDuration]) : Unit = { override def deconstructDeployable(time: Option[FiniteDuration]) : Unit = {
AutomaticOperation = false val zone = TurretObject.Zone
val zone = turret.Zone val seats = TurretObject.Seats.values
val seats = turret.Seats.values
//either we have no seats or no one gets to sit //either we have no seats or no one gets to sit
val retime = if (seats.count(_.isOccupied) > 0) { val retime = if (seats.count(_.isOccupied) > 0) {
//it's possible to request deconstruction of one's own field turret while seated in it //it's possible to request deconstruction of one's own field turret while seated in it
@ -254,7 +110,7 @@ class TurretControl(turret: TurretDeployable)
player.VehicleSeated = None player.VehicleSeated = None
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! VehicleServiceMessage(
zone.id, zone.id,
VehicleAction.KickPassenger(player.GUID, 4, wasKickedByDriver, turret.GUID) VehicleAction.KickPassenger(player.GUID, 4, wasKickedByDriver, TurretObject.GUID)
) )
} }
} }
@ -265,31 +121,8 @@ class TurretControl(turret: TurretDeployable)
super.deconstructDeployable(retime) super.deconstructDeployable(retime)
} }
override def finalizeDeployable(callback: ActorRef): Unit = {
super.finalizeDeployable(callback)
AutomaticOperation = true
}
override def unregisterDeployable(obj: Deployable): Unit = { override def unregisterDeployable(obj: Deployable): Unit = {
val zone = obj.Zone val zone = obj.Zone
TaskWorkflow.execute(GUIDTask.unregisterDeployableTurret(zone.GUID, turret)) TaskWorkflow.execute(GUIDTask.unregisterDeployableTurret(zone.GUID, TurretObject))
}
//make certain vehicles don't charge shields too quickly
def canChargeShields: Boolean = {
val func: InGameActivity => Boolean = WithShields.LastShieldChargeOrDamage(System.currentTimeMillis(), turret.Definition)
turret.Health > 0 && turret.Shields < turret.MaxShields &&
turret.History.findLast(func).isEmpty
}
def chargeShields(amount: Int, motivator: Option[SourceEntry]): Unit = {
if (canChargeShields) {
turret.LogActivity(ShieldCharge(amount, motivator))
turret.Shields = turret.Shields + amount
turret.Zone.VehicleEvents ! VehicleServiceMessage(
s"${turret.Actor}",
VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), turret.GUID, turret.Definition.shieldUiAttribute, turret.Shields)
)
}
} }
} }

View file

@ -1,72 +1,29 @@
// Copyright (c) 2023 PSForever // Copyright (c) 2023 PSForever
package net.psforever.objects.serverobject.turret package net.psforever.objects.serverobject.turret
import akka.actor.Actor
import net.psforever.objects.Player import net.psforever.objects.Player
import net.psforever.objects.equipment.JammableMountedWeapons
import net.psforever.objects.serverobject.PlanetSideServerObject 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.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 trait MountableTurretControl
extends Actor extends TurretControl
with FactionAffinityBehavior.Check with MountableBehavior {
with MountableBehavior override def TurretObject: PlanetSideServerObject with WeaponTurret with Mountable
with DamageableWeaponTurret
with RepairableWeaponTurret
with JammableMountedWeapons { /* note: jammable status is reported as vehicle events, not local events */
def TurretObject: PlanetSideServerObject with WeaponTurret with Mountable
override def postStop(): Unit = {
super.postStop()
damageableWeaponTurretPostStop()
}
/** commonBehavior does not implement mountingBehavior; please do so when implementing */ /** commonBehavior does not implement mountingBehavior; please do so when implementing */
def commonBehavior: Receive = override def commonBehavior: Receive =
checkBehavior super.commonBehavior
.orElse(jammableBehavior)
.orElse(dismountBehavior) .orElse(dismountBehavior)
.orElse(takesDamage)
.orElse(canBeRepairedByNanoDispenser)
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
(!TurretObject.Definition.FactionLocked || player.Faction == obj.Faction) && !obj.Destroyed ): Boolean = MountableTurret.MountTest(TurretObject, player)
} }
/** object MountableTurret {
* An override for `Restoration`, best for facility turrets. def MountTest(obj: PlanetSideServerObject with WeaponTurret with Mountable, player: Player): Boolean = {
* @param obj the entity being restored (!obj.Definition.FactionLocked || player.Faction == obj.Faction) && !obj.Destroyed
*/
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))
} }
} }

View file

@ -0,0 +1,62 @@
// Copyright (c) 2023 PSForever
package net.psforever.objects.serverobject.turret
import akka.actor.Actor
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.repair.RepairableWeaponTurret
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
trait TurretControl
extends Actor
with FactionAffinityBehavior.Check
with DamageableWeaponTurret
with RepairableWeaponTurret
with JammableMountedWeapons { /* note: jammable status is reported as vehicle events, not local events */
def TurretObject: PlanetSideServerObject with WeaponTurret
override def postStop(): Unit = {
super.postStop()
damageableWeaponTurretPostStop()
}
def commonBehavior: Receive =
checkBehavior
.orElse(jammableBehavior)
.orElse(takesDamage)
.orElse(canBeRepairedByNanoDispenser)
/**
* An override for `Restoration`, best for 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 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
CancelJammeredSound(target)
CancelJammeredStatus(target)
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 50, 1))
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 51, 1))
}
}

View file

@ -784,7 +784,7 @@ class DamageableWeaponTurretDamageTest extends ActorTest {
zone.AvatarEvents = avatarProbe.ref zone.AvatarEvents = avatarProbe.ref
zone.VehicleEvents = vehicleProbe.ref zone.VehicleEvents = vehicleProbe.ref
val turret = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) //2 val turret = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) //2
turret.Actor = system.actorOf(Props(classOf[TurretControl], turret), "turret-control") turret.Actor = system.actorOf(Props(classOf[TurretDeployableControl], turret), "turret-control")
turret.Zone = zone turret.Zone = zone
turret.Position = Vector3(1, 0, 0) turret.Position = Vector3(1, 0, 0)
turret.LogActivity(SpawningActivity(SourceEntry(turret), zone.Number, None)) //seed a spawn event turret.LogActivity(SpawningActivity(SourceEntry(turret), zone.Number, None)) //seed a spawn event
@ -882,7 +882,7 @@ class DamageableWeaponTurretJammerTest extends ActorTest {
zone.VehicleEvents = vehicleProbe.ref zone.VehicleEvents = vehicleProbe.ref
val turret = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) //2, 5, 6 val turret = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) //2, 5, 6
turret.Actor = system.actorOf(Props(classOf[TurretControl], turret), "turret-control") turret.Actor = system.actorOf(Props(classOf[TurretDeployableControl], turret), "turret-control")
turret.Zone = zone turret.Zone = zone
turret.Position = Vector3(1, 0, 0) turret.Position = Vector3(1, 0, 0)
val turretWeapon = turret.Weapons.values.head.Equipment.get.asInstanceOf[Tool] val turretWeapon = turret.Weapons.values.head.Equipment.get.asInstanceOf[Tool]

View file

@ -597,7 +597,7 @@ class TurretControlConstructTest extends ActorTest {
"TurretControl" should { "TurretControl" should {
"construct" in { "construct" in {
val obj = new TurretDeployable(GlobalDefinitions.spitfire_turret) val obj = new TurretDeployable(GlobalDefinitions.spitfire_turret)
system.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_test") system.actorOf(Props(classOf[TurretDeployableControl], obj), s"${obj.Definition.Name}_test")
} }
} }
} }
@ -642,7 +642,7 @@ class TurretControlMountTest extends ActorTest {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
this.actor = new TestProbe(system).ref.toTyped[ZoneActor.Command] this.actor = new TestProbe(system).ref.toTyped[ZoneActor.Command]
} }
obj.Actor = system.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_test") obj.Actor = system.actorOf(Props(classOf[TurretDeployableControl], obj), s"${obj.Definition.Name}_test")
assert(obj.Seats(0).occupant.isEmpty) assert(obj.Seats(0).occupant.isEmpty)
val player1 = Player(Avatar(0, "test1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute)) val player1 = Player(Avatar(0, "test1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute))
@ -662,7 +662,7 @@ class TurretControlBlockMountTest extends ActorTest {
"block mounting by others if already mounted by someone" in { "block mounting by others if already mounted by someone" in {
val obj = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) { GUID = PlanetSideGUID(1) } val obj = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) { GUID = PlanetSideGUID(1) }
obj.Faction = PlanetSideEmpire.TR obj.Faction = PlanetSideEmpire.TR
obj.Actor = system.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_test") obj.Actor = system.actorOf(Props(classOf[TurretDeployableControl], obj), s"${obj.Definition.Name}_test")
obj.Zone = new Zone("test", new ZoneMap("test"), 0) { obj.Zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
this.actor = new TestProbe(system).ref.toTyped[ZoneActor.Command] this.actor = new TestProbe(system).ref.toTyped[ZoneActor.Command]
@ -694,7 +694,7 @@ class TurretControlBlockBetrayalMountTest extends ActorTest {
"block mounting by players of another faction" in { "block mounting by players of another faction" in {
val obj = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) { GUID = PlanetSideGUID(1) } val obj = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) { GUID = PlanetSideGUID(1) }
obj.Faction = PlanetSideEmpire.TR obj.Faction = PlanetSideEmpire.TR
obj.Actor = system.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_test") obj.Actor = system.actorOf(Props(classOf[TurretDeployableControl], obj), s"${obj.Definition.Name}_test")
assert(obj.Seats(0).occupant.isEmpty) assert(obj.Seats(0).occupant.isEmpty)
val player = Player(Avatar(0, "test", PlanetSideEmpire.VS, CharacterSex.Male, 0, CharacterVoice.Mute)) val player = Player(Avatar(0, "test", PlanetSideEmpire.VS, CharacterSex.Male, 0, CharacterVoice.Mute))
@ -718,7 +718,7 @@ class TurretControlDismountTest extends ActorTest {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
this.actor = new TestProbe(system).ref.toTyped[ZoneActor.Command] this.actor = new TestProbe(system).ref.toTyped[ZoneActor.Command]
} }
obj.Actor = system.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_test") obj.Actor = system.actorOf(Props(classOf[TurretDeployableControl], obj), s"${obj.Definition.Name}_test")
assert(obj.Seats(0).occupant.isEmpty) assert(obj.Seats(0).occupant.isEmpty)
val player = Player(Avatar(0, "test", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute)) val player = Player(Avatar(0, "test", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute))
@ -758,7 +758,7 @@ class TurretControlBetrayalMountTest extends ActorTest {
} }
} }
obj.Faction = PlanetSideEmpire.TR obj.Faction = PlanetSideEmpire.TR
obj.Actor = system.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_test") obj.Actor = system.actorOf(Props(classOf[TurretDeployableControl], obj), s"${obj.Definition.Name}_test")
val probe = new TestProbe(system) val probe = new TestProbe(system)
assert(obj.Seats(0).occupant.isEmpty) assert(obj.Seats(0).occupant.isEmpty)