mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-03-02 20:10:24 +00:00
preliminary functional implant hacking; am going to explore better hacking policies
This commit is contained in:
parent
8afe7fa248
commit
e0439a790e
8 changed files with 241 additions and 45 deletions
|
|
@ -165,7 +165,7 @@ object GlobalDefinitionsMiscellaneous {
|
|||
cert_terminal.Geometry = GeometryForm.representByCylinder(radius = 0.66405f, height = 1.09374f)
|
||||
|
||||
implant_terminal_mech.Name = "implant_terminal_mech"
|
||||
implant_terminal_mech.MaxHealth = 1500 //TODO 1000; right now, 1000 (mech) + 500 (interface)
|
||||
implant_terminal_mech.MaxHealth = 1000
|
||||
implant_terminal_mech.Damageable = true
|
||||
implant_terminal_mech.Repairable = true
|
||||
implant_terminal_mech.autoRepair = AutoRepairStats(1.6f, 5000, 2400, 0.05f)
|
||||
|
|
@ -176,7 +176,7 @@ object GlobalDefinitionsMiscellaneous {
|
|||
implant_terminal_interface.Name = "implant_terminal_interface"
|
||||
implant_terminal_interface.Tab += 0 -> ImplantPage(ImplantTerminalDefinition.implants)
|
||||
implant_terminal_interface.MaxHealth = 500
|
||||
implant_terminal_interface.Damageable = false //TODO true
|
||||
implant_terminal_interface.Damageable = false //true
|
||||
implant_terminal_interface.Repairable = true
|
||||
implant_terminal_interface.autoRepair = AutoRepairStats(1, 5000, 200, 1)
|
||||
implant_terminal_interface.RepairIfDestroyed = true
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
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}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
|
|
@ -24,28 +22,7 @@ trait CaptureTerminalAwareBehavior {
|
|||
|
||||
protected def captureTerminalIsResecured(@unused terminal: CaptureTerminal): Unit = { /* intentionally blank */ }
|
||||
|
||||
protected def captureTerminalIsHacked(@unused terminal: CaptureTerminal): Unit = {
|
||||
// Remove seated occupants for mountables
|
||||
CaptureTerminalAwareObject match {
|
||||
case mountable: Mountable =>
|
||||
val guid = mountable.GUID
|
||||
val zone = mountable.Zone
|
||||
val zoneId = zone.id
|
||||
val events = zone.VehicleEvents
|
||||
mountable.Seats.values.zipWithIndex.foreach {
|
||||
case (seat, seat_num) =>
|
||||
seat.occupant.collect {
|
||||
case player =>
|
||||
seat.unmount(player)
|
||||
player.VehicleSeated = None
|
||||
if (player.HasGUID) {
|
||||
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, seat_num, unk2=true, guid))
|
||||
}
|
||||
}
|
||||
}
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
protected def captureTerminalIsHacked(@unused terminal: CaptureTerminal): Unit = { /* intentionally blank */ }
|
||||
}
|
||||
|
||||
object CaptureTerminalAwareBehavior {
|
||||
|
|
|
|||
|
|
@ -23,13 +23,13 @@ object CaptureTerminals {import scala.concurrent.duration._
|
|||
def FinishHackingCaptureConsole(target: CaptureTerminal, hackingPlayer: Player, unk: Long)(): Unit = {
|
||||
import akka.pattern.ask
|
||||
|
||||
log.info(s"${hackingPlayer.toString} hacked a ${target.Definition.Name}")
|
||||
// Wait for the target actor to set the HackedBy property
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
ask(target.Actor, CommonMessages.Hack(hackingPlayer, target))(timeout = 2 second)
|
||||
.mapTo[CommonMessages.EntityHackState]
|
||||
.onComplete {
|
||||
case Success(_) =>
|
||||
log.info(s"${hackingPlayer.toString} hacked a ${target.Definition.Name}")
|
||||
val zone = target.Zone
|
||||
val zoneid = zone.id
|
||||
val events = zone.LocalEvents
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.serverobject.terminals.implant
|
||||
|
||||
import akka.actor.ActorRef
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.serverobject.hackable.{GenericHackables, Hackable}
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalControl}
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.types.PlanetSideGUID
|
||||
|
||||
object ImplantInterfaceControl {
|
||||
private def FindPairedTerminalMech(
|
||||
zone: Zone,
|
||||
interfaceGuid: PlanetSideGUID
|
||||
): Option[Amenity with Hackable] = {
|
||||
zone
|
||||
.map
|
||||
.terminalToInterface
|
||||
.find { case (_, guid) => guid == interfaceGuid.guid }
|
||||
.flatMap { case (mechGuid, _) => zone.GUID(mechGuid) }
|
||||
.collect { case mech: ImplantTerminalMech if !mech.Destroyed && mech.HackedBy.isEmpty => mech }
|
||||
}
|
||||
}
|
||||
|
||||
class ImplantInterfaceControl(private val terminal: Terminal)
|
||||
extends TerminalControl(terminal) {
|
||||
|
||||
override def performHack(player: Player, data: Option[Any], replyTo: ActorRef): Unit = {
|
||||
HackableObject.HackedBy
|
||||
.orElse {
|
||||
super.performHack(player, data, replyTo)
|
||||
ImplantInterfaceControl
|
||||
.FindPairedTerminalMech(terminal.Zone, terminal.GUID)
|
||||
.foreach(GenericHackables.FinishHacking(_, player, unk = 3212836864L)())
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.serverobject.terminals.implant
|
||||
|
||||
import akka.actor.ActorContext
|
||||
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalDefinition}
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
object ImplantTerminalInterface {
|
||||
/**
|
||||
* Instantiate and configure a `Terminal` object
|
||||
* @param pdef `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
||||
* @param pos position
|
||||
* @param id the unique id that will be assigned to this entity
|
||||
* @param context a context to allow the object to properly set up `ActorSystem` functionality
|
||||
* @return the `Terminal` object
|
||||
*/
|
||||
def Constructor(pos: Vector3, pdef: TerminalDefinition)(id: Int, context: ActorContext): Terminal = {
|
||||
import akka.actor.Props
|
||||
|
||||
val obj = Terminal(pdef)
|
||||
obj.Position = pos
|
||||
obj.Actor = context.actorOf(Props(classOf[ImplantInterfaceControl], obj), s"${obj.Definition.Name}_$id")
|
||||
obj
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +1,46 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.terminals.implant
|
||||
|
||||
import akka.actor.ActorRef
|
||||
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.hackable.{GenericHackables, Hackable, HackableBehavior}
|
||||
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
||||
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableAmenity, RepairableEntity}
|
||||
import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityControl}
|
||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAwareBehavior
|
||||
import net.psforever.objects.serverobject.structures.{Amenity, Building, PoweredAmenityControl}
|
||||
import net.psforever.objects.serverobject.terminals.Terminal
|
||||
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAwareBehavior}
|
||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||
import net.psforever.objects.vital.interaction.DamageResult
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.objects.{GlobalDefinitions, Player, SimpleItem}
|
||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
object ImplantTerminalMechControl {
|
||||
private def FindPairedTerminalInterface(
|
||||
zone: Zone,
|
||||
mechGuid: PlanetSideGUID
|
||||
): Option[Amenity with Hackable] = {
|
||||
zone
|
||||
.map
|
||||
.terminalToInterface
|
||||
.find { case (guid, _) => guid == mechGuid.guid }
|
||||
.flatMap { case (_, interfaceGuid) => zone.GUID(interfaceGuid) }
|
||||
.collect { case terminal: Terminal if !terminal.Destroyed && terminal.HackedBy.isEmpty => terminal }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `Actor` that handles messages being dispatched to a specific `ImplantTerminalMech`.
|
||||
* @param mech the "mech" object being governed
|
||||
*/
|
||||
* An `Actor` that handles messages being dispatched to a specific `ImplantTerminalMech`.
|
||||
* @param mech the "mech" object being governed
|
||||
*/
|
||||
class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
||||
extends PoweredAmenityControl
|
||||
extends PoweredAmenityControl
|
||||
with FactionAffinityBehavior.Check
|
||||
with MountableBehavior
|
||||
with HackableBehavior.GenericHackable
|
||||
|
|
@ -41,9 +62,11 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
|||
.orElse(takesDamage)
|
||||
.orElse(canBeRepairedByNanoDispenser)
|
||||
.orElse(autoRepairBehavior)
|
||||
.orElse(captureTerminalAwareBehaviour)
|
||||
|
||||
def poweredStateLogic : Receive =
|
||||
commonBehavior
|
||||
.orElse(hackableBehavior)
|
||||
.orElse(mountBehavior)
|
||||
.orElse {
|
||||
case CommonMessages.Use(player, Some(item: SimpleItem))
|
||||
|
|
@ -56,15 +79,16 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
|||
GenericHackables.FinishHacking(mech, player, 3212836864L),
|
||||
GenericHackables.HackingTickAction(progressType = 1, player, mech, item.GUID)
|
||||
)
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
|
||||
def unpoweredStateLogic: Receive =
|
||||
commonBehavior
|
||||
.orElse(hackableBehavior)
|
||||
.orElse {
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
|
||||
override protected def mountTest(
|
||||
|
|
@ -120,14 +144,11 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
|||
val zoneId = zone.id
|
||||
val events = zone.VehicleEvents
|
||||
mech.Seats.values.foreach(seat =>
|
||||
seat.occupant match {
|
||||
case Some(player) =>
|
||||
seat.occupant.collect {
|
||||
case player =>
|
||||
seat.unmount(player)
|
||||
player.VehicleSeated = None
|
||||
if (player.HasGUID) {
|
||||
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2 = false, guid))
|
||||
}
|
||||
case None => ;
|
||||
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2=false, guid))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -140,4 +161,123 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
|||
super.Restoration(obj)
|
||||
RepairableAmenity.RestorationOfHistory(obj)
|
||||
}
|
||||
|
||||
override def performHack(player: Player, data: Option[Any], replyTo: ActorRef): Unit = {
|
||||
//todo don't now how to properly hack this amenity
|
||||
super.performHack(player, data, replyTo)
|
||||
val zone = HackableObject.Zone
|
||||
val guid = HackableObject.GUID
|
||||
val localFaction = mech.Faction
|
||||
val events = zone.LocalEvents
|
||||
if (player.Faction == localFaction) {
|
||||
if (mech.Owner.asInstanceOf[Building].CaptureTerminalIsHacked) {
|
||||
//this is actually futile, as a hacked base does not grant access to the terminal
|
||||
events ! LocalServiceMessage(localFaction.toString, LocalAction.SetEmpire(guid, localFaction))
|
||||
}
|
||||
kickAllOccupantsNotOfFaction(zone, guid, mech, localFaction)
|
||||
} else {
|
||||
opposingFactionsMayAccess(zone, guid, localFaction)
|
||||
kickAllOccupantsOfFaction(zone, guid, mech, localFaction)
|
||||
}
|
||||
ImplantTerminalMechControl
|
||||
.FindPairedTerminalInterface(zone, guid)
|
||||
.foreach(GenericHackables.FinishHacking(_, player, unk = 3212836864L)())
|
||||
}
|
||||
|
||||
override def performClearHack(data: Option[Any], replyTo: ActorRef): Unit = {
|
||||
//todo don't now how to properly unhack this amenity
|
||||
HackableObject.HackedBy.collect { _ =>
|
||||
super.performClearHack(data, replyTo)
|
||||
val toFaction = HackableObject.Faction
|
||||
val zone = HackableObject.Zone
|
||||
val guid = HackableObject.GUID
|
||||
noAccessByOpposingFactions(zone, guid, toFaction)
|
||||
kickAllOccupantsNotOfFaction(zone, guid, mech, toFaction)
|
||||
}
|
||||
}
|
||||
|
||||
override protected def captureTerminalIsHacked(@unused terminal: CaptureTerminal): Unit = {
|
||||
//todo don't now how to properly handle a hacked mech
|
||||
super.captureTerminalIsHacked(terminal)
|
||||
val zone = HackableObject.Zone
|
||||
val guid = HackableObject.GUID
|
||||
kickAllOccupantsNotOfFactionWithTest(zone, guid, mech, (a: PlanetSideEmpire.Value) => { true })
|
||||
}
|
||||
|
||||
override protected def captureTerminalIsResecured(terminal: CaptureTerminal): Unit = {
|
||||
//todo don't now how to properly handle a hacked mech
|
||||
super.captureTerminalIsResecured(terminal)
|
||||
//if hacked, correct
|
||||
val zone = HackableObject.Zone
|
||||
val guid = HackableObject.GUID
|
||||
val toFaction = HackableObject.Faction
|
||||
HackableObject.HackedBy.collect {
|
||||
case hackInfo if hackInfo.hackerFaction != toFaction =>
|
||||
opposingFactionsMayAccess(zone, guid, toFaction)
|
||||
}
|
||||
}
|
||||
|
||||
private def opposingFactionsMayAccess(
|
||||
zone: Zone,
|
||||
guid: PlanetSideGUID,
|
||||
setToFaction: PlanetSideEmpire.Value
|
||||
): Unit = {
|
||||
val events = zone.LocalEvents
|
||||
opposingFactionsAre(setToFaction).foreach { faction =>
|
||||
events ! LocalServiceMessage(faction.toString, LocalAction.SetEmpire(guid, faction))
|
||||
}
|
||||
}
|
||||
|
||||
private def noAccessByOpposingFactions(
|
||||
zone: Zone,
|
||||
guid: PlanetSideGUID,
|
||||
setToFaction: PlanetSideEmpire.Value
|
||||
): Unit = {
|
||||
val events = zone.LocalEvents
|
||||
opposingFactionsAre(setToFaction).foreach { faction =>
|
||||
events ! LocalServiceMessage(faction.toString, LocalAction.SetEmpire(guid, setToFaction))
|
||||
}
|
||||
}
|
||||
|
||||
private def opposingFactionsAre(faction: PlanetSideEmpire.Value): PlanetSideEmpire.ValueSet = {
|
||||
PlanetSideEmpire
|
||||
.values
|
||||
.filterNot { f => f == PlanetSideEmpire.NEUTRAL && f == faction }
|
||||
}
|
||||
|
||||
private def kickAllOccupantsOfFaction(
|
||||
zone: Zone,
|
||||
guid: PlanetSideGUID,
|
||||
obj: Mountable,
|
||||
isFaction: PlanetSideEmpire.Value
|
||||
): Unit = {
|
||||
kickAllOccupantsNotOfFactionWithTest(zone, guid, obj, (a: PlanetSideEmpire.Value) => { a == isFaction })
|
||||
}
|
||||
|
||||
private def kickAllOccupantsNotOfFaction(
|
||||
zone: Zone,
|
||||
guid: PlanetSideGUID,
|
||||
obj: Mountable,
|
||||
isFaction: PlanetSideEmpire.Value
|
||||
): Unit = {
|
||||
kickAllOccupantsNotOfFactionWithTest(zone, guid, obj, (a: PlanetSideEmpire.Value) => { a != isFaction })
|
||||
}
|
||||
|
||||
private def kickAllOccupantsNotOfFactionWithTest(
|
||||
zone: Zone,
|
||||
guid: PlanetSideGUID,
|
||||
obj: Mountable,
|
||||
test: PlanetSideEmpire.Value => Boolean
|
||||
): Unit = {
|
||||
val zoneId = zone.id
|
||||
val events = zone.LocalEvents
|
||||
obj.Seats.values.foreach(seat =>
|
||||
seat.occupant.collect {
|
||||
case player if test(player.Faction) =>
|
||||
seat.unmount(player)
|
||||
player.VehicleSeated = None
|
||||
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2 = false, guid))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -330,6 +330,21 @@ class FacilityTurretControl(turret: FacilityTurret)
|
|||
}
|
||||
|
||||
override protected def captureTerminalIsHacked(terminal: CaptureTerminal): Unit = {
|
||||
super.captureTerminalIsHacked(terminal)
|
||||
// Remove seated occupants
|
||||
val guid = turret.GUID
|
||||
val zone = turret.Zone
|
||||
val zoneId = zone.id
|
||||
val events = zone.VehicleEvents
|
||||
turret.Seats.values.zipWithIndex.foreach {
|
||||
case (seat, seat_num) =>
|
||||
seat.occupant.collect {
|
||||
case player =>
|
||||
seat.unmount(player)
|
||||
player.VehicleSeated = None
|
||||
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, seat_num, unk2=true, guid))
|
||||
}
|
||||
}
|
||||
captureTerminalChanges(terminal, super.captureTerminalIsHacked, actionDelays = 3000L)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
|||
import net.psforever.objects.serverobject.shuttle.OrbitalShuttlePad
|
||||
import net.psforever.objects.serverobject.structures.{Building, BuildingDefinition, FoundationBuilder, StructureType, WarpGate}
|
||||
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalDefinition}
|
||||
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
|
||||
import net.psforever.objects.serverobject.terminals.implant.{ImplantTerminalInterface, ImplantTerminalMech}
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.serverobject.turret.{FacilityTurret, FacilityTurretDefinition, VanuSentry}
|
||||
import net.psforever.objects.serverobject.zipline.ZipLinePath
|
||||
|
|
@ -637,7 +637,7 @@ object Zones {
|
|||
|
||||
zoneMap.addLocalObject(
|
||||
closestTerminal.guid,
|
||||
Terminal.Constructor(closestTerminal.position, GlobalDefinitions.implant_terminal_interface),
|
||||
ImplantTerminalInterface.Constructor(closestTerminal.position, GlobalDefinitions.implant_terminal_interface),
|
||||
owningBuildingGuid = ownerGuid
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue