mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-19 18:14:44 +00:00
Hijacking Turrets (#1207)
* omft jacking functional; omft shields have been wired but remain disabled * breaking up classes related to different kinds of turret deployables
This commit is contained in:
parent
92063ba3a2
commit
593caec8cf
|
|
@ -37,6 +37,7 @@ import net.psforever.objects.vital.{VehicleDismountActivity, VehicleMountActivit
|
|||
import net.psforever.objects.vital.collision.{CollisionReason, CollisionWithReason}
|
||||
import net.psforever.objects.vital.etc.SuicideReason
|
||||
import net.psforever.objects.vital.interaction.DamageInteraction
|
||||
import net.psforever.objects.zones.blockmap.BlockMapEntity
|
||||
import net.psforever.objects.zones.{Zone, ZoneProjectile, Zoning}
|
||||
import net.psforever.packet.PlanetSideGamePacket
|
||||
import net.psforever.packet.game.objectcreate.ObjectClass
|
||||
|
|
@ -117,10 +118,9 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
|
|||
}
|
||||
}
|
||||
ops.fallHeightTracker(pos.z)
|
||||
if (isCrouching && !player.Crouching) {
|
||||
//dev stuff goes here
|
||||
sendResponse(CreateShortcutMessage(player.GUID, 2, Some(Shortcut.Implant("second_wind"))))
|
||||
}
|
||||
// if (isCrouching && !player.Crouching) {
|
||||
// //dev stuff goes here
|
||||
// }
|
||||
player.Position = pos
|
||||
player.Velocity = vel
|
||||
player.Orientation = Vector3(player.Orientation.x, pitch, yaw)
|
||||
|
|
@ -813,19 +813,18 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
|
|||
continent
|
||||
.GUID(vehicleGuid)
|
||||
.foreach {
|
||||
case obj: Vehicle if !obj.Destroyed && obj.MountedIn.isEmpty => // vehicle will try to charge even if destroyed & cargo vehicles need to be excluded
|
||||
obj.Actor ! CommonMessages.ChargeShields(
|
||||
15,
|
||||
Some(continent.blockMap.sector(obj).buildingList.maxBy(_.Definition.SOIRadius))
|
||||
)
|
||||
case obj: Vehicle if obj.MountedIn.nonEmpty =>
|
||||
false
|
||||
case obj: Vitality if obj.Destroyed => () //some entities will try to charge even if destroyed
|
||||
case obj: Vehicle if obj.MountedIn.nonEmpty => () //cargo vehicles need to be excluded
|
||||
case obj: Vehicle =>
|
||||
commonFacilityShieldCharging(obj)
|
||||
case obj: TurretDeployable =>
|
||||
commonFacilityShieldCharging(obj)
|
||||
case _ if vehicleGuid.nonEmpty =>
|
||||
log.warn(
|
||||
s"FacilityBenefitShieldChargeRequest: ${player.Name} can not find vehicle ${vehicleGuid.get.guid} in zone ${continent.id}"
|
||||
s"FacilityBenefitShieldChargeRequest: ${player.Name} can not find chargeable entity ${vehicleGuid.get.guid} in ${continent.id}"
|
||||
)
|
||||
case _ =>
|
||||
log.warn(s"FacilityBenefitShieldChargeRequest: ${player.Name} is not seated in a vehicle")
|
||||
log.warn(s"FacilityBenefitShieldChargeRequest: ${player.Name} is not seated in anything")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1532,4 +1531,11 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
|
|||
)
|
||||
)
|
||||
}
|
||||
|
||||
private def commonFacilityShieldCharging(obj: PlanetSideServerObject with BlockMapEntity): Unit = {
|
||||
obj.Actor ! CommonMessages.ChargeShields(
|
||||
15,
|
||||
Some(continent.blockMap.sector(obj).buildingList.maxBy(_.Definition.SOIRadius))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1023,11 +1023,11 @@ object GlobalDefinitions {
|
|||
|
||||
val jammer_mine: MineDeployableDefinition = MineDeployableDefinition(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)
|
||||
|
||||
|
|
@ -1035,13 +1035,13 @@ object GlobalDefinitions {
|
|||
|
||||
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
|
||||
|
||||
|
|
|
|||
158
src/main/scala/net/psforever/objects/SmallTurretDeployable.scala
Normal file
158
src/main/scala/net/psforever/objects/SmallTurretDeployable.scala
Normal 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
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +1,26 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects
|
||||
|
||||
import akka.actor.{Actor, ActorContext, ActorRef, Props}
|
||||
import net.psforever.objects.ce.{Deployable, DeployableBehavior, DeployedItem, InteractWithTurrets}
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.ce.{Deployable, DeployableBehavior, InteractWithTurrets}
|
||||
import net.psforever.objects.definition.DeployableDefinition
|
||||
import net.psforever.objects.definition.converter.SmallTurretConverter
|
||||
import net.psforever.objects.equipment.JammableUnit
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
||||
import net.psforever.objects.serverobject.damage.Damageable
|
||||
import net.psforever.objects.serverobject.hackable.Hackable
|
||||
import net.psforever.objects.serverobject.mount.{InteractWithRadiationCloudsSeatedInEntity, Mountable}
|
||||
import net.psforever.objects.serverobject.turret.auto.AutomatedTurret.Target
|
||||
import net.psforever.objects.serverobject.turret.auto.{AffectedByAutomaticTurretFire, AutomatedTurret, AutomatedTurretBehavior}
|
||||
import net.psforever.objects.serverobject.turret.{MountableTurretControl, TurretDefinition, WeaponTurret}
|
||||
import net.psforever.objects.serverobject.mount.InteractWithRadiationCloudsSeatedInEntity
|
||||
import net.psforever.objects.serverobject.turret.auto.{AffectedByAutomaticTurretFire, AutomatedTurret}
|
||||
import net.psforever.objects.serverobject.turret.{TurretControl, TurretDefinition, WeaponTurret}
|
||||
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
|
||||
import net.psforever.objects.vital.damage.DamageCalculations
|
||||
import net.psforever.objects.vital.interaction.DamageResult
|
||||
import net.psforever.objects.vital.resistance.StandardResistanceProfile
|
||||
import net.psforever.objects.vital.{SimpleResolutions, StandardVehicleResistance}
|
||||
import net.psforever.objects.zones.InteractsWithZone
|
||||
import net.psforever.packet.game.TriggeredSound
|
||||
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||
import net.psforever.types.PlanetSideGUID
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
|
|
@ -34,6 +32,9 @@ class TurretDeployable(tdef: TurretDeployableDefinition)
|
|||
with InteractsWithZone
|
||||
with StandardResistanceProfile
|
||||
with Hackable {
|
||||
HackSound = TriggeredSound.HackVehicle
|
||||
HackDuration = Array(0, 20, 10, 5)
|
||||
|
||||
if (tdef.Seats.nonEmpty) {
|
||||
interaction(new InteractWithTurrets())
|
||||
interaction(new InteractWithRadiationCloudsSeatedInEntity(obj = this, range = 100f))
|
||||
|
|
@ -50,10 +51,12 @@ class TurretDeployable(tdef: TurretDeployableDefinition)
|
|||
.getOrElse(SourceEntry(this))
|
||||
}
|
||||
|
||||
override def MaxShields: Int = Definition.MaxShields
|
||||
|
||||
override def Definition: TurretDeployableDefinition = tdef
|
||||
}
|
||||
|
||||
class TurretDeployableDefinition(private val objectId: Int)
|
||||
abstract class TurretDeployableDefinition(private val objectId: Int)
|
||||
extends DeployableDefinition(objectId)
|
||||
with TurretDefinition {
|
||||
Name = "turret_deployable"
|
||||
|
|
@ -66,161 +69,36 @@ class TurretDeployableDefinition(private val objectId: Int)
|
|||
override def MaxHealth: Int = super[DeployableDefinition].MaxHealth
|
||||
//override to clarify inheritance conflict
|
||||
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 */
|
||||
|
||||
class TurretControl(turret: TurretDeployable)
|
||||
abstract class TurretDeployableControl
|
||||
extends Actor
|
||||
with DeployableBehavior
|
||||
with FactionAffinityBehavior.Check
|
||||
with MountableTurretControl
|
||||
with AutomatedTurretBehavior
|
||||
with TurretControl
|
||||
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 = {
|
||||
super.postStop()
|
||||
deployableBehaviorPostStop()
|
||||
selfReportingDatabaseUpdate()
|
||||
automaticTurretPostStop()
|
||||
}
|
||||
|
||||
def receive: Receive =
|
||||
commonBehavior
|
||||
override def commonBehavior: Receive =
|
||||
super.commonBehavior
|
||||
.orElse(deployableBehavior)
|
||||
.orElse(checkBehavior)
|
||||
.orElse(mountBehavior)
|
||||
.orElse(automatedTurretBehavior)
|
||||
.orElse(takeAutomatedDamage)
|
||||
.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 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 = {
|
||||
AutomaticOperation = false
|
||||
super.DestructionAwareness(target, cause)
|
||||
CancelJammeredSound(target)
|
||||
CancelJammeredStatus(target)
|
||||
Deployables.AnnounceDestroyDeployable(turret, None)
|
||||
Deployables.AnnounceDestroyDeployable(DeployableObject, None)
|
||||
}
|
||||
|
||||
override def deconstructDeployable(time: Option[FiniteDuration]) : Unit = {
|
||||
AutomaticOperation = false
|
||||
val zone = turret.Zone
|
||||
val seats = turret.Seats.values
|
||||
val zone = TurretObject.Zone
|
||||
val seats = TurretObject.Seats.values
|
||||
//either we have no seats or no one gets to sit
|
||||
val retime = if (seats.count(_.isOccupied) > 0) {
|
||||
//it's possible to request deconstruction of one's own field turret while seated in it
|
||||
|
|
@ -232,7 +110,7 @@ class TurretControl(turret: TurretDeployable)
|
|||
player.VehicleSeated = None
|
||||
zone.VehicleEvents ! VehicleServiceMessage(
|
||||
zone.id,
|
||||
VehicleAction.KickPassenger(player.GUID, 4, wasKickedByDriver, turret.GUID)
|
||||
VehicleAction.KickPassenger(player.GUID, 4, wasKickedByDriver, TurretObject.GUID)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -243,13 +121,8 @@ 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))
|
||||
TaskWorkflow.execute(GUIDTask.unregisterDeployableTurret(zone.GUID, TurretObject))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,7 @@ trait BaseDeployable
|
|||
Shields
|
||||
}
|
||||
|
||||
def MaxShields: Int = {
|
||||
0 //Definition.MaxShields
|
||||
}
|
||||
def MaxShields: Int = 0
|
||||
|
||||
def MaxHealth: Int
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package net.psforever.objects.definition
|
||||
|
||||
import net.psforever.objects.vital.{DamagingActivity, InGameActivity, ShieldCharge}
|
||||
|
||||
trait WithShields {
|
||||
/** ... */
|
||||
var shieldUiAttribute: Int = 68
|
||||
|
|
@ -7,6 +9,7 @@ trait WithShields {
|
|||
private var defaultShields : Option[Int] = None
|
||||
/** maximum vehicle shields (generally: 20% of health)
|
||||
* for normal vehicles, offered through amp station facility benefits
|
||||
* for omft, gained in friendly soi (in which the turret may not be constructed)
|
||||
* for BFR's, it charges naturally
|
||||
**/
|
||||
private var maxShields: Int = 0
|
||||
|
|
@ -79,3 +82,20 @@ trait WithShields {
|
|||
ShieldDrain
|
||||
}
|
||||
}
|
||||
|
||||
object WithShields {
|
||||
/**
|
||||
* Determine if a given activity entry would invalidate the act of charging shields this tick.
|
||||
* @param now the current time (in milliseconds)
|
||||
* @param act a `VitalsActivity` entry to test
|
||||
* @return `true`, if the shield charge would be blocked;
|
||||
* `false`, otherwise
|
||||
*/
|
||||
def LastShieldChargeOrDamage(now: Long, vdef: WithShields)(act: InGameActivity): Boolean = {
|
||||
act match {
|
||||
case dact: DamagingActivity => now - dact.time < vdef.ShieldDamageDelay //damage delays next charge
|
||||
case vsc: ShieldCharge => now - vsc.time < vdef.ShieldPeriodicDelay //previous charge delays next
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -318,6 +318,7 @@ object GlobalDefinitionsDeployable {
|
|||
portable_manned_turret.Damageable = true
|
||||
portable_manned_turret.Repairable = true
|
||||
portable_manned_turret.RepairIfDestroyed = false
|
||||
portable_manned_turret.MaxShields = 0//200
|
||||
portable_manned_turret.WeaponPaths += 1 -> new mutable.HashMap()
|
||||
portable_manned_turret.WeaponPaths(1) += TurretUpgrade.None -> energy_gun
|
||||
portable_manned_turret.Seats += 0 -> new SeatDefinition()
|
||||
|
|
@ -352,6 +353,7 @@ object GlobalDefinitionsDeployable {
|
|||
portable_manned_turret_nc.Damageable = true
|
||||
portable_manned_turret_nc.Repairable = true
|
||||
portable_manned_turret_nc.RepairIfDestroyed = false
|
||||
portable_manned_turret_nc.MaxShields = 0//200
|
||||
portable_manned_turret_nc.WeaponPaths += 1 -> new mutable.HashMap()
|
||||
portable_manned_turret_nc.WeaponPaths(1) += TurretUpgrade.None -> energy_gun_nc
|
||||
portable_manned_turret_nc.Seats += 0 -> new SeatDefinition()
|
||||
|
|
@ -385,6 +387,7 @@ object GlobalDefinitionsDeployable {
|
|||
portable_manned_turret_tr.Damageable = true
|
||||
portable_manned_turret_tr.Repairable = true
|
||||
portable_manned_turret_tr.RepairIfDestroyed = false
|
||||
portable_manned_turret_tr.MaxShields = 0//200
|
||||
portable_manned_turret_tr.WeaponPaths += 1 -> new mutable.HashMap()
|
||||
portable_manned_turret_tr.WeaponPaths(1) += TurretUpgrade.None -> energy_gun_tr
|
||||
portable_manned_turret_tr.Seats += 0 -> new SeatDefinition()
|
||||
|
|
@ -418,6 +421,7 @@ object GlobalDefinitionsDeployable {
|
|||
portable_manned_turret_vs.Damageable = true
|
||||
portable_manned_turret_vs.Repairable = true
|
||||
portable_manned_turret_vs.RepairIfDestroyed = false
|
||||
portable_manned_turret_vs.MaxShields = 0//200
|
||||
portable_manned_turret_vs.WeaponPaths += 1 -> new mutable.HashMap()
|
||||
portable_manned_turret_vs.WeaponPaths(1) += TurretUpgrade.None -> energy_gun_vs
|
||||
portable_manned_turret_vs.Seats += 0 -> new SeatDefinition()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) 2020 PSForever
|
||||
package net.psforever.objects.serverobject.hackable
|
||||
|
||||
import net.psforever.objects.serverobject.turret.FacilityTurret
|
||||
import net.psforever.objects.{Player, Vehicle}
|
||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||
import net.psforever.packet.game.{HackMessage, HackState}
|
||||
|
|
@ -45,18 +44,18 @@ object GenericHackables {
|
|||
case hackable: Hackable => hackable.HackDuration(playerHackLevel).toFloat
|
||||
case _ =>
|
||||
log.warn(
|
||||
s"${player.Name} tried to hack an object that has no hack time defined - ${obj.Definition.Name}#${obj.GUID} on ${obj.Zone.id}"
|
||||
s"${player.Name} tried to hack an object that has no hack time defined - ${obj.Definition.Name}@${obj.GUID.guid} in ${obj.Zone.id}"
|
||||
)
|
||||
0f
|
||||
}
|
||||
if (timeToHack == 0) {
|
||||
log.warn(
|
||||
s"${player.Name} tried to hack an object that they don't have the correct hacking level for - ${obj.Definition.Name}#${obj.GUID} on ${obj.Zone.id}"
|
||||
s"${player.Name} tried to hack an object that they don't have the correct hacking level for - ${obj.Definition.Name}@${obj.GUID.guid} in ${obj.Zone.id}"
|
||||
)
|
||||
0f
|
||||
} else {
|
||||
//timeToHack is in seconds; progress is measured in quarters of a second (250ms)
|
||||
(100f / timeToHack) / 4
|
||||
25f / timeToHack
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -108,43 +107,6 @@ object GenericHackables {
|
|||
vis != HackState.Cancelled
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the progress of the user applying a tool to upgrade a facility turret.
|
||||
* This action is using the nano dispenser and requires separate handling from REK hacking.
|
||||
* Largely a copy/paste of the above, but some of it was removed as it doesn't work/apply with upgrading a turret.
|
||||
* @see `HackMessage`
|
||||
* @see `HackState`
|
||||
* @param progressType 1 - remote electronics kit hack (various ...);
|
||||
* 2 - nano dispenser (upgrade canister) turret upgrade
|
||||
* @param tplayer the player performing the action
|
||||
* @param turret the object being affected
|
||||
* @param tool_guid the tool being used to affest the object
|
||||
* @param progress the current progress value
|
||||
* @return `true`, if the next cycle of progress should occur;
|
||||
* `false`, otherwise
|
||||
*/
|
||||
def TurretUpgradingTickAction(progressType: Int, tplayer: Player, turret: FacilityTurret, tool_guid: PlanetSideGUID)(
|
||||
progress: Float
|
||||
): Boolean = {
|
||||
//hack state for progress bar visibility
|
||||
val vis = if (progress <= 0L) {
|
||||
HackState.Start
|
||||
} else if (progress >= 100L) {
|
||||
HackState.Finished
|
||||
} else {
|
||||
updateTurretUpgradeTime()
|
||||
HackState.Ongoing
|
||||
}
|
||||
turret.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
tplayer.Name,
|
||||
AvatarAction.SendResponse(
|
||||
Service.defaultPlayerGUID,
|
||||
HackMessage(progressType, turret.GUID, tplayer.GUID, progress.toInt, 0L, vis, 8L)
|
||||
)
|
||||
)
|
||||
vis != HackState.Cancelled
|
||||
}
|
||||
|
||||
/**
|
||||
* The process of hacking an object is completed.
|
||||
* Pass the message onto the hackable object and onto the local events system.
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ class FacilityTurretControl(turret: FacilityTurret)
|
|||
sender() ! CommonMessages.Progress(
|
||||
1.25f,
|
||||
WeaponTurrets.FinishUpgradingMannedTurret(TurretObject, player, item, upgrade),
|
||||
GenericHackables.TurretUpgradingTickAction(progressType = 2, player, TurretObject, item.GUID)
|
||||
WeaponTurrets.TurretUpgradingTickAction(progressType = 2, player, TurretObject, item.GUID)
|
||||
)
|
||||
}
|
||||
case TurretUpgrader.UpgradeCompleted(_) =>
|
||||
|
|
|
|||
|
|
@ -1,72 +1,29 @@
|
|||
// 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 Actor
|
||||
with FactionAffinityBehavior.Check
|
||||
with MountableBehavior
|
||||
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()
|
||||
}
|
||||
extends TurretControl
|
||||
with MountableBehavior {
|
||||
override def TurretObject: PlanetSideServerObject with WeaponTurret with Mountable
|
||||
|
||||
/** commonBehavior does not implement mountingBehavior; please do so when implementing */
|
||||
def commonBehavior: Receive =
|
||||
checkBehavior
|
||||
.orElse(jammableBehavior)
|
||||
override def commonBehavior: Receive =
|
||||
super.commonBehavior
|
||||
.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
|
||||
}
|
||||
player: Player
|
||||
): Boolean = MountableTurret.MountTest(TurretObject, player)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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))
|
||||
object MountableTurret {
|
||||
def MountTest(obj: PlanetSideServerObject with WeaponTurret with Mountable, player: Player): Boolean = {
|
||||
(!obj.Definition.FactionLocked || player.Faction == obj.Faction) && !obj.Destroyed
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,17 @@
|
|||
// Copyright (c) 2020 PSForever
|
||||
package net.psforever.objects.serverobject.turret
|
||||
|
||||
import net.psforever.objects.{Player, Tool}
|
||||
import net.psforever.packet.game.InventoryStateMessage
|
||||
import net.psforever.objects.avatar.Certification
|
||||
import net.psforever.objects.ce.Deployable
|
||||
import net.psforever.objects.serverobject.hackable.GenericHackables.updateTurretUpgradeTime
|
||||
import net.psforever.objects.{Player, Tool, TurretDeployable}
|
||||
import net.psforever.packet.game.{HackMessage, HackState, InventoryStateMessage}
|
||||
import net.psforever.services.Service
|
||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
import net.psforever.services.vehicle.VehicleServiceMessage
|
||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||
import net.psforever.services.vehicle.support.TurretUpgrader
|
||||
import net.psforever.types.PlanetSideGUID
|
||||
|
||||
object WeaponTurrets {
|
||||
private val log = org.log4s.getLogger("WeaponTurrets")
|
||||
|
|
@ -52,4 +57,76 @@ object WeaponTurrets {
|
|||
events ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.ClearSpecific(List(target), zone))
|
||||
events ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(target, zone, upgrade))
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the progress of the user applying a tool to upgrade a facility turret.
|
||||
* This action is using the nano dispenser and requires separate handling from REK hacking.
|
||||
* Largely a copy/paste of the above, but some of it was removed as it doesn't work/apply with upgrading a turret.
|
||||
* @see `HackMessage`
|
||||
* @see `HackState`
|
||||
* @param progressType 1 - remote electronics kit hack (various ...);
|
||||
* 2 - nano dispenser (upgrade canister) turret upgrade
|
||||
* @param tplayer the player performing the action
|
||||
* @param turret the object being affected
|
||||
* @param tool_guid the tool being used to affest the object
|
||||
* @param progress the current progress value
|
||||
* @return `true`, if the next cycle of progress should occur;
|
||||
* `false`, otherwise
|
||||
*/
|
||||
def TurretUpgradingTickAction(progressType: Int, tplayer: Player, turret: FacilityTurret, tool_guid: PlanetSideGUID)(
|
||||
progress: Float
|
||||
): Boolean = {
|
||||
//hack state for progress bar visibility
|
||||
val vis = if (progress <= 0L) {
|
||||
HackState.Start
|
||||
} else if (progress >= 100L) {
|
||||
HackState.Finished
|
||||
} else {
|
||||
updateTurretUpgradeTime()
|
||||
HackState.Ongoing
|
||||
}
|
||||
turret.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
tplayer.Name,
|
||||
AvatarAction.SendResponse(
|
||||
Service.defaultPlayerGUID,
|
||||
HackMessage(progressType, turret.GUID, tplayer.GUID, progress.toInt, 0L, vis, 8L)
|
||||
)
|
||||
)
|
||||
vis != HackState.Cancelled
|
||||
}
|
||||
|
||||
def FinishHackingTurretDeployable(target: TurretDeployable, hacker: Player)(): Unit = {
|
||||
org.log4s.getLogger("TurretDeployable").info(s"${hacker.Name} has jacked a ${target.Definition.Name}")
|
||||
val zone = target.Zone
|
||||
val certs = hacker.avatar.certifications
|
||||
if (certs.contains(Certification.ExpertHacking) || certs.contains(Certification.ElectronicsExpert)) {
|
||||
// Forcefully dismount all seated occupants from the turret
|
||||
target.Seats.values.foreach { seat =>
|
||||
seat.occupant.collect {
|
||||
player: Player =>
|
||||
seat.unmount(player)
|
||||
player.VehicleSeated = None
|
||||
zone.VehicleEvents ! VehicleServiceMessage(
|
||||
zone.id,
|
||||
VehicleAction.KickPassenger(player.GUID, 4, unk2 = false, target.GUID)
|
||||
)
|
||||
}
|
||||
}
|
||||
//hacker owns the deployable now
|
||||
target.OwnerGuid = None
|
||||
target.Actor ! Deployable.Ownership(hacker)
|
||||
//convert faction
|
||||
zone.AvatarEvents ! AvatarServiceMessage(
|
||||
zone.id,
|
||||
AvatarAction.SetEmpire(Service.defaultPlayerGUID, target.GUID, hacker.Faction)
|
||||
)
|
||||
zone.LocalEvents ! LocalServiceMessage(
|
||||
zone.id,
|
||||
LocalAction.TriggerSound(hacker.GUID, target.HackSound, target.Position, 30, 0.49803925f)
|
||||
)
|
||||
} else {
|
||||
//deconstruct
|
||||
target.Actor ! Deployable.Deconstruct()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package net.psforever.objects.vehicles.control
|
|||
import akka.actor.Cancellable
|
||||
import net.psforever.actors.zone.ZoneActor
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.definition.VehicleDefinition
|
||||
import net.psforever.objects.definition.{VehicleDefinition, WithShields}
|
||||
import net.psforever.objects.definition.converter.OCM
|
||||
import net.psforever.objects.entity.WorldEntity
|
||||
import net.psforever.objects.equipment.{ArmorSiphonBehavior, Equipment, EquipmentSlot, JammableMountedWeapons}
|
||||
|
|
@ -27,7 +27,7 @@ import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, VehicleSource}
|
|||
import net.psforever.objects.vehicles._
|
||||
import net.psforever.objects.vehicles.interaction.WithWater
|
||||
import net.psforever.objects.vital.interaction.DamageResult
|
||||
import net.psforever.objects.vital.{DamagingActivity, InGameActivity, ShieldCharge, SpawningActivity, VehicleDismountActivity, VehicleMountActivity}
|
||||
import net.psforever.objects.vital.{InGameActivity, ShieldCharge, SpawningActivity, VehicleDismountActivity, VehicleMountActivity}
|
||||
import net.psforever.objects.zones._
|
||||
import net.psforever.packet.PlanetSideGamePacket
|
||||
import net.psforever.packet.game._
|
||||
|
|
@ -562,7 +562,7 @@ class VehicleControl(vehicle: Vehicle)
|
|||
|
||||
//make certain vehicles don't charge shields too quickly
|
||||
def canChargeShields: Boolean = {
|
||||
val func: InGameActivity => Boolean = VehicleControl.LastShieldChargeOrDamage(System.currentTimeMillis(), vehicle.Definition)
|
||||
val func: InGameActivity => Boolean = WithShields.LastShieldChargeOrDamage(System.currentTimeMillis(), vehicle.Definition)
|
||||
vehicle.Health > 0 && vehicle.Shields < vehicle.MaxShields &&
|
||||
vehicle.History.findLast(func).isEmpty
|
||||
}
|
||||
|
|
@ -705,8 +705,6 @@ class VehicleControl(vehicle: Vehicle)
|
|||
}
|
||||
|
||||
object VehicleControl {
|
||||
import net.psforever.objects.vital.ShieldCharge
|
||||
|
||||
private case class PrepareForDeletion()
|
||||
|
||||
final case class Disable(kickPassengers: Boolean = false)
|
||||
|
|
@ -716,19 +714,4 @@ object VehicleControl {
|
|||
private case object RadiationTick
|
||||
|
||||
final case class AssignOwnership(player: Option[Player])
|
||||
|
||||
/**
|
||||
* Determine if a given activity entry would invalidate the act of charging vehicle shields this tick.
|
||||
* @param now the current time (in milliseconds)
|
||||
* @param act a `VitalsActivity` entry to test
|
||||
* @return `true`, if the shield charge would be blocked;
|
||||
* `false`, otherwise
|
||||
*/
|
||||
def LastShieldChargeOrDamage(now: Long, vdef: VehicleDefinition)(act: InGameActivity): Boolean = {
|
||||
act match {
|
||||
case dact: DamagingActivity => now - dact.time < vdef.ShieldDamageDelay //damage delays next charge
|
||||
case vsc: ShieldCharge => now - vsc.time < vdef.ShieldPeriodicDelay //previous charge delays next
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -775,7 +775,7 @@ class DamageableWeaponTurretDamageTest extends ActorTest {
|
|||
zone.AvatarEvents = avatarProbe.ref
|
||||
zone.VehicleEvents = vehicleProbe.ref
|
||||
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.Position = Vector3(1, 0, 0)
|
||||
turret.LogActivity(SpawningActivity(SourceEntry(turret), zone.Number, None)) //seed a spawn event
|
||||
|
|
@ -873,7 +873,7 @@ class DamageableWeaponTurretJammerTest extends ActorTest {
|
|||
zone.VehicleEvents = vehicleProbe.ref
|
||||
|
||||
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.Position = Vector3(1, 0, 0)
|
||||
val turretWeapon: Tool = turret.Weapons.values.head.Equipment.get.asInstanceOf[Tool]
|
||||
|
|
|
|||
|
|
@ -584,7 +584,7 @@ class TurretControlConstructTest extends ActorTest {
|
|||
"TurretControl" should {
|
||||
"construct" in {
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -629,7 +629,7 @@ class TurretControlMountTest extends ActorTest {
|
|||
override def SetupNumberPools() = {}
|
||||
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)
|
||||
val player1 = Player(Avatar(0, "test1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute))
|
||||
|
|
@ -649,7 +649,7 @@ class TurretControlBlockMountTest extends ActorTest {
|
|||
"block mounting by others if already mounted by someone" in {
|
||||
val obj = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) { GUID = PlanetSideGUID(1) }
|
||||
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) {
|
||||
override def SetupNumberPools() = {}
|
||||
this.actor = new TestProbe(system).ref.toTyped[ZoneActor.Command]
|
||||
|
|
@ -681,7 +681,7 @@ class TurretControlBlockBetrayalMountTest extends ActorTest {
|
|||
"block mounting by players of another faction" in {
|
||||
val obj = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) { GUID = PlanetSideGUID(1) }
|
||||
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)
|
||||
val player = Player(Avatar(0, "test", PlanetSideEmpire.VS, CharacterSex.Male, 0, CharacterVoice.Mute))
|
||||
|
|
@ -705,7 +705,7 @@ class TurretControlDismountTest extends ActorTest {
|
|||
override def SetupNumberPools() = {}
|
||||
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)
|
||||
val player = Player(Avatar(0, "test", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute))
|
||||
|
|
@ -746,7 +746,7 @@ class TurretControlBetrayalMountTest extends ActorTest {
|
|||
}
|
||||
}
|
||||
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)
|
||||
|
||||
assert(obj.Seats(0).occupant.isEmpty)
|
||||
|
|
|
|||
Loading…
Reference in a new issue