diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala
index cad22888..4857fa52 100644
--- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala
+++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala
@@ -533,7 +533,7 @@ object GamePacketOpcode extends Enumeration {
case 0xb2 => game.VoiceHostInfo.decode
case 0xb3 => game.BattleplanMessage.decode
case 0xb4 => game.BattleExperienceMessage.decode
- case 0xb5 => noDecoder(TargetingImplantRequest)
+ case 0xb5 => game.TargetingImplantRequest.decode
case 0xb6 => game.ZonePopulationUpdateMessage.decode
case 0xb7 => game.DisconnectMessage.decode
// 0xb8
diff --git a/common/src/main/scala/net/psforever/packet/game/TargetingImplantRequest.scala b/common/src/main/scala/net/psforever/packet/game/TargetingImplantRequest.scala
new file mode 100644
index 00000000..63cceeb6
--- /dev/null
+++ b/common/src/main/scala/net/psforever/packet/game/TargetingImplantRequest.scala
@@ -0,0 +1,36 @@
+// Copyright (c) 2017 PSForever
+package net.psforever.packet.game
+
+import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
+import scodec.Codec
+import scodec.codecs._
+
+/**
+ * An entry regarding a specific target.
+ * @param target_guid the target
+ * @param unk na
+ */
+final case class TargetRequest(target_guid : PlanetSideGUID,
+ unk : Boolean)
+
+/**
+ * Dispatched by the client when the advanced targeting implant activates to collect status information from the server.
+ *
+ * This packet is answered by a `TargetingInfoMessage` with `List` entries of thed corresponding UIDs.
+ * @param target_list a `List` of targets
+ */
+final case class TargetingImplantRequest(target_list : List[TargetRequest])
+ extends PlanetSideGamePacket {
+ type Packet = TargetingImplantRequest
+ def opcode = GamePacketOpcode.TargetingImplantRequest
+ def encode = TargetingImplantRequest.encode(this)
+}
+
+object TargetingImplantRequest extends Marshallable[TargetingImplantRequest] {
+ private val request_codec : Codec[TargetRequest] = (
+ ("target_guid" | PlanetSideGUID.codec) ::
+ ("unk" | bool)
+ ).as[TargetRequest]
+
+ implicit val codec : Codec[TargetingImplantRequest] = ("target_list" | listOfN(intL(6), request_codec)).as[TargetingImplantRequest]
+}
diff --git a/common/src/test/scala/game/TargetingImplantRequestTest.scala b/common/src/test/scala/game/TargetingImplantRequestTest.scala
new file mode 100644
index 00000000..0a2112c1
--- /dev/null
+++ b/common/src/test/scala/game/TargetingImplantRequestTest.scala
@@ -0,0 +1,116 @@
+// Copyright (c) 2017 PSForever
+package game
+
+import org.specs2.mutable._
+import net.psforever.packet._
+import net.psforever.packet.game._
+import scodec.bits._
+
+class TargetingImplantRequestTest extends Specification {
+ val string_single = hex"b5 061016"
+ val string_long = hex"b5 41edeb12d4409f0144053f8010541ba91d03df376831b1e26000611041e1107c0209c0"//0510085013d9ffb6720d5b132900003770?
+
+ "decode (single)" in {
+ PacketCoding.DecodePacket(string_single).require match {
+ case TargetingImplantRequest(target_list) =>
+ target_list.length mustEqual 1
+ //0
+ target_list.head.target_guid mustEqual PlanetSideGUID(1412)
+ target_list.head.unk mustEqual true
+ case _ =>
+ ko
+ }
+ }
+
+ "decode (long)" in {
+ PacketCoding.DecodePacket(string_long).require match {
+ case TargetingImplantRequest(target_list) =>
+ target_list.length mustEqual 16
+ //0
+ target_list.head.target_guid mustEqual PlanetSideGUID(31355)
+ target_list.head.unk mustEqual true
+ //1
+ target_list(1).target_guid mustEqual PlanetSideGUID(27273)
+ target_list(1).unk mustEqual false
+ //2
+ target_list(2).target_guid mustEqual PlanetSideGUID(40768)
+ target_list(2).unk mustEqual false
+ //3
+ target_list(3).target_guid mustEqual PlanetSideGUID(34818)
+ target_list(3).unk mustEqual false
+ //4
+ target_list(4).target_guid mustEqual PlanetSideGUID(65044)
+ target_list(4).unk mustEqual false
+ //5
+ target_list(5).target_guid mustEqual PlanetSideGUID(33280)
+ target_list(5).unk mustEqual true
+ //6
+ target_list(6).target_guid mustEqual PlanetSideGUID(47681)
+ target_list(6).unk mustEqual true
+ //7
+ target_list(7).target_guid mustEqual PlanetSideGUID(40995)
+ target_list(7).unk mustEqual false
+ //8
+ target_list(8).target_guid mustEqual PlanetSideGUID(52727)
+ target_list(8).unk mustEqual true
+ //9
+ target_list(9).target_guid mustEqual PlanetSideGUID(6324)
+ target_list(9).unk mustEqual true
+ //10
+ target_list(10).target_guid mustEqual PlanetSideGUID(58033)
+ target_list(10).unk mustEqual false
+ //11
+ target_list(11).target_guid mustEqual PlanetSideGUID(192)
+ target_list(11).unk mustEqual true
+ //12
+ target_list(12).target_guid mustEqual PlanetSideGUID(16772)
+ target_list(12).unk mustEqual false
+ //13
+ target_list(13).target_guid mustEqual PlanetSideGUID(2063)
+ target_list(13).unk mustEqual true
+ //14
+ target_list(14).target_guid mustEqual PlanetSideGUID(49159)
+ target_list(14).unk mustEqual false
+ //15
+ target_list(15).target_guid mustEqual PlanetSideGUID(14401)
+ target_list(15).unk mustEqual false
+ case _ =>
+ ko
+ }
+ }
+
+ "encode (single)" in {
+ val msg = TargetingImplantRequest(
+ TargetRequest(PlanetSideGUID(1412), true) ::
+ Nil
+ )
+ val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
+
+ pkt mustEqual string_single
+ }
+
+ "encode (long)" in {
+ val msg = TargetingImplantRequest(
+ TargetRequest(PlanetSideGUID(31355), true) ::
+ TargetRequest(PlanetSideGUID(27273), false) ::
+ TargetRequest(PlanetSideGUID(40768), false) ::
+ TargetRequest(PlanetSideGUID(34818), false) ::
+ TargetRequest(PlanetSideGUID(65044), false) ::
+ TargetRequest(PlanetSideGUID(33280), true) ::
+ TargetRequest(PlanetSideGUID(47681), true) ::
+ TargetRequest(PlanetSideGUID(40995), false) ::
+ TargetRequest(PlanetSideGUID(52727), true) ::
+ TargetRequest(PlanetSideGUID(6324), true) ::
+ TargetRequest(PlanetSideGUID(58033), false) ::
+ TargetRequest(PlanetSideGUID(192), true) ::
+ TargetRequest(PlanetSideGUID(16772), false) ::
+ TargetRequest(PlanetSideGUID(2063), true) ::
+ TargetRequest(PlanetSideGUID(49159), false) ::
+ TargetRequest(PlanetSideGUID(14401), false) ::
+ Nil
+ )
+ val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
+
+ pkt mustEqual string_long
+ }
+}
diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala
index 8c778c33..3a7cd910 100644
--- a/pslogin/src/main/scala/WorldSessionActor.scala
+++ b/pslogin/src/main/scala/WorldSessionActor.scala
@@ -437,6 +437,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ WeaponDryFireMessage(weapon) =>
log.info("WeaponDryFireMessage: "+msg)
+ case msg @ TargetingImplantRequest(list) =>
+ log.info("TargetingImplantRequest: "+msg)
+
case default => log.error(s"Unhandled GamePacket ${pkt}")
}