diff --git a/src/main/scala/net/psforever/actors/session/AvatarActor.scala b/src/main/scala/net/psforever/actors/session/AvatarActor.scala
index 0adefdf1..50423946 100644
--- a/src/main/scala/net/psforever/actors/session/AvatarActor.scala
+++ b/src/main/scala/net/psforever/actors/session/AvatarActor.scala
@@ -1,3 +1,4 @@
+// Copyright (c) 2019 PSForever
package net.psforever.actors.session
import java.util.concurrent.atomic.AtomicInteger
@@ -16,7 +17,7 @@ import net.psforever.objects._
import net.psforever.objects.ballistics.PlayerSource
import net.psforever.objects.locker.LockerContainer
import net.psforever.objects.vital.HealFromImplant
-import net.psforever.packet.game.objectcreate.ObjectClass
+import net.psforever.packet.game.objectcreate.{ObjectClass, RibbonBars}
import net.psforever.packet.game._
import net.psforever.types._
import net.psforever.util.Database._
@@ -178,6 +179,8 @@ object AvatarActor {
/** Set cosmetics. Only allowed for BR24 or higher. */
final case class SetCosmetics(personalStyles: Set[Cosmetic]) extends Command
+ final case class SetRibbon(ribbon: MeritCommendation.Value, bar: RibbonBarSlot.Value) extends Command
+
private case class ServiceManagerLookupResult(result: ServiceManager.LookupResult) extends Command
final case class SetStamina(stamina: Int) extends Command
@@ -188,6 +191,14 @@ object AvatarActor {
final case class AvatarLoginResponse(avatar: Avatar)
+ def changeRibbons(ribbons: RibbonBars, ribbon: MeritCommendation.Value, bar: RibbonBarSlot.Value): RibbonBars = {
+ bar match {
+ case RibbonBarSlot.Top => ribbons.copy(upper = ribbon)
+ case RibbonBarSlot.Middle => ribbons.copy(middle = ribbon)
+ case RibbonBarSlot.Bottom => ribbons.copy(lower = ribbon)
+ case RibbonBarSlot.TermOfService => ribbons.copy(tos = ribbon)
+ }
+ }
}
class AvatarActor(
@@ -379,7 +390,7 @@ class AvatarActor(
))
// if we need to start stamina regeneration
tryRestoreStaminaForSession(stamina = 1) match {
- case Some(sess) =>
+ case Some(_) =>
defaultStaminaRegen(initialDelay = 0.5f seconds)
case _ => ;
}
@@ -1003,6 +1014,22 @@ class AvatarActor(
case SetCosmetics(cosmetics) =>
setCosmetics(cosmetics)
Behaviors.same
+
+ case SetRibbon(ribbon, bar) =>
+ val previousRibbonBars = avatar.ribbonBars
+ val useRibbonBars = Seq(previousRibbonBars.upper, previousRibbonBars.middle, previousRibbonBars.lower)
+ .indexWhere { _ == ribbon } match {
+ case -1 => previousRibbonBars
+ case n => AvatarActor.changeRibbons(previousRibbonBars, MeritCommendation.None, RibbonBarSlot(n))
+ }
+ replaceAvatar(avatar.copy(ribbonBars = AvatarActor.changeRibbons(useRibbonBars, ribbon, bar)))
+ val player = session.get.player
+ val zone = player.Zone
+ zone.AvatarEvents ! AvatarServiceMessage(
+ zone.id,
+ AvatarAction.SendResponse(Service.defaultPlayerGUID, DisplayedAwardMessage(player.GUID, ribbon, bar))
+ )
+ Behaviors.same
}
.receiveSignal {
case (_, PostStop) =>
diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala
index 8616a6a4..9063e81e 100644
--- a/src/main/scala/net/psforever/actors/session/SessionActor.scala
+++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala
@@ -159,6 +159,8 @@ object SessionActor {
tool: ConstructionItem,
index: Int
)
+
+ private final case class AvatarAwardMessageBundle(bundle: Iterable[Iterable[PlanetSidePacket]], delay: Long)
}
class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], connectionId: String, sessionId: Long)
@@ -279,6 +281,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
var heightTrend: Boolean = false //up = true, down = false
var heightHistory: Float = 0f
val collisionHistory: mutable.HashMap[ActorRef, Long] = mutable.HashMap()
+ var populateAvatarAwardRibbonsFunc: (Int, Long) => Unit = setupAvatarAwardMessageDelivery
var clientKeepAlive: Cancellable = Default.Cancellable
var progressBarUpdate: Cancellable = Default.Cancellable
@@ -1347,6 +1350,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
}
}
+ case SessionActor.AvatarAwardMessageBundle(pkts, delay) =>
+ performAvatarAwardMessageDelivery(pkts, delay)
+
case ResponseToSelf(pkt) =>
sendResponse(pkt)
@@ -3157,8 +3163,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
if (tplayer.ExoSuit == ExoSuitType.MAX) {
sendResponse(PlanetsideAttributeMessage(guid, 7, tplayer.Capacitor.toLong))
}
- //AvatarAwardMessage
- //DisplayAwardMessage
+ // AvatarAwardMessage
+ populateAvatarAwardRibbonsFunc(1, 20L)
+
sendResponse(PlanetsideStringAttributeMessage(guid, 0, "Outfit Name"))
//squad stuff (loadouts, assignment)
squadSetup()
@@ -3251,6 +3258,83 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
HandleSetCurrentAvatar(tplayer)
}
+ /**
+ * Don't extract the award advancement information from a player character upon respawning or zoning.
+ * You only need to perform that population once at login.
+ * @param bundleSize it doesn't matter
+ * @param delay it doesn't matter
+ */
+ def skipAvatarAwardMessageDelivery(bundleSize: Int, delay: Long): Unit = { }
+
+ /**
+ * Extract the award advancement information from a player character, and
+ * coordinate timed dispatches of groups of packets.
+ * @param bundleSize divide packets into groups of this size
+ * @param delay dispatch packet divisions in intervals
+ */
+ def setupAvatarAwardMessageDelivery(bundleSize: Int, delay: Long): Unit = {
+ setupAvatarAwardMessageDelivery(player, bundleSize, delay)
+ populateAvatarAwardRibbonsFunc = skipAvatarAwardMessageDelivery
+ }
+
+ /**
+ * Extract the merit commendation advancement information from a player character,
+ * filter unnecessary or not applicable statistics,
+ * translate the information into packet data, and
+ * coordinate timed dispatches of groups of packets.
+ * @param tplayer the player character
+ * @param bundleSize divide packets into groups of this size
+ * @param delay dispatch packet divisions in intervals
+ */
+ def setupAvatarAwardMessageDelivery(tplayer: Player, bundleSize: Int, delay: Long): Unit = {
+ val date: Int = (System.currentTimeMillis() / 1000L).toInt - 604800 //last week, in seconds
+ performAvatarAwardMessageDelivery(
+ Award
+ .values
+ .filter { merit =>
+ val label = merit.value
+ val alignment = merit.alignment
+ if (merit.category == AwardCategory.Exclusive) false
+ else if (alignment != PlanetSideEmpire.NEUTRAL && alignment != player.Faction) false
+ else if (label.contains("Male") && player.Sex != CharacterSex.Male) false
+ else if (label.contains("Female") && player.Sex != CharacterSex.Female) false
+ else true
+ }
+ .flatMap { merit =>
+ merit.progression.map { level =>
+ AvatarAwardMessage(level.commendation, AwardCompletion(date))
+ }
+ }
+ .grouped(bundleSize)
+ .iterator
+ .to(Iterable),
+ delay
+ )
+ }
+
+ /**
+ * Coordinate timed dispatches of groups of packets.
+ * @param messageBundles groups of packets to be dispatched
+ * @param delay dispatch packet divisions in intervals
+ */
+ def performAvatarAwardMessageDelivery(
+ messageBundles: Iterable[Iterable[PlanetSidePacket]],
+ delay: Long
+ ): Unit = {
+ messageBundles match {
+ case Nil => ;
+ case x :: Nil =>
+ x.foreach { sendResponse }
+ case x :: xs =>
+ x.foreach { sendResponse }
+ context.system.scheduler.scheduleOnce(
+ delay.milliseconds,
+ self,
+ SessionActor.AvatarAwardMessageBundle(xs, delay)
+ )
+ }
+ }
+
/**
* These messages are dispatched when first starting up the client and connecting to the server for the first time.
* While many of these messages will be reused for other situations, they appear in this order only during startup.
@@ -5966,12 +6050,16 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
log.error(s"InvalidTerrain: ${player.Name} is complaining about a thing@$vehicle_guid that can not be found")
}
- case msg @ ActionCancelMessage(u1, u2, u3) =>
+ case ActionCancelMessage(_, _, _) =>
progressBarUpdate.cancel()
progressBarValue = None
case TradeMessage(trade) =>
- log.info(s"${player.Name} wants to trade, for some reason - $trade")
+ log.trace(s"${player.Name} wants to trade for some reason - $trade")
+
+ case DisplayedAwardMessage(_, ribbon, bar) =>
+ log.trace(s"${player.Name} changed the $bar displayed award ribbon to $ribbon")
+ avatarActor ! AvatarActor.SetRibbon(ribbon, bar)
case _ =>
log.warn(s"Unhandled GamePacket $pkt")
diff --git a/src/main/scala/net/psforever/objects/avatar/Avatar.scala b/src/main/scala/net/psforever/objects/avatar/Avatar.scala
index 036273e1..d488dd68 100644
--- a/src/main/scala/net/psforever/objects/avatar/Avatar.scala
+++ b/src/main/scala/net/psforever/objects/avatar/Avatar.scala
@@ -1,3 +1,4 @@
+// Copyright (c) 2017 PSForever
package net.psforever.objects.avatar
import net.psforever.objects.definition.{AvatarDefinition, BasicDefinition}
@@ -6,6 +7,7 @@ import net.psforever.objects.inventory.LocallyRegisteredInventory
import net.psforever.objects.loadouts.{Loadout, SquadLoadout}
import net.psforever.objects.locker.{LockerContainer, LockerEquipment}
import net.psforever.objects.{GlobalDefinitions, OffhandEquipmentSlot}
+import net.psforever.packet.game.objectcreate.RibbonBars
import net.psforever.types._
import org.joda.time.{Duration, LocalDateTime, Seconds}
@@ -94,6 +96,7 @@ case class Avatar(
stamina: Int = 100,
fatigued: Boolean = false,
cosmetics: Option[Set[Cosmetic]] = None,
+ ribbonBars: RibbonBars = RibbonBars(),
certifications: Set[Certification] = Set(),
loadouts: Seq[Option[Loadout]] = Seq.fill(20)(None),
squadLoadouts: Seq[Option[SquadLoadout]] = Seq.fill(10)(None),
diff --git a/src/main/scala/net/psforever/objects/avatar/Award.scala b/src/main/scala/net/psforever/objects/avatar/Award.scala
new file mode 100644
index 00000000..29239d1c
--- /dev/null
+++ b/src/main/scala/net/psforever/objects/avatar/Award.scala
@@ -0,0 +1,1201 @@
+// Copyright (c) 2022 PSForever
+package net.psforever.objects.avatar
+
+import enumeratum.values.{StringEnum, StringEnumEntry}
+import net.psforever.types.{MeritCommendation, PlanetSideEmpire}
+
+/**
+ * Awards organize merit commendations into an iterative series that have their own accomplishment statistics.
+ * @see `MeritCommendation.Value`
+ * @param commendation the merit commendation attached to this rank
+ */
+final case class CommendationRank(commendation: MeritCommendation.Value)
+
+/**
+ * A unique accomplishment that statuses positive player behavior and
+ * assigns classification and advancement metrics to the accomplishment.
+ * @param value the specific label that indicates this award
+ * @param category a generalization of the award's accreditation
+ * @param progression the iterative merit commendations associated with increasing ranks of this award
+ */
+sealed abstract class Award(
+ val value: String,
+ val category: AwardCategory.Value,
+ val progression: List[CommendationRank]
+ ) extends StringEnumEntry {
+ assert(
+ Merit.values.exists(_.toString().equals(value)),
+ s"$value is not a merit found in the appropriate Enumeration"
+ )
+ assert(
+ progression.nonEmpty,
+ s"$value must define a base progression rank"
+ )
+
+ def alignment: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
+}
+
+sealed abstract class NewConglomerateAward(
+ override val value: String,
+ override val category: AwardCategory.Value,
+ override val progression: List[CommendationRank]
+ ) extends Award(value, category, progression) {
+ override def alignment: PlanetSideEmpire.Value = PlanetSideEmpire.NC
+}
+
+sealed abstract class TerranRepublicAward(
+ override val value: String,
+ override val category: AwardCategory.Value,
+ override val progression: List[CommendationRank]
+ ) extends Award(value, category, progression) {
+ override def alignment: PlanetSideEmpire.Value = PlanetSideEmpire.TR
+}
+
+sealed abstract class VanuSovereigntyAward(
+ override val value: String,
+ override val category: AwardCategory.Value,
+ override val progression: List[CommendationRank]
+ ) extends Award(value, category, progression) {
+ override def alignment: PlanetSideEmpire.Value = PlanetSideEmpire.VS
+}
+
+/**
+ * A collection of all award labels.
+ */
+object Merit extends Enumeration {
+ val AdvancedMedic = Value("AdvancedMedic")
+ val AdvancedMedicAssists = Value("AdvancedMedicAssists")
+ val AirDefender = Value("AirDefender")
+ val AMSSupport = Value("AMSSupport")
+ val AntiVehicular = Value("AntiVehicular")
+ val Avenger = Value("Avenger")
+ val BendingMovieActor = Value("BendingMovieActor")
+ val BFRAdvanced = Value("BFRAdvanced")
+ val BFRBuster = Value("BFRBuster")
+ val BlackOpsHunter = Value("BlackOpsHunter")
+ val BlackOpsParticipant = Value("BlackOpsParticipant")
+ val BlackOpsVictory = Value("BlackOpsVictory")
+ val Bombadier = Value("Bombadier")
+ val BomberAce = Value("BomberAce")
+ val Boomer = Value("Boomer")
+ val CalvaryDriver = Value("CalvaryDriver")
+ val CalvaryPilot = Value("CalvaryPilot")
+ val CMTopOutfit = Value("CMTopOutfit")
+ val CombatMedic = Value("CombatMedic")
+ val CombatRepair = Value("CombatRepair")
+ val ContestFirstBR40 = Value("ContestFirstBR40")
+ val ContestMovieMaker = Value("ContestMovieMaker")
+ val ContestMovieMakerOutfit = Value("ContestMovieMakerOutfit")
+ val ContestPlayerOfTheMonth = Value("ContestPlayerOfTheMonth")
+ val ContestPlayerOfTheYear = Value("ContestPlayerOfTheYear")
+ val CSAppreciation = Value("CSAppreciation")
+ val DefenseNC = Value("DefenseNC")
+ val DefenseTR = Value("DefenseTR")
+ val DefenseVS = Value("DefenseVS")
+ val DevilDogsMovie = Value("DevilDogsMovie")
+ val DogFighter = Value("DogFighter")
+ val DriverGunner = Value("DriverGunner")
+ val EliteAssault = Value("EliteAssault")
+ val EmeraldVeteran = Value("EmeraldVeteran")
+ val Engineer = Value("Engineer")
+ val EquipmentSupport = Value("EquipmentSupport")
+ val EventNC = Value("EventNC")
+ val EventNCCommander = Value("EventNCCommander")
+ val EventNCElite = Value("EventNCElite")
+ val EventNCSoldier = Value("EventNCSoldier")
+ val EventTR = Value("EventTR")
+ val EventTRCommander = Value("EventTRCommander")
+ val EventTRElite = Value("EventTRElite")
+ val EventTRSoldier = Value("EventTRSoldier")
+ val EventVS = Value("EventVS")
+ val EventVSCommander = Value("EventVSCommander")
+ val EventVSElite = Value("EventVSElite")
+ val EventVSSoldier = Value("EventVSSoldier")
+ val Explorer = Value("Explorer")
+ val FanFaire2005Commander = Value("FanFaire2005Commander")
+ val FanFaire2005Soldier = Value("FanFaire2005Soldier")
+ val FanFaire2006Atlanta = Value("FanFaire2006Atlanta")
+ val FanFaire2007 = Value("FanFaire2007")
+ val FanFaire2008 = Value("FanFaire2008")
+ val FanFaire2009 = Value("FanFaire2009")
+ val GalaxySupport = Value("GalaxySupport")
+ val Grenade = Value("Grenade")
+ val GroundGunner = Value("GroundGunner")
+ val HackingSupport = Value("HackingSupport")
+ val HalloweenMassacre2006NC = Value("HalloweenMassacre2006NC")
+ val HalloweenMassacre2006TR = Value("HalloweenMassacre2006TR")
+ val HalloweenMassacre2006VS = Value("HalloweenMassacre2006VS")
+ val HeavyAssault = Value("HeavyAssault")
+ val HeavyInfantry = Value("HeavyInfantry")
+ val InfantryExpert = Value("InfantryExpert")
+ val Jacking = Value("Jacking")
+ val KnifeCombat = Value("KnifeCombat")
+ val LightInfantry = Value("LightInfantry")
+ val LockerCracker = Value("LockerCracker")
+ val LodestarSupport = Value("LodestarSupport")
+ val Loser = Value("Loser")
+ val MarkovVeteran = Value("MarkovVeteran")
+ val Max = Value("Max")
+ val MaxBuster = Value("MaxBuster")
+ val MediumAssault = Value("MediumAssault")
+ val None = Value("None") //the no merit commendation award label
+ val Orion = Value("Orion")
+ val Osprey = Value("Osprey")
+ val Phalanx = Value("Phalanx")
+ val PSUMaAttendee = Value("PSUMaAttendee")
+ val PSUMbAttendee = Value("PSUMbAttendee")
+ val QAAppreciation = Value("QAAppreciation")
+ val ReinforcementHackSpecialist = Value("ReinforcementHackSpecialist")
+ val ReinforcementInfantrySpecialist = Value("ReinforcementInfantrySpecialist")
+ val ReinforcementSpecialist = Value("ReinforcementSpecialist")
+ val ReinforcementVehicleSpecialist = Value("ReinforcementVehicleSpecialist")
+ val RouterSupport = Value("RouterSupport")
+ val RouterTelepadDeploy = Value("RouterTelepadDeploy")
+ val ScavengerNC = Value("ScavengerNC")
+ val ScavengerTR = Value("ScavengerTR")
+ val ScavengerVS = Value("ScavengerVS")
+ val Sniper = Value("Sniper")
+ val SpecialAssault = Value("SpecialAssault")
+ val StandardAssault = Value("StandardAssault")
+ val StracticsHistorian = Value("StracticsHistorian")
+ val Supply = Value("Supply")
+ val TankBuster = Value("TankBuster")
+ val TermOfServiceNC = Value("TermOfServiceNC")
+ val TermOfServiceTR = Value("TermOfServiceTR")
+ val TermOfServiceVS = Value("TermOfServiceVS")
+ val TinyRoboticSupport = Value("TinyRoboticSupport")
+ val Transport = Value("Transport")
+ val TransportationCitation = Value("TransportationCitation")
+ val ValentineFemale = Value("ValentineFemale")
+ val ValentineMale = Value("ValentineMale")
+ val WernerVeteran = Value("WernerVeteran")
+ val XmasGingerman = Value("XmasGingerman")
+ val XmasSnowman = Value("XmasSnowman")
+ val XmasSpirit = Value("XmasSpirit")
+}
+
+/**
+ * A collection of all award categories.
+ */
+object AwardCategory extends Enumeration {
+ val
+ Activity,
+ Defense,
+ Exclusive,
+ Support,
+ Vehicular,
+ Weaponry
+ = Value
+}
+
+object Award extends StringEnum[Award] {
+ import net.psforever.types.MeritCommendation._
+
+ val values = findValues
+
+ case object AdvancedMedic extends Award(
+ value = "AdvancedMedic",
+ AwardCategory.Support,
+ List(
+ CommendationRank(AdvancedMedic1),
+ CommendationRank(AdvancedMedic2),
+ CommendationRank(AdvancedMedic3),
+ CommendationRank(AdvancedMedic4),
+ CommendationRank(AdvancedMedic5),
+ CommendationRank(AdvancedMedic6),
+ CommendationRank(AdvancedMedic7)
+ )
+ )
+ case object AdvancedMedicAssists extends Award(
+ value = "AdvancedMedicAssists",
+ AwardCategory.Support,
+ List(
+ CommendationRank(AdvancedMedicAssists1),
+ CommendationRank(AdvancedMedicAssists2),
+ CommendationRank(AdvancedMedicAssists3),
+ CommendationRank(AdvancedMedicAssists4),
+ CommendationRank(AdvancedMedicAssists5),
+ CommendationRank(AdvancedMedicAssists6),
+ CommendationRank(AdvancedMedicAssists7)
+ )
+ )
+ case object AirDefender extends Award(
+ value = "AirDefender",
+ AwardCategory.Vehicular,
+ List(
+ CommendationRank(AirDefender1),
+ CommendationRank(AirDefender2),
+ CommendationRank(AirDefender3),
+ CommendationRank(AirDefender4),
+ CommendationRank(AirDefender5),
+ CommendationRank(AirDefender6),
+ CommendationRank(AirDefender7)
+ )
+ )
+ case object AMSSupport extends Award(
+ value = "AMSSupport",
+ AwardCategory.Support,
+ List(
+ CommendationRank(AMSSupport1),
+ CommendationRank(AMSSupport2),
+ CommendationRank(AMSSupport3),
+ CommendationRank(AMSSupport4),
+ CommendationRank(AMSSupport5),
+ CommendationRank(AMSSupport6),
+ CommendationRank(AMSSupport7)
+ )
+ )
+ case object AntiVehicular extends Award(
+ value = "AntiVehicular",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(AntiVehicular1),
+ CommendationRank(AntiVehicular2),
+ CommendationRank(AntiVehicular3),
+ CommendationRank(AntiVehicular4),
+ CommendationRank(AntiVehicular5),
+ CommendationRank(AntiVehicular6),
+ CommendationRank(AntiVehicular7)
+ )
+ )
+ case object Avenger extends TerranRepublicAward(
+ value = "Avenger",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(Avenger1),
+ CommendationRank(Avenger2),
+ CommendationRank(Avenger3),
+ CommendationRank(Avenger4),
+ CommendationRank(Avenger5),
+ CommendationRank(Avenger6),
+ CommendationRank(Avenger7)
+ )
+ )
+ case object BendingMovieActor extends Award(
+ value = "BendingMovieActor",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.BendingMovieActor))
+ )
+ case object BFRAdvanced extends Award(
+ value = "BFRAdvanced",
+ AwardCategory.Vehicular,
+ List(
+ CommendationRank(MeritCommendation.BFRAdvanced),
+ CommendationRank(MeritCommendation.BFRAdvanced2),
+ CommendationRank(MeritCommendation.BFRAdvanced3),
+ CommendationRank(MeritCommendation.BFRAdvanced4),
+ CommendationRank(MeritCommendation.BFRAdvanced5)
+ )
+ )
+ case object BFRBuster extends Award(
+ value = "BFRBuster",
+ AwardCategory.Activity,
+ List(
+ CommendationRank(BFRBuster1),
+ CommendationRank(BFRBuster2),
+ CommendationRank(BFRBuster3),
+ CommendationRank(BFRBuster4),
+ CommendationRank(BFRBuster5),
+ CommendationRank(BFRBuster6),
+ CommendationRank(BFRBuster7)
+ )
+ )
+ case object BlackOpsHunter extends Award(
+ value = "BlackOpsHunter",
+ AwardCategory.Activity,
+ List(
+ CommendationRank(MeritCommendation.BlackOpsHunter1),
+ CommendationRank(MeritCommendation.BlackOpsHunter2),
+ CommendationRank(MeritCommendation.BlackOpsHunter3),
+ CommendationRank(MeritCommendation.BlackOpsHunter4),
+ CommendationRank(MeritCommendation.BlackOpsHunter5)
+ )
+ )
+ case object BlackOpsParticipant extends Award(
+ value = "BlackOpsParticipant",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.BlackOpsParticipant))
+ )
+ case object BlackOpsVictory extends Award(
+ value = "BlackOpsVictory",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.BlackOpsVictory))
+ )
+ case object Bombadier extends Award(
+ value = "Bombadier",
+ AwardCategory.Vehicular,
+ List(
+ CommendationRank(Bombadier1),
+ CommendationRank(Bombadier2),
+ CommendationRank(Bombadier3),
+ CommendationRank(Bombadier4),
+ CommendationRank(Bombadier5),
+ CommendationRank(Bombadier6),
+ CommendationRank(Bombadier7)
+ )
+ )
+ case object BomberAce extends Award(
+ value = "BomberAce",
+ AwardCategory.Vehicular,
+ List(
+ CommendationRank(BomberAce1),
+ CommendationRank(BomberAce2),
+ CommendationRank(BomberAce3),
+ CommendationRank(BomberAce4),
+ CommendationRank(BomberAce5),
+ CommendationRank(BomberAce6),
+ CommendationRank(BomberAce7)
+ )
+ )
+ case object Boomer extends Award(
+ value = "Boomer",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(Boomer1),
+ CommendationRank(Boomer2),
+ CommendationRank(Boomer3),
+ CommendationRank(Boomer4),
+ CommendationRank(Boomer5),
+ CommendationRank(Boomer6),
+ CommendationRank(Boomer7)
+ )
+ )
+ case object CalvaryDriver extends Award(
+ value = "CalvaryDriver",
+ AwardCategory.Vehicular,
+ List(
+ CommendationRank(CalvaryDriver1),
+ CommendationRank(CalvaryDriver2),
+ CommendationRank(CalvaryDriver3),
+ CommendationRank(CalvaryDriver4),
+ CommendationRank(CalvaryDriver5),
+ CommendationRank(CalvaryDriver6),
+ CommendationRank(CalvaryDriver7)
+ )
+ )
+ case object CalvaryPilot extends Award(
+ value = "CalvaryPilot",
+ AwardCategory.Vehicular,
+ List(
+ CommendationRank(MeritCommendation.CalvaryPilot),
+ CommendationRank(CalvaryPilot2),
+ CommendationRank(CalvaryPilot3),
+ CommendationRank(CalvaryPilot4),
+ CommendationRank(CalvaryPilot5),
+ CommendationRank(CalvaryPilot6),
+ CommendationRank(CalvaryPilot7)
+ )
+ )
+ case object CMTopOutfit extends Award(
+ value = "CMTopOutfit",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.CMTopOutfit))
+ )
+ case object CombatMedic extends Award(
+ value = "CombatMedic",
+ AwardCategory.Support,
+ List(
+ CommendationRank(MeritCommendation.CombatMedic),
+ CommendationRank(CombatMedic2),
+ CommendationRank(CombatMedic3),
+ CommendationRank(CombatMedic4),
+ CommendationRank(CombatMedic5),
+ CommendationRank(CombatMedic6),
+ CommendationRank(CombatMedic7)
+ )
+ )
+ case object CombatRepair extends Award(
+ value = "CombatRepair",
+ AwardCategory.Support,
+ List(
+ CommendationRank(CombatRepair1),
+ CommendationRank(CombatRepair2),
+ CommendationRank(CombatRepair3),
+ CommendationRank(CombatRepair4),
+ CommendationRank(CombatRepair5),
+ CommendationRank(CombatRepair6),
+ CommendationRank(CombatRepair7)
+ )
+ )
+ case object ContestFirstBR40 extends Award(
+ value = "ContestFirstBR40",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.ContestFirstBR40))
+ )
+ case object ContestMovieMaker extends Award(
+ value = "ContestMovieMaker",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.ContestMovieMaker))
+ )
+ case object ContestMovieMakerOutfit extends Award(
+ value = "ContestMovieMakerOutfit",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.ContestMovieMakerOutfit))
+ )
+ case object ContestPlayerOfTheMonth extends Award(
+ value = "ContestPlayerOfTheMonth",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.ContestPlayerOfTheMonth))
+ )
+ case object ContestPlayerOfTheYear extends Award(
+ value = "ContestPlayerOfTheYear",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.ContestPlayerOfTheYear))
+ )
+ case object CSAppreciation extends Award(
+ value = "CSAppreciation",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.CSAppreciation))
+ )
+ case object DefenseNC extends NewConglomerateAward(
+ value = "DefenseNC",
+ AwardCategory.Defense,
+ List(
+ CommendationRank(DefenseNC1),
+ CommendationRank(DefenseNC2),
+ CommendationRank(DefenseNC3),
+ CommendationRank(DefenseNC4),
+ CommendationRank(DefenseNC5),
+ CommendationRank(DefenseNC6),
+ CommendationRank(DefenseNC7)
+ )
+ )
+ case object DefenseTR extends TerranRepublicAward(
+ value = "DefenseTR",
+ AwardCategory.Defense,
+ List(
+ CommendationRank(DefenseTR1),
+ CommendationRank(DefenseTR2),
+ CommendationRank(DefenseTR3),
+ CommendationRank(DefenseTR4),
+ CommendationRank(DefenseTR5),
+ CommendationRank(DefenseTR6),
+ CommendationRank(DefenseTR7)
+ )
+ )
+ case object DefenseVS extends VanuSovereigntyAward(
+ value = "DefenseVS",
+ AwardCategory.Defense,
+ List(
+ CommendationRank(DefenseVS1),
+ CommendationRank(DefenseVS2),
+ CommendationRank(DefenseVS3),
+ CommendationRank(DefenseVS4),
+ CommendationRank(DefenseVS5),
+ CommendationRank(DefenseVS6),
+ CommendationRank(DefenseVS7)
+ )
+ )
+ case object DevilDogsMovie extends Award(
+ value = "DevilDogsMovie",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.DevilDogsMovie))
+ )
+ case object DogFighter extends Award(
+ value = "DogFighter",
+ AwardCategory.Vehicular,
+ List(
+ CommendationRank(DogFighter1),
+ CommendationRank(DogFighter2),
+ CommendationRank(DogFighter3),
+ CommendationRank(DogFighter4),
+ CommendationRank(DogFighter5),
+ CommendationRank(DogFighter6),
+ CommendationRank(DogFighter7)
+ )
+ )
+ case object DriverGunner extends Award(
+ value = "DriverGunner",
+ AwardCategory.Vehicular,
+ List(
+ CommendationRank(DriverGunner1),
+ CommendationRank(DriverGunner2),
+ CommendationRank(DriverGunner3),
+ CommendationRank(DriverGunner4),
+ CommendationRank(DriverGunner5),
+ CommendationRank(DriverGunner6),
+ CommendationRank(DriverGunner7)
+ )
+ )
+ case object EliteAssault extends Award(
+ value = "EliteAssault",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(EliteAssault0),
+ CommendationRank(EliteAssault1),
+ CommendationRank(EliteAssault2),
+ CommendationRank(EliteAssault3),
+ CommendationRank(EliteAssault4),
+ CommendationRank(EliteAssault5),
+ CommendationRank(EliteAssault6),
+ CommendationRank(EliteAssault7)
+ )
+ )
+ case object EmeraldVeteran extends Award(
+ value = "EmeraldVeteran",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.EmeraldVeteran))
+ )
+ case object Engineer extends Award(
+ value = "Engineer",
+ AwardCategory.Support,
+ List(
+ CommendationRank(Engineer1),
+ CommendationRank(Engineer2),
+ CommendationRank(Engineer3),
+ CommendationRank(Engineer4),
+ CommendationRank(Engineer5),
+ CommendationRank(Engineer6)
+ )
+ )
+ case object EquipmentSupport extends Award(
+ value = "EquipmentSupport",
+ AwardCategory.Support,
+ List(
+ CommendationRank(EquipmentSupport1),
+ CommendationRank(EquipmentSupport2),
+ CommendationRank(EquipmentSupport3),
+ CommendationRank(EquipmentSupport4),
+ CommendationRank(EquipmentSupport5),
+ CommendationRank(EquipmentSupport6),
+ CommendationRank(EquipmentSupport7)
+ )
+ )
+ case object EventNCCommander extends NewConglomerateAward(
+ value = "EventNCCommander",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.EventNCCommander))
+ )
+ case object EventNCElite extends NewConglomerateAward(
+ value = "EventNCElite",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.EventNCElite))
+ )
+ case object EventNCSoldier extends NewConglomerateAward(
+ value = "EventNCSoldier",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.EventNCSoldier))
+ )
+ case object EventTRCommander extends TerranRepublicAward(
+ value = "EventTRCommander",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.EventTRCommander))
+ )
+ case object EventTRElite extends TerranRepublicAward(
+ value = "EventTRElite",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.EventTRElite))
+ )
+ case object EventTRSoldier extends TerranRepublicAward(
+ value = "EventTRSoldier",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.EventTRSoldier))
+ )
+ case object EventVSCommander extends VanuSovereigntyAward(
+ value = "EventVSCommander",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.EventVSCommander))
+ )
+ case object EventVSElite extends VanuSovereigntyAward(
+ value = "EventVSElite",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.EventVSElite))
+ )
+ case object EventVSSoldier extends VanuSovereigntyAward(
+ value = "EventVSSoldier",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.EventVSSoldier))
+ )
+// case object EventNC extends NewConglomerateAward(
+// value = "EventNC",
+// AwardCategory.Exclusive,
+// List(
+// CommendationRank(MeritCommendation.EventNCSoldier),
+// CommendationRank(MeritCommendation.EventNCElite),
+// CommendationRank(MeritCommendation.EventNCCommander)
+// )
+// )
+// case object EventTR extends TerranRepublicAward(
+// value = "EventTR",
+// AwardCategory.Exclusive,
+// List(
+// CommendationRank(MeritCommendation.EventTRSoldier),
+// CommendationRank(MeritCommendation.EventTRElite),
+// CommendationRank(MeritCommendation.EventTRCommander)
+// )
+// )
+// case object EventVS extends VanuSovereigntyAward(
+// value = "EventVS",
+// AwardCategory.Exclusive,
+// List(
+// CommendationRank(MeritCommendation.EventVSSoldier),
+// CommendationRank(MeritCommendation.EventVSElite),
+// CommendationRank(MeritCommendation.EventVSCommander)
+// )
+// )
+ case object Explorer extends Award(
+ value = "Explorer",
+ AwardCategory.Activity,
+ List(CommendationRank(MeritCommendation.Explorer1))
+ )
+ case object FanFaire2005Commander extends Award(
+ value = "FanFaire2005Commander",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.FanFaire2005Commander))
+ )
+ case object FanFaire2005Soldier extends Award(
+ value = "FanFaire2005Soldier",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.FanFaire2005Soldier))
+ )
+ case object FanFaire2006Atlanta extends Award(
+ value = "FanFaire2006Atlanta",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.FanFaire2006Atlanta))
+ )
+ case object FanFaire2007 extends Award(
+ value = "FanFaire2007",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.FanFaire2007))
+ )
+ case object FanFaire2008 extends Award(
+ value = "FanFaire2008",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.FanFaire2008))
+ )
+ case object FanFaire2009 extends Award(
+ value = "FanFaire2009",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.FanFaire2009))
+ )
+ case object GalaxySupport extends Award(
+ value = "GalaxySupport",
+ AwardCategory.Support,
+ List(
+ CommendationRank(GalaxySupport1),
+ CommendationRank(GalaxySupport2),
+ CommendationRank(GalaxySupport3),
+ CommendationRank(GalaxySupport4),
+ CommendationRank(GalaxySupport5),
+ CommendationRank(GalaxySupport6),
+ CommendationRank(GalaxySupport7)
+ )
+ )
+ case object Grenade extends Award(
+ value = "Grenade",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(Grenade1),
+ CommendationRank(Grenade2),
+ CommendationRank(Grenade3),
+ CommendationRank(Grenade4),
+ CommendationRank(Grenade5),
+ CommendationRank(Grenade6),
+ CommendationRank(Grenade7)
+ )
+ )
+ case object GroundGunner extends Award(
+ value = "GroundGunner",
+ AwardCategory.Vehicular,
+ List(
+ CommendationRank(GroundGunner1),
+ CommendationRank(GroundGunner2),
+ CommendationRank(GroundGunner3),
+ CommendationRank(GroundGunner4),
+ CommendationRank(GroundGunner5),
+ CommendationRank(GroundGunner6),
+ CommendationRank(GroundGunner7)
+ )
+ )
+ case object HackingSupport extends Award(
+ value = "HackingSupport",
+ AwardCategory.Support,
+ List(
+ CommendationRank(HackingSupport1),
+ CommendationRank(HackingSupport2),
+ CommendationRank(HackingSupport3),
+ CommendationRank(HackingSupport4),
+ CommendationRank(HackingSupport5),
+ CommendationRank(HackingSupport6),
+ CommendationRank(HackingSupport7)
+ )
+ )
+ case object HalloweenMassacre2006NC extends NewConglomerateAward(
+ value = "HalloweenMassacre2006NC",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.HalloweenMassacre2006NC))
+ )
+ case object HalloweenMassacre2006TR extends TerranRepublicAward(
+ value = "HalloweenMassacre2006TR",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.HalloweenMassacre2006TR))
+ )
+ case object HalloweenMassacre2006VS extends VanuSovereigntyAward(
+ value = "HalloweenMassacre2006VS",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.HalloweenMassacre2006VS))
+ )
+ case object HeavyAssault extends Award(
+ value = "HeavyAssault",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(HeavyAssault1),
+ CommendationRank(HeavyAssault2),
+ CommendationRank(HeavyAssault3),
+ CommendationRank(HeavyAssault4),
+ CommendationRank(HeavyAssault5),
+ CommendationRank(HeavyAssault6),
+ CommendationRank(HeavyAssault7)
+ )
+ )
+ case object HeavyInfantry extends Award(
+ value = "HeavyInfantry",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(MeritCommendation.HeavyInfantry),
+ CommendationRank(HeavyInfantry2),
+ CommendationRank(HeavyInfantry3),
+ CommendationRank(HeavyInfantry4)
+ )
+ )
+ case object InfantryExpert extends Award(
+ value = "InfantryExpert",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(InfantryExpert1),
+ CommendationRank(InfantryExpert2),
+ CommendationRank(InfantryExpert3)
+ )
+ )
+ case object Jacking extends Award(
+ value = "Jacking",
+ AwardCategory.Activity,
+ List(
+ CommendationRank(MeritCommendation.Jacking),
+ CommendationRank(Jacking2),
+ CommendationRank(Jacking3),
+ CommendationRank(Jacking4),
+ CommendationRank(Jacking5),
+ CommendationRank(Jacking6),
+ CommendationRank(Jacking7)
+ )
+ )
+ case object KnifeCombat extends Award(
+ value = "KnifeCombat",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(KnifeCombat1),
+ CommendationRank(KnifeCombat2),
+ CommendationRank(KnifeCombat3),
+ CommendationRank(KnifeCombat4),
+ CommendationRank(KnifeCombat5),
+ CommendationRank(KnifeCombat6),
+ CommendationRank(KnifeCombat7)
+ )
+ )
+ case object LightInfantry extends Award(
+ value = "LightInfantry",
+ AwardCategory.Weaponry,
+ List(CommendationRank(MeritCommendation.LightInfantry))
+ )
+ case object LockerCracker extends Award(
+ value = "LockerCracker",
+ AwardCategory.Support,
+ List(
+ CommendationRank(LockerCracker1),
+ CommendationRank(LockerCracker2),
+ CommendationRank(LockerCracker3),
+ CommendationRank(LockerCracker4),
+ CommendationRank(LockerCracker5),
+ CommendationRank(LockerCracker6),
+ CommendationRank(LockerCracker7)
+ )
+ )
+ case object LodestarSupport extends Award(
+ value = "LodestarSupport",
+ AwardCategory.Support,
+ List(
+ CommendationRank(LodestarSupport1),
+ CommendationRank(LodestarSupport2),
+ CommendationRank(LodestarSupport3),
+ CommendationRank(LodestarSupport4),
+ CommendationRank(LodestarSupport5),
+ CommendationRank(LodestarSupport6),
+ CommendationRank(LodestarSupport7)
+ )
+ )
+ case object Loser extends Award(
+ value = "Loser",
+ AwardCategory.Exclusive,
+ List(
+ CommendationRank(MeritCommendation.Loser),
+ CommendationRank(MeritCommendation.Loser2),
+ CommendationRank(MeritCommendation.Loser3),
+ CommendationRank(MeritCommendation.Loser4)
+ )
+ )
+ case object MarkovVeteran extends Award(
+ value = "MarkovVeteran",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.MarkovVeteran))
+ )
+ case object Max extends Award(
+ value = "Max",
+ AwardCategory.Vehicular,
+ List(
+ CommendationRank(Max1),
+ CommendationRank(Max2),
+ CommendationRank(Max3),
+ CommendationRank(Max4),
+ CommendationRank(Max5),
+ CommendationRank(Max6)
+ )
+ )
+ case object MaxBuster extends Award(
+ value = "MaxBuster",
+ AwardCategory.Activity,
+ List(
+ CommendationRank(MaxBuster1),
+ CommendationRank(MaxBuster2),
+ CommendationRank(MaxBuster3),
+ CommendationRank(MaxBuster4),
+ CommendationRank(MaxBuster5),
+ CommendationRank(MaxBuster6)
+ )
+ )
+ case object MediumAssault extends Award(
+ value = "MediumAssault",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(MediumAssault1),
+ CommendationRank(MediumAssault2),
+ CommendationRank(MediumAssault3),
+ CommendationRank(MediumAssault4),
+ CommendationRank(MediumAssault5),
+ CommendationRank(MediumAssault6),
+ CommendationRank(MediumAssault7)
+ )
+ )
+ case object None extends Award(
+ value = "None",
+ AwardCategory.Exclusive,
+ List(
+ CommendationRank(MeritCommendation.None)
+ )
+ )
+ case object Orion extends VanuSovereigntyAward(
+ value = "Orion",
+ AwardCategory.Vehicular,
+ List(
+ CommendationRank(Orion1),
+ CommendationRank(Orion2),
+ CommendationRank(Orion3),
+ CommendationRank(Orion4),
+ CommendationRank(Orion5),
+ CommendationRank(Orion6),
+ CommendationRank(Orion7)
+ )
+ )
+ case object Osprey extends NewConglomerateAward(
+ value = "Osprey",
+ AwardCategory.Vehicular,
+ List(
+ CommendationRank(Osprey1),
+ CommendationRank(Osprey2),
+ CommendationRank(Osprey3),
+ CommendationRank(Osprey4),
+ CommendationRank(Osprey5),
+ CommendationRank(Osprey6),
+ CommendationRank(Osprey7)
+ )
+ )
+ case object Phalanx extends Award(
+ value = "Phalanx",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(Phalanx1),
+ CommendationRank(Phalanx2),
+ CommendationRank(Phalanx3),
+ CommendationRank(Phalanx4),
+ CommendationRank(Phalanx5),
+ CommendationRank(Phalanx6),
+ CommendationRank(Phalanx7)
+ )
+ )
+ case object PSUMaAttendee extends Award(
+ value = "PSUMaAttendee",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.PSUMaAttendee))
+ )
+ case object PSUMbAttendee extends Award(
+ value = "PSUMbAttendee",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.PSUMbAttendee))
+ )
+ case object QAAppreciation extends Award(
+ value = "QAAppreciation",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.QAAppreciation))
+ )
+ case object ReinforcementHackSpecialist extends Award(
+ value = "ReinforcementHackSpecialist",
+ AwardCategory.Support,
+ List(CommendationRank(MeritCommendation.ReinforcementHackSpecialist))
+ )
+ case object ReinforcementInfantrySpecialist extends Award(
+ value = "ReinforcementInfantrySpecialist",
+ AwardCategory.Support,
+ List(CommendationRank(MeritCommendation.ReinforcementInfantrySpecialist))
+ )
+ case object ReinforcementSpecialist extends Award(
+ value = "ReinforcementSpecialist",
+ AwardCategory.Support,
+ List(CommendationRank(MeritCommendation.ReinforcementSpecialist))
+ )
+ case object ReinforcementVehicleSpecialist extends Award(
+ value = "ReinforcementVehicleSpecialist",
+ AwardCategory.Support,
+ List(CommendationRank(MeritCommendation.ReinforcementVehicleSpecialist))
+ )
+ case object RouterSupport extends Award(
+ value = "RouterSupport",
+ AwardCategory.Support,
+ List(
+ CommendationRank(RouterSupport1),
+ CommendationRank(RouterSupport2),
+ CommendationRank(RouterSupport3),
+ CommendationRank(RouterSupport4),
+ CommendationRank(RouterSupport5),
+ CommendationRank(RouterSupport6),
+ CommendationRank(RouterSupport7)
+ )
+ )
+ case object RouterTelepadDeploy extends Award(
+ value = "RouterTelepadDeploy",
+ AwardCategory.Support,
+ List(
+ CommendationRank(RouterTelepadDeploy1),
+ CommendationRank(RouterTelepadDeploy2),
+ CommendationRank(RouterTelepadDeploy3),
+ CommendationRank(RouterTelepadDeploy4),
+ CommendationRank(RouterTelepadDeploy5),
+ CommendationRank(RouterTelepadDeploy6),
+ CommendationRank(RouterTelepadDeploy7)
+ )
+ )
+ case object ScavengerNC extends NewConglomerateAward(
+ value = "ScavengerNC",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(ScavengerNC1),
+ CommendationRank(ScavengerNC2),
+ CommendationRank(ScavengerNC3),
+ CommendationRank(ScavengerNC4),
+ CommendationRank(ScavengerNC5),
+ CommendationRank(ScavengerNC6)
+ )
+ )
+ case object ScavengerTR extends TerranRepublicAward(
+ value = "ScavengerTR",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(ScavengerTR1),
+ CommendationRank(ScavengerTR2),
+ CommendationRank(ScavengerTR3),
+ CommendationRank(ScavengerTR4),
+ CommendationRank(ScavengerTR5),
+ CommendationRank(ScavengerTR6)
+ )
+ )
+ case object ScavengerVS extends VanuSovereigntyAward(
+ value = "ScavengerVS",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(ScavengerVS1),
+ CommendationRank(ScavengerVS2),
+ CommendationRank(ScavengerVS3),
+ CommendationRank(ScavengerVS4),
+ CommendationRank(ScavengerVS5),
+ CommendationRank(ScavengerVS6)
+ )
+ )
+ case object Sniper extends Award(
+ value = "Sniper",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(Sniper1),
+ CommendationRank(Sniper2),
+ CommendationRank(Sniper3),
+ CommendationRank(Sniper4),
+ CommendationRank(Sniper5),
+ CommendationRank(Sniper6),
+ CommendationRank(Sniper7)
+ )
+ )
+ case object SpecialAssault extends Award(
+ value = "SpecialAssault",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(SpecialAssault1),
+ CommendationRank(SpecialAssault2),
+ CommendationRank(SpecialAssault3),
+ CommendationRank(SpecialAssault4),
+ CommendationRank(SpecialAssault5),
+ CommendationRank(SpecialAssault6),
+ CommendationRank(SpecialAssault7)
+ )
+ )
+ case object StandardAssault extends Award(
+ value = "StandardAssault",
+ AwardCategory.Weaponry,
+ List(
+ CommendationRank(StandardAssault1),
+ CommendationRank(StandardAssault2),
+ CommendationRank(StandardAssault3),
+ CommendationRank(StandardAssault4),
+ CommendationRank(StandardAssault5),
+ CommendationRank(StandardAssault6),
+ CommendationRank(StandardAssault7)
+ )
+ )
+ case object StracticsHistorian extends Award(
+ value = "StracticsHistorian",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.StracticsHistorian))
+ )
+ case object Supply extends Award(
+ value = "Supply",
+ AwardCategory.Activity,
+ List(
+ CommendationRank(Supply1),
+ CommendationRank(Supply2),
+ CommendationRank(Supply3),
+ CommendationRank(Supply4),
+ CommendationRank(Supply5),
+ CommendationRank(Supply6),
+ CommendationRank(Supply7)
+ )
+ )
+ case object TankBuster extends Award(
+ value = "TankBuster",
+ AwardCategory.Activity,
+ List(
+ CommendationRank(TankBuster1),
+ CommendationRank(TankBuster2),
+ CommendationRank(TankBuster3),
+ CommendationRank(TankBuster4),
+ CommendationRank(TankBuster5),
+ CommendationRank(TankBuster6),
+ CommendationRank(TankBuster7)
+ )
+ )
+ case object TermOfServiceNC extends NewConglomerateAward(
+ value = "TermOfServiceNC",
+ AwardCategory.Exclusive, //Activity,
+ List(
+ CommendationRank(OneYearNC),
+ CommendationRank(TwoYearNC),
+ CommendationRank(ThreeYearNC),
+ CommendationRank(FourYearNC),
+ CommendationRank(FiveYearNC),
+ CommendationRank(SixYearNC)
+ )
+ )
+ case object TermOfServiceTR extends TerranRepublicAward(
+ value = "TermOfServiceTR",
+ AwardCategory.Exclusive, //Activity,
+ List(
+ CommendationRank(OneYearTR),
+ CommendationRank(TwoYearTR),
+ CommendationRank(ThreeYearTR),
+ CommendationRank(FourYearTR),
+ CommendationRank(FiveYearTR),
+ CommendationRank(SixYearTR)
+ )
+ )
+ case object TermOfServiceVS extends VanuSovereigntyAward(
+ value = "TermOfServiceVS",
+ AwardCategory.Exclusive, //Activity,
+ List(
+ CommendationRank(OneYearVS),
+ CommendationRank(TwoYearVS),
+ CommendationRank(ThreeYearVS),
+ CommendationRank(FourYearVS),
+ CommendationRank(FiveYearVS),
+ CommendationRank(SixYearVS)
+ )
+ )
+ case object TinyRoboticSupport extends Award(
+ value = "TinyRoboticSupport",
+ AwardCategory.Support,
+ List(
+ CommendationRank(TinyRoboticSupport1),
+ CommendationRank(TinyRoboticSupport2),
+ CommendationRank(TinyRoboticSupport3),
+ CommendationRank(TinyRoboticSupport4),
+ CommendationRank(TinyRoboticSupport5),
+ CommendationRank(TinyRoboticSupport6),
+ CommendationRank(TinyRoboticSupport7)
+ )
+ )
+ case object Transport extends Award(
+ value = "Transport",
+ AwardCategory.Activity,
+ List(
+ CommendationRank(Transport1),
+ CommendationRank(Transport2),
+ CommendationRank(Transport3),
+ CommendationRank(Transport4),
+ CommendationRank(Transport5),
+ CommendationRank(Transport6),
+ CommendationRank(Transport7)
+ )
+ )
+ case object TransportationCitation extends Award(
+ value = "TransportationCitation",
+ AwardCategory.Activity,
+ List(
+ CommendationRank(TransportationCitation1),
+ CommendationRank(TransportationCitation2),
+ CommendationRank(TransportationCitation3),
+ CommendationRank(TransportationCitation4),
+ CommendationRank(TransportationCitation5)
+ )
+ )
+ case object ValentineFemale extends Award(
+ value = "ValentineFemale",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.ValentineFemale))
+ )
+ case object ValentineMale extends Award(
+ value = "ValentineMale",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.ValentineMale))
+ )
+ case object WernerVeteran extends Award(
+ value = "WernerVeteran",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.WernerVeteran))
+ )
+ case object XmasGingerman extends Award(
+ value = "XmasGingerman",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.XmasGingerman))
+ )
+ case object XmasSnowman extends Award(
+ value = "XmasSnowman",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.XmasSnowman))
+ )
+ case object XmasSpirit extends Award(
+ value = "XmasSpirit",
+ AwardCategory.Exclusive,
+ List(CommendationRank(MeritCommendation.XmasSpirit))
+ )
+
+ final val common: List[Award] = List(
+ AdvancedMedic, AdvancedMedicAssists, AirDefender, AMSSupport, AntiVehicular,
+ BFRAdvanced, BFRBuster, Bombadier, BomberAce, Boomer,
+ TankBuster, TinyRoboticSupport, Transport, TransportationCitation
+ )
+}
diff --git a/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala b/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala
index 97c77b54..2a95d425 100644
--- a/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala
+++ b/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala
@@ -105,7 +105,7 @@ object AvatarConverter {
unk7 = false,
on_zipline = None
)
- CharacterAppearanceData(aa, ab, RibbonBars())
+ CharacterAppearanceData(aa, ab, obj.avatar.ribbonBars)
}
def MakeCharacterData(obj: Player): (Boolean, Boolean) => CharacterData = {
diff --git a/src/main/scala/net/psforever/objects/definition/converter/CharacterSelectConverter.scala b/src/main/scala/net/psforever/objects/definition/converter/CharacterSelectConverter.scala
index 12a5d77d..9133065e 100644
--- a/src/main/scala/net/psforever/objects/definition/converter/CharacterSelectConverter.scala
+++ b/src/main/scala/net/psforever/objects/definition/converter/CharacterSelectConverter.scala
@@ -79,7 +79,7 @@ class CharacterSelectConverter extends AvatarConverter {
unk7 = false,
on_zipline = None
)
- CharacterAppearanceData(aa, ab, RibbonBars())
+ CharacterAppearanceData(aa, ab, obj.avatar.ribbonBars)
}
private def MakeDetailedCharacterData(obj: Player): Option[Int] => DetailedCharacterData = {
diff --git a/src/main/scala/net/psforever/objects/definition/converter/CorpseConverter.scala b/src/main/scala/net/psforever/objects/definition/converter/CorpseConverter.scala
index fd9ba634..3c985ac6 100644
--- a/src/main/scala/net/psforever/objects/definition/converter/CorpseConverter.scala
+++ b/src/main/scala/net/psforever/objects/definition/converter/CorpseConverter.scala
@@ -70,7 +70,7 @@ class CorpseConverter extends AvatarConverter {
unk7 = false,
on_zipline = None
)
- CharacterAppearanceData(aa, ab, RibbonBars())
+ CharacterAppearanceData(aa, ab, obj.avatar.ribbonBars)
}
private def MakeDetailedCharacterData(obj: Player): Option[Int] => DetailedCharacterData = {
diff --git a/src/main/scala/net/psforever/packet/game/AvatarAwardMessage.scala b/src/main/scala/net/psforever/packet/game/AvatarAwardMessage.scala
index bda9214a..60660dba 100644
--- a/src/main/scala/net/psforever/packet/game/AvatarAwardMessage.scala
+++ b/src/main/scala/net/psforever/packet/game/AvatarAwardMessage.scala
@@ -2,37 +2,73 @@
package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
+import net.psforever.types.MeritCommendation
import scodec.Codec
import scodec.codecs._
import shapeless.{::, HNil}
-import scala.annotation.switch
-
-abstract class AwardOption(val code: Int) {
- def unk1: Long
- def unk2: Long
+/**
+ * Base class for all merit commendation advancement stages.
+ */
+sealed trait AwardOption {
+ def value: Long
+ def completion: Long
}
-
-final case class AwardOptionZero(unk1: Long, unk2: Long) extends AwardOption(code = 0)
-
-final case class AwardOptionOne(unk1: Long) extends AwardOption(code = 1) {
- def unk2: Long = 0L
+/**
+ * Display this award's development progress.
+ * @param value the current count towards this award
+ * @param completion the target (maximum) count
+ */
+final case class AwardProgress(value: Long, completion: Long) extends AwardOption
+/**
+ * Display this award's qualification progress.
+ * The process is the penultimate conditions necessary for award completion,
+ * separate from the aforementioned progress.
+ * This is almost always a kill streak,
+ * where the user must terminate a certain numbers of enemies without dying.
+ * @param value the current count towards this award
+ */
+final case class AwardQualificationProgress(value: Long) extends AwardOption {
+ /** zero'd as the value is not reported here */
+ def completion: Long = 0L
}
-
-final case class AwardOptionTwo(unk1: Long) extends AwardOption(code = 3) {
- def unk2: Long = 0L
+/**
+ * Display this award as completed.
+ * @param value the date (mm/dd/yyyy) that the award was achieved in POSIX seconds;
+ * that's `System.currentTimeMillis() / 1000`
+ */
+final case class AwardCompletion(value: Long) extends AwardOption {
+ /** same as the parameter value */
+ def completion: Long = value
}
/**
- * na
- * @param unk1 na
- * @param unk2 na
- * @param unk3 na
+ * Dispatched from the server to load information about a character's merit commendation awards progress.
+ *
+ * The three stages of a merit commendation award are: progress, qualification, and completion.
+ * The progress stage and the qualification stage have their own development conditions.
+ * Ocassionally, the development is nonexistent and the award is merely an on/off switch.
+ * Occasionally, there is no qualification requirement and the award merely advances in the progress stage
+ * then transitions directly from progress to completion.
+ * Completion information is available from the character info / achievements tab
+ * and takes the form of ribbons associated with the merit commendation at a given rank
+ * and the date that rank was attained.
+ * Progress and qualification information are visible from the character info / achievements / award progress window
+ * and take the form of the name and rank of the merit commendation
+ * and two numbers that indicate the current and the goal towards the next stage.
+ * The completion stage is also visible from this window
+ * and will take the form of the same name and rank of the merit commendation indicated as "Completed" as of a date.
+ * @see `MeritCommendation.Value`
+ * @param merit_commendation the award and rank
+ * @param state the current state of the award advancement
+ * @param unk na;
+ * 0 and 1 are the possible values;
+ * 0 is the common value
*/
final case class AvatarAwardMessage(
- unk1: Long,
- unk2: AwardOption,
- unk3: Int
+ merit_commendation: MeritCommendation.Value,
+ state: AwardOption,
+ unk: Int
)
extends PlanetSideGamePacket {
type Packet = AvatarAwardMessage
@@ -41,61 +77,67 @@ final case class AvatarAwardMessage(
}
object AvatarAwardMessage extends Marshallable[AvatarAwardMessage] {
- private val codec_one: Codec[AwardOptionOne] = {
+ def apply(meritCommendation: MeritCommendation.Value, state: AwardOption):AvatarAwardMessage =
+ AvatarAwardMessage(meritCommendation, state, unk = 0)
+
+ private val qualification_codec: Codec[AwardOption] = {
uint32L.hlist
- }.xmap[AwardOptionOne](
+ }.xmap[AwardOption](
{
- case a :: HNil => AwardOptionOne(a)
+ case a :: HNil => AwardQualificationProgress(a)
},
{
- case AwardOptionOne(a) => a :: HNil
+ case AwardQualificationProgress(a) => a :: HNil
}
)
- private val codec_two: Codec[AwardOptionTwo] = {
+ private val completion_codec: Codec[AwardOption] = {
uint32L.hlist
- }.xmap[AwardOptionTwo](
+ }.xmap[AwardOption](
{
- case a :: HNil => AwardOptionTwo(a)
+ case a :: HNil => AwardCompletion(a)
},
{
- case AwardOptionTwo(a) => a :: HNil
+ case AwardCompletion(a) => a :: HNil
}
)
- private val codec_zero: Codec[AwardOptionZero] = {
+ private val progress_codec: Codec[AwardOption] = {
uint32L :: uint32L
- }.xmap[AwardOptionZero](
+ }.xmap[AwardOption](
{
- case a :: b :: HNil => AwardOptionZero(a, b)
+ case a :: b :: HNil => AwardProgress(a, b)
},
{
- case AwardOptionZero(a, b) => a :: b :: HNil
+ case AwardProgress(a, b) => a :: b :: HNil
}
)
- private def selectAwardOption(code: Int): Codec[AwardOption] = {
- ((code: @switch) match {
- case 2 | 3 => codec_two
- case 1 => codec_one
- case 0 => codec_zero
- }).asInstanceOf[Codec[AwardOption]]
- }
-
implicit val codec: Codec[AvatarAwardMessage] = (
- ("unk1" | uint32L) ::
- (uint2 >>:~ { code =>
- ("unk2" | selectAwardOption(code)) ::
- ("unk3" | uint8L)
- })
- ).xmap[AvatarAwardMessage](
- {
- case unk1 :: _ :: unk2 :: unk3 :: HNil =>
- AvatarAwardMessage(unk1, unk2, unk3)
- },
- {
- case AvatarAwardMessage(unk1, unk2, unk3) =>
- unk1 :: unk2.code :: unk2 :: unk3 :: HNil
- }
- )
+ ("merit_commendation" | MeritCommendation.codec) ::
+ ("state" | either(bool,
+ either(bool, progress_codec, qualification_codec).xmap[AwardOption](
+ {
+ case Left(d) => d
+ case Right(d) => d
+ },
+ {
+ case d: AwardProgress => Left(d)
+ case d: AwardQualificationProgress => Right(d)
+ }
+ ),
+ completion_codec
+ ).xmap[AwardOption](
+ {
+ case Left(d) => d
+ case Right(d) => d
+ },
+ {
+ case d: AwardProgress => Left(d)
+ case d: AwardQualificationProgress => Left(d)
+ case d: AwardCompletion => Right(d)
+ }
+ )) ::
+ ("unk" | uint8L)
+ ).as[AvatarAwardMessage]
}
diff --git a/src/main/scala/net/psforever/packet/game/DisplayedAwardMessage.scala b/src/main/scala/net/psforever/packet/game/DisplayedAwardMessage.scala
index f3144199..2bc7fd16 100644
--- a/src/main/scala/net/psforever/packet/game/DisplayedAwardMessage.scala
+++ b/src/main/scala/net/psforever/packet/game/DisplayedAwardMessage.scala
@@ -9,7 +9,7 @@ import scodec.codecs._
/**
* An `Enumeration` of the slots for award ribbons on a player's `RibbonBars`.
*/
-object RibbonBarsSlot extends Enumeration {
+object RibbonBarSlot extends Enumeration {
type Type = Value
val Top, Middle, Bottom, TermOfService //technically,the slot above "Top"
@@ -21,29 +21,28 @@ object RibbonBarsSlot extends Enumeration {
/**
* Dispatched to configure a player's merit commendation ribbons.
*
- * Normally, this packet is dispatched by the client when managing merit commendations through the "Character Info/Achievements" tab.
+ * Normally, this packet is dispatched by the client when managing merit commendations
+ * through the "Character Info/Achievements" tab.
* On Gemini Live, this packet was also always dispatched once by the server during character login.
* It set the term of service ribbon explicitly.
* Generally, this was unnecessary, as the encoded character data maintains information about displayed ribbons.
- * This behavior was probably a routine that ensured that correct yearly progression was tracked if the player earned it while offline.
+ * This behavior was probably a routine that ensured that correct yearly progression was tracked
+ * if the player earned it while offline.
* It never set any of the other ribbon slot positions during login.
*
* A specific ribbon may only be set once to one slot.
* The last set slot is considered the valid position to which that ribbon will be placed/moved.
* @param player_guid the player
- * @param ribbon the award to be displayed;
- * defaults to `MeritCommendation.None`;
- * use `MeritCommendation.None` when indicating "no ribbon"
- * @param bar any of the four positions where the award ribbon is to be displayed;
- * defaults to `TermOfService`
+ * @param ribbon the award to be displayed
+ * @param bar any of the four positions where the award ribbon is to be displayed
* @see `RibbonBars`
* @see `MeritCommendation`
*/
final case class DisplayedAwardMessage(
- player_guid: PlanetSideGUID,
- ribbon: MeritCommendation.Value = MeritCommendation.None,
- bar: RibbonBarsSlot.Value = RibbonBarsSlot.TermOfService
-) extends PlanetSideGamePacket {
+ player_guid: PlanetSideGUID,
+ ribbon: MeritCommendation.Value,
+ bar: RibbonBarSlot.Value
+ ) extends PlanetSideGamePacket {
type Packet = DisplayedAwardMessage
def opcode = GamePacketOpcode.DisplayedAwardMessage
def encode = DisplayedAwardMessage.encode(this)
@@ -52,7 +51,7 @@ final case class DisplayedAwardMessage(
object DisplayedAwardMessage extends Marshallable[DisplayedAwardMessage] {
implicit val codec: Codec[DisplayedAwardMessage] = (
("player_guid" | PlanetSideGUID.codec) ::
- ("ribbon" | MeritCommendation.codec) ::
- ("bar" | RibbonBarsSlot.codec)
+ ("ribbon" | MeritCommendation.codec) ::
+ ("bar" | RibbonBarSlot.codec)
).as[DisplayedAwardMessage]
}
diff --git a/src/test/scala/game/AvatarAwardMessageTest.scala b/src/test/scala/game/AvatarAwardMessageTest.scala
index 5568b26c..1d2e5555 100644
--- a/src/test/scala/game/AvatarAwardMessageTest.scala
+++ b/src/test/scala/game/AvatarAwardMessageTest.scala
@@ -4,18 +4,20 @@ package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
+import net.psforever.types.MeritCommendation
import scodec.bits._
class AvatarAwardMessageTest extends Specification {
val string0 = hex"cf 15010000014000003d0040000000"
val string1 = hex"cf 2a010000c717b12a0000"
val string2 = hex"cf a6010000e9058cab0080"
+ val string3 = hex"cf 7a010000400000000000"
"decode (0)" in {
PacketCoding.decodePacket(string0).require match {
case AvatarAwardMessage(unk1, unk2, unk3) =>
- unk1 mustEqual 277
- unk2 mustEqual AwardOptionZero(5, 500)
+ unk1 mustEqual MeritCommendation.Max1
+ unk2 mustEqual AwardProgress(5, 500)
unk3 mustEqual 0
case _ =>
ko
@@ -25,8 +27,8 @@ class AvatarAwardMessageTest extends Specification {
"decode (1)" in {
PacketCoding.decodePacket(string1).require match {
case AvatarAwardMessage(unk1, unk2, unk3) =>
- unk1 mustEqual 298
- unk2 mustEqual AwardOptionTwo(2831441436L)
+ unk1 mustEqual MeritCommendation.OneYearVS
+ unk2 mustEqual AwardCompletion(1415720846L)
unk3 mustEqual 0
case _ =>
ko
@@ -36,32 +38,50 @@ class AvatarAwardMessageTest extends Specification {
"decode (2)" in {
PacketCoding.decodePacket(string2).require match {
case AvatarAwardMessage(unk1, unk2, unk3) =>
- unk1 mustEqual 422
- unk2 mustEqual AwardOptionTwo(2888963748L)
- unk3 mustEqual 2
+ unk1 mustEqual MeritCommendation.TwoYearVS
+ unk2 mustEqual AwardCompletion(1444482002L)
+ unk3 mustEqual 1
+ case _ =>
+ ko
+ }
+ }
+
+ "decode (3)" in {
+ PacketCoding.decodePacket(string3).require match {
+ case AvatarAwardMessage(unk1, unk2, unk3) =>
+ unk1 mustEqual MeritCommendation.StandardAssault3
+ unk2 mustEqual AwardQualificationProgress(0)
+ unk3 mustEqual 0
case _ =>
ko
}
}
"encode (0)" in {
- val msg = AvatarAwardMessage(277, AwardOptionZero(5, 500), 0)
+ val msg = AvatarAwardMessage(MeritCommendation.Max1, AwardProgress(5, 500))
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual string0
}
"encode (1)" in {
- val msg = AvatarAwardMessage(298, AwardOptionTwo(2831441436L), 0)
+ val msg = AvatarAwardMessage(MeritCommendation.OneYearVS, AwardCompletion(1415720846L))
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual string1
}
"encode (2)" in {
- val msg = AvatarAwardMessage(422, AwardOptionTwo(2888963748L), 2)
+ val msg = AvatarAwardMessage(MeritCommendation.TwoYearVS, AwardCompletion(1444482002L), 1)
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual string2
}
+
+ "encode (3)" in {
+ val msg = AvatarAwardMessage(MeritCommendation.StandardAssault3, AwardQualificationProgress(0))
+ val pkt = PacketCoding.encodePacket(msg).require.toByteVector
+
+ pkt mustEqual string3
+ }
}
diff --git a/src/test/scala/game/DisplayedAwardMessageTest.scala b/src/test/scala/game/DisplayedAwardMessageTest.scala
index 2bb05d76..a8534898 100644
--- a/src/test/scala/game/DisplayedAwardMessageTest.scala
+++ b/src/test/scala/game/DisplayedAwardMessageTest.scala
@@ -15,14 +15,14 @@ class DisplayedAwardMessageTest extends Specification {
case DisplayedAwardMessage(player_guid, ribbon, bar) =>
player_guid mustEqual PlanetSideGUID(1695)
ribbon mustEqual MeritCommendation.TwoYearVS
- bar mustEqual RibbonBarsSlot.TermOfService
+ bar mustEqual RibbonBarSlot.TermOfService
case _ =>
ko
}
}
"encode" in {
- val msg = DisplayedAwardMessage(PlanetSideGUID(1695), MeritCommendation.TwoYearVS, RibbonBarsSlot.TermOfService)
+ val msg = DisplayedAwardMessage(PlanetSideGUID(1695), MeritCommendation.TwoYearVS, RibbonBarSlot.TermOfService)
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual string