diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index 6e9984e5..01cc9437 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -532,7 +532,7 @@ object GamePacketOpcode extends Enumeration { case 0xb1 => noDecoder(VoiceHostKill) case 0xb2 => noDecoder(VoiceHostInfo) case 0xb3 => noDecoder(BattleplanMessage) - case 0xb4 => noDecoder(BattleExperienceMessage) + case 0xb4 => game.BattleExperienceMessage.decode case 0xb5 => noDecoder(TargetingImplantRequest) case 0xb6 => game.ZonePopulationUpdateMessage.decode case 0xb7 => noDecoder(DisconnectMessage) diff --git a/common/src/main/scala/net/psforever/packet/game/BattleExperienceMessage.scala b/common/src/main/scala/net/psforever/packet/game/BattleExperienceMessage.scala new file mode 100644 index 00000000..542f76da --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/BattleExperienceMessage.scala @@ -0,0 +1,39 @@ +// 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._ + +/** + * Inform the client how many battle experience points (BEP) the player currently has earned.
+ *
+ * The amount of `experience` earned is an accumulating value. + * Whenever the server sends this packet, the value of this field is equal to the player's current total BEP. + * Each packet updates to a higher BEP score and the client occasionally reports of the difference as an event message. + * "You have been awarded `x` battle experience points." + * Milestone notifications that occur due to BEP gain, e.g., rank progression, will trigger naturally as the client is updated.
+ *
+ * It is possible to award more battle experience than is necessary to progress one's character to the highest battle rank. + * (This must be accomplished in a single event packet.) + * Only the most significant notification will be displayed. + * @param player_guid the player + * @param experience the current total experience + * @param unk na; always zero? + */ +final case class BattleExperienceMessage(player_guid : PlanetSideGUID, + experience : Long, + unk : Int) + extends PlanetSideGamePacket { + type Packet = BattleExperienceMessage + def opcode = GamePacketOpcode.BattleExperienceMessage + def encode = BattleExperienceMessage.encode(this) +} + +object BattleExperienceMessage extends Marshallable[BattleExperienceMessage] { + implicit val codec : Codec[BattleExperienceMessage] = ( + ("player_guid" | PlanetSideGUID.codec) :: + ("experience" | ulongL(32)) :: + ("unk" | uint8L) + ).as[BattleExperienceMessage] +} diff --git a/common/src/test/scala/GamePacketTest.scala b/common/src/test/scala/GamePacketTest.scala index 2f7e8a11..a1b6a9c7 100644 --- a/common/src/test/scala/GamePacketTest.scala +++ b/common/src/test/scala/GamePacketTest.scala @@ -703,6 +703,28 @@ class GamePacketTest extends Specification { } } + "BattleExperienceMessage" should { + val string = hex"B4 8A0A E7030000 00" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case BattleExperienceMessage(player_guid, experience, unk) => + player_guid mustEqual PlanetSideGUID(2698) + experience mustEqual 999 + unk mustEqual 0 + case default => + ko + } + } + + "encode" in { + val msg = BattleExperienceMessage(PlanetSideGUID(2698), 999, 0) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } + } + "ZonePopulationUpdateMessage" should { val string = hex"B6 0400 9E010000 8A000000 25000000 8A000000 25000000 8A000000 25000000 8A000000 25000000"