diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala
index f29757b0..42c6b365 100644
--- a/src/main/scala/net/psforever/actors/session/SessionActor.scala
+++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala
@@ -6,8 +6,8 @@ import akka.actor.typed.scaladsl.adapter._
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
import akka.pattern.ask
import akka.util.Timeout
-import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeUnit
import net.psforever.actors.net.MiddlewareActor
import net.psforever.services.ServiceManager.Lookup
import net.psforever.objects.locker.LockerContainer
@@ -37,7 +37,6 @@ import net.psforever.objects.serverobject.deploy.Deployment
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.serverobject.generator.Generator
import net.psforever.objects.serverobject.hackable.Hackable
-import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
import net.psforever.objects.serverobject.locks.IFFLock
import net.psforever.objects.serverobject.mblocker.Locker
import net.psforever.objects.serverobject.mount.Mountable
@@ -45,6 +44,8 @@ import net.psforever.objects.serverobject.pad.VehicleSpawnPad
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
import net.psforever.objects.serverobject.structures.{Amenity, Building, StructureType, WarpGate}
import net.psforever.objects.serverobject.terminals._
+import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminals}
+import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.serverobject.turret.{FacilityTurret, WeaponTurret}
import net.psforever.objects.serverobject.zipline.ZipLinePath
@@ -57,6 +58,7 @@ import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.vital.projectile.ProjectileReason
import net.psforever.objects.zones.{Zone, ZoneHotSpotProjector, Zoning}
import net.psforever.packet._
+import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
import net.psforever.packet.game.{HotSpotInfo => PacketHotSpotInfo, _}
import net.psforever.packet.game.objectcreate._
import net.psforever.services.ServiceManager.LookupResult
@@ -64,7 +66,7 @@ import net.psforever.services.account.{AccountPersistenceService, PlayerToken, R
import net.psforever.services.avatar.{AvatarAction, AvatarResponse, AvatarServiceMessage, AvatarServiceResponse}
import net.psforever.services.chat.ChatService
import net.psforever.services.galaxy.{GalaxyAction, GalaxyResponse, GalaxyServiceMessage, GalaxyServiceResponse}
-import net.psforever.services.local.support.RouterTelepadActivation
+import net.psforever.services.local.support.{HackCaptureActor, RouterTelepadActivation}
import net.psforever.services.local.{LocalAction, LocalResponse, LocalServiceMessage, LocalServiceResponse}
import net.psforever.services.properties.PropertyOverrideManager
import net.psforever.services.support.SupportActor
@@ -2285,7 +2287,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
DeconstructDeployable(obj, guid, pos, obj.Orientation, 2)
}
- case LocalResponse.HackClear(target_guid, unk1, unk2) =>
+ case LocalResponse.SendHackMessageHackCleared(target_guid, unk1, unk2) =>
log.trace(s"Clearing hack for ${target_guid}")
// Reset hack state for all players
sendResponse(HackMessage(0, target_guid, guid, 0, unk1, HackState.HackCleared, unk2))
@@ -2293,8 +2295,8 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
case LocalResponse.HackObject(target_guid, unk1, unk2) =>
HackObject(target_guid, unk1, unk2)
- case LocalResponse.HackCaptureTerminal(target_guid, unk1, unk2, isResecured) =>
- HackCaptureTerminal(target_guid, unk1, unk2, isResecured)
+ case LocalResponse.SendPlanetsideAttributeMessage(target_guid, attribute_number, attribute_value) =>
+ SendPlanetsideAttributeMessage(target_guid, attribute_number, attribute_value)
case LocalResponse.ObjectDelete(object_guid, unk) =>
if (tplayer_guid != guid) {
@@ -2646,6 +2648,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
case VehicleResponse.KickPassenger(seat_num, wasKickedByDriver, vehicle_guid) =>
// seat_num seems to be correct if passenger is kicked manually by driver, but always seems to return 4 if user is kicked by seat permissions
sendResponse(DismountVehicleMsg(guid, BailType.Kicked, wasKickedByDriver))
+ player.VehicleSeated = None
if (tplayer_guid == guid) {
continent.GUID(vehicle_guid) match {
case Some(obj: Vehicle) =>
@@ -6679,7 +6682,10 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
case obj: Hackable if obj.HackedBy.nonEmpty =>
amenity.Definition match {
case GlobalDefinitions.capture_terminal =>
- HackCaptureTerminal(amenity.GUID, 0L, 0L, false)
+ SendPlanetsideAttributeMessage(
+ amenity.GUID,
+ PlanetsideAttributeEnum.ControlConsoleHackUpdate,
+ HackCaptureActor.GetHackUpdateAttributeValue(amenity.asInstanceOf[CaptureTerminal], isResecured = false))
case _ =>
HackObject(amenity.GUID, 1114636288L, 8L) //generic hackable object
}
@@ -6723,51 +6729,13 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
}
/**
- * na
- * @param target_guid na
- * @param unk1 na
- * @param unk2 na
- * @param isResecured na
+ * Send a PlanetsideAttributeMessage packet to the client
+ * @param target_guid The target of the attribute
+ * @param attribute_number The attribute number
+ * @param attribute_value The attribute value
*/
- def HackCaptureTerminal(target_guid: PlanetSideGUID, unk1: Long, unk2: Long, isResecured: Boolean): Unit = {
- var value = 0L
- if (isResecured) {
- value = 17039360L
- sendResponse(PlanetsideAttributeMessage(target_guid, 20, value))
- } else {
- continent.GUID(target_guid) match {
- case Some(capture_terminal: Amenity with Hackable) =>
- capture_terminal.HackedBy match {
- case Some(Hackable.HackInfo(_, _, hfaction, _, start, length)) =>
- val hack_time_remaining_ms =
- TimeUnit.MILLISECONDS.convert(math.max(0, start + length - System.nanoTime), TimeUnit.NANOSECONDS)
- val deciseconds_remaining = (hack_time_remaining_ms / 100)
- //See PlanetSideAttributeMessage #20 documentation for an explanation of how the timer is calculated
- val start_num = hfaction match {
- case PlanetSideEmpire.TR => 65536L
- case PlanetSideEmpire.NC => 131072L
- case PlanetSideEmpire.VS => 196608L
- }
- value = start_num + deciseconds_remaining
- sendResponse(PlanetsideAttributeMessage(target_guid, 20, value))
- GetMountableAndSeat(None, player, continent) match {
- case (Some(mountable: Amenity), Some(seat)) if mountable.Owner.GUID == capture_terminal.Owner.GUID =>
- mountable.Seats(seat).Occupant = None
- player.VehicleSeated = None
- continent.VehicleEvents ! VehicleServiceMessage(
- continent.id,
- VehicleAction.KickPassenger(player.GUID, seat, true, mountable.GUID)
- )
- case _ => ;
- }
- case _ => log.warn("HackCaptureTerminal: hack state monitor not defined")
- }
- case _ =>
- log.warn(
- s"HackCaptureTerminal: couldn't find capture terminal with GUID ${target_guid} in zone ${continent.id}"
- )
- }
- }
+ def SendPlanetsideAttributeMessage(target_guid: PlanetSideGUID, attribute_number: PlanetsideAttributeEnum, attribute_value: Long): Unit = {
+ sendResponse(PlanetsideAttributeMessage(target_guid, attribute_number, attribute_value))
}
/**
diff --git a/src/main/scala/net/psforever/actors/zone/BuildingActor.scala b/src/main/scala/net/psforever/actors/zone/BuildingActor.scala
index 8f1abea7..b4a9c421 100644
--- a/src/main/scala/net/psforever/actors/zone/BuildingActor.scala
+++ b/src/main/scala/net/psforever/actors/zone/BuildingActor.scala
@@ -1,5 +1,6 @@
package net.psforever.actors.zone
+import akka.actor.Actor
import akka.actor.typed.receptionist.Receptionist
import akka.actor.typed.scaladsl.{ActorContext, Behaviors, StashBuffer}
import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy}
@@ -8,11 +9,14 @@ import net.psforever.actors.commands.NtuCommand
import net.psforever.objects.NtuContainer
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl}
+import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.structures.{Amenity, Building, StructureType, WarpGate}
+import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAware, CaptureTerminalAwareBehavior}
+import net.psforever.objects.serverobject.turret.{FacilityTurret, FacilityTurretControl}
import net.psforever.objects.zones.Zone
import net.psforever.persistence
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.types.{PlanetSideEmpire, PlanetSideGeneratorState}
+import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, PlanetSideGeneratorState}
import net.psforever.util.Database._
import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage}
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
@@ -201,6 +205,22 @@ class BuildingActor(
}
Behaviors.same
+ case AmenityStateChange(terminal: CaptureTerminal, data) =>
+ // Notify amenities that listen for CC hack state changes, e.g. wall turrets to dismount seated players
+ building.Amenities.filter(x => x.isInstanceOf[CaptureTerminalAware]).foreach(amenity => {
+ amenity.Actor ! CaptureTerminalAwareBehavior.TerminalStatusChanged(terminal, data.get.asInstanceOf[Boolean])
+ })
+
+ // When a CC is hacked (or resecured) all currently hacked amenities for the base should return to their default unhacked state
+ building.HackableAmenities.foreach(amenity => {
+ if (amenity.HackedBy.isDefined) {
+ zone.LocalEvents ! LocalServiceMessage(amenity.Zone.id,LocalAction.ClearTemporaryHack(PlanetSideGUID(0), amenity))
+ }
+ })
+
+ // No map update needed - will be sent by `HackCaptureActor` when required
+ Behaviors.same
+
case AmenityStateChange(_, _) =>
//TODO when parameter object is finally immutable, perform analysis on it to determine specific actions
//for now, just update the map
diff --git a/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
index 18d12666..7b967c10 100644
--- a/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
+++ b/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
@@ -11,7 +11,6 @@ import net.psforever.objects.inventory.InventoryTile
import net.psforever.objects.serverobject.aura.Aura
import net.psforever.objects.serverobject.doors.DoorDefinition
import net.psforever.objects.serverobject.generator.GeneratorDefinition
-import net.psforever.objects.serverobject.implantmech.ImplantTerminalMechDefinition
import net.psforever.objects.serverobject.locks.IFFLockDefinition
import net.psforever.objects.serverobject.mblocker.LockerDefinition
import net.psforever.objects.serverobject.pad.VehicleSpawnPadDefinition
@@ -20,6 +19,8 @@ import net.psforever.objects.serverobject.terminals._
import net.psforever.objects.serverobject.tube.SpawnTubeDefinition
import net.psforever.objects.serverobject.resourcesilo.ResourceSiloDefinition
import net.psforever.objects.serverobject.structures.{AutoRepairStats, BuildingDefinition, WarpGateDefinition}
+import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalDefinition
+import net.psforever.objects.serverobject.terminals.implant.{ImplantTerminalDefinition, ImplantTerminalMechDefinition}
import net.psforever.objects.serverobject.turret.{FacilityTurretDefinition, TurretUpgrade}
import net.psforever.objects.vehicles.{DestroyedVehicle, InternalTelepadDefinition, SeatArmorRestriction, UtilityType}
import net.psforever.objects.vital.base.DamageType
diff --git a/src/main/scala/net/psforever/objects/Player.scala b/src/main/scala/net/psforever/objects/Player.scala
index dd16b592..80d2b027 100644
--- a/src/main/scala/net/psforever/objects/Player.scala
+++ b/src/main/scala/net/psforever/objects/Player.scala
@@ -521,7 +521,7 @@ class Player(var avatar: Avatar)
} else {
""
}
- s"${avatar.name}$guid ${Health}/${MaxHealth} ${Armor}/${MaxArmor}"
+ s"${avatar.name}$guid ${avatar.faction} H: ${Health}/${MaxHealth} A: ${Armor}/${MaxArmor}"
}
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala b/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala
index b1c24b43..c6a93bed 100644
--- a/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala
@@ -2,7 +2,6 @@
package net.psforever.objects.serverobject.structures
import java.util.concurrent.TimeUnit
-
import akka.actor.ActorContext
import net.psforever.actors.zone.BuildingActor
import net.psforever.objects.{GlobalDefinitions, NtuContainer, Player}
@@ -11,13 +10,13 @@ import net.psforever.objects.serverobject.generator.Generator
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.painbox.Painbox
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
-import net.psforever.objects.serverobject.terminals.CaptureTerminal
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.BuildingInfoUpdateMessage
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, PlanetSideGeneratorState, Vector3}
import scalax.collection.{Graph, GraphEdge}
import akka.actor.typed.scaladsl.adapter._
+import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
class Building(
private val name: String,
@@ -123,6 +122,10 @@ class Building(
}
}
+ def HackableAmenities: List[Amenity with Hackable] = {
+ Amenities.filter(x => x.isInstanceOf[Hackable]).map(x => x.asInstanceOf[Amenity with Hackable])
+ }
+
def CaptureTerminalIsHacked: Boolean = {
CaptureTerminal match {
case Some(obj: CaptureTerminal) =>
diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/CaptureTerminals.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/CaptureTerminals.scala
deleted file mode 100644
index 84acaea9..00000000
--- a/src/main/scala/net/psforever/objects/serverobject/terminals/CaptureTerminals.scala
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2020 PSForever
-package net.psforever.objects.serverobject.terminals
-
-import net.psforever.objects.Player
-import net.psforever.objects.serverobject.CommonMessages
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-
-import scala.util.{Failure, Success}
-
-object CaptureTerminals {
- private val log = org.log4s.getLogger("CaptureTerminals")
-
- /**
- * The process of hacking an object is completed.
- * Pass the message onto the hackable object and onto the local events system.
- * @param target the `Hackable` object that has been hacked
- * @param unk na;
- * used by `HackMessage` as `unk5`
- * @see `HackMessage`
- */
- //TODO add params here depending on which params in HackMessage are important
- def FinishHackingCaptureConsole(target: CaptureTerminal, user: Player, unk: Long)(): Unit = {
- import akka.pattern.ask
- import scala.concurrent.duration._
- log.info(s"Hacked a $target")
- // Wait for the target actor to set the HackedBy property, otherwise LocalAction.HackTemporarily will not complete properly
- import scala.concurrent.ExecutionContext.Implicits.global
- val tplayer = user
- ask(target.Actor, CommonMessages.Hack(tplayer, target))(1 second).mapTo[Boolean].onComplete {
- case Success(_) =>
- val zone = target.Zone
- val zoneId = zone.id
- val pguid = tplayer.GUID
- zone.LocalEvents ! LocalServiceMessage(
- zoneId,
- LocalAction.TriggerSound(pguid, target.HackSound, tplayer.Position, 30, 0.49803925f)
- )
- zone.LocalEvents ! LocalServiceMessage(
- zoneId,
- LocalAction.HackCaptureTerminal(pguid, zone, target, unk, 8L, tplayer.Faction == target.Faction)
- )
- case Failure(_) => log.warn(s"Hack message failed on target guid: ${target.GUID}")
- }
- }
-}
diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/CaptureTerminal.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminal.scala
similarity index 81%
rename from src/main/scala/net/psforever/objects/serverobject/terminals/CaptureTerminal.scala
rename to src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminal.scala
index 333fd0c5..3ad5847f 100644
--- a/src/main/scala/net/psforever/objects/serverobject/terminals/CaptureTerminal.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminal.scala
@@ -1,4 +1,4 @@
-package net.psforever.objects.serverobject.terminals
+package net.psforever.objects.serverobject.terminals.capture
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.structures.Amenity
@@ -9,6 +9,15 @@ class CaptureTerminal(private val idef: CaptureTerminalDefinition) extends Ameni
def Definition: CaptureTerminalDefinition = idef
HackDuration = Array(60, 40, 20, 15)
HackSound = TriggeredSound.HackTerminal
+
+ override def toString: String = {
+ val guid = if (HasGUID) {
+ s" ${Continent}-${GUID.guid}"
+ } else {
+ ""
+ }
+ s"${this.getClass.getName}: $guid ($Faction)"
+ }
}
object CaptureTerminal {
diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalAware.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalAware.scala
new file mode 100644
index 00000000..204186e8
--- /dev/null
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalAware.scala
@@ -0,0 +1,10 @@
+package net.psforever.objects.serverobject.terminals.capture
+
+/**
+ * A trait to mark an Amenity as being aware that a capture terminal exists on the parent object
+ * and that it is interested in status updates about that capture terminal, for example mountables to kick players out once the CC is hacked
+ * @see CaptureTerminalAwareBehavior
+ */
+trait CaptureTerminalAware {
+
+}
diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalAwareBehavior.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalAwareBehavior.scala
new file mode 100644
index 00000000..985f122e
--- /dev/null
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalAwareBehavior.scala
@@ -0,0 +1,37 @@
+package net.psforever.objects.serverobject.terminals.capture
+
+import akka.actor.Actor.Receive
+import net.psforever.objects.serverobject.mount.Mountable
+import net.psforever.objects.serverobject.structures.Amenity
+import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+
+/**
+ * The behaviours corresponding to an Amenity that is marked as being CaptureTerminalAware
+ * @see CaptureTerminalAware
+ */
+trait CaptureTerminalAwareBehavior {
+ def CaptureTerminalAwareObject : Amenity with CaptureTerminalAware
+
+ val captureTerminalAwareBehaviour: Receive = {
+ case CaptureTerminalAwareBehavior.TerminalStatusChanged(terminal, isResecured) =>
+ isResecured match {
+ case true => ; // CC is resecured
+ case false => // CC is hacked
+ // Remove seated occupants for mountables
+ if (CaptureTerminalAwareObject.isInstanceOf[Mountable]) {
+ CaptureTerminalAwareObject.asInstanceOf[Mountable].Seats.filter(x => x._2.isOccupied).foreach(x => {
+ val (seat_num, seat) = x
+ CaptureTerminalAwareObject.Zone.VehicleEvents ! VehicleServiceMessage(
+ CaptureTerminalAwareObject.Zone.id,
+ VehicleAction.KickPassenger(seat.Occupant.get.GUID, seat_num, true, CaptureTerminalAwareObject.GUID))
+
+ seat.Occupant = None
+ })
+ }
+ }
+ }
+}
+
+object CaptureTerminalAwareBehavior {
+ final case class TerminalStatusChanged(terminal: CaptureTerminal, isResecured: Boolean)
+}
diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/CaptureTerminalControl.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalControl.scala
similarity index 95%
rename from src/main/scala/net/psforever/objects/serverobject/terminals/CaptureTerminalControl.scala
rename to src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalControl.scala
index 044a1f5f..973f2d74 100644
--- a/src/main/scala/net/psforever/objects/serverobject/terminals/CaptureTerminalControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalControl.scala
@@ -1,11 +1,11 @@
// Copyright (c) 2017 PSForever
-package net.psforever.objects.serverobject.terminals
+package net.psforever.objects.serverobject.terminals.capture
import akka.actor.Actor
-import net.psforever.objects.{GlobalDefinitions, SimpleItem}
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
+import net.psforever.objects.{GlobalDefinitions, SimpleItem}
class CaptureTerminalControl(terminal: CaptureTerminal)
extends Actor
diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/CaptureTerminalDefinition.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalDefinition.scala
similarity index 86%
rename from src/main/scala/net/psforever/objects/serverobject/terminals/CaptureTerminalDefinition.scala
rename to src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalDefinition.scala
index 1bd20001..8d366fc7 100644
--- a/src/main/scala/net/psforever/objects/serverobject/terminals/CaptureTerminalDefinition.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalDefinition.scala
@@ -1,4 +1,4 @@
-package net.psforever.objects.serverobject.terminals
+package net.psforever.objects.serverobject.terminals.capture
import net.psforever.objects.serverobject.structures.AmenityDefinition
diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala
new file mode 100644
index 00000000..9a37c1a3
--- /dev/null
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala
@@ -0,0 +1,65 @@
+package net.psforever.objects.serverobject.terminals.capture
+
+import net.psforever.actors.zone.BuildingActor
+import net.psforever.objects.Player
+import net.psforever.objects.serverobject.CommonMessages
+import net.psforever.objects.serverobject.hackable.Hackable
+import net.psforever.packet.game.PlanetsideAttributeEnum
+import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.types.PlanetSideEmpire
+
+import java.util.concurrent.TimeUnit
+import scala.util.{Failure, Success}
+
+object CaptureTerminals {
+ private val log = org.log4s.getLogger("CaptureTerminals")
+
+ /**
+ * The process of hacking an object is completed.
+ * Pass the message onto the hackable object and onto the local events system.
+ * @param target the `Hackable` object that has been hacked
+ * @param hackingPlayer The player that hacked the control console
+ * @param unk na;
+ * used by `HackMessage` as `unk5`
+ * @see `HackMessage`
+ */
+ //TODO add params here depending on which params in HackMessage are important
+ def FinishHackingCaptureConsole(target: CaptureTerminal, hackingPlayer: Player, unk: Long)(): Unit = {
+ import akka.pattern.ask
+
+ import scala.concurrent.duration._
+ log.info(s"${hackingPlayer.toString} Hacked a ${target.toString}")
+ // Wait for the target actor to set the HackedBy property
+ import scala.concurrent.ExecutionContext.Implicits.global
+ ask(target.Actor, CommonMessages.Hack(hackingPlayer, target))(1 second).mapTo[Boolean].onComplete {
+ case Success(_) =>
+ target.Zone.LocalEvents ! LocalServiceMessage(
+ target.Zone.id,
+ LocalAction.TriggerSound(hackingPlayer.GUID, target.HackSound, hackingPlayer.Position, 30, 0.49803925f)
+ )
+
+ val isResecured = hackingPlayer.Faction == target.Faction
+
+ if (isResecured) {
+ // Resecure the CC
+ target.Zone.LocalEvents ! LocalServiceMessage(
+ target.Zone.id,
+ LocalAction.ResecureCaptureTerminal(
+ target
+ )
+ )
+ } else {
+ // Start the CC hack timer
+ target.Zone.LocalEvents ! LocalServiceMessage(
+ target.Zone.id,
+ LocalAction.StartCaptureTerminalHack(
+ target
+ )
+ )
+ }
+ case Failure(_) => log.warn(s"Hack message failed on target guid: ${target.GUID}")
+ }
+ }
+
+
+}
diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/ImplantTerminalDefinition.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalDefinition.scala
similarity index 95%
rename from src/main/scala/net/psforever/objects/serverobject/terminals/ImplantTerminalDefinition.scala
rename to src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalDefinition.scala
index 96ed4d15..33d21502 100644
--- a/src/main/scala/net/psforever/objects/serverobject/terminals/ImplantTerminalDefinition.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalDefinition.scala
@@ -1,5 +1,5 @@
// Copyright (c) 2017 PSForever
-package net.psforever.objects.serverobject.terminals
+package net.psforever.objects.serverobject.terminals.implant
import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.definition.ImplantDefinition
diff --git a/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMech.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMech.scala
similarity index 94%
rename from src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMech.scala
rename to src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMech.scala
index 607d0bca..063f1560 100644
--- a/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMech.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMech.scala
@@ -1,10 +1,11 @@
// Copyright (c) 2017 PSForever
-package net.psforever.objects.serverobject.implantmech
+package net.psforever.objects.serverobject.terminals.implant
import net.psforever.objects.Player
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.structures.Amenity
+import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAware
import net.psforever.objects.vehicles.Seat
import net.psforever.packet.game.TriggeredSound
import net.psforever.types.Vector3
@@ -17,7 +18,8 @@ import net.psforever.types.Vector3
class ImplantTerminalMech(private val idef: ImplantTerminalMechDefinition)
extends Amenity
with Mountable
- with Hackable {
+ with Hackable
+ with CaptureTerminalAware {
private val seats: Map[Int, Seat] = Map(0 -> new Seat(idef.Seats(0)))
HackSound = TriggeredSound.HackTerminal
diff --git a/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechControl.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechControl.scala
similarity index 94%
rename from src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechControl.scala
rename to src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechControl.scala
index 8d893e5b..d2b386b3 100644
--- a/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechControl.scala
@@ -1,16 +1,17 @@
// Copyright (c) 2017 PSForever
-package net.psforever.objects.serverobject.implantmech
+package net.psforever.objects.serverobject.terminals.implant
-import net.psforever.objects.{GlobalDefinitions, Player, SimpleItem}
-import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
-import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
import net.psforever.objects.serverobject.damage.Damageable.Target
import net.psforever.objects.serverobject.damage.{Damageable, DamageableEntity, DamageableMountable}
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
+import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableEntity}
import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityControl}
+import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAwareBehavior
+import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.vital.interaction.DamageResult
+import net.psforever.objects.{GlobalDefinitions, Player, SimpleItem}
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
/**
@@ -25,13 +26,15 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
with HackableBehavior.GenericHackable
with DamageableEntity
with RepairableEntity
- with AmenityAutoRepair {
+ with AmenityAutoRepair
+ with CaptureTerminalAwareBehavior {
def MountableObject = mech
def HackableObject = mech
def FactionObject = mech
def DamageableObject = mech
def RepairableObject = mech
def AutoRepairObject = mech
+ def CaptureTerminalAwareObject = mech
def commonBehavior: Receive =
checkBehavior
diff --git a/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechDefinition.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechDefinition.scala
similarity index 93%
rename from src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechDefinition.scala
rename to src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechDefinition.scala
index 64db0cb5..0b351212 100644
--- a/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechDefinition.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechDefinition.scala
@@ -1,5 +1,5 @@
// Copyright (c) 2017 PSForever
-package net.psforever.objects.serverobject.implantmech
+package net.psforever.objects.serverobject.terminals.implant
import net.psforever.objects.definition.SeatDefinition
import net.psforever.objects.serverobject.structures.AmenityDefinition
diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala
index 370004ce..cc4de5eb 100644
--- a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala
@@ -3,9 +3,14 @@ package net.psforever.objects.serverobject.turret
import net.psforever.objects.equipment.JammableUnit
import net.psforever.objects.serverobject.structures.Amenity
+import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAware
import net.psforever.types.Vector3
-class FacilityTurret(tDef: FacilityTurretDefinition) extends Amenity with WeaponTurret with JammableUnit {
+class FacilityTurret(tDef: FacilityTurretDefinition)
+ extends Amenity
+ with WeaponTurret
+ with JammableUnit
+ with CaptureTerminalAware {
WeaponTurret.LoadDefinition(this)
def MountPoints: Map[Int, Int] = Definition.MountPoints.toMap
diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala
index 415c0f1f..53a27e49 100644
--- a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala
@@ -10,6 +10,7 @@ import net.psforever.objects.serverobject.damage.{Damageable, DamageableWeaponTu
import net.psforever.objects.serverobject.hackable.GenericHackables
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableWeaponTurret}
import net.psforever.objects.serverobject.structures.PoweredAmenityControl
+import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAwareBehavior
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
@@ -35,13 +36,15 @@ class FacilityTurretControl(turret: FacilityTurret)
with DamageableWeaponTurret
with RepairableWeaponTurret
with AmenityAutoRepair
- with JammableMountedWeapons {
+ with JammableMountedWeapons
+ with CaptureTerminalAwareBehavior {
def FactionObject = turret
def MountableObject = turret
def JammableObject = turret
def DamageableObject = turret
def RepairableObject = turret
def AutoRepairObject = turret
+ def CaptureTerminalAwareObject = turret
// Used for timing ammo recharge for vanu turrets in caves
var weaponAmmoRechargeTimer = Default.Cancellable
@@ -59,6 +62,7 @@ class FacilityTurretControl(turret: FacilityTurret)
.orElse(takesDamage)
.orElse(canBeRepairedByNanoDispenser)
.orElse(autoRepairBehavior)
+ .orElse(captureTerminalAwareBehaviour)
def poweredStateLogic: Receive =
commonBehavior
@@ -113,7 +117,6 @@ class FacilityTurretControl(turret: FacilityTurret)
weaponAmmoRechargeTimer.cancel()
weaponAmmoRechargeTimer = Default.Cancellable
}
-
case _ => ;
}
diff --git a/src/main/scala/net/psforever/objects/zones/Zone.scala b/src/main/scala/net/psforever/objects/zones/Zone.scala
index 8622ca76..17f393bc 100644
--- a/src/main/scala/net/psforever/objects/zones/Zone.scala
+++ b/src/main/scala/net/psforever/objects/zones/Zone.scala
@@ -39,6 +39,7 @@ import net.psforever.actors.session.AvatarActor
import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.serverobject.PlanetSideServerObject
+import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.vehicles.UtilityType
import net.psforever.objects.vital.etc.ExplodingEntityReason
@@ -255,7 +256,7 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
case (mechGuid, interfaceGuid) =>
validateObject(
mechGuid,
- (x: PlanetSideGameObject) => x.isInstanceOf[serverobject.implantmech.ImplantTerminalMech],
+ (x: PlanetSideGameObject) => x.isInstanceOf[ImplantTerminalMech],
"implant terminal mech"
)
validateObject(
diff --git a/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala b/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
index d3a8044f..a8922214 100644
--- a/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
+++ b/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
@@ -1,6 +1,7 @@
// Copyright (c) 2016 PSForever.net to present
package net.psforever.packet.game
+import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.PlanetSideGUID
import scodec.Codec
@@ -71,11 +72,11 @@ import scodec.codecs._
* Format is: Time left - 2 bytes, faction - 1 byte (1-4), isResecured - 1 byte (0-1)`
*