Fix implant terminal hacking (#246)

* Fix hacking implant terminals

* Remove duplication and apply some DRY
This commit is contained in:
Mazo 2019-04-04 19:26:43 +01:00 committed by Fate-JH
parent cd5caf58a0
commit 8313ce6491
10 changed files with 99 additions and 50 deletions

View file

@ -0,0 +1,27 @@
package net.psforever.objects.serverobject.hackable
import akka.actor.Actor
import net.psforever.objects.serverobject.CommonMessages
object HackableBehavior {
/**
* The logic governing generic `Hackable` objects that use the `Hack` and `ClearHack` message.
* This is a mix-in trait for combining with existing Receive` logic.
* @see `Hackable`
*/
trait GenericHackable {
this : Actor =>
def HackableObject : Hackable
val hackableBehavior : Receive = {
case CommonMessages.Hack(player) =>
val obj = HackableObject
obj.HackedBy = player
sender ! true
case CommonMessages.ClearHack() =>
val obj = HackableObject
obj.HackedBy = None
}
}
}

View file

@ -3,18 +3,24 @@ package net.psforever.objects.serverobject.implantmech
import net.psforever.objects.Player
import net.psforever.objects.definition.ObjectDefinition
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.vehicles.Seat
import net.psforever.packet.game.TriggeredSound
/**
* A structure-owned server object that is the visible and `Mountable` component of an implant terminal.
* For the most part, it merely implements the support data structures indicated by `Mountable`.
* @param idef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
*/
class ImplantTerminalMech(private val idef : ImplantTerminalMechDefinition) extends Amenity with Mountable {
class ImplantTerminalMech(private val idef : ImplantTerminalMechDefinition) extends Amenity with Mountable with Hackable {
private val seats : Map[Int, Seat] = Map( 0 -> new Seat(idef.Seats(0)) )
HackSound = TriggeredSound.HackTerminal
HackEffectDuration = Array(0, 30, 60, 90)
HackDuration = Array(0, 10, 5, 3)
def Seats : Map[Int, Seat] = seats
def Seat(seatNum : Int) : Option[Seat] = seats.get(seatNum)

View file

@ -4,20 +4,23 @@ package net.psforever.objects.serverobject.implantmech
import akka.actor.Actor
import net.psforever.objects.serverobject.mount.MountableBehavior
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.hackable.HackableBehavior
/**
* An `Actor` that handles messages being dispatched to a specific `ImplantTerminalMech`.
* @param mech the "mech" object being governed
*/
class ImplantTerminalMechControl(mech : ImplantTerminalMech) extends Actor with FactionAffinityBehavior.Check
with MountableBehavior.Mount with MountableBehavior.Dismount {
with MountableBehavior.Mount with MountableBehavior.Dismount with HackableBehavior.GenericHackable {
def MountableObject = mech //do not add type!
def HackableObject = mech
def FactionObject : FactionAffinity = mech
def receive : Receive = checkBehavior
.orElse(mountBehavior)
.orElse(dismountBehavior)
.orElse(hackableBehavior)
.orElse {
case _ => ;
}

View file

@ -4,22 +4,20 @@ package net.psforever.objects.serverobject.locks
import akka.actor.Actor
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.hackable.HackableBehavior
/**
* An `Actor` that handles messages being dispatched to a specific `IFFLock`.
* @param lock the `IFFLock` object being governed
* @see `CommonMessages`
*/
class IFFLockControl(lock : IFFLock) extends Actor with FactionAffinityBehavior.Check {
class IFFLockControl(lock : IFFLock) extends Actor with FactionAffinityBehavior.Check with HackableBehavior.GenericHackable {
def FactionObject : FactionAffinity = lock
def HackableObject = lock
def receive : Receive = checkBehavior.orElse {
case CommonMessages.Hack(player) =>
lock.HackedBy = player
sender ! true
case CommonMessages.ClearHack() =>
lock.HackedBy = None
case _ => ; //no default message
def receive : Receive = checkBehavior
.orElse(hackableBehavior)
.orElse {
case _ => ; //no default message
}
}

View file

@ -2,22 +2,20 @@
package net.psforever.objects.serverobject.mblocker
import akka.actor.Actor
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.hackable.HackableBehavior
/**
* An `Actor` that handles messages being dispatched to a specific `Locker`.
* @param locker the `Locker` object being governed
*/
class LockerControl(locker : Locker) extends Actor with FactionAffinityBehavior.Check {
class LockerControl(locker : Locker) extends Actor with FactionAffinityBehavior.Check with HackableBehavior.GenericHackable {
def FactionObject : FactionAffinity = locker
def HackableObject = locker
def receive : Receive = checkBehavior.orElse {
case CommonMessages.Hack(player) =>
locker.HackedBy = player
sender ! true
case CommonMessages.ClearHack() =>
locker.HackedBy = None
case _ => ;
def receive : Receive = checkBehavior
.orElse(hackableBehavior)
.orElse {
case _ => ;
}
}

View file

@ -5,6 +5,7 @@ import akka.actor.Actor
import net.psforever.objects.PlanetSideGameObject
import net.psforever.objects.entity.{Identifiable, WorldEntity}
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.turret.TurretDefinition
import net.psforever.types.Vector3
@ -25,7 +26,14 @@ object MountableBehavior {
val obj = MountableObject
obj.Seat(seat_num) match {
case Some(seat) =>
if(user.Faction == obj.Faction && (seat.Occupant = user).contains(user)) {
var isHacked = false
if(MountableObject.isInstanceOf[Hackable]) {
// This is a special case for implant terminals, since they're both mountable and hackable, but not jackable.
isHacked = MountableObject.asInstanceOf[Hackable].HackedBy.isDefined
}
if((user.Faction == obj.Faction || isHacked) && (seat.Occupant = user).contains(user)) {
user.VehicleSeated = obj.GUID
sender ! Mountable.MountMessages(user, Mountable.CanMount(obj, seat_num))
}

View file

@ -4,18 +4,16 @@ package net.psforever.objects.serverobject.terminals
import akka.actor.Actor
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.hackable.HackableBehavior
class CaptureTerminalControl(terminal : CaptureTerminal) extends Actor with FactionAffinityBehavior.Check {
class CaptureTerminalControl(terminal : CaptureTerminal) extends Actor with FactionAffinityBehavior.Check with HackableBehavior.GenericHackable {
def FactionObject : FactionAffinity = terminal
def HackableObject = terminal
def receive : Receive = checkBehavior.orElse {
case CommonMessages.Hack(player) =>
terminal.HackedBy = player
sender ! true
case CommonMessages.ClearHack() =>
terminal.HackedBy = None
def receive : Receive = checkBehavior
.orElse(hackableBehavior)
.orElse {
case _ => ; //no default message
}
}

View file

@ -5,6 +5,7 @@ import akka.actor.{Actor, ActorRef, Cancellable}
import net.psforever.objects._
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.hackable.HackableBehavior
import services.{Service, ServiceManager}
import scala.collection.mutable
@ -16,13 +17,14 @@ import scala.concurrent.duration._
* it returns the same type of messages - wrapped in a `TerminalMessage` - to the `sender`.
* @param term the proximity unit (terminal)
*/
class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor with FactionAffinityBehavior.Check {
class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor with FactionAffinityBehavior.Check with HackableBehavior.GenericHackable {
var service : ActorRef = ActorRef.noSender
var terminalAction : Cancellable = DefaultCancellable.obj
val callbacks : mutable.ListBuffer[ActorRef] = new mutable.ListBuffer[ActorRef]()
val log = org.log4s.getLogger
def FactionObject : FactionAffinity = term
def HackableObject = term
def TerminalObject : Terminal with ProximityUnit = term
@ -41,7 +43,8 @@ class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor
}
def Run : Receive = checkBehavior
.orElse {
.orElse(hackableBehavior)
.orElse {
case CommonMessages.Use(_, Some(target : PlanetSideGameObject)) =>
if(term.Definition.asInstanceOf[ProximityDefinition].Validations.exists(p => p(target))) {
Use(target, term.Continent, sender)
@ -79,13 +82,6 @@ class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor
}
})
case CommonMessages.Hack(player) =>
term.HackedBy = player
sender ! true
case CommonMessages.ClearHack() =>
term.HackedBy = None
case ProximityUnit.Action(_, _) =>
//reserved

View file

@ -4,26 +4,24 @@ package net.psforever.objects.serverobject.terminals
import akka.actor.Actor
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.hackable.HackableBehavior
/**
* An `Actor` that handles messages being dispatched to a specific `Terminal`.
* @param term the `Terminal` object being governed
*/
class TerminalControl(term : Terminal) extends Actor with FactionAffinityBehavior.Check {
class TerminalControl(term : Terminal) extends Actor with FactionAffinityBehavior.Check with HackableBehavior.GenericHackable {
def FactionObject : FactionAffinity = term
def HackableObject = term
def receive : Receive = checkBehavior.orElse {
case Terminal.Request(player, msg) =>
sender ! Terminal.TerminalMessage(player, msg, term.Request(player, msg))
def receive : Receive = checkBehavior
.orElse(hackableBehavior)
.orElse {
case Terminal.Request(player, msg) =>
sender ! Terminal.TerminalMessage(player, msg, term.Request(player, msg))
case CommonMessages.Hack(player) =>
term.HackedBy = player
sender ! true
case CommonMessages.ClearHack() =>
term.HackedBy = None
case _ => ;
}
case _ => ;
}
override def toString : String = term.Definition.Name
}

View file

@ -3673,6 +3673,23 @@ class WorldSessionActor extends Actor with MDCContextAware {
log.info(s"UseItem: not $player's locker")
}
case Some(implant_terminal : ImplantTerminalMech) =>
if(implant_terminal.Faction != player.Faction && implant_terminal.HackedBy.isEmpty) {
player.Slot(player.DrawnSlot).Equipment match {
case Some(tool: SimpleItem) =>
if (tool.Definition == GlobalDefinitions.remote_electronics_kit) {
val hackSpeed = GetPlayerHackSpeed(implant_terminal)
if(hackSpeed > 0) {
progressBarValue = Some(-hackSpeed)
self ! WorldSessionActor.HackingProgress(progressType = 1, player, implant_terminal, tool.GUID, hackSpeed, FinishHacking(implant_terminal, 3212836864L))
log.info("Hacking an implant terminal")
}
}
case _ => ;
}
}
case Some(captureTerminal : CaptureTerminal) =>
val hackedByCurrentFaction = (captureTerminal.Faction != player.Faction && !captureTerminal.HackedBy.isEmpty && captureTerminal.HackedBy.head._1.Faction == player.Faction)
val ownedByPlayerFactionAndHackedByEnemyFaction = (captureTerminal.Faction == player.Faction && !captureTerminal.HackedBy.isEmpty)