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)`
* * `24 - Learn certification:`
*