diff --git a/common/src/main/scala/net/psforever/packet/game/CreateShortcutMessage.scala b/common/src/main/scala/net/psforever/packet/game/CreateShortcutMessage.scala
index f3bcd4da9..bdd77ed8e 100644
--- a/common/src/main/scala/net/psforever/packet/game/CreateShortcutMessage.scala
+++ b/common/src/main/scala/net/psforever/packet/game/CreateShortcutMessage.scala
@@ -6,7 +6,7 @@ import scodec.Codec
import scodec.codecs._
/**
- * Create a quick-use button for the hotbar.
+ * Details regarding this shortcut.
*
* Purpose:
* `advanced_regen` (regeneration)
@@ -20,52 +20,65 @@ import scodec.codecs._
* `shortcut_macro`
* `silent_run` (sensor shield)
* `surge`
- * `targeting`
- * @param player_guid the player
- * @param slot the hotbar slot number (one-indexed)
- * @param unk1 na
- * @param unk2 na
+ * `targeting` (enchanced targetting)
* @param purpose the primary purpose/use of this shortcut
* @param effect1 for macros, a three letter acronym displayed in the hotbar
* @param effect2 for macros, the chat message content
*/
-//TODO must handle case 0x28 xxxx 01 00 00 for moving shortcuts
+final case class Shortcut(purpose : String,
+ effect1 : String = "",
+ effect2 : String = "")
+
+/**
+ * Manipulate a quick-use button for the hotbar.
+ *
+ * na
+ * @param player_guid the player
+ * @param slot the hotbar slot number (one-indexed)
+ * @param unk1 na
+ * @param unk2 na
+ * @param shortcut optional; details about the shortcut to be created
+ */
final case class CreateShortcutMessage(player_guid : PlanetSideGUID,
slot : Int,
unk1 : Int,
unk2 : Int,
- purpose : String = "",
- effect1 : String = "",
- effect2 : String = "")
+ shortcut : Option[Shortcut] = None)
extends PlanetSideGamePacket {
type Packet = CreateShortcutMessage
def opcode = GamePacketOpcode.CreateShortcutMessage
def encode = CreateShortcutMessage.encode(this)
}
-//*
-object CreateShortcutMessage extends Marshallable[CreateShortcutMessage] {
- implicit val codec : Codec[CreateShortcutMessage] = (
- ("player_guid" | PlanetSideGUID.codec) ::
- ("slot" | uint8L) ::
- ("unk1" | uint8L) ::
- ("unk2" | uintL(3)) ::
- ("purpose" | PacketHelpers.encodedStringAligned(5)) ::
+
+object Shortcut extends Marshallable[Shortcut] {
+ // Needs to be Marshallable[T] for .as[T] to work its magic on the type of the codec Codec[T]
+ implicit val codec : Codec[Shortcut] = (
+ ("purpose" | PacketHelpers.encodedStringAligned(5)) ::
("effect1" | PacketHelpers.encodedWideString) ::
("effect2" | PacketHelpers.encodedWideString)
- ).as[CreateShortcutMessage]
+ ).as[Shortcut]
+
+ // Convenient predefined Shortcuts for the Medkit and Implants
+ final val AUDIO_AMPLIFIER : Shortcut = Shortcut("audio_amplifier")
+ final val DARKLIGHT_VISION : Shortcut = Shortcut("darklight_vision")
+ final val ENHANCED_TARGETING = Shortcut("targeting")
+ final val MEDKIT : Shortcut = Shortcut("medkit")
+ final val MELEE_BOOSTER : Shortcut = Shortcut("melee_booster")
+ final val PERSONAL_SHIELD : Shortcut = Shortcut("personal_shield")
+ final val RANGE_MAGNIFIER : Shortcut = Shortcut("range_magnifier")
+ final val REGENERATION : Shortcut = Shortcut("advanced_regen")
+ final val SECOND_WIND : Shortcut = Shortcut("second_wind")
+ final val SENSOR_SHIELD : Shortcut = Shortcut("silent_run")
+ final val SURGE : Shortcut = Shortcut("surge")
}
-// */
-/*
+
object CreateShortcutMessage extends Marshallable[CreateShortcutMessage] {
implicit val codec : Codec[CreateShortcutMessage] = (
("player_guid" | PlanetSideGUID.codec) ::
("slot" | uint8L) ::
("unk1" | uint8L) ::
- ("unk2" | uintL(3)) >>:~ ( value =>
- conditional(value.last > 0, "purpose" | PacketHelpers.encodedStringAligned(5)) ::
- conditional(value.last > 0, "effect1" | PacketHelpers.encodedWideString) ::
- conditional(value.last > 0, "effect2" | PacketHelpers.encodedWideString)
- )
+ (("unk2" | uintL(3)) >>:~ { value =>
+ conditional(value > 0, "shortcut" | Shortcut.codec).hlist
+ })
).as[CreateShortcutMessage]
}
-// */
diff --git a/common/src/test/scala/GamePacketTest.scala b/common/src/test/scala/GamePacketTest.scala
index 19a8c3262..ab89e8789 100644
--- a/common/src/test/scala/GamePacketTest.scala
+++ b/common/src/test/scala/GamePacketTest.scala
@@ -307,14 +307,15 @@ class GamePacketTest extends Specification {
"decode (medkit)" in {
PacketCoding.DecodePacket(stringMedkit).require match {
- case CreateShortcutMessage(player_guid, slot, unk1, unk2, purpose, effect1, effect2) =>
+ case CreateShortcutMessage(player_guid, slot, unk1, unk2, shortcut) =>
player_guid mustEqual PlanetSideGUID(4210)
slot mustEqual 1
unk1 mustEqual 0
unk2 mustEqual 4
- purpose mustEqual "medkit"
- effect1 mustEqual ""
- effect2 mustEqual ""
+ shortcut.isDefined mustEqual true
+ shortcut.get.purpose mustEqual "medkit"
+ shortcut.get.effect1 mustEqual ""
+ shortcut.get.effect2 mustEqual ""
case default =>
ko
}
@@ -322,14 +323,15 @@ class GamePacketTest extends Specification {
"decode (implant)" in {
PacketCoding.DecodePacket(stringImplant).require match {
- case CreateShortcutMessage(player_guid, slot, unk1, unk2, purpose, effect1, effect2) =>
+ case CreateShortcutMessage(player_guid, slot, unk1, unk2, shortcut) =>
player_guid mustEqual PlanetSideGUID(4210)
slot mustEqual 4
unk1 mustEqual 0
unk2 mustEqual 6
- purpose mustEqual "surge"
- effect1 mustEqual ""
- effect2 mustEqual ""
+ shortcut.isDefined mustEqual true
+ shortcut.get.purpose mustEqual "surge"
+ shortcut.get.effect1 mustEqual ""
+ shortcut.get.effect2 mustEqual ""
case default =>
ko
}
@@ -337,14 +339,15 @@ class GamePacketTest extends Specification {
"decode (macro)" in {
PacketCoding.DecodePacket(stringMacro).require match {
- case CreateShortcutMessage(player_guid, slot, unk1, unk2, purpose, effect1, effect2) =>
+ case CreateShortcutMessage(player_guid, slot, unk1, unk2, shortcut) =>
player_guid mustEqual PlanetSideGUID(1356)
slot mustEqual 8
unk1 mustEqual 0
unk2 mustEqual 5
- purpose mustEqual "shortcut_macro"
- effect1 mustEqual "NTU"
- effect2 mustEqual "/platoon Incoming NTU spam!"
+ shortcut.isDefined mustEqual true
+ shortcut.get.purpose mustEqual "shortcut_macro"
+ shortcut.get.effect1 mustEqual "NTU"
+ shortcut.get.effect2 mustEqual "/platoon Incoming NTU spam!"
case default =>
ko
}
@@ -352,42 +355,40 @@ class GamePacketTest extends Specification {
"decode (remove)" in {
PacketCoding.DecodePacket(stringRemove).require match {
- case CreateShortcutMessage(player_guid, slot, unk1, unk2, purpose, effect1, effect2) =>
+ case CreateShortcutMessage(player_guid, slot, unk1, unk2, shortcut) =>
player_guid mustEqual PlanetSideGUID(1356)
slot mustEqual 1
unk1 mustEqual 0
unk2 mustEqual 0
- purpose mustEqual ""
- effect1 mustEqual ""
- effect2 mustEqual ""
+ shortcut.isDefined mustEqual false
case default =>
ko
}
}
"encode (medkit)" in {
- val msg = CreateShortcutMessage(PlanetSideGUID(4210), 1, 0, 4, "medkit")
+ val msg = CreateShortcutMessage(PlanetSideGUID(4210), 1, 0, 4, Some(Shortcut("medkit")))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringMedkit
}
"encode (implant)" in {
- val msg = CreateShortcutMessage(PlanetSideGUID(4210), 4, 0, 6, "surge")
+ val msg = CreateShortcutMessage(PlanetSideGUID(4210), 4, 0, 6, Some(Shortcut("surge")))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringImplant
}
"encode (macro)" in {
- val msg = CreateShortcutMessage(PlanetSideGUID(1356), 8, 0, 5, "shortcut_macro", "NTU", "/platoon Incoming NTU spam!")
+ val msg = CreateShortcutMessage(PlanetSideGUID(1356), 8, 0, 5, Some(Shortcut("shortcut_macro", "NTU", "/platoon Incoming NTU spam!")))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringMacro
}
"encode (remove)" in {
- val msg = CreateShortcutMessage(PlanetSideGUID(1356), 1, 0, 0, "")
+ val msg = CreateShortcutMessage(PlanetSideGUID(1356), 1, 0, 0)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringRemove
diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala
index 625838e79..4902709da 100644
--- a/pslogin/src/main/scala/WorldSessionActor.scala
+++ b/pslogin/src/main/scala/WorldSessionActor.scala
@@ -171,7 +171,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
true))) //Boosted generator room pain field
sendResponse(PacketCoding.CreateGamePacket(0, SetCurrentAvatarMessage(PlanetSideGUID(guid),0,0)))
- sendResponse(PacketCoding.CreateGamePacket(0, CreateShortcutMessage(PlanetSideGUID(guid), 1, 0, 6, "medkit")))
+ sendResponse(PacketCoding.CreateGamePacket(0, CreateShortcutMessage(PlanetSideGUID(guid), 1, 0, 6, Some(Shortcut.MEDKIT))))
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global