mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-20 02:24:45 +00:00
Merge pull request #218 from Mazo/feature/TerminalHacking
Terminal hacking
This commit is contained in:
commit
3717d84750
|
|
@ -0,0 +1,49 @@
|
|||
package net.psforever.objects.serverobject.hackable
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.packet.game.{PlanetSideGUID, TriggeredSound}
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
trait Hackable {
|
||||
/** An entry that maintains a reference to the `Player`, and the player's GUID and location when the message was received. */
|
||||
private var hackedBy : Option[(Player, PlanetSideGUID, Vector3)] = None
|
||||
|
||||
private var hackSound : TriggeredSound.Value = TriggeredSound.HackDoor
|
||||
|
||||
def HackedBy : Option[(Player, PlanetSideGUID, Vector3)] = hackedBy
|
||||
|
||||
def HackedBy_=(agent : Player) : Option[(Player, PlanetSideGUID, Vector3)] = HackedBy_=(Some(agent))
|
||||
|
||||
/**
|
||||
* Set the hack state of this object by recording important information about the player that caused it.
|
||||
* Set the hack state if there is no current hack state.
|
||||
* Override the hack state with a new hack state if the new user has different faction affiliation.
|
||||
* @param agent a `Player`, or no player
|
||||
* @return the player hack entry
|
||||
*/
|
||||
def HackedBy_=(agent : Option[Player]) : Option[(Player, PlanetSideGUID, Vector3)] = {
|
||||
hackedBy match {
|
||||
case None =>
|
||||
//set the hack state if there is no current hack state
|
||||
if(agent.isDefined) {
|
||||
hackedBy = Some(agent.get, agent.get.GUID, agent.get.Position)
|
||||
}
|
||||
case Some(_) =>
|
||||
//clear the hack state
|
||||
if(agent.isEmpty) {
|
||||
hackedBy = None
|
||||
}
|
||||
//override the hack state with a new hack state if the new user has different faction affiliation
|
||||
else if(agent.get.Faction != hackedBy.get._1.Faction) {
|
||||
hackedBy = Some(agent.get, agent.get.GUID, agent.get.Position)
|
||||
}
|
||||
}
|
||||
HackedBy
|
||||
}
|
||||
|
||||
def HackSound : TriggeredSound.Value = hackSound
|
||||
def HackSound_=(sound : TriggeredSound.Value) : TriggeredSound.Value = {
|
||||
hackSound = sound
|
||||
hackSound
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.locks
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.serverobject.hackable.Hackable
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types.Vector3
|
||||
import net.psforever.packet.game.TriggeredSound
|
||||
|
||||
/**
|
||||
* A structure-owned server object that is a "door lock."<br>
|
||||
|
|
@ -15,44 +14,9 @@ import net.psforever.types.Vector3
|
|||
* The `IFFLock` is ideally associated with a server map object - a `Door` - to which it acts as a gatekeeper.
|
||||
* @param idef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
||||
*/
|
||||
class IFFLock(private val idef : IFFLockDefinition) extends Amenity {
|
||||
/**
|
||||
* An entry that maintains a reference to the `Player`, and the player's GUID and location when the message was received.
|
||||
*/
|
||||
private var hackedBy : Option[(Player, PlanetSideGUID, Vector3)] = None
|
||||
|
||||
def HackedBy : Option[(Player, PlanetSideGUID, Vector3)] = hackedBy
|
||||
|
||||
def HackedBy_=(agent : Player) : Option[(Player, PlanetSideGUID, Vector3)] = HackedBy_=(Some(agent))
|
||||
|
||||
/**
|
||||
* Set the hack state of this object by recording important information about the player that caused it.
|
||||
* Set the hack state if there is no current hack state.
|
||||
* Override the hack state with a new hack state if the new user has different faction affiliation.
|
||||
* @param agent a `Player`, or no player
|
||||
* @return the player hack entry
|
||||
*/
|
||||
def HackedBy_=(agent : Option[Player]) : Option[(Player, PlanetSideGUID, Vector3)] = {
|
||||
hackedBy match {
|
||||
case None =>
|
||||
//set the hack state if there is no current hack state
|
||||
if(agent.isDefined) {
|
||||
hackedBy = Some(agent.get, agent.get.GUID, agent.get.Position)
|
||||
}
|
||||
case Some(_) =>
|
||||
//clear the hack state
|
||||
if(agent.isEmpty) {
|
||||
hackedBy = None
|
||||
}
|
||||
//override the hack state with a new hack state if the new user has different faction affiliation
|
||||
else if(agent.get.Faction != hackedBy.get._1.Faction) {
|
||||
hackedBy = Some(agent.get, agent.get.GUID, agent.get.Position)
|
||||
}
|
||||
}
|
||||
HackedBy
|
||||
}
|
||||
|
||||
class IFFLock(private val idef : IFFLockDefinition) extends Amenity with Hackable {
|
||||
def Definition : IFFLockDefinition = idef
|
||||
HackSound = TriggeredSound.HackDoor
|
||||
}
|
||||
|
||||
object IFFLock {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class IFFLockControl(lock : IFFLock) extends Actor with FactionAffinityBehavior.
|
|||
def receive : Receive = checkBehavior.orElse {
|
||||
case CommonMessages.Hack(player) =>
|
||||
lock.HackedBy = player
|
||||
|
||||
sender ! true
|
||||
case CommonMessages.ClearHack() =>
|
||||
lock.HackedBy = None
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,13 @@ package net.psforever.objects.serverobject.mblocker
|
|||
|
||||
import akka.actor.{ActorContext, Props}
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
import net.psforever.objects.serverobject.hackable.Hackable
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.packet.game.TriggeredSound
|
||||
|
||||
class Locker extends Amenity {
|
||||
class Locker extends Amenity with Hackable {
|
||||
def Definition : LockerDefinition = GlobalDefinitions.mb_locker
|
||||
HackSound = TriggeredSound.HackTerminal
|
||||
}
|
||||
|
||||
object Locker {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package net.psforever.objects.serverobject.mblocker
|
||||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||
|
||||
/**
|
||||
|
|
@ -12,6 +13,11 @@ class LockerControl(locker : Locker) extends Actor with FactionAffinityBehavior.
|
|||
def FactionObject : FactionAffinity = locker
|
||||
|
||||
def receive : Receive = checkBehavior.orElse {
|
||||
case CommonMessages.Hack(player) =>
|
||||
locker.HackedBy = player
|
||||
sender ! true
|
||||
case CommonMessages.ClearHack() =>
|
||||
locker.HackedBy = None
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||
|
||||
/**
|
||||
|
|
@ -18,6 +19,11 @@ class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor
|
|||
def receive : Receive = checkBehavior
|
||||
.orElse(proximityBehavior)
|
||||
.orElse {
|
||||
case CommonMessages.Hack(player) =>
|
||||
term.HackedBy = player
|
||||
sender ! true
|
||||
case CommonMessages.ClearHack() =>
|
||||
term.HackedBy = None
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,48 +3,17 @@ package net.psforever.objects.serverobject.terminals
|
|||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.definition.VehicleDefinition
|
||||
import net.psforever.objects.serverobject.hackable.Hackable
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||
import net.psforever.types.{TransactionType, Vector3}
|
||||
import net.psforever.packet.game.{ItemTransactionMessage, TriggeredSound}
|
||||
import net.psforever.types.TransactionType
|
||||
|
||||
/**
|
||||
* A structure-owned server object that is a "terminal" that can be accessed for amenities and services.
|
||||
* @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
||||
*/
|
||||
class Terminal(tdef : TerminalDefinition) extends Amenity {
|
||||
/** An entry that maintains a reference to the `Player`, and the player's GUID and location when the message was received. */
|
||||
private var hackedBy : Option[(Player, PlanetSideGUID, Vector3)] = None
|
||||
|
||||
def HackedBy : Option[(Player, PlanetSideGUID, Vector3)] = hackedBy
|
||||
|
||||
def HackedBy_=(agent : Player) : Option[(Player, PlanetSideGUID, Vector3)] = HackedBy_=(Some(agent))
|
||||
|
||||
/**
|
||||
* Set the hack state of this object by recording important information about the player that caused it.
|
||||
* Set the hack state if there is no current hack state.
|
||||
* Override the hack state with a new hack state if the new user has different faction affiliation.
|
||||
* @param agent a `Player`, or no player
|
||||
* @return the player hack entry
|
||||
*/
|
||||
def HackedBy_=(agent : Option[Player]) : Option[(Player, PlanetSideGUID, Vector3)] = {
|
||||
hackedBy match {
|
||||
case None =>
|
||||
//set the hack state if there is no current hack state
|
||||
if(agent.isDefined) {
|
||||
hackedBy = Some(agent.get, agent.get.GUID, agent.get.Position)
|
||||
}
|
||||
case Some(_) =>
|
||||
//clear the hack state
|
||||
if(agent.isEmpty) {
|
||||
hackedBy = None
|
||||
}
|
||||
//override the hack state with a new hack state if the new user has different faction affiliation
|
||||
else if(agent.get.Faction != hackedBy.get._1.Faction) {
|
||||
hackedBy = Some(agent.get, agent.get.GUID, agent.get.Position)
|
||||
}
|
||||
}
|
||||
HackedBy
|
||||
}
|
||||
class Terminal(tdef : TerminalDefinition) extends Amenity with Hackable {
|
||||
HackSound = TriggeredSound.HackTerminal
|
||||
|
||||
//the following fields and related methods are neither finalized nor integrated; GOTO Request
|
||||
private var health : Int = 100 //TODO not real health value
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||
|
||||
/**
|
||||
|
|
@ -15,6 +16,12 @@ class TerminalControl(term : Terminal) extends Actor with FactionAffinityBehavio
|
|||
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 _ => ;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ import scodec.codecs._
|
|||
* `77 - Cavern Facility Captures. Value is the number of captures`<br>
|
||||
* `78 - Cavern Kills. Value is the number of kills`<br>
|
||||
* `106 - Custom Head`<br>
|
||||
* `116 - Apply colour to REK beam and REK icon above players (0 = yellow, 1 = red, 2 = purple, 3 = blue)`<br>
|
||||
* Client to Server : <br>
|
||||
* `106 - Custom Head`<br>
|
||||
* <br>
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ object TriggeredSound extends Enumeration {
|
|||
|
||||
val
|
||||
SpawnInTube,
|
||||
Unknown1,
|
||||
Hack,
|
||||
HackTerminal,
|
||||
HackVehicle,
|
||||
HackDoor,
|
||||
Unknown4,
|
||||
LockedOut,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import scodec.codecs._
|
|||
/**
|
||||
* (Where the child object was before it was moved is not specified or important.)<br>
|
||||
* @param avatar_guid the player.
|
||||
* @param unk1 dont know how call that. It's the "item" ID when use a rek to hack or a medkit to heal.
|
||||
* @param item_used_guid The "item" GUID used e.g. a rek to hack or a medkit to heal.
|
||||
* @param object_guid can be : Door, Terminal, Avatar (medkit).
|
||||
* @param unk2 ???
|
||||
* @param unk3 ??? true when use a rek (false when door, medkit or open equip term)
|
||||
|
|
@ -21,7 +21,7 @@ import scodec.codecs._
|
|||
* @param itemType object ID from game_objects.adb (ex 612 is an equipment terminal, for medkit we have 121 (avatar))
|
||||
*/
|
||||
final case class UseItemMessage(avatar_guid : PlanetSideGUID,
|
||||
unk1 : Int,
|
||||
item_used_guid : Int,
|
||||
object_guid : PlanetSideGUID,
|
||||
unk2 : Long,
|
||||
unk3 : Boolean,
|
||||
|
|
@ -40,7 +40,7 @@ final case class UseItemMessage(avatar_guid : PlanetSideGUID,
|
|||
object UseItemMessage extends Marshallable[UseItemMessage] {
|
||||
implicit val codec : Codec[UseItemMessage] = (
|
||||
("avatar_guid" | PlanetSideGUID.codec) ::
|
||||
("unk1" | uint16L) ::
|
||||
("item_used_guid" | uint16L) ::
|
||||
("object_guid" | PlanetSideGUID.codec) ::
|
||||
("unk2" | uint32L) ::
|
||||
("unk3" | bool) ::
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import net.psforever.objects.serverobject.affinity.FactionAffinity
|
|||
import net.psforever.objects.serverobject.deploy.Deployment
|
||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
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
|
||||
|
|
@ -44,8 +45,10 @@ import services.vehicle.VehicleAction.UnstowEquipment
|
|||
import services.vehicle.{VehicleAction, VehicleResponse, VehicleServiceMessage, VehicleServiceResponse}
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.concurrent.Future
|
||||
import scala.concurrent.duration._
|
||||
import scala.util.Success
|
||||
import akka.pattern.ask
|
||||
|
||||
class WorldSessionActor extends Actor with MDCContextAware {
|
||||
import WorldSessionActor._
|
||||
|
|
@ -391,13 +394,23 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(GenericObjectStateMsg(door_guid, 17))
|
||||
|
||||
case LocalResponse.HackClear(target_guid, unk1, unk2) =>
|
||||
// Reset hack state for all players
|
||||
sendResponse(HackMessage(0, target_guid, guid, 0, unk1, HackState.HackCleared, unk2))
|
||||
// Set the object faction displayed back to it's original owner faction
|
||||
sendResponse(SetEmpireMessage(target_guid, continent.GUID(target_guid).get.asInstanceOf[FactionAffinity].Faction))
|
||||
|
||||
case LocalResponse.HackObject(target_guid, unk1, unk2) =>
|
||||
if(tplayer_guid != guid) {
|
||||
if(tplayer_guid != guid && continent.GUID(target_guid).get.asInstanceOf[Hackable].HackedBy.get._1.Faction != player.Faction) {
|
||||
// If the player is not in the faction that hacked this object then send the packet that it's been hacked, so they can either unhack it or use the hacked object
|
||||
// Don't send this to the faction that hacked the object, otherwise it will interfere with the new SetEmpireMessage QoL change that changes the object colour to their faction (but only visible to that faction)
|
||||
sendResponse(HackMessage(0, target_guid, guid, 100, unk1, HackState.Hacked, unk2))
|
||||
}
|
||||
|
||||
if(continent.GUID(target_guid).get.asInstanceOf[Hackable].HackedBy.get._1.Faction == player.Faction){
|
||||
// Make the hacked object look like it belongs to the hacking empire, but only for that empire's players (so that infiltrators on stealth missions won't be given away to opposing factions)
|
||||
sendResponse(SetEmpireMessage(target_guid, player.Faction))
|
||||
}
|
||||
|
||||
case LocalResponse.ProximityTerminalEffect(object_guid, effectState) =>
|
||||
if(tplayer_guid != guid) {
|
||||
sendResponse(ProximityTerminalUseMessage(PlanetSideGUID(0), object_guid, effectState))
|
||||
|
|
@ -1510,7 +1523,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
if(progressBarVal > 100) { //done
|
||||
progressBarValue = None
|
||||
log.info(s"Hacked a $target")
|
||||
sendResponse(HackMessage(0, target.GUID, player.GUID, 100, 1114636288L, HackState.Hacked, 8L))
|
||||
// sendResponse(HackMessage(0, target.GUID, player.GUID, 100, 1114636288L, HackState.Hacked, 8L))
|
||||
completeAction()
|
||||
}
|
||||
else { //continue next tick
|
||||
|
|
@ -2257,6 +2270,23 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
else if((player.DrawnSlot = held_holsters) != before) {
|
||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.ObjectHeld(player.GUID, player.LastDrawnSlot))
|
||||
|
||||
|
||||
// Ignore non-equipment holsters
|
||||
//todo: check current suit holster slots?
|
||||
if(held_holsters >= 0 && held_holsters < 5) {
|
||||
player.Holsters()(held_holsters).Equipment match {
|
||||
case Some(unholsteredItem : Equipment) =>
|
||||
if(unholsteredItem.Definition == GlobalDefinitions.remote_electronics_kit) {
|
||||
// Player has ulholstered a REK - we need to set an atttribute on the REK itself to change the beam/icon colour to the correct one for the player's hack level
|
||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(unholsteredItem.GUID, 116, GetPlayerHackData().hackLevel))
|
||||
}
|
||||
case None => ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Stop using proximity terminals if player unholsters a weapon (which should re-trigger the proximity effect and re-holster the weapon)
|
||||
if(player.VisibleSlots.contains(held_holsters)) {
|
||||
usingMedicalTerminal match {
|
||||
case Some(term_guid) =>
|
||||
|
|
@ -2437,7 +2467,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case msg @ AvatarImplantMessage(_, _, _, _) => //(player_guid, unk1, unk2, implant) =>
|
||||
log.info("AvatarImplantMessage: " + msg)
|
||||
|
||||
case msg @ UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType) =>
|
||||
case msg @ UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType) =>
|
||||
log.info("UseItem: " + msg)
|
||||
// TODO: Not all fields in the response are identical to source in real packet logs (but seems to be ok)
|
||||
// TODO: Not all incoming UseItemMessage's respond with another UseItemMessage (i.e. doors only send out GenericObjectStateMsg)
|
||||
|
|
@ -2459,9 +2489,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
player.Slot(player.DrawnSlot).Equipment match {
|
||||
case Some(tool : SimpleItem) =>
|
||||
if(tool.Definition == GlobalDefinitions.remote_electronics_kit) {
|
||||
//TODO get player hack level (for now, presume 15s in intervals of 4/s)
|
||||
progressBarValue = Some(-2.66f)
|
||||
self ! WorldSessionActor.ItemHacking(player, panel, tool.GUID, 2.66f, FinishHackingDoor(panel, 1114636288L))
|
||||
progressBarValue = Some(-GetPlayerHackSpeed())
|
||||
self ! WorldSessionActor.ItemHacking(player, panel, tool.GUID, GetPlayerHackSpeed(), FinishHacking(panel, 1114636288L))
|
||||
log.info("Hacking a door~")
|
||||
}
|
||||
case _ => ;
|
||||
|
|
@ -2471,11 +2500,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case Some(obj : Player) =>
|
||||
if(obj.isBackpack) {
|
||||
log.info(s"UseItem: $player looting the corpse of $obj")
|
||||
sendResponse(UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
accessedContainer = Some(obj)
|
||||
}
|
||||
else if(!unk3) { //potential kit use
|
||||
continent.GUID(unk1) match {
|
||||
continent.GUID(item_used_guid) match {
|
||||
case Some(kit : Kit) =>
|
||||
player.Find(kit) match {
|
||||
case Some(index) =>
|
||||
|
|
@ -2491,7 +2520,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case Some(index) =>
|
||||
whenUsedLastKit = System.currentTimeMillis
|
||||
player.Slot(index).Equipment = None //remove from slot immediately; must exist on client for next packet
|
||||
sendResponse(UseItemMessage(avatar_guid, unk1, object_guid, 0, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, 0, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
sendResponse(ObjectDeleteMessage(kit.GUID, 0))
|
||||
taskResolver ! GUIDTask.UnregisterEquipment(kit)(continent.GUID)
|
||||
//TODO better health/damage control workflow
|
||||
|
|
@ -2513,16 +2542,26 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case Some(item) =>
|
||||
log.warn(s"UseItem: looking for Kit to use, but found $item instead")
|
||||
case None =>
|
||||
log.warn(s"UseItem: anticipated a Kit $unk1, but can't find it")
|
||||
log.warn(s"UseItem: anticipated a Kit $item_used_guid, but can't find it")
|
||||
}
|
||||
}
|
||||
|
||||
case Some(obj : Locker) =>
|
||||
if(player.Faction == obj.Faction) {
|
||||
if(obj.Faction != player.Faction && obj.HackedBy.isEmpty) {
|
||||
player.Slot(player.DrawnSlot).Equipment match {
|
||||
case Some(tool: SimpleItem) =>
|
||||
if (tool.Definition == GlobalDefinitions.remote_electronics_kit) {
|
||||
progressBarValue = Some(-GetPlayerHackSpeed())
|
||||
self ! WorldSessionActor.ItemHacking(player, obj, tool.GUID, GetPlayerHackSpeed(), FinishHacking(obj, 3212836864L))
|
||||
log.info("Hacking a locker")
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
} else if(player.Faction == obj.Faction || !obj.HackedBy.isEmpty) {
|
||||
log.info(s"UseItem: $player accessing a locker")
|
||||
val container = player.Locker
|
||||
accessedContainer = Some(container)
|
||||
sendResponse(UseItemMessage(avatar_guid, unk1, container.GUID, unk2, unk3, unk4, unk5, unk6, unk7, unk8, 456))
|
||||
sendResponse(UseItemMessage(avatar_guid, item_used_guid, container.GUID, unk2, unk3, unk4, unk5, unk6, unk7, unk8, 456))
|
||||
}
|
||||
else {
|
||||
log.info(s"UseItem: not $player's locker")
|
||||
|
|
@ -2545,7 +2584,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
obj.AccessingTrunk = player.GUID
|
||||
accessedContainer = Some(obj)
|
||||
AccessContents(obj)
|
||||
sendResponse(UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
}
|
||||
else {
|
||||
log.info(s"UseItem: $obj's trunk is not currently accessible for $player")
|
||||
|
|
@ -2578,14 +2617,29 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
else if(obj.Definition.isInstanceOf[RepairRearmSiloDefinition]) {
|
||||
FindLocalVehicle match {
|
||||
case Some(vehicle) =>
|
||||
sendResponse(UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
sendResponse(UseItemMessage(avatar_guid, unk1, vehicle.GUID, unk2, unk3, unk4, unk5, unk6, unk7, unk8, vehicle.Definition.ObjectId))
|
||||
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
sendResponse(UseItemMessage(avatar_guid, item_used_guid, vehicle.GUID, unk2, unk3, unk4, unk5, unk6, unk7, unk8, vehicle.Definition.ObjectId))
|
||||
case None =>
|
||||
log.error("UseItem: expected seated vehicle, but found none")
|
||||
}
|
||||
}
|
||||
else {
|
||||
sendResponse(UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
if(obj.Faction != player.Faction && obj.HackedBy.isEmpty) {
|
||||
player.Slot(player.DrawnSlot).Equipment match {
|
||||
case Some(tool: SimpleItem) =>
|
||||
if (tool.Definition == GlobalDefinitions.remote_electronics_kit) {
|
||||
progressBarValue = Some(-GetPlayerHackSpeed())
|
||||
self ! WorldSessionActor.ItemHacking(player, obj, tool.GUID, GetPlayerHackSpeed(), FinishHacking(obj, 3212836864L))
|
||||
log.info("Hacking a terminal")
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
} else if (obj.Faction == player.Faction || !obj.HackedBy.isEmpty) {
|
||||
// If hacked only allow access to the faction that hacked it
|
||||
// Otherwise allow the faction that owns the terminal to use it
|
||||
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case Some(obj : SpawnTube) =>
|
||||
|
|
@ -2599,7 +2653,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
case Some(obj) =>
|
||||
log.warn(s"UseItem: don't know how to handle $obj; taking a shot in the dark")
|
||||
sendResponse(UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
|
||||
case None =>
|
||||
log.error(s"UseItem: can not find object $object_guid")
|
||||
|
|
@ -3423,20 +3477,25 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
|
||||
/**
|
||||
* The process of hacking the `Door` `IFFLock` is completed.
|
||||
* Pass the message onto the lock and onto the local events system.
|
||||
* @param target the `IFFLock` belonging to the door that is being hacked
|
||||
* 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 `HackingMessage` as `unk5`
|
||||
* used by `HackMessage` as `unk5`
|
||||
* @see `HackMessage`
|
||||
*/
|
||||
//TODO add params here depending on which params in HackMessage are important
|
||||
//TODO sound should be centered on IFFLock, not on player
|
||||
private def FinishHackingDoor(target : IFFLock, unk : Long)() : Unit = {
|
||||
target.Actor ! CommonMessages.Hack(player)
|
||||
localService ! LocalServiceMessage(continent.Id, LocalAction.TriggerSound(player.GUID, TriggeredSound.HackDoor, player.Position, 30, 0.49803925f))
|
||||
private def FinishHacking(target : PlanetSideServerObject with Hackable, unk : Long)() : Unit = {
|
||||
// Wait for the target actor to set the HackedBy property, otherwise LocalAction.HackTemporarily will not complete properly
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
ask(target.Actor, CommonMessages.Hack(player))(1 second).mapTo[Boolean].onComplete {
|
||||
case Success(_) =>
|
||||
localService ! LocalServiceMessage(continent.Id, LocalAction.TriggerSound(player.GUID, target.HackSound, player.Position, 30, 0.49803925f))
|
||||
localService ! LocalServiceMessage(continent.Id, LocalAction.HackTemporarily(player.GUID, continent, target, unk))
|
||||
case scala.util.Failure(_) => log.warn(s"Hack message failed on target guid: ${target.GUID}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Temporary function that iterates over vehicle permissions and turns them into `PlanetsideAttributeMessage` packets.<br>
|
||||
|
|
@ -4863,6 +4922,30 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
log.trace("WORLD SEND RAW: " + pkt)
|
||||
sendResponse(RawPacket(pkt))
|
||||
}
|
||||
|
||||
def GetPlayerHackSpeed(): Float = {
|
||||
if(player.Certifications.contains(CertificationType.ExpertHacking) || player.Certifications.contains(CertificationType.ElectronicsExpert)) {
|
||||
10.64f
|
||||
} else if(player.Certifications.contains(CertificationType.AdvancedHacking)) {
|
||||
5.32f
|
||||
} else {
|
||||
2.66f
|
||||
}
|
||||
}
|
||||
|
||||
def GetPlayerHackData(): PlayerHackData = {
|
||||
if(player.Certifications.contains(CertificationType.ExpertHacking) || player.Certifications.contains(CertificationType.ElectronicsExpert)) {
|
||||
PlayerHackData(3, 10.64f)
|
||||
} else if(player.Certifications.contains(CertificationType.AdvancedHacking)) {
|
||||
PlayerHackData(2, 7.98f)
|
||||
} else if (player.Certifications.contains(CertificationType.Hacking)) {
|
||||
PlayerHackData(1, 5.32f)
|
||||
} else {
|
||||
PlayerHackData(0, 2.66f)
|
||||
}
|
||||
}
|
||||
|
||||
case class PlayerHackData(hackLevel: Int, hackSpeed: Float)
|
||||
}
|
||||
|
||||
object WorldSessionActor {
|
||||
|
|
|
|||
Loading…
Reference in a new issue