diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala
index e94547b1..203dc2ac 100644
--- a/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala
+++ b/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala
@@ -3,8 +3,7 @@ package net.psforever.objects.definition.converter
import net.psforever.objects.{EquipmentSlot, Player}
import net.psforever.objects.equipment.Equipment
-import net.psforever.packet.game.PlanetSideGUID
-import net.psforever.packet.game.objectcreate.{BasicCharacterData, CharacterAppearanceData, CharacterData, DetailedCharacterData, DrawnSlot, InternalSlot, InventoryData, PlacementData, RibbonBars, UniformStyle}
+import net.psforever.packet.game.objectcreate.{BasicCharacterData, BattleRankFieldData, CharacterAppearanceData, CharacterData, DetailedCharacterData, DrawnSlot, InternalSlot, InventoryData, PlacementData, RibbonBars, UniformStyle}
import net.psforever.types.GrenadeState
import scala.annotation.tailrec
@@ -32,13 +31,15 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
Success(
DetailedCharacterData(
MakeAppearanceData(obj),
+ 0,
obj.MaxHealth,
obj.Health,
obj.Armor,
1, 7, 7,
obj.MaxStamina,
obj.Stamina,
- 28, 4, 44, 84, 104, 1900,
+ 28, 4,
+ BattleRankFieldData(44, 84, 104, 108, 112, 0, 0),
List.empty[String], //TODO fte list
List.empty[String], //TODO tutorial list
InventoryData((MakeHolsters(obj, BuildDetailedEquipment) ++ MakeFifthSlot(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot)),
diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedCharacterData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedCharacterData.scala
index 34e6a6db..b34d0f38 100644
--- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedCharacterData.scala
+++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedCharacterData.scala
@@ -2,10 +2,44 @@
package net.psforever.packet.game.objectcreate
import net.psforever.packet.{Marshallable, PacketHelpers}
-import scodec.{Attempt, Codec}
+import scodec.{Attempt, Codec, Err}
import scodec.codecs._
import shapeless.{::, HNil}
+final case class BattleRankFieldData(field00 : Int,
+ field01 : Int,
+ field02 : Int,
+ field03 : Int,
+ field04 : Int,
+ field05 : Int,
+ field06 : Int,
+ field07 : Option[Int] = None,
+ field08 : Option[Int] = None,
+ field09 : Option[Int] = None,
+ field0A : Option[Int] = None,
+ field0B : Option[Int] = None,
+ field0C : Option[Int] = None,
+ field0D : Option[Int] = None,
+ field0E : Option[Int] = None,
+ field0F : Option[Int] = None,
+ field10 : Option[Int] = None) extends StreamBitSize {
+ override def bitsize : Long = {
+ val extraFieldSize : Long = if(field10.isDefined) {
+ 72L
+ }
+ else if(field0E.isDefined) {
+ 50L
+ }
+ else if(field09.isDefined) {
+ 10L
+ }
+ else {
+ 0L
+ }
+ 55L + extraFieldSize
+ }
+}
+
/**
* A representation of the avatar portion of `ObjectCreateDetailedMessage` packet data.
* This densely-packed information outlines most of the specifics required to depict a character as an avatar.
@@ -46,14 +80,7 @@ import shapeless.{::, HNil}
* defaults to 28
* @param unk5 na;
* defaults to 4
- * @param unk6 na;
- * defaults to 44
- * @param unk7 na;
- * defaults to 84
- * @param unk8 na;
- * defaults to 104
- * @param unk9 na;
- * defaults to 1900
+ * @param brFields na
* @param firstTimeEvents the list of first time events performed by this avatar;
* the size field is a 32-bit number;
* the first entry may be padded
@@ -68,6 +95,7 @@ import shapeless.{::, HNil}
* @see `DrawnSlot`
*/
final case class DetailedCharacterData(appearance : CharacterAppearanceData,
+ bep : Int,
healthMax : Int,
health : Int,
armor : Int,
@@ -78,26 +106,24 @@ final case class DetailedCharacterData(appearance : CharacterAppearanceData,
stamina : Int,
unk4 : Int, //28
unk5 : Int, //4
- unk6 : Int, //44
- unk7 : Int, //84
- unk8 : Int, //104
- unk9 : Int, //1900
+ brFields : BattleRankFieldData,
firstTimeEvents : List[String],
tutorials : List[String],
inventory : Option[InventoryData],
drawn_slot : DrawnSlot.Value = DrawnSlot.None
- ) extends ConstructorData {
+ ) extends ConstructorData {
override def bitsize : Long = {
//factor guard bool values into the base size, not its corresponding optional field
val appearanceSize = appearance.bitsize
+ val brFieldSize = brFields.bitsize
val fteLen = firstTimeEvents.size //fte list
- var eventListSize : Long = 32L + DetailedCharacterData.ftePadding(fteLen)
+ var eventListSize : Long = 32L + DetailedCharacterData.ftePadding(fteLen, bep)
for(str <- firstTimeEvents) {
eventListSize += StreamBitSize.stringBitSize(str)
}
val tutLen = tutorials.size //tutorial list
- var tutorialListSize : Long = 32L + DetailedCharacterData.tutPadding(fteLen, tutLen)
+ var tutorialListSize : Long = 32L + DetailedCharacterData.tutPadding(fteLen, tutLen, bep)
for(str <- tutorials) {
tutorialListSize += StreamBitSize.stringBitSize(str)
}
@@ -105,28 +131,28 @@ final case class DetailedCharacterData(appearance : CharacterAppearanceData,
if(inventory.isDefined) {
inventorySize = inventory.get.bitsize
}
- 713L + appearanceSize + eventListSize + tutorialListSize + inventorySize
+ 658L + appearanceSize + brFieldSize + eventListSize + tutorialListSize + inventorySize
}
}
object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
- /**
- * Overloaded constructor for `DetailedCharacterData` that skips all the unknowns by assigning defaulted values.
- * It also allows for a not-optional inventory.
- * @param appearance data about the avatar's basic aesthetics
- * @param healthMax for `x / y` of hitpoints, this is the avatar's `y` value
- * @param health for `x / y` of hitpoints, this is the avatar's `x` value
- * @param armor for `x / y` of armor points, this is the avatar's `x` value
- * @param staminaMax for `x / y` of stamina points, this is the avatar's `y` value
- * @param stamina for `x / y` of stamina points, this is the avatar's `x` value
- * @param firstTimeEvents the list of first time events performed by this avatar
- * @param tutorials the list of tutorials completed by this avatar
- * @param inventory the avatar's inventory
- * @param drawn_slot the holster that is initially drawn
- * @return a `DetailedCharacterData` object
- */
- def apply(appearance : CharacterAppearanceData, healthMax : Int, health : Int, armor : Int, staminaMax : Int, stamina : Int, firstTimeEvents : List[String], tutorials : List[String], inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedCharacterData =
- new DetailedCharacterData(appearance, healthMax, health, armor, 1, 7, 7, staminaMax, stamina, 28, 4, 44, 84, 104, 1900, firstTimeEvents, tutorials, Some(inventory), drawn_slot)
+// /**
+// * Overloaded constructor for `DetailedCharacterData` that skips all the unknowns by assigning defaulted values.
+// * It also allows for a not-optional inventory.
+// * @param appearance data about the avatar's basic aesthetics
+// * @param healthMax for `x / y` of hitpoints, this is the avatar's `y` value
+// * @param health for `x / y` of hitpoints, this is the avatar's `x` value
+// * @param armor for `x / y` of armor points, this is the avatar's `x` value
+// * @param staminaMax for `x / y` of stamina points, this is the avatar's `y` value
+// * @param stamina for `x / y` of stamina points, this is the avatar's `x` value
+// * @param firstTimeEvents the list of first time events performed by this avatar
+// * @param tutorials the list of tutorials completed by this avatar
+// * @param inventory the avatar's inventory
+// * @param drawn_slot the holster that is initially drawn
+// * @return a `DetailedCharacterData` object
+// */
+// def apply(appearance : CharacterAppearanceData, bep : Int, healthMax : Int, health : Int, armor : Int, staminaMax : Int, stamina : Int, firstTimeEvents : List[String], tutorials : List[String], inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedCharacterData =
+// new DetailedCharacterData(appearance, bep, healthMax, health, armor, 1, 7, 7, staminaMax, stamina, 28, 4, 44, 84, 104, 1900, firstTimeEvents, tutorials, Some(inventory), drawn_slot)
/**
* Overloaded constructor for `DetailedCharacterData` that allows for a not-optional inventory.
@@ -142,97 +168,244 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
* @param unk4 na
* @param unk5 na
* @param unk6 na
- * @param unk7 na
- * @param unk8 na
- * @param unk9 na
* @param firstTimeEvents the list of first time events performed by this avatar
* @param tutorials the list of tutorials completed by this avatar
* @param inventory the avatar's inventory
* @param drawn_slot the holster that is initially drawn
* @return a `DetailedCharacterData` object
*/
- def apply(appearance : CharacterAppearanceData, healthMax : Int, health : Int, armor : Int, unk1 : Int, unk2 : Int, unk3 : Int, staminaMax : Int, stamina : Int, unk4 : Int, unk5 : Int, unk6 : Int, unk7 : Int, unk8 : Int, unk9 : Int, firstTimeEvents : List[String], tutorials : List[String], inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedCharacterData =
- new DetailedCharacterData(appearance, healthMax, health, armor, unk1, unk2, unk3, staminaMax, stamina, unk4, unk5, unk6, unk7, unk8, unk9, firstTimeEvents, tutorials, Some(inventory), drawn_slot)
+ def apply(appearance : CharacterAppearanceData, bep : Int, healthMax : Int, health : Int, armor : Int, unk1 : Int, unk2 : Int, unk3 : Int, staminaMax : Int, stamina : Int, unk4 : Int, unk5 : Int, unk6 : BattleRankFieldData, firstTimeEvents : List[String], tutorials : List[String], inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedCharacterData =
+ new DetailedCharacterData(appearance, bep, healthMax, health, armor, unk1, unk2, unk3, staminaMax, stamina, unk4, unk5, unk6, firstTimeEvents, tutorials, Some(inventory), drawn_slot)
+
+ private val br1FieldCodec : Codec[BattleRankFieldData] = ( // +0u
+ ("f1" | uint8L) ::
+ ("f2" | uint8L) ::
+ ("f3" | uint8L) ::
+ ("f4" | uint8L) ::
+ ("f5" | uint8L) ::
+ ("f6" | uint8L) ::
+ ("f7" | uintL(7))
+ ).exmap[BattleRankFieldData] (
+ {
+ case f1 :: f2 :: f3 :: f4 :: f5 :: f6 :: f7 :: HNil =>
+ Attempt.successful(BattleRankFieldData(f1, f2, f3, f4, f5, f6, f7))
+ },
+ {
+ case BattleRankFieldData(f1, f2, f3, f4, f5, f6, f7, _, _, _, _, _, _, _, _, _, _) =>
+ Attempt.successful(f1 :: f2 :: f3 :: f4 :: f5 :: f6 :: f7 :: HNil)
+ }
+ )
+
+ private val br6FieldCodec : Codec[BattleRankFieldData] = ( //+10u
+ ("f1" | uint8L) ::
+ ("f2" | uint8L) ::
+ ("f3" | uint8L) ::
+ ("f4" | uint8L) ::
+ ("f5" | uint8L) ::
+ ("f6" | uint8L) ::
+ ("f7" | uint8L) ::
+ ("f8" | uint8L) ::
+ ("f9" | bool)
+ ).exmap[BattleRankFieldData] (
+ {
+ case f1 :: f2 :: f3 :: f4 :: f5 :: f6 :: f7 :: f8 :: f9 :: HNil =>
+ val f9Int : Int = if(f9) { 1 } else { 0 }
+ Attempt.successful(BattleRankFieldData(f1, f2, f3, f4, f5, f6, f7, Some(f8), Some(f9Int)))
+ },
+ {
+ case BattleRankFieldData(f1, f2, f3, f4, f5, f6, f7, Some(f8), Some(f9), _, _, _, _, _, _, _, _) =>
+ val f9Bool : Boolean = if(f9 == 0) { false } else { true }
+ Attempt.successful(f1 :: f2 :: f3 :: f4 :: f5 :: f6 :: f7 :: f8 :: f9Bool :: HNil)
+ case _ =>
+ Attempt.failure(Err("expected battle rank 6 field data"))
+ }
+ )
+
+ private val br12FieldCodec : Codec[BattleRankFieldData] = ( //+52u
+ ("f1" | uint8L) ::
+ ("f2" | uint8L) ::
+ ("f3" | uint8L) ::
+ ("f4" | uint8L) ::
+ ("f5" | uint8L) ::
+ ("f6" | uint8L) ::
+ ("f7" | uint8L) ::
+ ("f8" | uint8L) ::
+ ("f9" | uint8L) ::
+ ("fA" | uint8L) ::
+ ("fB" | uint8L) ::
+ ("fC" | uint8L) ::
+ ("fD" | uint8L) ::
+ ("fE" | uintL(3))
+ ).exmap[BattleRankFieldData] (
+ {
+ case f1 :: f2 :: f3 :: f4 :: f5 :: f6 :: f7 :: f8 :: f9 :: fa :: fb :: fc :: fd :: fe :: HNil =>
+ Attempt.successful(BattleRankFieldData(f1, f2, f3, f4, f5, f6, f7, Some(f8), Some(f9), Some(fa), Some(fb), Some(fc), Some(fd), Some(fe)))
+ },
+ {
+ case BattleRankFieldData(f1, f2, f3, f4, f5, f6, f7, Some(f8), Some(f9), Some(fa), Some(fb), Some(fc), Some(fd), Some(fe), _, _, _) =>
+ Attempt.successful(f1 :: f2 :: f3 :: f4 :: f5 :: f6 :: f7 :: f8 :: f9 :: fa :: fb :: fc :: fd :: fe :: HNil)
+ case _ =>
+ Attempt.failure(Err("expected battle rank 12 field data"))
+ }
+ )
+
+ private val br18FieldCodec : Codec[BattleRankFieldData] = ( //+70u
+ ("f01" | uint8L) ::
+ ("f02" | uint8L) ::
+ ("f03" | uint8L) ::
+ ("f04" | uint8L) ::
+ ("f05" | uint8L) ::
+ ("f06" | uint8L) ::
+ ("f07" | uint8L) ::
+ ("f08" | uint8L) ::
+ ("f09" | uint8L) ::
+ ("f0A" | uint8L) ::
+ ("f0B" | uint8L) ::
+ ("f0C" | uint8L) ::
+ ("f0D" | uint8L) ::
+ ("f0E" | uint8L) ::
+ ("f0F" | uint8L) ::
+ ("f10" | uint8L) ::
+ ("f11" | bool)
+ ).exmap[BattleRankFieldData] (
+ {
+ case f01 :: f02 :: f03 :: f04 :: f05 :: f06 :: f07 :: f08 :: f09 :: f0a :: f0b :: f0c :: f0d :: f0e :: f0f :: f10 :: f11:: HNil =>
+ val f11Int : Int = if(f11) { 1 } else { 0 }
+ Attempt.successful(BattleRankFieldData(f01, f02, f03, f04, f05, f06, f07, Some(f08), Some(f09), Some(f0a), Some(f0b), Some(f0c), Some(f0d), Some(f0e), Some(f0f), Some(f10), Some(f11Int)))
+ },
+ {
+ case BattleRankFieldData(f01, f02, f03, f04, f05, f06, f07, Some(f08), Some(f09), Some(f0a), Some(f0b), Some(f0c), Some(f0d), Some(f0e), Some(f0f), Some(f10), Some(f11)) =>
+ val f11Bool : Boolean = if(f11 == 0) { false } else { true }
+ Attempt.successful(f01 :: f02 :: f03 :: f04 :: f05 :: f06 :: f07 :: f08 :: f09 :: f0a :: f0b :: f0c :: f0d :: f0e :: f0f :: f10 :: f11Bool :: HNil)
+ case _ =>
+ Attempt.failure(Err("expected battle rank 18 field data"))
+ }
+ )
/**
- * Get the padding of the first entry in the first time events list.
- * The padding will always be a number 0-7.
- * @param len the length of the list
- * @return the pad length in bits
+ * na
+ * @param bep the battle experience points
+ * @return the appropriate `Codec` for the fields representing a player with the implied battle rank
*/
- private def ftePadding(len : Long) : Int = {
- //TODO the parameters for this function are not correct
- //TODO the proper padding length should reflect all variability in the stream prior to this point
- if(len > 0) {
- 5
+ private def selectBattleRankFieldCodec(bep : Int) : Codec[BattleRankFieldData] = {
+ if(bep > 754370) {
+ br18FieldCodec
+ }
+ else if(bep > 197753) {
+ br12FieldCodec
+ }
+ else if(bep > 29999) {
+ br6FieldCodec
+ }
+ else {
+ br1FieldCodec
}
- else
- 0
}
/**
- * Get the padding of the first entry in the completed tutorials list.
- * The padding will always be a number 0-7.
- *
- * The tutorials list follows the first time event list and that contains byte-aligned strings too.
- * While there will be more to the padding, this other list is important.
- * Any elements in that list causes the automatic byte-alignment of this list's first entry.
- * @param len the length of the list
- * @return the pad length in bits
+ * The padding value of the first entry in either of two byte-aligned `List` structures.
+ * @param bep the battle experience points
+ * @return the pad length in bits `n < 8`
*/
- private def tutPadding(len : Long, len2 : Long) : Int = {
- if(len > 0) //automatic alignment from previous List
- 0
- else if(len2 > 0) //need to align for elements
+ private def bepFieldPadding(bep : Int) : Int = {
+ if(bep > 754370) { //BR18+
+ 7
+ }
+ else if(bep > 197753) { //BR12+
+ 1
+ }
+ else if(bep > 29999) { //BR6+
+ 3
+ }
+ else { //BR1+
5
- else //both lists are empty
+ }
+ }
+
+ /**
+ * Get the padding of the first entry in the first time events list.
+ * @param len the length of the list
+ * @param bep the battle experience points
+ * @return the pad length in bits `n < 8`
+ */
+ private def ftePadding(len : Long, bep : Int) : Int = {
+ //TODO the parameters for this function are not correct
+ //TODO the proper padding length should reflect all variability in the stream prior to this point
+ if(len > 0) {
+ bepFieldPadding(bep)
+ }
+ else {
0
+ }
+ }
+
+ /**
+ * Get the padding of the first entry in the completed tutorials list.
+ *
+ * The tutorials list follows the first time event list and also contains byte-aligned strings.
+ * If the both lists are populated or empty at the same time, the first entry will not need padding.
+ * If the first time events list is unpopulated, but this list is populated, the first entry will need padding bits.
+ * @param len the length of the list
+ * @param bep the battle experience points
+ * @return the pad length in bits `n < 8`
+ */
+ private def tutPadding(len : Long, len2 : Long, bep : Int) : Int = {
+ if(len > 0) {
+ //automatic alignment from previous List
+ 0
+ }
+ else if(len2 > 0) {
+ //need to align for elements
+ bepFieldPadding(bep)
+ }
+ else {
+ //both lists are empty
+ 0
+ }
}
implicit val codec : Codec[DetailedCharacterData] = (
("appearance" | CharacterAppearanceData.codec) ::
- ignore(160) ::
- ("healthMax" | uint16L) ::
- ("health" | uint16L) ::
- ignore(1) ::
- ("armor" | uint16L) ::
- ignore(9) ::
- ("unk1" | uint8L) ::
- ignore(8) ::
- ("unk2" | uint4L) ::
- ("unk3" | uintL(3)) ::
- ("staminaMax" | uint16L) ::
- ("stamina" | uint16L) ::
- ignore(149) ::
- ("unk4" | uint16L) ::
- ("unk5" | uint8L) ::
- ("unk6" | uint8L) ::
- ("unk7" | uint8L) ::
- ("unk8" | uint8L) ::
- ("unk9" | uintL(12)) ::
- ignore(19) ::
- (("firstTimeEvent_length" | uint32L) >>:~ { len =>
- conditional(len > 0, "firstTimeEvent_firstEntry" | PacketHelpers.encodedStringAligned( ftePadding(len) )) ::
- ("firstTimeEvent_list" | PacketHelpers.listOfNSized(len - 1, PacketHelpers.encodedString)) ::
- (("tutorial_length" | uint32L) >>:~ { len2 =>
- conditional(len2 > 0, "tutorial_firstEntry" | PacketHelpers.encodedStringAligned( tutPadding(len, len2) )) ::
- ("tutorial_list" | PacketHelpers.listOfNSized(len2 - 1, PacketHelpers.encodedString)) ::
- ignore(207) ::
- optional(bool, "inventory" | InventoryData.codec_detailed) ::
- ("drawn_slot" | DrawnSlot.codec) ::
- bool //usually false
- })
+ (("bep" | uint24L) >>:~ { bep =>
+ ignore(136) ::
+ ("healthMax" | uint16L) ::
+ ("health" | uint16L) ::
+ ignore(1) ::
+ ("armor" | uint16L) ::
+ ignore(9) ::
+ ("unk1" | uint8L) ::
+ ignore(8) ::
+ ("unk2" | uint4L) ::
+ ("unk3" | uintL(3)) ::
+ ("staminaMax" | uint16L) ::
+ ("stamina" | uint16L) ::
+ ignore(149) ::
+ ("unk4" | uint16L) ::
+ ("unk5" | uint8L) ::
+ ("brFields" | selectBattleRankFieldCodec(bep)) :: //TODO do this for all these fields until their bits are better defined
+ (("firstTimeEvent_length" | uint32L) >>:~ { len =>
+ conditional(len > 0, "firstTimeEvent_firstEntry" | PacketHelpers.encodedStringAligned(ftePadding(len, bep))) ::
+ ("firstTimeEvent_list" | PacketHelpers.listOfNSized(len - 1, PacketHelpers.encodedString)) ::
+ (("tutorial_length" | uint32L) >>:~ { len2 =>
+ conditional(len2 > 0, "tutorial_firstEntry" | PacketHelpers.encodedStringAligned(tutPadding(len, len2, bep))) ::
+ ("tutorial_list" | PacketHelpers.listOfNSized(len2 - 1, PacketHelpers.encodedString)) ::
+ ignore(207) ::
+ optional(bool, "inventory" | InventoryData.codec_detailed) ::
+ ("drawn_slot" | DrawnSlot.codec) ::
+ bool //usually false
+ })
+ })
})
).exmap[DetailedCharacterData] (
{
- case app :: _ :: b :: c :: _ :: d :: _ :: e :: _ :: f :: g :: h :: i :: _ :: j :: k :: l :: m :: n :: o :: _ :: _ :: q :: r :: _ :: t :: u :: _ :: v :: w :: false :: HNil =>
+ case app :: bep :: _ :: hpmax :: hp :: _ :: armor :: _ :: u1 :: _ :: u2 :: u3 :: stamax :: stam :: _ :: u4 :: u5 :: brFields :: _ :: fte0 :: fte1 :: _ :: tut0 :: tut1 :: _ :: inv :: drawn :: false :: HNil =>
//prepend the displaced first elements to their lists
- val fteList : List[String] = if(q.isDefined) { q.get :: r } else r
- val tutList : List[String] = if(t.isDefined) { t.get :: u } else u
- Attempt.successful(DetailedCharacterData(app, b, c, d, e, f, g, h, i, j, k, l, m, n, o, fteList, tutList, v, w))
+ val fteList : List[String] = if(fte0.isDefined) { fte0.get +: fte1 } else fte1
+ val tutList : List[String] = if(tut0.isDefined) { tut0.get +: tut1 } else tut1
+ Attempt.successful(DetailedCharacterData(app, bep, hpmax, hp, armor, u1, u2, u3, stamax, stam, u4, u5, brFields, fteList, tutList, inv, drawn))
},
{
- case DetailedCharacterData(app, b, c, d, e, f, g, h, i, j, k, l, m, n, o, fteList, tutList, p, q) =>
+ case DetailedCharacterData(app, bep, hpmax, hp, armor, u1, u2, u3, stamax, stam, u4, u5, brFields, fteList, tutList, inv, drawn) =>
//shift the first elements off their lists
var fteListCopy = fteList
var firstEvent : Option[String] = None
@@ -246,7 +419,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
firstTutorial = Some(tutList.head)
tutListCopy = tutList.drop(1)
}
- Attempt.successful(app :: () :: b :: c :: () :: d :: () :: e :: () :: f :: g :: h :: i :: () :: j :: k :: l :: m :: n :: o :: () :: fteList.size.toLong :: firstEvent :: fteListCopy :: tutList.size.toLong :: firstTutorial :: tutListCopy :: () :: p :: q :: false :: HNil)
+ Attempt.successful(app :: bep :: () :: hpmax :: hp :: () :: armor :: () :: u1 :: () :: u2 :: u3 :: stamax :: stam :: () :: u4 :: u5 :: brFields :: fteList.size.toLong :: firstEvent :: fteListCopy :: tutList.size.toLong :: firstTutorial :: tutListCopy :: () :: inv :: drawn :: false :: HNil)
}
)
}
diff --git a/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala b/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala
index dfccf584..188fd5d5 100644
--- a/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala
+++ b/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala
@@ -216,10 +216,13 @@ class ObjectCreateDetailedMessageTest extends Specification {
char.stamina mustEqual 100
char.unk4 mustEqual 28
char.unk5 mustEqual 4
- char.unk6 mustEqual 44
- char.unk7 mustEqual 84
- char.unk8 mustEqual 104
- char.unk9 mustEqual 1900
+ char.brFields.field00 mustEqual 44
+ char.brFields.field01 mustEqual 84
+ char.brFields.field02 mustEqual 104
+ char.brFields.field03 mustEqual 108
+ char.brFields.field04 mustEqual 112
+ char.brFields.field05 mustEqual 0
+ char.brFields.field06 mustEqual 0
char.firstTimeEvents.size mustEqual 4
char.firstTimeEvents.head mustEqual "xpe_sanctuary_help"
char.firstTimeEvents(1) mustEqual "xpe_th_firemodes"
@@ -405,11 +408,13 @@ class ObjectCreateDetailedMessageTest extends Specification {
Nil
val obj = DetailedCharacterData(
app,
+ 0,
100, 100,
50,
1, 7, 7,
100, 100,
- 28, 4, 44, 84, 104, 1900,
+ 28, 4,
+ BattleRankFieldData(44, 84, 104, 108, 112, 0, 0),
"xpe_sanctuary_help" :: "xpe_th_firemodes" :: "used_beamer" :: "map13" :: Nil,
List.empty,
InventoryData(inv),