From 6a1412a71b269263a39b5b798e1cd336afa7d729 Mon Sep 17 00:00:00 2001 From: Fate-JH Date: Wed, 4 Sep 2024 00:04:43 -0400 Subject: [PATCH] fixed vehicle interference; added missing ArmorShieldOff message; clearing countdown after vehicle spawn should stop countdown from appearing in subsequent vehicle spawns --- .../session/support/GeneralOperations.scala | 3 + .../support/SessionLocalHandlers.scala | 9 +-- .../GlobalDefinitionsMiscellaneous.scala | 4 +- .../serverobject/deploy/Interference.scala | 6 +- .../pad/VehicleSpawnControl.scala | 27 ++++--- .../objects/zones/ZoneVehicleActor.scala | 79 ++++++++++++++----- 6 files changed, 85 insertions(+), 43 deletions(-) diff --git a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala index afbe13088..67bf09d4e 100644 --- a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala @@ -673,6 +673,9 @@ class GeneralOperations( case _ => () } } else { + if (player.Capacitor < 1f && player.UsingSpecial == SpecialExoSuitDefinition.Mode.Shielded) { + sendResponse(ChatMsg(ChatMessageType.UNK_227, "@ArmorShieldOff")) + } player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal continent.AvatarEvents ! AvatarServiceMessage( continent.id, diff --git a/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala index 7706b54ee..7fc6a893b 100644 --- a/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala +++ b/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala @@ -2,17 +2,12 @@ package net.psforever.actors.session.support import akka.actor.ActorContext -import net.psforever.objects.{PlanetSideGameObject, Players, TurretDeployable} +import net.psforever.objects.{Players, TurretDeployable} import net.psforever.objects.ce.Deployable import net.psforever.objects.guid.{GUIDTask, TaskWorkflow} -import net.psforever.objects.serverobject.environment.EnvironmentAttribute -import net.psforever.objects.serverobject.environment.interaction.InteractWithEnvironment -import net.psforever.objects.serverobject.environment.interaction.common.Watery import net.psforever.objects.serverobject.interior.Sidedness -import net.psforever.objects.serverobject.llu.CaptureFlag -import net.psforever.objects.zones.InteractsWithZone import net.psforever.packet.game.GenericObjectActionMessage -import net.psforever.services.local.{LocalAction, LocalResponse, LocalServiceMessage} +import net.psforever.services.local.LocalResponse import net.psforever.types.PlanetSideGUID trait LocalHandlerFunctions extends CommonSessionInterfacingFunctionality { diff --git a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala index 11059fbab..3c4650132 100644 --- a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala +++ b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala @@ -801,7 +801,7 @@ object GlobalDefinitionsMiscellaneous { AutoRanges( detection = 125f, trigger = 100f, - escape = 200f + escape = 150f ), AutoChecks( validation = List( @@ -813,7 +813,7 @@ object GlobalDefinitionsMiscellaneous { ), retaliatoryDelay = 4000L, //8000L cylindrical = true, - cylindricalExtraHeight = 50f, + cylindricalExtraHeight = 25f, detectionSweepTime = 2.seconds, refireTime = 362.milliseconds //312.milliseconds ) diff --git a/src/main/scala/net/psforever/objects/serverobject/deploy/Interference.scala b/src/main/scala/net/psforever/objects/serverobject/deploy/Interference.scala index 8b0cae70e..da5fba1a4 100644 --- a/src/main/scala/net/psforever/objects/serverobject/deploy/Interference.scala +++ b/src/main/scala/net/psforever/objects/serverobject/deploy/Interference.scala @@ -46,11 +46,11 @@ object Interference { * @param zone game world in which this test will be conducted; * entity should be `ZoneAware`, but it may not be set correctly during this part of its internal process * @param obj entity that may be interfered with - * @return a different entity that causes the test entity to suffer interference + * @return other entities that causes the test entity to suffer interference */ - def Test(zone: Zone, obj: PlanetSideGameObject with FactionAffinity): Option[PlanetSideGameObject with FactionAffinity] = { + def Test(zone: Zone, obj: PlanetSideGameObject with FactionAffinity): Seq[PlanetSideGameObject with FactionAffinity] = { val (data, filterFunc) = SetupForTest(zone, obj) - data.find(filterFunc) + data.filter(filterFunc) } /** diff --git a/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala b/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala index 375525032..29bd0f511 100644 --- a/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala @@ -80,7 +80,7 @@ class VehicleSpawnControl(pad: VehicleSpawnPad) } override def postStop() : Unit = { - periodicReminder.cancel() + discontinueCurrentReminder() queueManagement.cancel() } @@ -120,7 +120,7 @@ class VehicleSpawnControl(pad: VehicleSpawnPad) evaluateBlockedReminder() case VehicleSpawnControl.ProcessControl.Flush => - periodicReminder.cancel() + discontinueCurrentReminder() orders.foreach { CancelOrder(_, Some("@SVCP_RemovedFromVehicleQueue_Generic")) } orders = Nil trackedOrder.foreach { @@ -237,7 +237,7 @@ class VehicleSpawnControl(pad: VehicleSpawnPad) * `None`, if no order found or submitted */ private def ProcessOrder(order: Option[VehicleSpawnPad.VehicleOrder]): Unit = { - periodicReminder.cancel() + discontinueCurrentReminder() order.collect { case VehicleSpawnPad.VehicleOrder(driver, vehicle, terminal) => val size = orders.size + 1 @@ -347,32 +347,39 @@ class VehicleSpawnControl(pad: VehicleSpawnPad) retimePeriodicReminder( shaveOffFirstElementAndDiffSecondElement(pad.Definition.BlockedReminderMessageDelays) ) + trackedOrder } else if (reminderSeq.size == 1) { //end reminder standaloneBlockedReminder( VehicleSpawnPad.VehicleOrder(entry.driver, entry.vehicle, null), Some("@PadDeconstruct_Done") ) - periodicReminder.cancel() - periodicReminder = Default.Cancellable - reminderSeq = List() + None } else { //continue reminder BlockedReminder(entry, orders) retimePeriodicReminder( shaveOffFirstElementAndDiffSecondElement(reminderSeq) ) + trackedOrder } - trackedOrder } .orElse { - periodicReminder.cancel() - periodicReminder = Default.Cancellable - reminderSeq = List() + discontinueCurrentReminder() None } } + /** + * The periodic reminder will no longer be repeated. + * Sequences tied to the periodic reminder should be reset. + */ + private def discontinueCurrentReminder(): Unit = { + periodicReminder.cancel() + periodicReminder = Default.Cancellable + reminderSeq = List() + } + /** * na * @param blockedOrder the previous order whose vehicle is blocking the spawn pad from operating diff --git a/src/main/scala/net/psforever/objects/zones/ZoneVehicleActor.scala b/src/main/scala/net/psforever/objects/zones/ZoneVehicleActor.scala index 1b4195651..4e05d85d3 100644 --- a/src/main/scala/net/psforever/objects/zones/ZoneVehicleActor.scala +++ b/src/main/scala/net/psforever/objects/zones/ZoneVehicleActor.scala @@ -3,10 +3,10 @@ package net.psforever.objects.zones import akka.actor.Actor import net.psforever.actors.zone.ZoneActor -import net.psforever.objects.definition.VehicleDefinition +import net.psforever.objects.definition.{ObjectDefinition, VehicleDefinition} import net.psforever.objects.serverobject.deploy.{Deployment, Interference} import net.psforever.objects.vital.InGameHistory -import net.psforever.objects.{Default, GlobalDefinitions, Vehicle} +import net.psforever.objects.{Default, Vehicle} import net.psforever.packet.game.ChatMsg import net.psforever.services.Service import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} @@ -69,15 +69,18 @@ class ZoneVehicleActor( sender() ! Zone.Vehicle.CanNotDespawn(zone, vehicle, "can not find") } - case Zone.Vehicle.TryDeploymentChange(vehicle, toDeployState) - if toDeployState == DriveState.Deploying && - (ZoneVehicleActor.temporaryInterferenceTest(vehicle, temporaryInterference) || Interference.Test(zone, vehicle).nonEmpty) => - sender() ! Zone.Vehicle.CanNotDeploy(zone, vehicle, toDeployState, "blocked by a nearby entity") - - case Zone.Vehicle.TryDeploymentChange(vehicle, toDeployState) - if toDeployState == DriveState.Deploying => - tryAddToInterferenceField(vehicle.Position, vehicle.Faction, vehicle.Definition) - vehicle.Actor.tell(Deployment.TryDeploymentChange(toDeployState), sender()) + case Zone.Vehicle.TryDeploymentChange(vehicle, DriveState.Deploying) => + if (ZoneVehicleActor.ReportOnInterferenceResults( + zone, + vehicle, + ZoneVehicleActor.temporaryInterferenceTest(vehicle, temporaryInterference) ++ + Interference.Test(zone, vehicle).map(_.Definition) + )) { + sender() ! Zone.Vehicle.CanNotDeploy(zone, vehicle, DriveState.Deploying, "blocked by a nearby entity") + } else { + tryAddToInterferenceField(vehicle.Position, vehicle.Faction, vehicle.Definition) + vehicle.Actor.tell(Deployment.TryDeploymentChange(DriveState.Deploying), sender()) + } case Zone.Vehicle.TryDeploymentChange(vehicle, toDeployState) => vehicle.Actor.tell(Deployment.TryDeploymentChange(toDeployState), sender()) @@ -86,14 +89,16 @@ class ZoneVehicleActor( case Zone.Vehicle.CanNotDespawn(_, _, _) => () - case Zone.Vehicle.CanNotDeploy(_, vehicle, toState, _) - if vehicle.Definition == GlobalDefinitions.ams && - (toState == DriveState.Deploying || toState == DriveState.Deployed) => - val pos = vehicle.Position - zone.VehicleEvents ! VehicleServiceMessage( - vehicle.Seats.headOption.flatMap(_._2.occupant).map(_.Name).getOrElse("Driver"), - VehicleAction.SendResponse(Service.defaultPlayerGUID, ChatMsg(ChatMessageType.UNK_227, "@nodeploy_ams")) + case Zone.Vehicle.CanNotDeploy(_, vehicle, DriveState.Deploying, reason) => + ZoneVehicleActor.ReportOnInterferenceResults( + zone, + vehicle, + ZoneVehicleActor.temporaryInterferenceTest(vehicle, temporaryInterference) ++ + Interference.Test(zone, vehicle).map(_.Definition) ) + val pos = vehicle.Position + val driverMoniker = vehicle.Seats.headOption.flatMap(_._2.occupant).map(_.Name).getOrElse("Driver") + log.warn(s"$driverMoniker's ${vehicle.Definition.Name} can not deploy in ${zone.id} because $reason") temporaryInterference = temporaryInterference.filterNot(_._1 == pos) case Zone.Vehicle.CanNotDeploy(_, vehicle, _, reason) => @@ -146,22 +151,54 @@ object ZoneVehicleActor { private def temporaryInterferenceTest( vehicle: Vehicle, existingInterferences: Seq[(Vector3, PlanetSideEmpire.Value, VehicleDefinition)] - ): Boolean = { + ): Seq[VehicleDefinition] = { val vPosition = vehicle.Position val vFaction = vehicle.Faction val vDefinition = vehicle.Definition if (vDefinition.interference eq Interference.AllowAll) { - false + Nil } else { existingInterferences .collect { case (p, faction, d) if faction == vFaction => (p, d) } - .exists { case (position, definition) => + .filter { case (position, definition) => val interference = definition.interference (interference ne Interference.AllowAll) && { lazy val distanceSq = Vector3.DistanceSquared(position, vPosition) definition == vDefinition && distanceSq < interference.main * interference.main } } + .map(_._2) + } + } + + private def ReportOnInterferenceResults( + zone: Zone, + vehicle: Vehicle, + reportedInterferenceList: Seq[ObjectDefinition] + ): Boolean = { + if (reportedInterferenceList.nonEmpty) { + reportedInterferenceList + .find(_.isInstanceOf[VehicleDefinition]) + .map { definition => s"@nodeploy_${definition.Name}" } + .orElse { + val sharedGroupId = vehicle.Definition.interference.sharedGroupId + if (sharedGroupId > 0) { + reportedInterferenceList + .find(_.interference.sharedGroupId == sharedGroupId) + .map(_ => "@nodeploy_sharedinterference") + } else { + None + } + } + .foreach { msg => + zone.VehicleEvents ! VehicleServiceMessage( + vehicle.Seats.headOption.flatMap(_._2.occupant).map(_.Name).getOrElse(""), + VehicleAction.SendResponse(Service.defaultPlayerGUID, ChatMsg(ChatMessageType.UNK_227, msg)) + ) + } + true + } else { + false } } }