mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-11 22:44:37 +00:00
partially-working vehicle favorites system; modifications to existing favorites system, identification of packet parameters
This commit is contained in:
parent
9d7d1b0456
commit
2a4fe4865e
15 changed files with 295 additions and 88 deletions
|
|
@ -17,7 +17,7 @@ class Avatar(val name : String, val faction : PlanetSideEmpire.Value, val sex :
|
||||||
/** Certifications */
|
/** Certifications */
|
||||||
private val certs : mutable.Set[CertificationType.Value] = mutable.Set[CertificationType.Value]()
|
private val certs : mutable.Set[CertificationType.Value] = mutable.Set[CertificationType.Value]()
|
||||||
/** Implants<br>
|
/** Implants<br>
|
||||||
* Unlike other objects, the maximum number of `ImplantSlots` are built into the `Avatar`.
|
* Unlike other objects, all `ImplantSlot` objects are already built into the `Avatar`.
|
||||||
* Additionally, implants do not have tightly-coupled "`Definition` objects" that explain a formal implant object.
|
* Additionally, implants do not have tightly-coupled "`Definition` objects" that explain a formal implant object.
|
||||||
* The `ImplantDefinition` objects themselves are moved around as if they were the implants.
|
* The `ImplantDefinition` objects themselves are moved around as if they were the implants.
|
||||||
* The terms externally used for the states of process is "installed" and "uninstalled."
|
* The terms externally used for the states of process is "installed" and "uninstalled."
|
||||||
|
|
@ -25,9 +25,12 @@ class Avatar(val name : String, val faction : PlanetSideEmpire.Value, val sex :
|
||||||
* @see `DetailedCharacterData.implants`
|
* @see `DetailedCharacterData.implants`
|
||||||
*/
|
*/
|
||||||
private val implants : Array[ImplantSlot] = Array.fill[ImplantSlot](3)(new ImplantSlot)
|
private val implants : Array[ImplantSlot] = Array.fill[ImplantSlot](3)(new ImplantSlot)
|
||||||
/** Loadouts */
|
/** Loadouts<br>
|
||||||
private val loadouts : Array[Option[Loadout]] = Array.fill[Option[Loadout]](10)(None)
|
* 0-9 are Infantry loadouts
|
||||||
/** Locker (inventory slot number five) */
|
* 10-14 are Vehicle loadouts
|
||||||
|
*/
|
||||||
|
private val loadouts : Array[Option[Loadout]] = Array.fill[Option[Loadout]](15)(None)
|
||||||
|
/** Locker */
|
||||||
private val locker : LockerContainer = new LockerContainer() {
|
private val locker : LockerContainer = new LockerContainer() {
|
||||||
override def toString : String = {
|
override def toString : String = {
|
||||||
s"$name's ${Definition.Name}"
|
s"$name's ${Definition.Name}"
|
||||||
|
|
@ -154,6 +157,12 @@ class Avatar(val name : String, val faction : PlanetSideEmpire.Value, val sex :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def SaveLoadout(owner : Vehicle, label : String, line : Int) : Unit = {
|
||||||
|
if(line > 9 && line < loadouts.length) {
|
||||||
|
loadouts(line) = Some(Loadout.Create(owner, label))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def LoadLoadout(line : Int) : Option[Loadout] = loadouts.lift(line).getOrElse(None)
|
def LoadLoadout(line : Int) : Option[Loadout] = loadouts.lift(line).getOrElse(None)
|
||||||
|
|
||||||
def DeleteLoadout(line : Int) : Unit = {
|
def DeleteLoadout(line : Int) : Unit = {
|
||||||
|
|
|
||||||
|
|
@ -349,6 +349,39 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ
|
||||||
|
|
||||||
def VisibleSlots : Set[Int] = weapons.keySet
|
def VisibleSlots : Set[Int] = weapons.keySet
|
||||||
|
|
||||||
|
override def Slot(slotNum : Int) : EquipmentSlot = {
|
||||||
|
weapons.get(slotNum)
|
||||||
|
// .orElse(utilities.get(slotNum) match {
|
||||||
|
// case Some(_) =>
|
||||||
|
// //TODO what do now?
|
||||||
|
// None
|
||||||
|
// case None => ;
|
||||||
|
// None
|
||||||
|
// })
|
||||||
|
.orElse(Some(Inventory.Slot(slotNum))).get
|
||||||
|
}
|
||||||
|
|
||||||
|
override def Find(guid : PlanetSideGUID) : Option[Int] = {
|
||||||
|
weapons.find({ case (_, obj) =>
|
||||||
|
obj.Equipment match {
|
||||||
|
case Some(item) =>
|
||||||
|
if(item.HasGUID && item.GUID == guid) {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
case None =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}) match {
|
||||||
|
case Some((index, _)) =>
|
||||||
|
Some(index)
|
||||||
|
case None =>
|
||||||
|
Inventory.Find(guid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A reference to the `Vehicle` `Trunk` space.
|
* A reference to the `Vehicle` `Trunk` space.
|
||||||
* @return this `Vehicle` `Trunk`
|
* @return this `Vehicle` `Trunk`
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class OrderTerminalABDefinition(object_id : Int) extends EquipmentTerminalDefini
|
||||||
override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = buyFunc(player, msg)
|
override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = buyFunc(player, msg)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a `TransactionType.InfantryLoadout` action by the user.
|
* Process a `TransactionType.Loadout` action by the user.
|
||||||
* `Loadout` objects are blueprints composed of exo-suit specifications and simplified `Equipment`-to-slot mappings.
|
* `Loadout` objects are blueprints composed of exo-suit specifications and simplified `Equipment`-to-slot mappings.
|
||||||
* If a valid loadout is found, its data is transformed back into actual `Equipment` for return to the user.
|
* If a valid loadout is found, its data is transformed back into actual `Equipment` for return to the user.
|
||||||
* Loadouts that would suit the player into a mechanized assault exo-suit are not permitted.
|
* Loadouts that would suit the player into a mechanized assault exo-suit are not permitted.
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class OrderTerminalDefinition extends EquipmentTerminalDefinition(612) {
|
||||||
override def Buy(player: Player, msg : ItemTransactionMessage) : Terminal.Exchange = buyFunc(player, msg)
|
override def Buy(player: Player, msg : ItemTransactionMessage) : Terminal.Exchange = buyFunc(player, msg)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a `TransactionType.InfantryLoadout` action by the user.
|
* Process a `TransactionType.Loadout` action by the user.
|
||||||
* `Loadout` objects are blueprints composed of exo-suit specifications and simplified `Equipment`-to-slot mappings.
|
* `Loadout` objects are blueprints composed of exo-suit specifications and simplified `Equipment`-to-slot mappings.
|
||||||
* If a valid loadout is found, its data is transformed back into actual `Equipment` for return to the user.
|
* If a valid loadout is found, its data is transformed back into actual `Equipment` for return to the user.
|
||||||
* @param player the player
|
* @param player the player
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
package net.psforever.objects.serverobject.terminals
|
package net.psforever.objects.serverobject.terminals
|
||||||
|
|
||||||
import net.psforever.objects.Player
|
import net.psforever.objects.Player
|
||||||
|
import net.psforever.objects.inventory.InventoryItem
|
||||||
|
import net.psforever.objects.loadouts.VehicleLoadout
|
||||||
|
import net.psforever.objects.serverobject.terminals.EquipmentTerminalDefinition.BuildSimplifiedPattern
|
||||||
import net.psforever.packet.game.ItemTransactionMessage
|
import net.psforever.packet.game.ItemTransactionMessage
|
||||||
|
|
||||||
class RepairRearmSiloDefinition(objectId : Int) extends EquipmentTerminalDefinition(objectId) {
|
class RepairRearmSiloDefinition(objectId : Int) extends EquipmentTerminalDefinition(objectId) {
|
||||||
|
|
@ -13,10 +16,12 @@ class RepairRearmSiloDefinition(objectId : Int) extends EquipmentTerminalDefinit
|
||||||
|
|
||||||
override def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
override def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
||||||
if(msg.item_page == 4) { //Favorites tab
|
if(msg.item_page == 4) { //Favorites tab
|
||||||
player.LoadLoadout(msg.unk1) match {
|
player.LoadLoadout(msg.unk1 + 10) match {
|
||||||
case Some(loadout) =>
|
case Some(loadout : VehicleLoadout) =>
|
||||||
Terminal.VehicleLoadout(Nil, Nil)
|
val weapons = loadout.VisibleSlots.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) })
|
||||||
case None =>
|
val inventory = loadout.Inventory.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) })
|
||||||
|
Terminal.VehicleLoadout(loadout.vehicle_definition, weapons, inventory)
|
||||||
|
case _ =>
|
||||||
Terminal.NoDeal()
|
Terminal.NoDeal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
package net.psforever.objects.serverobject.terminals
|
package net.psforever.objects.serverobject.terminals
|
||||||
|
|
||||||
import net.psforever.objects.Player
|
import net.psforever.objects.Player
|
||||||
|
import net.psforever.objects.definition.VehicleDefinition
|
||||||
import net.psforever.objects.serverobject.structures.Amenity
|
import net.psforever.objects.serverobject.structures.Amenity
|
||||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||||
import net.psforever.types.{TransactionType, Vector3}
|
import net.psforever.types.{TransactionType, Vector3}
|
||||||
|
|
@ -73,7 +74,7 @@ class Terminal(tdef : TerminalDefinition) extends Amenity {
|
||||||
case TransactionType.Sell =>
|
case TransactionType.Sell =>
|
||||||
tdef.Sell(player, msg)
|
tdef.Sell(player, msg)
|
||||||
|
|
||||||
case TransactionType.InfantryLoadout =>
|
case TransactionType.Loadout =>
|
||||||
tdef.Loadout(player, msg)
|
tdef.Loadout(player, msg)
|
||||||
|
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -190,7 +191,7 @@ object Terminal {
|
||||||
*/
|
*/
|
||||||
final case class InfantryLoadout(exosuit : ExoSuitType.Value, subtype : Int = 0, holsters : List[InventoryItem], inventory : List[InventoryItem]) extends Exchange
|
final case class InfantryLoadout(exosuit : ExoSuitType.Value, subtype : Int = 0, holsters : List[InventoryItem], inventory : List[InventoryItem]) extends Exchange
|
||||||
|
|
||||||
final case class VehicleLoadout(weapons : List[InventoryItem], inventory : List[InventoryItem]) extends Exchange
|
final case class VehicleLoadout(vehicle_definition : VehicleDefinition, weapons : List[InventoryItem], inventory : List[InventoryItem]) extends Exchange
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the special effects caused by a proximity-base service.
|
* Start the special effects caused by a proximity-base service.
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ abstract class TerminalDefinition(objectId : Int) extends net.psforever.objects.
|
||||||
def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal()
|
def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The unimplemented functionality for this `Terminal`'s `TransactionType.InfantryLoadout` activity.
|
* The unimplemented functionality for this `Terminal`'s `TransactionType.Loadout` activity.
|
||||||
*/
|
*/
|
||||||
def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal()
|
def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
package net.psforever.packet.game
|
package net.psforever.packet.game
|
||||||
|
|
||||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||||
|
import net.psforever.types.LoadoutType
|
||||||
import scodec.Codec
|
import scodec.Codec
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
import shapeless.{::, HNil}
|
import shapeless.{::, HNil}
|
||||||
|
|
@ -18,12 +19,6 @@ import shapeless.{::, HNil}
|
||||||
* Infantry equipment favorites are appended with a code for the type of exo-suit that they will load on a player.
|
* Infantry equipment favorites are appended with a code for the type of exo-suit that they will load on a player.
|
||||||
* This does not match the same two field numbering system as in `ArmorChangedMessage` packets.<br>
|
* This does not match the same two field numbering system as in `ArmorChangedMessage` packets.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* Lists:<br>
|
|
||||||
* `
|
|
||||||
* 0 - Equipment Terminal (infantry)<br>
|
|
||||||
* 1 - Repair/Rearm Silo (standard vehicles)<br>
|
|
||||||
* `
|
|
||||||
* <br>
|
|
||||||
* Armors:<br>
|
* Armors:<br>
|
||||||
* `
|
* `
|
||||||
* 1 - Agile<br>
|
* 1 - Agile<br>
|
||||||
|
|
@ -33,13 +28,7 @@ import shapeless.{::, HNil}
|
||||||
* 6 - AV MAX<br>
|
* 6 - AV MAX<br>
|
||||||
* `
|
* `
|
||||||
* <br>
|
* <br>
|
||||||
* Exploration 1:<br>
|
* Exploration:<br>
|
||||||
* The identifier for the list is two bits so four separated lists of `Favorites` are supportable.
|
|
||||||
* Two of the lists are common enough and we can assume one of the others is related to Battleframe Robotics.
|
|
||||||
* These lists also do not include `Squad Defintion...` presets.
|
|
||||||
* What are the unknown lists?<br>
|
|
||||||
* <br>
|
|
||||||
* Exploration 2:<br>
|
|
||||||
* There are three unaccounted exo-suit indices - 0, 3, and 7;
|
* There are three unaccounted exo-suit indices - 0, 3, and 7;
|
||||||
* and, there are two specific kinds of exo-suit that are not defined - Infiltration and Standard.
|
* and, there are two specific kinds of exo-suit that are not defined - Infiltration and Standard.
|
||||||
* It is possible that one of the indices also defines the generic MAX (see `ArmorChangedMessage`).
|
* It is possible that one of the indices also defines the generic MAX (see `ArmorChangedMessage`).
|
||||||
|
|
@ -50,11 +39,11 @@ import shapeless.{::, HNil}
|
||||||
* @param label the identifier for this entry
|
* @param label the identifier for this entry
|
||||||
* @param armor the type of exo-suit, if an Infantry loadout
|
* @param armor the type of exo-suit, if an Infantry loadout
|
||||||
*/
|
*/
|
||||||
final case class FavoritesMessage(list : Int,
|
final case class FavoritesMessage(list : LoadoutType.Value,
|
||||||
player_guid : PlanetSideGUID,
|
player_guid : PlanetSideGUID,
|
||||||
line : Int,
|
line : Int,
|
||||||
label : String,
|
label : String,
|
||||||
armor : Option[Int] = None)
|
armor : Option[Int])
|
||||||
extends PlanetSideGamePacket {
|
extends PlanetSideGamePacket {
|
||||||
type Packet = FavoritesMessage
|
type Packet = FavoritesMessage
|
||||||
def opcode = GamePacketOpcode.FavoritesMessage
|
def opcode = GamePacketOpcode.FavoritesMessage
|
||||||
|
|
@ -62,12 +51,16 @@ final case class FavoritesMessage(list : Int,
|
||||||
}
|
}
|
||||||
|
|
||||||
object FavoritesMessage extends Marshallable[FavoritesMessage] {
|
object FavoritesMessage extends Marshallable[FavoritesMessage] {
|
||||||
|
def apply(list : LoadoutType.Value, player_guid : PlanetSideGUID, line : Int, label : String) : FavoritesMessage = {
|
||||||
|
FavoritesMessage(list, player_guid, line, label, None)
|
||||||
|
}
|
||||||
|
|
||||||
implicit val codec : Codec[FavoritesMessage] = (
|
implicit val codec : Codec[FavoritesMessage] = (
|
||||||
("list" | uint2L) >>:~ { value =>
|
("list" | LoadoutType.codec) >>:~ { value =>
|
||||||
("player_guid" | PlanetSideGUID.codec) ::
|
("player_guid" | PlanetSideGUID.codec) ::
|
||||||
("line" | uint4L) ::
|
("line" | uint4L) ::
|
||||||
("label" | PacketHelpers.encodedWideStringAligned(2)) ::
|
("label" | PacketHelpers.encodedWideStringAligned(2)) ::
|
||||||
conditional(value == 0, "armor" | uintL(3))
|
conditional(value == LoadoutType.Infantry, "armor" | uintL(3))
|
||||||
}).xmap[FavoritesMessage] (
|
}).xmap[FavoritesMessage] (
|
||||||
{
|
{
|
||||||
case lst :: guid :: ln :: str :: arm :: HNil =>
|
case lst :: guid :: ln :: str :: arm :: HNil =>
|
||||||
|
|
@ -75,7 +68,7 @@ object FavoritesMessage extends Marshallable[FavoritesMessage] {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case FavoritesMessage(lst, guid, ln, str, arm) =>
|
case FavoritesMessage(lst, guid, ln, str, arm) =>
|
||||||
val armset : Option[Int] = if(lst == 0 && arm.isEmpty) { Some(0) } else { arm }
|
val armset : Option[Int] = if(lst == LoadoutType.Infantry && arm.isEmpty) { Some(0) } else { arm }
|
||||||
lst :: guid :: ln :: str :: armset :: HNil
|
lst :: guid :: ln :: str :: armset :: HNil
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,33 @@
|
||||||
package net.psforever.packet.game
|
package net.psforever.packet.game
|
||||||
|
|
||||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||||
|
import net.psforever.types.LoadoutType
|
||||||
import scodec.Codec
|
import scodec.Codec
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
|
|
||||||
object FavoritesAction extends Enumeration {
|
object FavoritesAction extends Enumeration {
|
||||||
type Type = Value
|
type Type = Value
|
||||||
|
|
||||||
val Unknown,
|
val
|
||||||
Save,
|
Unknown,
|
||||||
Delete = Value
|
Save,
|
||||||
|
Delete
|
||||||
|
= Value
|
||||||
|
|
||||||
implicit val codec = PacketHelpers.createEnumerationCodec(this, uint2L)
|
implicit val codec = PacketHelpers.createEnumerationCodec(this, uint2L)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param player_guid the player
|
||||||
|
* @param list na
|
||||||
|
* @param action the behavior of this packet
|
||||||
|
* @param line what line of the applicable loadout ("Saved Favorites") list is modified
|
||||||
|
* @param label applicable when a load out is being saved;
|
||||||
|
* this is the string that will be displayed in the list of loadouts on that line
|
||||||
|
*/
|
||||||
final case class FavoritesRequest(player_guid : PlanetSideGUID,
|
final case class FavoritesRequest(player_guid : PlanetSideGUID,
|
||||||
unk : Int,
|
list : LoadoutType.Value,
|
||||||
action : FavoritesAction.Value,
|
action : FavoritesAction.Value,
|
||||||
line : Int,
|
line : Int,
|
||||||
label : Option[String])
|
label : Option[String])
|
||||||
|
|
@ -29,7 +41,7 @@ final case class FavoritesRequest(player_guid : PlanetSideGUID,
|
||||||
object FavoritesRequest extends Marshallable[FavoritesRequest] {
|
object FavoritesRequest extends Marshallable[FavoritesRequest] {
|
||||||
implicit val codec : Codec[FavoritesRequest] = (
|
implicit val codec : Codec[FavoritesRequest] = (
|
||||||
("player_guid" | PlanetSideGUID.codec) ::
|
("player_guid" | PlanetSideGUID.codec) ::
|
||||||
("unk" | uint2L) ::
|
("list" | LoadoutType.codec) ::
|
||||||
(("action" | FavoritesAction.codec) >>:~ { action =>
|
(("action" | FavoritesAction.codec) >>:~ { action =>
|
||||||
("line" | uint4L) ::
|
("line" | uint4L) ::
|
||||||
conditional(action == FavoritesAction.Save, "label" | PacketHelpers.encodedWideString)
|
conditional(action == FavoritesAction.Save, "label" | PacketHelpers.encodedWideString)
|
||||||
|
|
|
||||||
16
common/src/main/scala/net/psforever/types/LoadoutType.scala
Normal file
16
common/src/main/scala/net/psforever/types/LoadoutType.scala
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.types
|
||||||
|
|
||||||
|
import net.psforever.packet.PacketHelpers
|
||||||
|
import scodec.codecs.uint2L
|
||||||
|
|
||||||
|
object LoadoutType extends Enumeration {
|
||||||
|
type Type = Value
|
||||||
|
|
||||||
|
val
|
||||||
|
Infantry,
|
||||||
|
Vehicle
|
||||||
|
= Value
|
||||||
|
|
||||||
|
implicit val codec = PacketHelpers.createEnumerationCodec(this, uint2L)
|
||||||
|
}
|
||||||
|
|
@ -12,7 +12,7 @@ object TransactionType extends Enumeration {
|
||||||
Sell, // or forget on certif term
|
Sell, // or forget on certif term
|
||||||
Unk4,
|
Unk4,
|
||||||
Unk5,
|
Unk5,
|
||||||
InfantryLoadout,
|
Loadout,
|
||||||
Unk7
|
Unk7
|
||||||
= Value
|
= Value
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package game
|
||||||
import org.specs2.mutable._
|
import org.specs2.mutable._
|
||||||
import net.psforever.packet._
|
import net.psforever.packet._
|
||||||
import net.psforever.packet.game._
|
import net.psforever.packet.game._
|
||||||
|
import net.psforever.types.LoadoutType
|
||||||
import scodec.bits._
|
import scodec.bits._
|
||||||
|
|
||||||
class FavoritesMessageTest extends Specification {
|
class FavoritesMessageTest extends Specification {
|
||||||
|
|
@ -13,7 +14,7 @@ class FavoritesMessageTest extends Specification {
|
||||||
"decode (for infantry)" in {
|
"decode (for infantry)" in {
|
||||||
PacketCoding.DecodePacket(stringInfantry).require match {
|
PacketCoding.DecodePacket(stringInfantry).require match {
|
||||||
case FavoritesMessage(list, player_guid, line, label, armor) =>
|
case FavoritesMessage(list, player_guid, line, label, armor) =>
|
||||||
list mustEqual 0
|
list mustEqual LoadoutType.Infantry
|
||||||
player_guid mustEqual PlanetSideGUID(3760)
|
player_guid mustEqual PlanetSideGUID(3760)
|
||||||
line mustEqual 0
|
line mustEqual 0
|
||||||
label mustEqual "Agile (basic)"
|
label mustEqual "Agile (basic)"
|
||||||
|
|
@ -25,7 +26,7 @@ class FavoritesMessageTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode (for infantry)" in {
|
"encode (for infantry)" in {
|
||||||
val msg = FavoritesMessage(0, PlanetSideGUID(3760), 0, "Agile (basic)", Option(1))
|
val msg = FavoritesMessage(LoadoutType.Infantry, PlanetSideGUID(3760), 0, "Agile (basic)", Option(1))
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual stringInfantry
|
pkt mustEqual stringInfantry
|
||||||
|
|
@ -34,7 +35,7 @@ class FavoritesMessageTest extends Specification {
|
||||||
"decode (for vehicles)" in {
|
"decode (for vehicles)" in {
|
||||||
PacketCoding.DecodePacket(stringVehicles).require match {
|
PacketCoding.DecodePacket(stringVehicles).require match {
|
||||||
case FavoritesMessage(list, player_guid, line, label, armor) =>
|
case FavoritesMessage(list, player_guid, line, label, armor) =>
|
||||||
list mustEqual 1
|
list mustEqual LoadoutType.Vehicle
|
||||||
player_guid mustEqual PlanetSideGUID(4210)
|
player_guid mustEqual PlanetSideGUID(4210)
|
||||||
line mustEqual 0
|
line mustEqual 0
|
||||||
label mustEqual "Skyguard"
|
label mustEqual "Skyguard"
|
||||||
|
|
@ -45,7 +46,7 @@ class FavoritesMessageTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode (for vehicles)" in {
|
"encode (for vehicles)" in {
|
||||||
val msg = FavoritesMessage(1, PlanetSideGUID(4210), 0, "Skyguard")
|
val msg = FavoritesMessage(LoadoutType.Vehicle, PlanetSideGUID(4210), 0, "Skyguard")
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual stringVehicles
|
pkt mustEqual stringVehicles
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package game
|
||||||
import org.specs2.mutable._
|
import org.specs2.mutable._
|
||||||
import net.psforever.packet._
|
import net.psforever.packet._
|
||||||
import net.psforever.packet.game._
|
import net.psforever.packet.game._
|
||||||
|
import net.psforever.types.LoadoutType
|
||||||
import scodec.bits._
|
import scodec.bits._
|
||||||
|
|
||||||
class FavoritesRequestTest extends Specification {
|
class FavoritesRequestTest extends Specification {
|
||||||
|
|
@ -11,9 +12,9 @@ class FavoritesRequestTest extends Specification {
|
||||||
|
|
||||||
"decode (for infantry)" in {
|
"decode (for infantry)" in {
|
||||||
PacketCoding.DecodePacket(stringInfantry).require match {
|
PacketCoding.DecodePacket(stringInfantry).require match {
|
||||||
case FavoritesRequest(player_guid, unk, action, line, label) =>
|
case FavoritesRequest(player_guid, list, action, line, label) =>
|
||||||
player_guid mustEqual PlanetSideGUID(75)
|
player_guid mustEqual PlanetSideGUID(75)
|
||||||
unk mustEqual 0
|
list mustEqual LoadoutType.Infantry
|
||||||
action mustEqual FavoritesAction.Save
|
action mustEqual FavoritesAction.Save
|
||||||
line mustEqual 1
|
line mustEqual 1
|
||||||
label.isDefined mustEqual true
|
label.isDefined mustEqual true
|
||||||
|
|
@ -24,7 +25,7 @@ class FavoritesRequestTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode (for infantry)" in {
|
"encode (for infantry)" in {
|
||||||
val msg = FavoritesRequest(PlanetSideGUID(75), 0, FavoritesAction.Save, 1, Some("Example"))
|
val msg = FavoritesRequest(PlanetSideGUID(75), LoadoutType.Infantry, FavoritesAction.Save, 1, Some("Example"))
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual stringInfantry
|
pkt mustEqual stringInfantry
|
||||||
|
|
|
||||||
|
|
@ -68,10 +68,10 @@ class OrderTerminalABTest extends Specification {
|
||||||
player.ExoSuit = ExoSuitType.MAX
|
player.ExoSuit = ExoSuitType.MAX
|
||||||
avatar.SaveLoadout(player, "test2", 1)
|
avatar.SaveLoadout(player, "test2", 1)
|
||||||
|
|
||||||
val msg1 = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.InfantryLoadout, 4, "", 0, PlanetSideGUID(0))
|
val msg1 = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Loadout, 4, "", 0, PlanetSideGUID(0))
|
||||||
terminal.Request(player, msg1) mustEqual Terminal.InfantryLoadout(ExoSuitType.Standard, 0, Nil, Nil)
|
terminal.Request(player, msg1) mustEqual Terminal.InfantryLoadout(ExoSuitType.Standard, 0, Nil, Nil)
|
||||||
|
|
||||||
val msg2 = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.InfantryLoadout, 4, "", 1, PlanetSideGUID(0))
|
val msg2 = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Loadout, 4, "", 1, PlanetSideGUID(0))
|
||||||
terminal.Request(player, msg2) mustEqual Terminal.NoDeal()
|
terminal.Request(player, msg2) mustEqual Terminal.NoDeal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import net.psforever.types._
|
||||||
import services._
|
import services._
|
||||||
import services.avatar.{AvatarAction, AvatarResponse, AvatarServiceMessage, AvatarServiceResponse}
|
import services.avatar.{AvatarAction, AvatarResponse, AvatarServiceMessage, AvatarServiceResponse}
|
||||||
import services.local.{LocalAction, LocalResponse, LocalServiceMessage, LocalServiceResponse}
|
import services.local.{LocalAction, LocalResponse, LocalServiceMessage, LocalServiceResponse}
|
||||||
|
import services.vehicle.VehicleAction.UnstowEquipment
|
||||||
import services.vehicle.{VehicleAction, VehicleResponse, VehicleServiceMessage, VehicleServiceResponse}
|
import services.vehicle.{VehicleAction, VehicleResponse, VehicleServiceMessage, VehicleServiceResponse}
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
|
|
@ -818,7 +819,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case Terminal.InfantryLoadout(exosuit, subtype, holsters, inventory) =>
|
case Terminal.InfantryLoadout(exosuit, subtype, holsters, inventory) =>
|
||||||
//TODO optimizations against replacing Equipment with the exact same Equipment and potentially for recycling existing Equipment
|
//TODO optimizations against replacing Equipment with the exact same Equipment and potentially for recycling existing Equipment
|
||||||
log.info(s"$tplayer wants to change equipment loadout to their option #${msg.unk1 + 1}")
|
log.info(s"$tplayer wants to change equipment loadout to their option #${msg.unk1 + 1}")
|
||||||
sendResponse(ItemTransactionResultMessage (msg.terminal_guid, TransactionType.InfantryLoadout, true))
|
sendResponse(ItemTransactionResultMessage (msg.terminal_guid, TransactionType.Loadout, true))
|
||||||
val dropPred = DropPredicate(tplayer)
|
val dropPred = DropPredicate(tplayer)
|
||||||
val (dropHolsters, beforeHolsters) = clearHolsters(tplayer.Holsters().iterator).partition(dropPred)
|
val (dropHolsters, beforeHolsters) = clearHolsters(tplayer.Holsters().iterator).partition(dropPred)
|
||||||
val (dropInventory, beforeInventory) = tplayer.Inventory.Clear().partition(dropPred)
|
val (dropInventory, beforeInventory) = tplayer.Inventory.Clear().partition(dropPred)
|
||||||
|
|
@ -881,7 +882,59 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
val objDef = obj.Definition
|
val objDef = obj.Definition
|
||||||
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.EquipmentOnGround(tplayer.GUID, pos, orient, objDef.ObjectId, obj.GUID, objDef.Packet.ConstructorData(obj).get))
|
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.EquipmentOnGround(tplayer.GUID, pos, orient, objDef.ObjectId, obj.GUID, objDef.Packet.ConstructorData(obj).get))
|
||||||
})
|
})
|
||||||
sendResponse(ItemTransactionResultMessage (msg.terminal_guid, TransactionType.InfantryLoadout, true))
|
sendResponse(ItemTransactionResultMessage (msg.terminal_guid, TransactionType.Loadout, true))
|
||||||
|
|
||||||
|
case Terminal.VehicleLoadout(definition, weapons, inventory) =>
|
||||||
|
log.info(s"$tplayer wants to change their vehicle equipment loadout to their option #${msg.unk1 + 1}")
|
||||||
|
log.info(s"Vehicle: $definition")
|
||||||
|
log.info(s"Weapons (${weapons.size}): $weapons")
|
||||||
|
log.info(s"Inventory (${inventory.size}): $inventory")
|
||||||
|
LocalVehicle match {
|
||||||
|
case Some(vehicle) =>
|
||||||
|
sendResponse(ItemTransactionResultMessage (msg.terminal_guid, TransactionType.Loadout, true))
|
||||||
|
val (_, afterInventory) = inventory.partition( DropPredicate(tplayer) ) //dropped items are lost
|
||||||
|
//common action - remove old inventory
|
||||||
|
val deleteEquipment : (Int,Equipment)=>Unit = DeleteEquipmentFromVehicle(vehicle)
|
||||||
|
vehicle.Inventory.Clear().foreach({ case InventoryItem(obj, index) =>
|
||||||
|
deleteEquipment(index, obj)
|
||||||
|
taskResolver ! GUIDTask.UnregisterEquipment(obj)(continent.GUID)
|
||||||
|
})
|
||||||
|
val stowEquipment : (Int,Equipment)=>TaskResolver.GiveTask = StowNewEquipmentInVehicle(vehicle)
|
||||||
|
(if(vehicle.Definition == definition) {
|
||||||
|
//vehicles are the same type; transfer over weapons
|
||||||
|
vehicle.Weapons
|
||||||
|
.filter({ case (_, slot) => slot.Equipment.nonEmpty })
|
||||||
|
.foreach({ case (_, slot) =>
|
||||||
|
val equipment = slot.Equipment.get
|
||||||
|
slot.Equipment = None
|
||||||
|
val equipment_guid = equipment.GUID
|
||||||
|
sendResponse(ObjectDeleteMessage(equipment_guid, 0))
|
||||||
|
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, equipment_guid))
|
||||||
|
taskResolver ! GUIDTask.UnregisterEquipment(equipment)(continent.GUID)
|
||||||
|
})
|
||||||
|
weapons.foreach({ case InventoryItem(obj, index) =>
|
||||||
|
//create weapons and share with everyone
|
||||||
|
taskResolver ! PutNewWeaponInVehicleSlot(vehicle, obj.asInstanceOf[Tool], index)
|
||||||
|
})
|
||||||
|
afterInventory
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//do not transfer over weapons
|
||||||
|
if(vehicle.Definition.TrunkSize == definition.TrunkSize && vehicle.Definition.TrunkOffset == definition.TrunkOffset) {
|
||||||
|
afterInventory
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//accommodate as much of inventory as possible
|
||||||
|
//TODO map x,y -> x,y rather than reorganize items
|
||||||
|
val (stow, _) = GridInventory.recoverInventory(afterInventory, vehicle.Inventory) //dropped items can be forgotten
|
||||||
|
stow
|
||||||
|
}
|
||||||
|
}).foreach({ case InventoryItem(obj, index) =>
|
||||||
|
taskResolver ! stowEquipment(index, obj)
|
||||||
|
})
|
||||||
|
case None =>
|
||||||
|
log.error(s"can not apply the loadout - can not find a vehicle")
|
||||||
|
}
|
||||||
|
|
||||||
case Terminal.LearnCertification(cert, cost) =>
|
case Terminal.LearnCertification(cert, cost) =>
|
||||||
if(!tplayer.Certifications.contains(cert)) {
|
if(!tplayer.Certifications.contains(cert)) {
|
||||||
|
|
@ -895,9 +948,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Learn, false))
|
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Learn, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
case Terminal.VehicleLoadout(weapons, inventory) =>
|
|
||||||
log.info(s"$tplayer wants to change their vehicle equipment loadout to their option #${msg.unk1 + 1}")
|
|
||||||
|
|
||||||
case Terminal.SellCertification(cert, cost) =>
|
case Terminal.SellCertification(cert, cost) =>
|
||||||
if(tplayer.Certifications.contains(cert)) {
|
if(tplayer.Certifications.contains(cert)) {
|
||||||
log.info(s"$tplayer is forgetting the $cert certification for $cost points")
|
log.info(s"$tplayer is forgetting the $cert certification for $cost points")
|
||||||
|
|
@ -1424,9 +1474,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
AwardBattleExperiencePoints(avatar, 1000000L)
|
AwardBattleExperiencePoints(avatar, 1000000L)
|
||||||
player = new Player(avatar)
|
player = new Player(avatar)
|
||||||
//player.Position = Vector3(3561.0f, 2854.0f, 90.859375f) //home3, HART C
|
//player.Position = Vector3(3561.0f, 2854.0f, 90.859375f) //home3, HART C
|
||||||
//player.Orientation = Vector3(0f, 0f, 90f)
|
player.Position = Vector3(3940.3984f, 4343.625f, 266.45312f)
|
||||||
player.Position = Vector3(4262.211f ,4067.0625f ,262.35938f) //z6, Akna.tower
|
player.Orientation = Vector3(0f, 0f, 90f)
|
||||||
player.Orientation = Vector3(0f, 0f, 132.1875f)
|
//player.Position = Vector3(4262.211f ,4067.0625f ,262.35938f) //z6, Akna.tower
|
||||||
|
//player.Orientation = Vector3(0f, 0f, 132.1875f)
|
||||||
// player.ExoSuit = ExoSuitType.MAX //TODO strange issue; divide number above by 10 when uncommenting
|
// player.ExoSuit = ExoSuitType.MAX //TODO strange issue; divide number above by 10 when uncommenting
|
||||||
player.Slot(0).Equipment = SimpleItem(remote_electronics_kit) //Tool(GlobalDefinitions.StandardPistol(player.Faction))
|
player.Slot(0).Equipment = SimpleItem(remote_electronics_kit) //Tool(GlobalDefinitions.StandardPistol(player.Faction))
|
||||||
player.Slot(2).Equipment = Tool(punisher) //suppressor
|
player.Slot(2).Equipment = Tool(punisher) //suppressor
|
||||||
|
|
@ -1757,15 +1808,15 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case x :: xs =>
|
case x :: xs =>
|
||||||
val (deleteFunc, modifyFunc) : ((Int, AmmoBox)=>Unit, (AmmoBox, Int)=>Unit) = obj match {
|
val (deleteFunc, modifyFunc) : ((Int, AmmoBox)=>Unit, (AmmoBox, Int)=>Unit) = obj match {
|
||||||
case (veh : Vehicle) =>
|
case (veh : Vehicle) =>
|
||||||
(DeleteAmmunitionInVehicle(veh), ModifyAmmunitionInVehicle(veh))
|
(DeleteEquipmentFromVehicle(veh), ModifyAmmunitionInVehicle(veh))
|
||||||
case _ =>
|
case _ =>
|
||||||
(DeleteAmmunition(obj), ModifyAmmunition(obj))
|
(DeleteEquipment(obj), ModifyAmmunition(obj))
|
||||||
}
|
}
|
||||||
val (stowFuncTask, stowFunc) : ((Int, AmmoBox)=>TaskResolver.GiveTask, (Int, AmmoBox)=>Unit) = obj match {
|
val (stowFuncTask, stowFunc) : ((Int, AmmoBox)=>TaskResolver.GiveTask, (Int, AmmoBox)=>Unit) = obj match {
|
||||||
case (veh : Vehicle) =>
|
case (veh : Vehicle) =>
|
||||||
(StowNewAmmunitionInVehicles(veh), StowAmmunitionInVehicles(veh))
|
(StowNewEquipmentInVehicle(veh), StowEquipmentInVehicles(veh))
|
||||||
case _ =>
|
case _ =>
|
||||||
(StowNewAmmunition(obj), StowAmmunition(obj))
|
(StowNewEquipment(obj), StowEquipment(obj))
|
||||||
}
|
}
|
||||||
xs.foreach(item => {
|
xs.foreach(item => {
|
||||||
obj.Inventory -= x.start
|
obj.Inventory -= x.start
|
||||||
|
|
@ -1977,9 +2028,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case x :: xs =>
|
case x :: xs =>
|
||||||
val (deleteFunc, modifyFunc) : ((Int, AmmoBox)=>Unit, (AmmoBox, Int)=>Unit) = obj match {
|
val (deleteFunc, modifyFunc) : ((Int, AmmoBox)=>Unit, (AmmoBox, Int)=>Unit) = obj match {
|
||||||
case (veh : Vehicle) =>
|
case (veh : Vehicle) =>
|
||||||
(DeleteAmmunitionInVehicle(veh), ModifyAmmunitionInVehicle(veh))
|
(DeleteEquipmentFromVehicle(veh), ModifyAmmunitionInVehicle(veh))
|
||||||
case _ =>
|
case _ =>
|
||||||
(DeleteAmmunition(obj), ModifyAmmunition(obj))
|
(DeleteEquipment(obj), ModifyAmmunition(obj))
|
||||||
}
|
}
|
||||||
xs.foreach(item => {
|
xs.foreach(item => {
|
||||||
deleteFunc(item.start, item.obj.asInstanceOf[AmmoBox])
|
deleteFunc(item.start, item.obj.asInstanceOf[AmmoBox])
|
||||||
|
|
@ -2071,7 +2122,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
findFunc(parent)
|
findFunc(parent)
|
||||||
case None =>
|
case None =>
|
||||||
None
|
None
|
||||||
}) match {
|
})
|
||||||
|
.orElse(LocalVehicle match {
|
||||||
|
case Some(parent) =>
|
||||||
|
findFunc(parent)
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
})
|
||||||
|
match {
|
||||||
case Some((parent, Some(slot))) =>
|
case Some((parent, Some(slot))) =>
|
||||||
taskResolver ! RemoveEquipmentFromSlot(parent, obj, slot)
|
taskResolver ! RemoveEquipmentFromSlot(parent, obj, slot)
|
||||||
log.info(s"RequestDestroy: equipment $object_guid")
|
log.info(s"RequestDestroy: equipment $object_guid")
|
||||||
|
|
@ -2360,18 +2418,42 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
log.error(s"ItemTransaction: $terminal_guid does not exist")
|
log.error(s"ItemTransaction: $terminal_guid does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
case msg @ FavoritesRequest(player_guid, unk, action, line, label) =>
|
case msg @ FavoritesRequest(player_guid, list, action, line, label) =>
|
||||||
log.info(s"FavoritesRequest: $msg")
|
log.info(s"FavoritesRequest: $msg")
|
||||||
if(player.GUID == player_guid) {
|
if(player.GUID == player_guid) {
|
||||||
val name = label.getOrElse("missing_loadout_name")
|
val lineno = if(list == LoadoutType.Vehicle) { line + 10 } else { line }
|
||||||
|
val name = label.getOrElse(s"missing_loadout_${line+1}")
|
||||||
action match {
|
action match {
|
||||||
case FavoritesAction.Unknown => ;
|
|
||||||
case FavoritesAction.Save =>
|
case FavoritesAction.Save =>
|
||||||
avatar.SaveLoadout(player, name, line)
|
(if(list == LoadoutType.Infantry) {
|
||||||
sendResponse(FavoritesMessage(0, player_guid, line, name))
|
Some(player)
|
||||||
|
}
|
||||||
|
else if(list == LoadoutType.Vehicle) {
|
||||||
|
player.VehicleSeated match {
|
||||||
|
case Some(vehicle_guid) =>
|
||||||
|
continent.GUID(vehicle_guid)
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
}) match {
|
||||||
|
case Some(owner : Player) =>
|
||||||
|
avatar.SaveLoadout(owner, name, lineno)
|
||||||
|
case Some(owner : Vehicle) =>
|
||||||
|
avatar.SaveLoadout(owner, name, lineno)
|
||||||
|
case Some(_) | None =>
|
||||||
|
log.error("FavoritesRequest: unexpected owner for favorites")
|
||||||
|
}
|
||||||
|
sendResponse(FavoritesMessage(list, player_guid, line, name))
|
||||||
|
|
||||||
case FavoritesAction.Delete =>
|
case FavoritesAction.Delete =>
|
||||||
avatar.DeleteLoadout(line)
|
avatar.DeleteLoadout(lineno)
|
||||||
sendResponse(FavoritesMessage(0, player_guid, line, ""))
|
sendResponse(FavoritesMessage(list, player_guid, line, ""))
|
||||||
|
|
||||||
|
case FavoritesAction.Unknown =>
|
||||||
|
log.warn("FavoritesRequest: unknown favorites action")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2653,6 +2735,46 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def PutNewWeaponInVehicleSlot(target : Vehicle, obj : Tool, index : Int) : TaskResolver.GiveTask = {
|
||||||
|
TaskResolver.GiveTask(
|
||||||
|
new Task() {
|
||||||
|
private val localTarget = target
|
||||||
|
private val localIndex = index
|
||||||
|
private val localObject = obj
|
||||||
|
private val localAnnounce = self
|
||||||
|
private val localAvatarService = avatarService
|
||||||
|
private val localVehicleService = vehicleService
|
||||||
|
|
||||||
|
override def isComplete : Task.Resolution.Value = {
|
||||||
|
if(localTarget.Slot(localIndex).Equipment.contains(localObject)) {
|
||||||
|
Task.Resolution.Success
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Task.Resolution.Incomplete
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def Execute(resolver : ActorRef) : Unit = {
|
||||||
|
localTarget.Slot(localIndex).Equipment = localObject
|
||||||
|
resolver ! scala.util.Success(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def onSuccess() : Unit = {
|
||||||
|
val definition = localObject.Definition
|
||||||
|
if(localTarget.VisibleSlots.contains(localIndex)) {
|
||||||
|
localAvatarService ! AvatarServiceMessage(continent.Id, AvatarAction.EquipmentInHand(localTarget.GUID, localTarget.GUID, localIndex, localObject))
|
||||||
|
}
|
||||||
|
val channel = s"${localTarget.Actor}"
|
||||||
|
(0 until localObject.MaxAmmoSlot).foreach({ index =>
|
||||||
|
val box = localObject.AmmoSlots(index).Box
|
||||||
|
val boxDef = box.Definition
|
||||||
|
val boxdata = boxDef.Packet.DetailedConstructorData(box).get
|
||||||
|
localVehicleService ! VehicleServiceMessage(channel, VehicleAction.InventoryState(PlanetSideGUID(0), box, localObject.GUID, index, boxdata))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, List(GUIDTask.RegisterTool(obj)(continent.GUID)))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct tasking that coordinates the following:<br>
|
* Construct tasking that coordinates the following:<br>
|
||||||
* 1) Remove a new piece of `Equipment` from where it is currently stored.<br>
|
* 1) Remove a new piece of `Equipment` from where it is currently stored.<br>
|
||||||
|
|
@ -3297,14 +3419,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an object that contains a box of amunition in its `Inventory` at a certain location,
|
* Given an object that contains an item (`Equipment`) in its `Inventory` at a certain location,
|
||||||
* remove it permanently.
|
* remove it permanently.
|
||||||
* @param obj the `Container`
|
* @param obj the `Container`
|
||||||
* @param start where the ammunition can be found
|
* @param start where the item can be found
|
||||||
* @param item an object to unregister (should have been the ammunition that was removed);
|
* @param item an object to unregister;
|
||||||
* not explicitly checked
|
* not explicitly checked
|
||||||
*/
|
*/
|
||||||
private def DeleteAmmunition(obj : PlanetSideGameObject with Container)(start : Int, item : AmmoBox) : Unit = {
|
private def DeleteEquipment(obj : PlanetSideGameObject with Container)(start : Int, item : Equipment) : Unit = {
|
||||||
val item_guid = item.GUID
|
val item_guid = item.GUID
|
||||||
obj.Inventory -= start
|
obj.Inventory -= start
|
||||||
taskResolver ! GUIDTask.UnregisterEquipment(item)(continent.GUID)
|
taskResolver ! GUIDTask.UnregisterEquipment(item)(continent.GUID)
|
||||||
|
|
@ -3312,17 +3434,17 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a vehicle that contains a box of amunition in its `Trunk` at a certain location,
|
* Given a vehicle that contains an item (`Equipment`) in its `Trunk` at a certain location,
|
||||||
* remove it permanently.
|
* remove it permanently.
|
||||||
* @see `DeleteAmmunition`
|
* @see `DeleteEquipment`
|
||||||
* @param obj the `Vehicle`
|
* @param obj the `Vehicle`
|
||||||
* @param start where the ammunition can be found
|
* @param start where the item can be found
|
||||||
* @param item an object to unregister (should have been the ammunition that was removed);
|
* @param item an object to unregister;
|
||||||
* not explicitly checked
|
* not explicitly checked
|
||||||
*/
|
*/
|
||||||
private def DeleteAmmunitionInVehicle(obj : Vehicle)(start : Int, item : AmmoBox) : Unit = {
|
private def DeleteEquipmentFromVehicle(obj : Vehicle)(start : Int, item : Equipment) : Unit = {
|
||||||
val item_guid = item.GUID
|
val item_guid = item.GUID
|
||||||
DeleteAmmunition(obj)(start, item)
|
DeleteEquipment(obj)(start, item)
|
||||||
vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player.GUID, item_guid))
|
vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player.GUID, item_guid))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3355,27 +3477,27 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Announce that an already-registered `AmmoBox` object exists in a given position in some `Container` object's inventory.
|
* Announce that an already-registered `AmmoBox` object exists in a given position in some `Container` object's inventory.
|
||||||
* @see `StowAmmunitionInVehicles`
|
* @see `StowEquipmentInVehicles`
|
||||||
* @see `ChangeAmmoMessage`
|
* @see `ChangeAmmoMessage`
|
||||||
* @param obj the `Container` object
|
* @param obj the `Container` object
|
||||||
* @param index an index in `obj`'s inventory
|
* @param index an index in `obj`'s inventory
|
||||||
* @param item an `AmmoBox`
|
* @param item an `AmmoBox`
|
||||||
*/
|
*/
|
||||||
def StowAmmunition(obj : PlanetSideGameObject with Container)(index : Int, item : AmmoBox) : Unit = {
|
def StowEquipment(obj : PlanetSideGameObject with Container)(index : Int, item : AmmoBox) : Unit = {
|
||||||
obj.Inventory += index -> item
|
obj.Inventory += index -> item
|
||||||
sendResponse(ObjectAttachMessage(obj.GUID, item.GUID, index))
|
sendResponse(ObjectAttachMessage(obj.GUID, item.GUID, index))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Announce that an already-registered `AmmoBox` object exists in a given position in some vehicle's inventory.
|
* Announce that an already-registered `AmmoBox` object exists in a given position in some vehicle's inventory.
|
||||||
* @see `StowAmmunition`
|
* @see `StowEquipment`
|
||||||
* @see `ChangeAmmoMessage`
|
* @see `ChangeAmmoMessage`
|
||||||
* @param obj the `Vehicle` object
|
* @param obj the `Vehicle` object
|
||||||
* @param index an index in `obj`'s inventory
|
* @param index an index in `obj`'s inventory
|
||||||
* @param item an `AmmoBox`
|
* @param item an `AmmoBox`
|
||||||
*/
|
*/
|
||||||
def StowAmmunitionInVehicles(obj : Vehicle)(index : Int, item : AmmoBox) : Unit = {
|
def StowEquipmentInVehicles(obj : Vehicle)(index : Int, item : AmmoBox) : Unit = {
|
||||||
StowAmmunition(obj)(index, item)
|
StowEquipment(obj)(index, item)
|
||||||
vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.StowEquipment(player.GUID, obj.GUID, index, item))
|
vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.StowEquipment(player.GUID, obj.GUID, index, item))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3383,14 +3505,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
* Prepare tasking that registers an `AmmoBox` object
|
* Prepare tasking that registers an `AmmoBox` object
|
||||||
* and announces that it exists in a given position in some `Container` object's inventory.
|
* and announces that it exists in a given position in some `Container` object's inventory.
|
||||||
* `PutEquipmentInSlot` is the fastest way to achieve these goals.
|
* `PutEquipmentInSlot` is the fastest way to achieve these goals.
|
||||||
* @see `StowNewAmmunitionInVehicles`
|
* @see `StowNewEquipmentInVehicle`
|
||||||
* @see `ChangeAmmoMessage`
|
* @see `ChangeAmmoMessage`
|
||||||
* @param obj the `Container` object
|
* @param obj the `Container` object
|
||||||
* @param index an index in `obj`'s inventory
|
* @param index an index in `obj`'s inventory
|
||||||
* @param item an `AmmoBox`
|
* @param item an `AmmoBox`
|
||||||
* @return a `TaskResolver.GiveTask` chain that executes the action
|
* @return a `TaskResolver.GiveTask` chain that executes the action
|
||||||
*/
|
*/
|
||||||
def StowNewAmmunition(obj : PlanetSideGameObject with Container)(index : Int, item : AmmoBox) : TaskResolver.GiveTask = {
|
def StowNewEquipment(obj : PlanetSideGameObject with Container)(index : Int, item : Equipment) : TaskResolver.GiveTask = {
|
||||||
PutEquipmentInSlot(obj, item, index)
|
PutEquipmentInSlot(obj, item, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3398,14 +3520,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
* Prepare tasking that registers an `AmmoBox` object
|
* Prepare tasking that registers an `AmmoBox` object
|
||||||
* and announces that it exists in a given position in some vehicle's inventory.
|
* and announces that it exists in a given position in some vehicle's inventory.
|
||||||
* `PutEquipmentInSlot` is the fastest way to achieve these goals.
|
* `PutEquipmentInSlot` is the fastest way to achieve these goals.
|
||||||
* @see `StowNewAmmunition`
|
* @see `StowNewEquipment`
|
||||||
* @see `ChangeAmmoMessage`
|
* @see `ChangeAmmoMessage`
|
||||||
* @param obj the `Container` object
|
* @param obj the `Container` object
|
||||||
* @param index an index in `obj`'s inventory
|
* @param index an index in `obj`'s inventory
|
||||||
* @param item an `AmmoBox`
|
* @param item an `AmmoBox`
|
||||||
* @return a `TaskResolver.GiveTask` chain that executes the action
|
* @return a `TaskResolver.GiveTask` chain that executes the action
|
||||||
*/
|
*/
|
||||||
def StowNewAmmunitionInVehicles(obj : Vehicle)(index : Int, item : AmmoBox) : TaskResolver.GiveTask = {
|
def StowNewEquipmentInVehicle(obj : Vehicle)(index : Int, item : Equipment) : TaskResolver.GiveTask = {
|
||||||
TaskResolver.GiveTask(
|
TaskResolver.GiveTask(
|
||||||
new Task() {
|
new Task() {
|
||||||
private val localService = vehicleService
|
private val localService = vehicleService
|
||||||
|
|
@ -3424,7 +3546,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
resolver ! scala.util.Success(this)
|
resolver ! scala.util.Success(this)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
List(StowNewAmmunition(obj)(index, item))
|
List(StowNewEquipment(obj)(index, item))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3640,6 +3762,20 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def LocalVehicle : Option[Vehicle] = {
|
||||||
|
player.VehicleSeated match {
|
||||||
|
case Some(vehicle_guid) =>
|
||||||
|
continent.GUID(vehicle_guid) match {
|
||||||
|
case Some(obj : Vehicle) =>
|
||||||
|
Some(obj)
|
||||||
|
case _ =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform specific operations depending on the target of deployment.
|
* Perform specific operations depending on the target of deployment.
|
||||||
* @param obj the object that has deployed
|
* @param obj the object that has deployed
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue