mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-04-22 04:15:19 +00:00
Timed capture consoles & towers / hacking improvements (#228)
* Add capture terminal definitions * Logging / documentation * Functionality for timed base hacks * Disable IFF locks while base is hacked * Hacking speed based on player's hacking certification level (and hack effect duration data - currently not functional) * Hack effect duration functionality * Sync hack states with clients joining the zone * Whitespace / comments * Allow IFF locks to be resecured by the owning faction if it has been hacked * Fix bases with no NTU silo failing to capture * Reset CC properly on hack that expires with no NTU in silo * Capture towers instantly and improve handling of hacked objects queue * Fix handling of neutral IFF Locks and remove unnecessary casting * Move HackCaptureActor to correct location * Re-enable Anguta door locks for air pad now hacking/resecuring IFF locks work Add capture terminals (timed CC only for now) for a few bases & a tower Add a few missed locks/doors Add a resource silo to Girru * Fix merge issues & missing documentation
This commit is contained in:
parent
8b5073dcbc
commit
abdebf09ba
23 changed files with 649 additions and 168 deletions
|
|
@ -10,6 +10,7 @@ import net.psforever.objects.serverobject.mblocker.Locker
|
|||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, StructureType, WarpGate}
|
||||
import net.psforever.objects.serverobject.terminals.{ProximityTerminal, Terminal}
|
||||
import net.psforever.objects.serverobject.terminals.{CaptureTerminal, ProximityTerminal, Terminal}
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
||||
import net.psforever.objects.serverobject.turret.MannedTurret
|
||||
|
|
@ -94,8 +95,8 @@ object Maps {
|
|||
DoorToLock(384, 1036)
|
||||
DoorToLock(386, 1038)
|
||||
DoorToLock(388, 1039)
|
||||
// DoorToLock(394, 1047)
|
||||
// DoorToLock(395, 1049)
|
||||
DoorToLock(394, 1047)
|
||||
DoorToLock(395, 1049)
|
||||
DoorToLock(401, 1053)
|
||||
DoorToLock(920, 968)
|
||||
|
||||
|
|
@ -173,6 +174,7 @@ object Maps {
|
|||
|
||||
def Building9() : Unit = { // Girru
|
||||
LocalBuilding(9, FoundationBuilder(Building.Structure(StructureType.Facility, Vector3(4397f, 5895f, 0)))) // Todo change pos
|
||||
LocalObject(225, CaptureTerminal.Constructor(capture_terminal))
|
||||
LocalObject(513, Door.Constructor)
|
||||
LocalObject(514, Door.Constructor)
|
||||
LocalObject(515, Door.Constructor)
|
||||
|
|
@ -225,6 +227,7 @@ object Maps {
|
|||
LocalObject(2015, Terminal.Constructor(order_terminal))
|
||||
LocalObject(2016, Terminal.Constructor(order_terminal))
|
||||
LocalObject(2017, Terminal.Constructor(order_terminal))
|
||||
LocalObject(2658, ResourceSilo.Constructor)
|
||||
LocalObject(2724, SpawnTube.Constructor(Vector3(4396.7656f, 5888.258f, 71.15625f), Vector3(0, 0, 92)))
|
||||
LocalObject(2725, SpawnTube.Constructor(Vector3(4397.211f, 5895.547f, 71.15625f), Vector3(0, 0, 92)))
|
||||
LocalObject(2726, SpawnTube.Constructor(Vector3(4397.2344f, 5902.8203f, 71.15625f), Vector3(0, 0, 92)))
|
||||
|
|
@ -244,6 +247,7 @@ object Maps {
|
|||
// LocalObject(1909, ProximityTerminal.Constructor(medical_terminal))
|
||||
// LocalObject(1910, ProximityTerminal.Constructor(medical_terminal))
|
||||
|
||||
ObjectToBuilding(225, 9)
|
||||
ObjectToBuilding(513, 9)
|
||||
ObjectToBuilding(514, 9)
|
||||
ObjectToBuilding(515, 9)
|
||||
|
|
@ -298,6 +302,7 @@ object Maps {
|
|||
ObjectToBuilding(2015, 9)
|
||||
ObjectToBuilding(2016, 9)
|
||||
ObjectToBuilding(2017, 9)
|
||||
ObjectToBuilding(2658, 9)
|
||||
ObjectToBuilding(2724, 9)
|
||||
ObjectToBuilding(2725, 9)
|
||||
ObjectToBuilding(2726, 9)
|
||||
|
|
@ -332,6 +337,7 @@ object Maps {
|
|||
|
||||
def Building10() : Unit = { // Hanish
|
||||
LocalBuilding(10, FoundationBuilder(Building.Structure(StructureType.Facility, Vector3(3749f, 5477f, 0)))) // Todo change pos
|
||||
LocalObject(223, CaptureTerminal.Constructor(capture_terminal))
|
||||
LocalObject(464, Door.Constructor)
|
||||
LocalObject(470, Door.Constructor(Vector3(3645.3984f, 5451.9688f, 88.890625f), Vector3(0, 0, 182)))
|
||||
LocalObject(471, Door.Constructor)
|
||||
|
|
@ -374,6 +380,7 @@ object Maps {
|
|||
LocalObject(971, IFFLock.Constructor)
|
||||
LocalObject(1105, IFFLock.Constructor)
|
||||
LocalObject(1106, IFFLock.Constructor)
|
||||
LocalObject(1107, IFFLock.Constructor)
|
||||
LocalObject(1108, IFFLock.Constructor)
|
||||
LocalObject(1113, IFFLock.Constructor)
|
||||
LocalObject(1114, IFFLock.Constructor)
|
||||
|
|
@ -431,6 +438,7 @@ object Maps {
|
|||
|
||||
// ObjectToBuilding(169, 10)
|
||||
// ObjectToBuilding(1906, 10)
|
||||
ObjectToBuilding(223, 10)
|
||||
ObjectToBuilding(464, 10)
|
||||
ObjectToBuilding(470, 10)
|
||||
ObjectToBuilding(471, 10)
|
||||
|
|
@ -469,10 +477,12 @@ object Maps {
|
|||
ObjectToBuilding(923, 10)
|
||||
ObjectToBuilding(932, 10)
|
||||
ObjectToBuilding(933, 10)
|
||||
ObjectToBuilding(959, 10)
|
||||
|
||||
ObjectToBuilding(971, 10)
|
||||
ObjectToBuilding(1105, 10)
|
||||
ObjectToBuilding(1106, 10)
|
||||
ObjectToBuilding(1107, 10)
|
||||
ObjectToBuilding(1108, 10)
|
||||
ObjectToBuilding(1113, 10)
|
||||
ObjectToBuilding(1114, 10)
|
||||
|
|
@ -528,6 +538,7 @@ object Maps {
|
|||
DoorToLock(475, 1108)
|
||||
DoorToLock(481, 1113)
|
||||
DoorToLock(771, 1106)
|
||||
DoorToLock(774, 1107)
|
||||
DoorToLock(779, 1114)
|
||||
DoorToLock(784, 1116)
|
||||
DoorToLock(785, 1115)
|
||||
|
|
@ -761,6 +772,7 @@ object Maps {
|
|||
}
|
||||
def Building33() : Unit = { // East Girru Gun Tower, Ishundar (ID: 62)
|
||||
LocalBuilding(33, FoundationBuilder(Building.Structure(StructureType.Tower, Vector3(4624f, 5915f, 0)))) // TODO loc
|
||||
LocalObject(2792, CaptureTerminal.Constructor(secondary_capture))
|
||||
LocalObject(2957, Door.Constructor)
|
||||
LocalObject(2958, Door.Constructor)
|
||||
LocalObject(542, Door.Constructor(Vector3(4625.9844f, 5910.211f, 55.75f), Vector3(0, 0, 180)))
|
||||
|
|
@ -777,6 +789,7 @@ object Maps {
|
|||
LocalObject(2733, SpawnTube.Constructor(respawn_tube_tower, Vector3(4624.758f, 5905.7344f, 45.984375f), Vector3(0, 0, 90)))
|
||||
LocalObject(2734, SpawnTube.Constructor(respawn_tube_tower, Vector3(4624.7266f, 5922.1484f, 45.984375f), Vector3(0, 0, 90)))
|
||||
|
||||
ObjectToBuilding(2792, 33)
|
||||
ObjectToBuilding(2957, 33)
|
||||
ObjectToBuilding(2958, 33)
|
||||
ObjectToBuilding(542, 33)
|
||||
|
|
@ -1694,6 +1707,7 @@ object Maps {
|
|||
LocalObject(396, Door.Constructor)
|
||||
LocalObject(397, Door.Constructor)
|
||||
LocalObject(398, Door.Constructor)
|
||||
LocalObject(399, Door.Constructor)
|
||||
LocalObject(462, Door.Constructor)
|
||||
LocalObject(463, Door.Constructor)
|
||||
LocalObject(522, ImplantTerminalMech.Constructor)
|
||||
|
|
@ -1741,6 +1755,7 @@ object Maps {
|
|||
ObjectToBuilding(396, 2)
|
||||
ObjectToBuilding(397, 2)
|
||||
ObjectToBuilding(398, 2)
|
||||
ObjectToBuilding(399, 2)
|
||||
ObjectToBuilding(462, 2)
|
||||
ObjectToBuilding(463, 2)
|
||||
ObjectToBuilding(522, 2)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
|
||||
|
|
@ -53,10 +54,11 @@ import services.vehicle.{VehicleAction, VehicleResponse, VehicleServiceMessage,
|
|||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.annotation.tailrec
|
||||
import scala.concurrent.Future
|
||||
import scala.concurrent.{Await, Future}
|
||||
import scala.concurrent.duration._
|
||||
import scala.util.Success
|
||||
import akka.pattern.ask
|
||||
import services.local.support.HackCaptureActor
|
||||
|
||||
class WorldSessionActor extends Actor with MDCContextAware {
|
||||
import WorldSessionActor._
|
||||
|
|
@ -560,10 +562,16 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(GenericObjectStateMsg(door_guid, 17))
|
||||
|
||||
case LocalResponse.HackClear(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))
|
||||
// Set the object faction displayed back to it's original owner faction
|
||||
sendResponse(SetEmpireMessage(target_guid, continent.GUID(target_guid).get.asInstanceOf[FactionAffinity].Faction))
|
||||
|
||||
continent.GUID(target_guid) match {
|
||||
case Some(obj) =>
|
||||
sendResponse(SetEmpireMessage(target_guid, obj.asInstanceOf[FactionAffinity].Faction))
|
||||
case None => ;
|
||||
}
|
||||
|
||||
case LocalResponse.HackObject(target_guid, unk1, unk2) =>
|
||||
if(tplayer_guid != guid && continent.GUID(target_guid).get.asInstanceOf[Hackable].HackedBy.get._1.Faction != player.Faction) {
|
||||
|
|
@ -576,7 +584,31 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
// 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.HackCaptureTerminal(target_guid, unk1, unk2, isResecured) =>
|
||||
var value = 0L
|
||||
|
||||
if(isResecured) {
|
||||
value = 17039360L
|
||||
} else {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
val future = ask(localService, HackCaptureActor.GetHackTimeRemainingNanos(target_guid))(1 second)
|
||||
val time = Await.result(future, 1 second).asInstanceOf[Long] // todo: blocking call. Not good.
|
||||
val hack_time_remaining_ms = TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS)
|
||||
val deciseconds_remaining = (hack_time_remaining_ms / 100)
|
||||
|
||||
val hacking_faction = continent.GUID(target_guid).get.asInstanceOf[Hackable].HackedBy.get._1.Faction
|
||||
|
||||
// See PlanetSideAttributeMessage #20 documentation for an explanation of how the timer is calculated
|
||||
val start_num = hacking_faction match {
|
||||
case PlanetSideEmpire.TR => 65536L
|
||||
case PlanetSideEmpire.NC => 131072L
|
||||
case PlanetSideEmpire.VS => 196608L
|
||||
}
|
||||
|
||||
value = start_num + deciseconds_remaining
|
||||
}
|
||||
|
||||
sendResponse(PlanetsideAttributeMessage(target_guid, 20, value))
|
||||
case LocalResponse.ProximityTerminalEffect(object_guid, effectState) =>
|
||||
if(tplayer_guid != guid) {
|
||||
sendResponse(ProximityTerminalUseMessage(PlanetSideGUID(0), object_guid, effectState))
|
||||
|
|
@ -585,6 +617,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case LocalResponse.TriggerSound(sound, pos, unk, volume) =>
|
||||
sendResponse(TriggerSoundMessage(sound, pos, unk, volume))
|
||||
|
||||
case LocalResponse.SetEmpire(object_guid, empire) =>
|
||||
sendResponse(SetEmpireMessage(object_guid, empire))
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
|
|
@ -1451,6 +1485,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
val popNC = poplist.count(_.faction == PlanetSideEmpire.NC)
|
||||
val popVS = poplist.count(_.faction == PlanetSideEmpire.VS)
|
||||
|
||||
// StopBundlingPackets() is called on ClientInitializationComplete
|
||||
StartBundlingPackets()
|
||||
zone.Buildings.foreach({ case(id, building) => initBuilding(continentNumber, id, building) })
|
||||
sendResponse(ZonePopulationUpdateMessage(continentNumber, 414, 138, popTR, 138, popNC, 138, popVS, 138, popBO))
|
||||
|
|
@ -2764,7 +2799,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
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))
|
||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(unholsteredItem.GUID, 116, GetPlayerHackLevel()))
|
||||
}
|
||||
case None => ;
|
||||
}
|
||||
|
|
@ -2971,9 +3006,21 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
continent.GUID(object_guid) match {
|
||||
case Some(door : Door) =>
|
||||
if(player.Faction == door.Faction || ((continent.Map.DoorToLock.get(object_guid.guid) match {
|
||||
case Some(lock_guid) => continent.GUID(lock_guid).get.asInstanceOf[IFFLock].HackedBy.isDefined
|
||||
case Some(lock_guid) =>
|
||||
val lock = continent.GUID(lock_guid).get.asInstanceOf[IFFLock]
|
||||
|
||||
var baseIsHacked = false
|
||||
lock.Owner.asInstanceOf[Building].Amenities.filter(x => x.Definition == GlobalDefinitions.capture_terminal).headOption.asInstanceOf[Option[CaptureTerminal]] match {
|
||||
case Some(obj: CaptureTerminal) =>
|
||||
baseIsHacked = obj.HackedBy.isDefined
|
||||
case None => ;
|
||||
}
|
||||
|
||||
// If the IFF lock has been hacked OR the base is neutral OR the base linked to the lock is hacked then open the door
|
||||
lock.HackedBy.isDefined || baseIsHacked || lock.Faction == PlanetSideEmpire.NEUTRAL
|
||||
case None => !door.isOpen
|
||||
}) || Vector3.ScalarProjection(door.Outwards, player.Position - door.Position) < 0f)) {
|
||||
// We're on the inside of the door - open the door
|
||||
door.Actor ! Door.Use(player, msg)
|
||||
}
|
||||
else if(door.isOpen) {
|
||||
|
|
@ -2995,13 +3042,25 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
|
||||
case Some(panel : IFFLock) =>
|
||||
if(panel.Faction != player.Faction && panel.HackedBy.isEmpty) {
|
||||
if((panel.Faction != player.Faction && panel.HackedBy.isEmpty) || (panel.Faction == player.Faction && panel.HackedBy.isDefined)) {
|
||||
player.Slot(player.DrawnSlot).Equipment match {
|
||||
case Some(tool : SimpleItem) =>
|
||||
if(tool.Definition == GlobalDefinitions.remote_electronics_kit) {
|
||||
progressBarValue = Some(-GetPlayerHackSpeed())
|
||||
self ! WorldSessionActor.HackingProgress(1, player, panel, tool.GUID, GetPlayerHackSpeed(), FinishHacking(panel, 1114636288L))
|
||||
log.info("Hacking a door~")
|
||||
val hackSpeed = GetPlayerHackSpeed(panel)
|
||||
|
||||
if(hackSpeed > 0) {
|
||||
progressBarValue = Some(-hackSpeed)
|
||||
if(panel.Faction != player.Faction) {
|
||||
// Enemy faction is hacking this IFF lock
|
||||
self ! WorldSessionActor.HackingProgress(progressType = 1, player, panel, tool.GUID, hackSpeed, FinishHacking(panel, 1114636288L))
|
||||
log.info("Hacking an IFF lock")
|
||||
} else {
|
||||
// IFF Lock is being resecured by it's owner faction
|
||||
self ! WorldSessionActor.HackingProgress(progressType = 1, player, panel, tool.GUID, hackSpeed, FinishResecuringIFFLock(panel))
|
||||
log.info("Resecuring an IFF lock")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
|
|
@ -3056,18 +3115,22 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
}
|
||||
|
||||
case Some(obj : Locker) =>
|
||||
if(obj.Faction != player.Faction && obj.HackedBy.isEmpty) {
|
||||
case Some(locker : Locker) =>
|
||||
if(locker.Faction != player.Faction && locker.HackedBy.isEmpty) {
|
||||
player.Slot(player.DrawnSlot).Equipment match {
|
||||
case Some(tool: SimpleItem) =>
|
||||
if (tool.Definition == GlobalDefinitions.remote_electronics_kit) {
|
||||
progressBarValue = Some(-GetPlayerHackSpeed())
|
||||
self ! WorldSessionActor.HackingProgress(1, player, obj, tool.GUID, GetPlayerHackSpeed(), FinishHacking(obj, 3212836864L))
|
||||
log.info("Hacking a locker")
|
||||
val hackSpeed = GetPlayerHackSpeed(locker)
|
||||
|
||||
if(hackSpeed > 0) {
|
||||
progressBarValue = Some(-hackSpeed)
|
||||
self ! WorldSessionActor.HackingProgress(progressType = 1, player, locker, tool.GUID, hackSpeed, FinishHacking(locker, 3212836864L))
|
||||
log.info("Hacking a locker")
|
||||
}
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
} else if(player.Faction == obj.Faction || !obj.HackedBy.isEmpty) {
|
||||
} else if(player.Faction == locker.Faction || !locker.HackedBy.isEmpty) {
|
||||
log.info(s"UseItem: $player accessing a locker")
|
||||
val container = player.Locker
|
||||
accessedContainer = Some(container)
|
||||
|
|
@ -3077,6 +3140,25 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
log.info(s"UseItem: not $player's locker")
|
||||
}
|
||||
|
||||
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)
|
||||
if(!hackedByCurrentFaction || ownedByPlayerFactionAndHackedByEnemyFaction) {
|
||||
player.Slot(player.DrawnSlot).Equipment match {
|
||||
case Some(tool: SimpleItem) =>
|
||||
if (tool.Definition == GlobalDefinitions.remote_electronics_kit) {
|
||||
val hackSpeed = GetPlayerHackSpeed(captureTerminal)
|
||||
|
||||
if(hackSpeed > 0) {
|
||||
progressBarValue = Some(-hackSpeed)
|
||||
self ! WorldSessionActor.HackingProgress(progressType = 1, player, captureTerminal, tool.GUID, hackSpeed, FinishHacking(captureTerminal, 3212836864L))
|
||||
log.info("Hacking a capture terminal")
|
||||
}
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
case Some(obj : MannedTurret) =>
|
||||
player.Slot(player.DrawnSlot).Equipment match {
|
||||
case Some(tool : Tool) =>
|
||||
|
|
@ -3085,11 +3167,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
if(ammo == Ammo.upgrade_canister && obj.Seats.values.count(_.isOccupied) == 0) {
|
||||
progressBarValue = Some(-1.25f)
|
||||
self ! WorldSessionActor.HackingProgress(
|
||||
2,
|
||||
progressType = 2,
|
||||
player,
|
||||
obj,
|
||||
tool.GUID,
|
||||
1.25f,
|
||||
delta = 1.25f,
|
||||
FinishUpgradingMannedTurret(obj, tool, TurretUpgrade(unk2.toInt))
|
||||
)
|
||||
}
|
||||
|
|
@ -3145,12 +3227,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
}
|
||||
|
||||
case Some(obj : Terminal) =>
|
||||
if(obj.Definition.isInstanceOf[MatrixTerminalDefinition]) {
|
||||
case Some(terminal : Terminal) =>
|
||||
if(terminal.Definition.isInstanceOf[MatrixTerminalDefinition]) {
|
||||
//TODO matrix spawn point; for now, just blindly bind to show work (and hope nothing breaks)
|
||||
sendResponse(BindPlayerMessage(1, "@ams", true, true, 0, 0, 0, obj.Position))
|
||||
sendResponse(BindPlayerMessage(1, "@ams", true, true, 0, 0, 0, terminal.Position))
|
||||
}
|
||||
else if(obj.Definition.isInstanceOf[RepairRearmSiloDefinition]) {
|
||||
else if(terminal.Definition.isInstanceOf[RepairRearmSiloDefinition]) {
|
||||
FindLocalVehicle match {
|
||||
case Some(vehicle) =>
|
||||
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
|
|
@ -3160,17 +3242,21 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
}
|
||||
else {
|
||||
if(obj.Faction != player.Faction && obj.HackedBy.isEmpty) {
|
||||
if(terminal.Faction != player.Faction && terminal.HackedBy.isEmpty) {
|
||||
player.Slot(player.DrawnSlot).Equipment match {
|
||||
case Some(tool: SimpleItem) =>
|
||||
if (tool.Definition == GlobalDefinitions.remote_electronics_kit) {
|
||||
progressBarValue = Some(-GetPlayerHackSpeed())
|
||||
self ! WorldSessionActor.HackingProgress(1, player, obj, tool.GUID, GetPlayerHackSpeed(), FinishHacking(obj, 3212836864L))
|
||||
log.info("Hacking a terminal")
|
||||
val hackSpeed = GetPlayerHackSpeed(terminal)
|
||||
|
||||
if(hackSpeed > 0) {
|
||||
progressBarValue = Some(-hackSpeed)
|
||||
self ! WorldSessionActor.HackingProgress(progressType = 1, player, terminal, tool.GUID, hackSpeed, FinishHacking(terminal, 3212836864L))
|
||||
log.info("Hacking a terminal")
|
||||
}
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
} else if (obj.Faction == player.Faction || !obj.HackedBy.isEmpty) {
|
||||
} else if (terminal.Faction == player.Faction || !terminal.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))
|
||||
|
|
@ -4135,10 +4221,23 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
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}")
|
||||
}
|
||||
target match {
|
||||
case term : CaptureTerminal =>
|
||||
val isResecured = player.Faction == target.Faction
|
||||
localService ! LocalServiceMessage(continent.Id, LocalAction.HackCaptureTerminal(player.GUID, continent, term, unk, 8L, isResecured))
|
||||
case _ =>localService ! LocalServiceMessage(continent.Id, LocalAction.HackTemporarily(player.GUID, continent, target, unk, target.HackEffectDuration(GetPlayerHackLevel())))
|
||||
}
|
||||
case scala.util.Failure(_) => log.warn(s"Hack message failed on target guid: ${target.GUID}")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The process of resecuring an IFF lock is finished
|
||||
* Clear the hack state and send to clients
|
||||
* @param lock the `IFFLock` object that has been resecured
|
||||
*/
|
||||
private def FinishResecuringIFFLock(lock: IFFLock)() : Unit = {
|
||||
localService ! LocalServiceMessage(continent.Id, LocalAction.ClearTemporaryHack(player.GUID, lock))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -4963,38 +5062,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
* @param building the building object
|
||||
*/
|
||||
def initFacility(continentNumber : Int, buildingNumber : Int, building : Building) : Unit = {
|
||||
var ntuLevel = 0
|
||||
building.Amenities.filter(x => (x.Definition == GlobalDefinitions.resource_silo)).headOption.asInstanceOf[Option[ResourceSilo]] match {
|
||||
case Some(obj: ResourceSilo) =>
|
||||
ntuLevel = obj.CapacitorDisplay.toInt
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
sendResponse(
|
||||
BuildingInfoUpdateMessage(
|
||||
continent_id = continentNumber,
|
||||
building_id = buildingNumber,
|
||||
ntu_level = ntuLevel,
|
||||
is_hacked = false,
|
||||
empire_hack = PlanetSideEmpire.NEUTRAL,
|
||||
hack_time_remaining = 0, // milliseconds
|
||||
empire_own = building.Faction,
|
||||
unk1 = 0, //!! Field != 0 will cause malformed packet. See class def.
|
||||
unk1x = None,
|
||||
generator_state = PlanetSideGeneratorState.Normal,
|
||||
spawn_tubes_normal = true,
|
||||
force_dome_active = false,
|
||||
lattice_benefit = 0,
|
||||
cavern_benefit = 0, //!! Field > 0 will cause malformed packet. See class def.
|
||||
unk4 = Nil,
|
||||
unk5 = 0,
|
||||
unk6 = false,
|
||||
unk7 = 8, //!! Field != 8 will cause malformed packet. See class def.
|
||||
unk7x = None,
|
||||
boost_spawn_pain = false,
|
||||
boost_generator_pain = false
|
||||
)
|
||||
)
|
||||
building.Actor ! Building.SendMapUpdate(all_clients = false)
|
||||
sendResponse(DensityLevelUpdateMessage(continentNumber, buildingNumber, List(0,0, 0,0, 0,0, 0,0)))
|
||||
}
|
||||
|
||||
|
|
@ -5058,18 +5126,35 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
amenity.Definition match {
|
||||
case GlobalDefinitions.resource_silo =>
|
||||
// Synchronise warning light & silo capacity
|
||||
var silo = amenity.asInstanceOf[ResourceSilo]
|
||||
val silo = amenity.asInstanceOf[ResourceSilo]
|
||||
sendResponse(PlanetsideAttributeMessage(amenityId, 45, silo.CapacitorDisplay))
|
||||
sendResponse(PlanetsideAttributeMessage(amenityId, 47, if(silo.LowNtuWarningOn) 1 else 0))
|
||||
|
||||
if(silo.ChargeLevel == 0) {
|
||||
// temporarily disabled until warpgates can bring ANTs from sanctuary, otherwise we'd be stuck in a situation with an unpowered base and no way to get an ANT to refill it.
|
||||
// sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(silo.Owner.asInstanceOf[Building].ModelId), 48, 1))
|
||||
//todo: temporarily disabled until warpgates can bring ANTs from sanctuary, otherwise we'd be stuck in a situation with an unpowered base and no way to get an ANT to refill it.
|
||||
//sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(silo.Owner.asInstanceOf[Building].ModelId), 48, 1))
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
// Synchronise hack states to clients joining the zone.
|
||||
// We'll have to fake LocalServiceResponse messages to self, otherwise it means duplicating the same hack handling code twice
|
||||
if(amenity.isInstanceOf[Hackable]) {
|
||||
val hackable = amenity.asInstanceOf[Hackable]
|
||||
|
||||
if(hackable.HackedBy.isDefined) {
|
||||
amenity.Definition match {
|
||||
case GlobalDefinitions.capture_terminal =>
|
||||
self ! LocalServiceResponse("", PlanetSideGUID(0), LocalResponse.HackCaptureTerminal(amenity.GUID, 0L, 0L, false))
|
||||
case _ =>
|
||||
// Generic hackable object
|
||||
self ! LocalServiceResponse("", PlanetSideGUID(0), LocalResponse.HackObject(amenity.GUID, 1114636288L, 8L))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
sendResponse(HackMessage(3, PlanetSideGUID(building.ModelId), PlanetSideGUID(0), 0, 3212836864L, HackState.HackCleared, 8))
|
||||
|
||||
// sendResponse(HackMessage(3, PlanetSideGUID(building.ModelId), PlanetSideGUID(0), 0, 3212836864L, HackState.HackCleared, 8))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -5844,29 +5929,31 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
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 GetPlayerHackSpeed(obj: PlanetSideServerObject with Hackable): Float = {
|
||||
val playerHackLevel = GetPlayerHackLevel()
|
||||
val timeToHack = obj.HackDuration(playerHackLevel)
|
||||
|
||||
if(timeToHack == 0) {
|
||||
log.warn(s"Player ${player.GUID} tried to hack an object ${obj.GUID} - ${obj.Definition.Name} that they don't have the correct hacking level for")
|
||||
0f
|
||||
}
|
||||
|
||||
// 250 ms per tick on the hacking progress bar
|
||||
val ticks = (timeToHack * 1000) / 250
|
||||
100f / ticks
|
||||
}
|
||||
|
||||
def GetPlayerHackData(): PlayerHackData = {
|
||||
def GetPlayerHackLevel(): Int = {
|
||||
if(player.Certifications.contains(CertificationType.ExpertHacking) || player.Certifications.contains(CertificationType.ElectronicsExpert)) {
|
||||
PlayerHackData(3, 10.64f)
|
||||
3
|
||||
} else if(player.Certifications.contains(CertificationType.AdvancedHacking)) {
|
||||
PlayerHackData(2, 7.98f)
|
||||
2
|
||||
} else if (player.Certifications.contains(CertificationType.Hacking)) {
|
||||
PlayerHackData(1, 5.32f)
|
||||
1
|
||||
} else {
|
||||
PlayerHackData(0, 2.66f)
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
case class PlayerHackData(hackLevel: Int, hackSpeed: Float)
|
||||
}
|
||||
|
||||
object WorldSessionActor {
|
||||
|
|
@ -5893,6 +5980,8 @@ object WorldSessionActor {
|
|||
* The process of "making progress" with a hack involves sending this message repeatedly until the progress is 100 or more.
|
||||
* To calculate the actual amount of change in the progress `delta`,
|
||||
* start with 100, divide by the length of time in seconds, then divide once more by 4.
|
||||
* @param progressType 1 - REK hack
|
||||
* 2 - Turret upgrade with glue gun + upgrade cannister
|
||||
* @param tplayer the player
|
||||
* @param target the object being hacked
|
||||
* @param tool_guid the REK
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue