diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index 0311c9da..ed42c8c9 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -457,7 +457,7 @@ object GamePacketOpcode extends Enumeration { case 0x72 => game.FriendsRequest.decode case 0x73 => game.FriendsResponse.decode case 0x74 => noDecoder(TriggerEnvironmentalDamageMessage) - case 0x75 => noDecoder(TrainingZoneMessage) + case 0x75 => game.TrainingZoneMessage.decode case 0x76 => noDecoder(DeployableObjectsInfoMessage) case 0x77 => noDecoder(SquadState) // 0x78 diff --git a/common/src/main/scala/net/psforever/packet/game/TrainingZoneMessage.scala b/common/src/main/scala/net/psforever/packet/game/TrainingZoneMessage.scala new file mode 100644 index 00000000..59367263 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/TrainingZoneMessage.scala @@ -0,0 +1,45 @@ +// Copyright (c) 2016 PSForever.net to present +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} +import scodec.Codec +import scodec.codecs._ + +/** + * Dispatched when the player wants to go to the training zones. + * When a player enters the virtual reality hallways behind sanctuary spawn rooms and walks to the base of the ramp, he is presented with a prompt. + * From the prompt, the player accepts either "Shooting Range" or "Vehicle Training Area."
+ *
+ * Both sets of training zones utilize the same map for their type - `map14` for shooting and `map15` for vehicles. + * The factions are kept separate so there are actually six separated zones - two each - to accommodate the three factions. + * There is no global map notation, i.e., `map##`, for going to a faction-instance training zone map. + * The zone modifier is used in conjunction with the `LoadMapMessage` packet to determine the faction-instance of the training map.
+ *
+ * Players are sent to their respective empire's area by default. + * A TR player utilizing the virtual reality hallway in the NC sanctuary and will still only be offered the TR virtual reality areas. + * Black OPs do not have normal access to virtual reality areas.
+ *
+ * Zone:
+ * 17 - `11` - TR Shooting Range
+ * 18 - `12` - NC Shooting Range
+ * 19 - `13` - VS Shooting Range
+ * 20 - `14` - TR Vehicle Training Area
+ * 21 - `15` - NC Vehicle Training Area
+ * 22 - `16` - VS Vehicle Training Area + * @param zone the virtual reality zone to send the player + * @param unk na; always 0? + */ +final case class TrainingZoneMessage(zone : PlanetSideGUID, + unk : Int = 0) + extends PlanetSideGamePacket { + type Packet = TrainingZoneMessage + def opcode = GamePacketOpcode.TrainingZoneMessage + def encode = TrainingZoneMessage.encode(this) +} + +object TrainingZoneMessage extends Marshallable[TrainingZoneMessage] { + implicit val codec : Codec[TrainingZoneMessage] = ( + ("zone" | PlanetSideGUID.codec) :: + ("unk" | uint16L) + ).as[TrainingZoneMessage] +} diff --git a/common/src/test/scala/GamePacketTest.scala b/common/src/test/scala/GamePacketTest.scala index 0632cb2a..15e9c277 100644 --- a/common/src/test/scala/GamePacketTest.scala +++ b/common/src/test/scala/GamePacketTest.scala @@ -1017,7 +1017,7 @@ class GamePacketTest extends Specification { pkt mustEqual string } } - + "FriendsResponse" should { val stringOneFriend = hex"73 61 8C 60 4B007500720074004800650063007400690063002D004700 00" val stringManyFriends = hex"73 01 AC 48 4100 6E00 6700 6500 6C00 6C00 6F00 2D00 5700 47 00 7400 6800 6500 7000 6800 6100 7400 7400 7000 6800 7200 6F00 6700 6700 46 80 4B00 6900 6D00 7000 6F00 7300 7300 6900 6200 6C00 6500 3100 3200 45 00 5A00 6500 6100 7200 7400 6800 6C00 6900 6E00 6700 46 00 4B00 7500 7200 7400 4800 6500 6300 7400 6900 6300 2D00 4700 00" @@ -1122,6 +1122,26 @@ class GamePacketTest extends Specification { } } + "TrainingZoneMessage" should { + val string = hex"75 13 000000" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case TrainingZoneMessage(zone, unk) => + zone mustEqual PlanetSideGUID(19) + case default => + ko + } + } + + "encode" in { + val msg = TrainingZoneMessage(PlanetSideGUID(19)) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } + } + "WeaponDryFireMessage" should { val string = hex"52 4C00"