diff --git a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala index 924c14ce..b3d80902 100644 --- a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala +++ b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala @@ -4867,8 +4867,9 @@ object GlobalDefinitions { fury.TrunkOffset = 30 fury.AutoPilotSpeeds = (24, 10) fury.DestroyedModel = Some(DestroyedVehicle.QuadAssault) + fury.JackingDuration = Array(0, 10, 3, 2) - quadassault.Name = "quadassault" + quadassault.Name = "quadassault" // Basilisk quadassault.MaxHealth = 650 quadassault.MaxShields = 130 + 1 quadassault.Seats += 0 -> new SeatDefinition() @@ -4881,8 +4882,9 @@ object GlobalDefinitions { quadassault.TrunkOffset = 30 quadassault.AutoPilotSpeeds = (24, 10) quadassault.DestroyedModel = Some(DestroyedVehicle.QuadAssault) + quadassault.JackingDuration = Array(0, 10, 3, 2) - quadstealth.Name = "quadstealth" + quadstealth.Name = "quadstealth" // Wraith quadstealth.MaxHealth = 650 quadstealth.MaxShields = 130 + 1 quadstealth.CanCloak = true @@ -4895,8 +4897,9 @@ object GlobalDefinitions { quadstealth.TrunkOffset = 30 quadstealth.AutoPilotSpeeds = (24, 10) quadstealth.DestroyedModel = Some(DestroyedVehicle.QuadStealth) + quadstealth.JackingDuration = Array(0, 10, 3, 2) - two_man_assault_buggy.Name = "two_man_assault_buggy" + two_man_assault_buggy.Name = "two_man_assault_buggy" // Harasser two_man_assault_buggy.MaxHealth = 1250 two_man_assault_buggy.MaxShields = 250 + 1 two_man_assault_buggy.Seats += 0 -> new SeatDefinition() @@ -4911,6 +4914,7 @@ object GlobalDefinitions { two_man_assault_buggy.TrunkOffset = 30 two_man_assault_buggy.AutoPilotSpeeds = (22, 8) two_man_assault_buggy.DestroyedModel = Some(DestroyedVehicle.TwoManAssaultBuggy) + two_man_assault_buggy.JackingDuration = Array(0, 15, 5, 3) skyguard.Name = "skyguard" skyguard.MaxHealth = 1000 @@ -4928,8 +4932,9 @@ object GlobalDefinitions { skyguard.TrunkOffset = 30 skyguard.AutoPilotSpeeds = (22, 8) skyguard.DestroyedModel = Some(DestroyedVehicle.Skyguard) + skyguard.JackingDuration = Array(0, 15, 5, 3) - threemanheavybuggy.Name = "threemanheavybuggy" + threemanheavybuggy.Name = "threemanheavybuggy" // Marauder threemanheavybuggy.MaxHealth = 1700 threemanheavybuggy.MaxShields = 340 + 1 threemanheavybuggy.Seats += 0 -> new SeatDefinition() @@ -4950,8 +4955,9 @@ object GlobalDefinitions { threemanheavybuggy.AutoPilotSpeeds = (22, 8) threemanheavybuggy.DestroyedModel = Some(DestroyedVehicle.ThreeManHeavyBuggy) threemanheavybuggy.Subtract.Damage1 = 5 + threemanheavybuggy.JackingDuration = Array(0, 20, 7, 5) - twomanheavybuggy.Name = "twomanheavybuggy" + twomanheavybuggy.Name = "twomanheavybuggy" // Enforcer twomanheavybuggy.MaxHealth = 1800 twomanheavybuggy.MaxShields = 360 + 1 twomanheavybuggy.Seats += 0 -> new SeatDefinition() @@ -4967,8 +4973,9 @@ object GlobalDefinitions { twomanheavybuggy.AutoPilotSpeeds = (22, 8) twomanheavybuggy.DestroyedModel = Some(DestroyedVehicle.TwoManHeavyBuggy) twomanheavybuggy.Subtract.Damage1 = 5 + twomanheavybuggy.JackingDuration = Array(0, 20, 7, 5) - twomanhoverbuggy.Name = "twomanhoverbuggy" + twomanhoverbuggy.Name = "twomanhoverbuggy" // Thresher twomanhoverbuggy.MaxHealth = 1600 twomanhoverbuggy.MaxShields = 320 + 1 twomanhoverbuggy.Seats += 0 -> new SeatDefinition() @@ -4984,8 +4991,9 @@ object GlobalDefinitions { twomanhoverbuggy.AutoPilotSpeeds = (22, 10) twomanhoverbuggy.DestroyedModel = Some(DestroyedVehicle.TwoManHoverBuggy) twomanhoverbuggy.Subtract.Damage1 = 5 + twomanhoverbuggy.JackingDuration = Array(0, 20, 7, 5) - mediumtransport.Name = "mediumtransport" + mediumtransport.Name = "mediumtransport" // Deliverer mediumtransport.MaxHealth = 2500 mediumtransport.MaxShields = 500 + 1 mediumtransport.Seats += 0 -> new SeatDefinition() @@ -5008,8 +5016,9 @@ object GlobalDefinitions { mediumtransport.AutoPilotSpeeds = (18, 6) mediumtransport.DestroyedModel = Some(DestroyedVehicle.MediumTransport) mediumtransport.Subtract.Damage1 = 7 + mediumtransport.JackingDuration = Array(0, 25, 8, 5) - battlewagon.Name = "battlewagon" + battlewagon.Name = "battlewagon" // Raider battlewagon.MaxHealth = 2500 battlewagon.MaxShields = 500 + 1 battlewagon.Seats += 0 -> new SeatDefinition() @@ -5035,6 +5044,7 @@ object GlobalDefinitions { battlewagon.TrunkOffset = 30 battlewagon.AutoPilotSpeeds = (18, 6) battlewagon.DestroyedModel = Some(DestroyedVehicle.MediumTransport) + battlewagon.JackingDuration = Array(0, 25, 8, 5) thunderer.Name = "thunderer" thunderer.MaxHealth = 2500 @@ -5059,6 +5069,7 @@ object GlobalDefinitions { thunderer.AutoPilotSpeeds = (18, 6) thunderer.DestroyedModel = Some(DestroyedVehicle.MediumTransport) thunderer.Subtract.Damage1 = 7 + thunderer.JackingDuration = Array(0, 25, 8, 5) aurora.Name = "aurora" aurora.MaxHealth = 2500 @@ -5083,8 +5094,9 @@ object GlobalDefinitions { aurora.AutoPilotSpeeds = (18, 6) aurora.DestroyedModel = Some(DestroyedVehicle.MediumTransport) aurora.Subtract.Damage1 = 7 + aurora.JackingDuration = Array(0, 25, 8 ,5) - apc_tr.Name = "apc_tr" + apc_tr.Name = "apc_tr" // Juggernaut apc_tr.MaxHealth = 6000 apc_tr.MaxShields = 1200 + 1 apc_tr.Seats += 0 -> new SeatDefinition() @@ -5129,8 +5141,9 @@ object GlobalDefinitions { apc_tr.TrunkOffset = 30 apc_tr.AutoPilotSpeeds = (16, 6) apc_tr.DestroyedModel = Some(DestroyedVehicle.Apc) + apc_tr.JackingDuration = Array(0, 45, 15, 10) - apc_nc.Name = "apc_nc" + apc_nc.Name = "apc_nc" // Vindicator apc_nc.MaxHealth = 6000 apc_nc.MaxShields = 1200 + 1 apc_nc.Seats += 0 -> new SeatDefinition() @@ -5175,8 +5188,9 @@ object GlobalDefinitions { apc_nc.TrunkOffset = 30 apc_nc.AutoPilotSpeeds = (16, 6) apc_nc.DestroyedModel = Some(DestroyedVehicle.Apc) + apc_nc.JackingDuration = Array(0, 45, 15, 10) - apc_vs.Name = "apc_vs" + apc_vs.Name = "apc_vs" // Leviathan apc_vs.MaxHealth = 6000 apc_vs.MaxShields = 1200 + 1 apc_vs.Seats += 0 -> new SeatDefinition() @@ -5221,6 +5235,7 @@ object GlobalDefinitions { apc_vs.TrunkOffset = 30 apc_vs.AutoPilotSpeeds = (16, 6) apc_vs.DestroyedModel = Some(DestroyedVehicle.Apc) + apc_vs.JackingDuration = Array(0, 45, 15, 10) lightning.Name = "lightning" lightning.MaxHealth = 2000 @@ -5236,6 +5251,7 @@ object GlobalDefinitions { lightning.AutoPilotSpeeds = (20, 8) lightning.DestroyedModel = Some(DestroyedVehicle.Lightning) lightning.Subtract.Damage1 = 7 + lightning.JackingDuration = Array(0, 20, 7 ,5) prowler.Name = "prowler" prowler.MaxHealth = 4800 @@ -5256,6 +5272,7 @@ object GlobalDefinitions { prowler.AutoPilotSpeeds = (14, 6) prowler.DestroyedModel = Some(DestroyedVehicle.Prowler) prowler.Subtract.Damage1 = 9 + prowler.JackingDuration = Array(0, 30, 10, 5) vanguard.Name = "vanguard" vanguard.MaxHealth = 5400 @@ -5272,6 +5289,7 @@ object GlobalDefinitions { vanguard.AutoPilotSpeeds = (16, 6) vanguard.DestroyedModel = Some(DestroyedVehicle.Vanguard) vanguard.Subtract.Damage1 = 9 + vanguard.JackingDuration = Array(0, 30, 10, 5) magrider.Name = "magrider" magrider.MaxHealth = 4200 @@ -5290,6 +5308,7 @@ object GlobalDefinitions { magrider.AutoPilotSpeeds = (18, 6) magrider.DestroyedModel = Some(DestroyedVehicle.Magrider) magrider.Subtract.Damage1 = 9 + magrider.JackingDuration = Array(0, 30, 10, 5) val utilityConverter = new UtilityVehicleConverter ant.Name = "ant" @@ -5307,6 +5326,7 @@ object GlobalDefinitions { ant.Packet = utilityConverter ant.DestroyedModel = Some(DestroyedVehicle.Ant) ant.Subtract.Damage1 = 5 + ant.JackingDuration = Array (0, 60, 20, 15) ams.Name = "ams" ams.MaxHealth = 3000 @@ -5327,6 +5347,7 @@ object GlobalDefinitions { ams.Packet = utilityConverter ams.DestroyedModel = Some(DestroyedVehicle.Ams) ams.Subtract.Damage1 = 10 + ams.JackingDuration = Array(0, 60, 20, 15) val variantConverter = new VariantVehicleConverter router.Name = "router" @@ -5346,6 +5367,7 @@ object GlobalDefinitions { router.Packet = variantConverter router.DestroyedModel = Some(DestroyedVehicle.Router) router.Subtract.Damage1 = 5 + router.JackingDuration = Array(0, 20, 7, 5) switchblade.Name = "switchblade" switchblade.MaxHealth = 1750 @@ -5365,6 +5387,7 @@ object GlobalDefinitions { switchblade.DestroyedModel = Some(DestroyedVehicle.Switchblade) switchblade.Subtract.Damage0 = 5 switchblade.Subtract.Damage1 = 5 + switchblade.JackingDuration = Array(0, 20, 7, 5) flail.Name = "flail" flail.MaxHealth = 2400 @@ -5382,6 +5405,7 @@ object GlobalDefinitions { flail.Packet = variantConverter flail.DestroyedModel = Some(DestroyedVehicle.Flail) flail.Subtract.Damage1 = 7 + flail.JackingDuration = Array(0, 20, 7, 5) mosquito.Name = "mosquito" mosquito.MaxHealth = 665 @@ -5398,8 +5422,9 @@ object GlobalDefinitions { mosquito.AutoPilotSpeeds = (0, 6) mosquito.Packet = variantConverter mosquito.DestroyedModel = Some(DestroyedVehicle.Mosquito) + mosquito.JackingDuration = Array(0, 20, 7, 5) - lightgunship.Name = "lightgunship" + lightgunship.Name = "lightgunship" // Reaver lightgunship.MaxHealth = 1000 lightgunship.MaxShields = 200 + 1 lightgunship.CanFly = true @@ -5415,6 +5440,7 @@ object GlobalDefinitions { lightgunship.Packet = variantConverter lightgunship.DestroyedModel = Some(DestroyedVehicle.LightGunship) lightgunship.Subtract.Damage1 = 3 + lightgunship.JackingDuration = Array(0, 30, 10, 5) wasp.Name = "wasp" wasp.MaxHealth = 515 @@ -5431,6 +5457,7 @@ object GlobalDefinitions { wasp.AutoPilotSpeeds = (0, 6) wasp.Packet = variantConverter wasp.DestroyedModel = Some(DestroyedVehicle.Mosquito) //set_resource_parent wasp game_objects mosquito + wasp.JackingDuration = Array(0, 20, 7, 5) liberator.Name = "liberator" liberator.MaxHealth = 2500 @@ -5455,6 +5482,7 @@ object GlobalDefinitions { liberator.Packet = variantConverter liberator.DestroyedModel = Some(DestroyedVehicle.Liberator) liberator.Subtract.Damage1 = 5 + liberator.JackingDuration = Array(0, 30, 10, 5) vulture.Name = "vulture" vulture.MaxHealth = 2500 @@ -5479,8 +5507,9 @@ object GlobalDefinitions { vulture.Packet = variantConverter vulture.DestroyedModel = Some(DestroyedVehicle.Liberator) //add_property vulture destroyedphysics liberator_destroyed vulture.Subtract.Damage1 = 5 + vulture.JackingDuration = Array(0, 30, 10, 5) - dropship.Name = "dropship" + dropship.Name = "dropship" // Galaxy dropship.MaxHealth = 5000 dropship.MaxShields = 1000 + 1 dropship.CanFly = true @@ -5535,6 +5564,7 @@ object GlobalDefinitions { dropship.Packet = variantConverter dropship.DestroyedModel = Some(DestroyedVehicle.Dropship) dropship.Subtract.Damage1 = 7 + dropship.JackingDuration = Array(0, 60, 20, 10) galaxy_gunship.Name = "galaxy_gunship" galaxy_gunship.MaxHealth = 6000 @@ -5568,6 +5598,7 @@ object GlobalDefinitions { galaxy_gunship.Packet = variantConverter galaxy_gunship.DestroyedModel = Some(DestroyedVehicle.Dropship) //the adb calls out a galaxy_gunship_destroyed but no such asset exists galaxy_gunship.Subtract.Damage1 = 7 + galaxy_gunship.JackingDuration = Array(0, 60, 20, 10) lodestar.Name = "lodestar" lodestar.MaxHealth = 5000 @@ -5591,6 +5622,7 @@ object GlobalDefinitions { lodestar.Packet = variantConverter lodestar.DestroyedModel = Some(DestroyedVehicle.Lodestar) lodestar.Subtract.Damage1 = 7 + lodestar.JackingDuration = Array(0, 60, 20, 10) phantasm.Name = "phantasm" phantasm.MaxHealth = 2500 @@ -5616,6 +5648,7 @@ object GlobalDefinitions { phantasm.AutoPilotSpeeds = (0, 6) phantasm.Packet = variantConverter phantasm.DestroyedModel = None //the adb calls out a phantasm_destroyed but no such asset exists + phantasm.JackingDuration = Array(0, 60, 20, 10) } /** diff --git a/common/src/main/scala/net/psforever/objects/Vehicle.scala b/common/src/main/scala/net/psforever/objects/Vehicle.scala index f4c141de..2b566812 100644 --- a/common/src/main/scala/net/psforever/objects/Vehicle.scala +++ b/common/src/main/scala/net/psforever/objects/Vehicle.scala @@ -123,6 +123,9 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ faction } + /** How long it takes to jack the vehicle in seconds, based on the hacker's certification level */ + def JackingDuration: Array[Int] = Definition.JackingDuration + def MountedIn : Option[PlanetSideGUID] = { this.mountedIn } diff --git a/common/src/main/scala/net/psforever/objects/definition/VehicleDefinition.scala b/common/src/main/scala/net/psforever/objects/definition/VehicleDefinition.scala index 0d90fabb..8f6fc071 100644 --- a/common/src/main/scala/net/psforever/objects/definition/VehicleDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/definition/VehicleDefinition.scala @@ -160,6 +160,13 @@ class VehicleDefinition(objectId : Int) extends ObjectDefinition(objectId) MaximumCapacitor } + private var jackDuration = Array(0, 0, 0, 0) + def JackingDuration: Array[Int] = jackDuration + def JackingDuration_=(arr: Array[Int]) : Array[Int] = { + jackDuration = arr + arr + } + def DestroyedModel : Option[DestroyedVehicle.Value] = destroyedModel def DestroyedModel_=(model : Option[DestroyedVehicle.Value]) : Option[DestroyedVehicle.Value] = { diff --git a/common/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala index 736d409f..17d255e5 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala @@ -28,7 +28,7 @@ class ResourceSiloControl(resourceSilo : ResourceSilo) extends Actor with Factio case ServiceManager.LookupResult("avatar", endpoint) => avatarService = endpoint - log.info("ResourceSiloControl: Silo " + resourceSilo.GUID + " Got avatar service " + endpoint) + log.trace("ResourceSiloControl: Silo " + resourceSilo.GUID + " Got avatar service " + endpoint) // todo: This is just a temporary solution to drain NTU over time. When base object destruction is properly implemented NTU should be deducted when base objects repair themselves context.system.scheduler.schedule(5 second, 5 second, self, ResourceSilo.UpdateChargeLevel(-1)) diff --git a/common/src/main/scala/net/psforever/objects/serverobject/structures/BuildingControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/structures/BuildingControl.scala index 90aa9ff1..3fd1a7cd 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/structures/BuildingControl.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/structures/BuildingControl.scala @@ -15,7 +15,7 @@ class BuildingControl(building : Building) extends Actor with FactionAffinityBeh private[this] val log = org.log4s.getLogger override def preStart = { - log.info(s"Starting BuildingControl for ${building.GUID} / ${building.MapId}") + log.trace(s"Starting BuildingControl for ${building.GUID} / ${building.MapId}") ServiceManager.serviceManager ! Lookup("galaxy") ServiceManager.serviceManager ! Lookup("local") } @@ -23,10 +23,10 @@ class BuildingControl(building : Building) extends Actor with FactionAffinityBeh def receive : Receive = checkBehavior.orElse { case ServiceManager.LookupResult("galaxy", endpoint) => galaxyService = endpoint - log.info("BuildingControl: Building " + building.GUID + " Got galaxy service " + endpoint) + log.trace("BuildingControl: Building " + building.GUID + " Got galaxy service " + endpoint) case ServiceManager.LookupResult("local", endpoint) => localService = endpoint - log.info("BuildingControl: Building " + building.GUID + " Got local service " + endpoint) + log.trace("BuildingControl: Building " + building.GUID + " Got local service " + endpoint) case FactionAffinity.ConvertFactionAffinity(faction) => val originalAffinity = building.Faction if(originalAffinity != (building.Faction = faction)) { @@ -37,7 +37,7 @@ class BuildingControl(building : Building) extends Actor with FactionAffinityBeh case Building.SendMapUpdate(all_clients: Boolean) => val zoneNumber = building.Zone.Number val buildingNumber = building.MapId - log.info(s"sending BuildingInfoUpdateMessage update - zone=$zoneNumber, building=$buildingNumber") + log.trace(s"sending BuildingInfoUpdateMessage update - zone=$zoneNumber, building=$buildingNumber") val ( ntuLevel, isHacked, empireHack, hackTimeRemaining, controllingEmpire, diff --git a/common/src/main/scala/net/psforever/packet/game/GenericObjectActionMessage.scala b/common/src/main/scala/net/psforever/packet/game/GenericObjectActionMessage.scala index f1c0d4d8..3dcaad6c 100644 --- a/common/src/main/scala/net/psforever/packet/game/GenericObjectActionMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/GenericObjectActionMessage.scala @@ -12,6 +12,13 @@ import shapeless.{::, HNil} * (Write more some other time.) * @param object_guid the target object * @param code the action code + * 24 - deconstructs player + * 28 - start imprinting process (progress bar + character animation) + * 32 - finish imprinting? + * 36 - cloak + * 40 - uncloak + * 82 - hit flinch? + * 138 - time till item can be used ????? * 44, 45, 46, 47 - Deploy capital base shield pole with animation and broadcasts "The capitol force dome at X has been activated" * 48, 49, 50, 51 - Stow capital base shield pole with animation and broadcasts "The capitol force dome at X has been deactivated" * 52, 53, 54, 55 - Deploy capital base shield pole (instantly, unless still in the middle of the stow animation) diff --git a/pslogin/src/main/scala/SessionRouter.scala b/pslogin/src/main/scala/SessionRouter.scala index b62bc4ad..acc1d3c4 100644 --- a/pslogin/src/main/scala/SessionRouter.scala +++ b/pslogin/src/main/scala/SessionRouter.scala @@ -112,7 +112,7 @@ class SessionRouter(role : String, pipeline : List[SessionPipeline]) extends Act } case SessionReaper() => sessionById.foreach { case (id, session) => - log.debug(session.toString) + log.trace(session.toString) if(session.getState == Closed()) { // clear mappings session.getPipeline.foreach(sessionByActor remove) diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 7b63bb88..93885272 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -2048,10 +2048,13 @@ class WorldSessionActor extends Actor with MDCContextAware { } case VehicleResponse.Ownership(vehicle_guid) => - sendResponse(PlanetsideAttributeMessage(tplayer_guid, 21, vehicle_guid)) + if(tplayer_guid == guid) { // Only the player that owns this vehicle needs the ownership packet + sendResponse(PlanetsideAttributeMessage(tplayer_guid, 21, vehicle_guid)) + } case VehicleResponse.PlanetsideAttribute(vehicle_guid, attribute_type, attribute_value) => if(tplayer_guid != guid) { + player.VehicleOwned = Some(vehicle_guid) sendResponse(PlanetsideAttributeMessage(vehicle_guid, attribute_type, attribute_value)) } @@ -2123,8 +2126,8 @@ class WorldSessionActor extends Actor with MDCContextAware { } } - case VehicleResponse.ForceDismountVehicleCargo(vehicle_guid, bailed, requestedByPassenger, kicked) => - DismountVehicleCargo(tplayer_guid, vehicle_guid, bailed, requestedByPassenger, kicked) + case VehicleResponse.ForceDismountVehicleCargo(cargo_guid, bailed, requestedByPassenger, kicked) => + DismountVehicleCargo(tplayer_guid, cargo_guid, bailed, requestedByPassenger, kicked) case VehicleResponse.KickCargo(vehicle, speed, delay) => if(player.VehicleSeated.nonEmpty && deadState == DeadState.Alive) { if(speed > 0) { @@ -2781,7 +2784,7 @@ class WorldSessionActor extends Actor with MDCContextAware { def handleControlPkt(pkt : PlanetSideControlPacket) = { pkt match { case sync @ ControlSync(diff, _, _, _, _, _, fa, fb) => - log.debug(s"SYNC: $sync") + log.trace(s"SYNC: $sync") val serverTick = Math.abs(System.nanoTime().toInt) // limit the size to prevent encoding error sendResponse(ControlSyncResp(diff, serverTick, fa, fb, fb, fa)) @@ -2889,10 +2892,10 @@ class WorldSessionActor extends Actor with MDCContextAware { case _ => ; } - case msg @ DismountVehicleCargoMsg(player_guid, vehicle_guid, bailed, requestedByPassenger, kicked) => + case msg @ DismountVehicleCargoMsg(player_guid, cargo_guid, bailed, requestedByPassenger, kicked) => log.info(msg.toString) if(!requestedByPassenger) { - DismountVehicleCargo(player_guid, vehicle_guid, bailed, requestedByPassenger, kicked) + DismountVehicleCargo(player_guid, cargo_guid, bailed, requestedByPassenger, kicked) } case msg @ CharacterCreateRequestMessage(name, head, voice, gender, empire) => @@ -4138,8 +4141,13 @@ class WorldSessionActor extends Actor with MDCContextAware { else if(equipment.isDefined) { equipment.get.Definition match { case GlobalDefinitions.remote_electronics_kit => - //TODO hacking behavior + val hackSpeed = GetPlayerHackSpeed(obj) + if(hackSpeed > 0) { + progressBarValue = Some(-hackSpeed) + self ! WorldSessionActor.HackingProgress(progressType = 1, player, obj, equipment.get.GUID, hackSpeed, FinishHackingVehicle(obj, 3212836864L)) + log.info("Hacking a vehicle") + } case _ => ; } } @@ -5289,14 +5297,108 @@ 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)) - target match { - case term : CaptureTerminal => + 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 hacking/jacking a vehicle is complete. + * Change the faction of the vehicle to the hacker's faction and remove all occupants. + * + * @param target The `Vehicle` object that has been hacked/jacked + * @param unk na; used by HackMessage` as `unk5` + */ + private def FinishHackingVehicle(target : Vehicle, unk : Long)(): Unit = { + log.info(s"Vehicle guid: ${target.GUID} has been jacked") + + + // Forcefully dismount any cargo + target.CargoHolds.values.foreach(cargoHold => { + cargoHold.Occupant match { + case Some(cargo : Vehicle) => { + cargo.Seats(0).Occupant match { + case Some(cargoDriver: Player) => + DismountVehicleCargo(cargoDriver.GUID, cargo.GUID, bailed = target.Flying, requestedByPassenger = false, kicked = true ) + case None => + log.error("FinishHackingVehicle: vehicle in cargo hold missing driver") + HandleDismountVehicleCargo(player.GUID, cargo.GUID, cargo, target.GUID, target, false, false, true) + } + } + case None => ; + } + }) + + // Forcefully dismount all seated occupants from the vehicle + target.Seats.values.foreach(seat => { + seat.Occupant match { + case Some(tplayer) => + seat.Occupant = None + tplayer.VehicleSeated = None + if(tplayer.HasGUID) { + vehicleService ! VehicleServiceMessage(tplayer.Continent, VehicleAction.KickPassenger(tplayer.GUID, 4, unk2 = false, target.GUID)) + } + case None => ; + } + }) + + // If the vehicle can fly and is flying deconstruct it, and well played to whomever managed to hack a plane in mid air. I'm impressed. + if(target.Definition.CanFly && target.Flying) { + // todo: Should this force the vehicle to land in the same way as when a pilot bails with passengers on board? + vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(target), continent)) + vehicleService ! VehicleServiceMessage.Decon(RemoverActor.AddTask(target, continent, Some(0 seconds))) + } else { // Otherwise handle ownership transfer as normal + // Remove ownership of our current vehicle, if we have one + player.VehicleOwned match { + case Some(guid : PlanetSideGUID) => + continent.GUID(guid) match { + case Some(vehicle: Vehicle) => + DisownVehicle(player, vehicle) + case _ => ; + } + case _ => ; + } + + target.Owner match { + case Some(previousOwnerGuid: PlanetSideGUID) => + // Remove ownership of the vehicle from the previous player + continent.GUID(previousOwnerGuid) match { + case Some(player: Player) => + DisownVehicle(player, target) + case _ => ; // Vehicle already has no owner + } + case _ => ; + } + + // Now take ownership of the jacked vehicle + target.Faction = player.Faction + OwnVehicle(target, player) + + //todo: Send HackMessage -> HackCleared to vehicle? can be found in packet captures. Not sure if necessary. + + // And broadcast the faction change to other clients + sendResponse(SetEmpireMessage(target.GUID, player.Faction)) + avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.SetEmpire(player.GUID, target.GUID, player.Faction)) + } + + localService ! LocalServiceMessage(continent.Id, LocalAction.TriggerSound(player.GUID, TriggeredSound.HackVehicle, target.Position, 30, 0.49803925f)) + + // Clean up after specific vehicles, e.g. remove router telepads + // If AMS is deployed, swap it to the new faction + target.Definition match { + case GlobalDefinitions.router => + log.info("FinishHackingVehicle: cleaning up after a router ...") + RemoveTelepads(target) + case GlobalDefinitions.ams + if(target.DeploymentState == DriveState.Deployed) => + vehicleService ! VehicleServiceMessage.AMSDeploymentChange(continent) + case _ => ; + } } /** @@ -5374,6 +5476,9 @@ class WorldSessionActor extends Actor with MDCContextAware { case Some(tplayer) => tplayer.VehicleOwned = vehicle.GUID vehicle.AssignOwnership(playerOpt) + + vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.Ownership(player.GUID, vehicle.GUID)) + ReloadVehicleAccessPermissions(vehicle) Some(vehicle) case None => None @@ -8459,22 +8564,25 @@ class WorldSessionActor extends Actor with MDCContextAware { case GlobalDefinitions.router => //this may repeat for multiple players on the same continent but that's okay(?) log.info("BeforeUnload: cleaning up after a router ...") - (vehicle.Utility(UtilityType.internal_router_telepad_deployable) match { - case Some(util : Utility.InternalTelepad) => - val telepad = util.Telepad - util.Active = false - util.Telepad = None - continent.GUID(telepad) - case _ => - None - }) match { - case Some(telepad : TelepadDeployable) => - log.info(s"BeforeUnload: deconstructing telepad $telepad that was linked to router $vehicle ...") - telepad.Active = false - localService ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(telepad), continent)) - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(telepad, continent, Some(0 seconds))) - case _ => ; - } + RemoveTelepads(vehicle) + case _ => ; + } + } + + def RemoveTelepads(vehicle: Vehicle) : Unit = { + (vehicle.Utility(UtilityType.internal_router_telepad_deployable) match { + case Some(util : Utility.InternalTelepad) => + val telepad = util.Telepad + util.Telepad = None + continent.GUID(telepad) + case _ => + None + }) match { + case Some(telepad : TelepadDeployable) => + log.info(s"BeforeUnload: deconstructing telepad $telepad that was linked to router $vehicle ...") + telepad.Active = false + localService ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(telepad), continent)) + localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(telepad, continent, Some(0 seconds))) case _ => ; } } @@ -8569,9 +8677,8 @@ class WorldSessionActor extends Actor with MDCContextAware { avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.SendResponse(player_guid, cargoDetachMessage)) driverOpt match { case Some(driver) => - if(kicked) { - vehicleService ! VehicleServiceMessage(s"${driver.Name}", VehicleAction.KickCargo(player_guid, cargo, cargo.Definition.AutoPilotSpeed2, 4500)) - } + vehicleService ! VehicleServiceMessage(s"${driver.Name}", VehicleAction.KickCargo(player_guid, cargo, cargo.Definition.AutoPilotSpeed2, 2500)) + import scala.concurrent.duration._ import scala.concurrent.ExecutionContext.Implicits.global //check every quarter second if the vehicle has moved far enough away to be considered dismounted @@ -8595,37 +8702,44 @@ class WorldSessionActor extends Actor with MDCContextAware { /** * na * @param player_guid na - * @param vehicle_guid na + * @param cargo_guid na * @param bailed na * @param requestedByPassenger na * @param kicked na */ - def DismountVehicleCargo(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, bailed : Boolean, requestedByPassenger : Boolean, kicked : Boolean) : Unit = { - continent.GUID(vehicle_guid) match { + def DismountVehicleCargo(player_guid : PlanetSideGUID, cargo_guid : PlanetSideGUID, bailed : Boolean, requestedByPassenger : Boolean, kicked : Boolean) : Unit = { + continent.GUID(cargo_guid) match { case Some(cargo : Vehicle) => continent.GUID(cargo.MountedIn) match { case Some(ferry : Vehicle) => - HandleDismountVehicleCargo(player_guid, vehicle_guid, cargo, ferry.GUID, ferry, bailed, requestedByPassenger, kicked) + HandleDismountVehicleCargo(player_guid, cargo_guid, cargo, ferry.GUID, ferry, bailed, requestedByPassenger, kicked) case _ => - log.warn(s"DismountVehicleCargo: target ${cargo.Definition.Name}@$vehicle_guid does not know what treats it as cargo") + log.warn(s"DismountVehicleCargo: target ${cargo.Definition.Name}@$cargo_guid does not know what treats it as cargo") } case _ => - log.warn(s"DismountVehicleCargo: target $vehicle_guid either is not a vehicle in ${continent.Id} or does not exist") + log.warn(s"DismountVehicleCargo: target $cargo_guid either is not a vehicle in ${continent.Id} or does not exist") } } - def GetPlayerHackSpeed(obj: PlanetSideServerObject with Hackable): Float = { + def GetPlayerHackSpeed(obj: PlanetSideServerObject): Float = { val playerHackLevel = GetPlayerHackLevel() - val timeToHack = obj.HackDuration(playerHackLevel) + + val timeToHack = obj match { + case (hackable: Hackable) => hackable.HackDuration(playerHackLevel) + case (vehicle: Vehicle) => vehicle.JackingDuration(playerHackLevel) + case _ => + log.warn(s"Player tried to hack an object that has no hack time defined ${obj.GUID} - ${obj.Definition.Name}") + 0 + } 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 + } else { + // 250 ms per tick on the hacking progress bar + val ticks = (timeToHack * 1000) / 250 + 100f / ticks } - - // 250 ms per tick on the hacking progress bar - val ticks = (timeToHack * 1000) / 250 - 100f / ticks } def GetPlayerHackLevel(): Int = {