mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
commit
86fc5e44d0
|
|
@ -2,6 +2,7 @@
|
|||
comment: off
|
||||
|
||||
ignore:
|
||||
- "common/src/main/scala/net/psforever/objects/avatar/Avatars.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/equipment/Ammo.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/equipment/CItem.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/equipment/EquipmentSize.scala"
|
||||
|
|
@ -11,7 +12,6 @@ ignore:
|
|||
- "common/src/main/scala/net/psforever/objects/vehicles/AccessPermissionGroup.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/vehicles/SeatArmoRestriction.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/vehicles/VehicleLockState.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/Avatars.scala"
|
||||
- "common/src/main/scala/net/psforever/packet/crypto"
|
||||
- "common/src/main/scala/net/psforever/packet/game/objectcreate/DrawnSlot.scala"
|
||||
- "common/src/main/scala/net/psforever/packet/game/objectcreate/DriveState.scala"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import net.psforever.objects.equipment.{Equipment, EquipmentSize}
|
|||
class EquipmentSlot {
|
||||
private var size : EquipmentSize.Value = EquipmentSize.Blocked
|
||||
private var tool : Option[Equipment] = None
|
||||
//TODO eventually move this object from storing the item directly to just storing its GUID?
|
||||
|
||||
def Size : EquipmentSize.Value = size
|
||||
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ object ExoSuitDefinition {
|
|||
MAX.MaxArmor = 650
|
||||
MAX.InventoryScale = InventoryTile.Tile1612
|
||||
MAX.InventoryOffset = 6
|
||||
MAX.Holster(0, EquipmentSize.Max)
|
||||
MAX.Holster(2, EquipmentSize.Max)
|
||||
MAX.Holster(4, EquipmentSize.Melee)
|
||||
|
||||
def apply(suitType : ExoSuitType.Value) : ExoSuitDefinition = {
|
||||
|
|
|
|||
|
|
@ -910,7 +910,7 @@ object GlobalDefinitions {
|
|||
bullet_20mm.Capacity = 200
|
||||
bullet_20mm.Tile = InventoryTile.Tile44
|
||||
|
||||
bullet_12mm.Capacity = 200
|
||||
bullet_12mm.Capacity = 300
|
||||
bullet_12mm.Tile = InventoryTile.Tile44
|
||||
|
||||
wasp_rocket_ammo.Capacity = 6
|
||||
|
|
@ -1397,6 +1397,24 @@ object GlobalDefinitions {
|
|||
flamethrower.FireModes(1).Magazine = 100
|
||||
flamethrower.FireModes(1).Chamber = 50
|
||||
flamethrower.Tile = InventoryTile.Tile63
|
||||
//TODO
|
||||
trhev_dualcycler.Size = EquipmentSize.Max
|
||||
trhev_dualcycler.AmmoTypes += bullet_9mm
|
||||
trhev_dualcycler.FireModes += new FireModeDefinition
|
||||
trhev_dualcycler.FireModes.head.AmmoTypeIndices += 0
|
||||
trhev_dualcycler.FireModes.head.AmmoSlotIndex = 0
|
||||
//TODO
|
||||
trhev_pounder.Size = EquipmentSize.Max
|
||||
trhev_pounder.AmmoTypes += bullet_9mm
|
||||
trhev_pounder.FireModes += new FireModeDefinition
|
||||
trhev_pounder.FireModes.head.AmmoTypeIndices += 0
|
||||
trhev_pounder.FireModes.head.AmmoSlotIndex = 0
|
||||
//TODO
|
||||
trhev_burster.Size = EquipmentSize.Max
|
||||
trhev_burster.AmmoTypes += bullet_9mm
|
||||
trhev_burster.FireModes += new FireModeDefinition
|
||||
trhev_burster.FireModes.head.AmmoTypeIndices += 0
|
||||
trhev_burster.FireModes.head.AmmoSlotIndex = 0
|
||||
|
||||
medicalapplicator.Size = EquipmentSize.Pistol
|
||||
medicalapplicator.AmmoTypes += health_canister
|
||||
|
|
@ -1511,7 +1529,7 @@ object GlobalDefinitions {
|
|||
skyguard_weapon_system.FireModes += new FireModeDefinition
|
||||
skyguard_weapon_system.FireModes(1).AmmoTypeIndices += 1
|
||||
skyguard_weapon_system.FireModes(1).AmmoSlotIndex = 1
|
||||
skyguard_weapon_system.FireModes(1).Magazine = 1 //TODO check
|
||||
skyguard_weapon_system.FireModes(1).Magazine = 250
|
||||
|
||||
grenade_launcher_marauder.Size = EquipmentSize.VehicleWeapon
|
||||
grenade_launcher_marauder.AmmoTypes += heavy_grenade_mortar
|
||||
|
|
@ -1692,7 +1710,7 @@ object GlobalDefinitions {
|
|||
lightning_weapon_system.FireModes += new FireModeDefinition
|
||||
lightning_weapon_system.FireModes(1).AmmoTypeIndices += 1
|
||||
lightning_weapon_system.FireModes(1).AmmoSlotIndex = 1
|
||||
lightning_weapon_system.FireModes(1).Magazine = 1 //TODO check
|
||||
lightning_weapon_system.FireModes(1).Magazine = 150
|
||||
|
||||
prowler_weapon_systemA.Size = EquipmentSize.VehicleWeapon
|
||||
prowler_weapon_systemA.AmmoTypes += bullet_105mm
|
||||
|
|
@ -1718,7 +1736,7 @@ object GlobalDefinitions {
|
|||
vanguard_weapon_system.FireModes += new FireModeDefinition
|
||||
vanguard_weapon_system.FireModes(1).AmmoTypeIndices += 1
|
||||
vanguard_weapon_system.FireModes(1).AmmoSlotIndex = 1
|
||||
vanguard_weapon_system.FireModes(1).Magazine = 1 //TODO check
|
||||
vanguard_weapon_system.FireModes(1).Magazine = 200
|
||||
|
||||
particle_beam_magrider.Size = EquipmentSize.VehicleWeapon
|
||||
particle_beam_magrider.AmmoTypes += pulse_battery
|
||||
|
|
@ -1754,11 +1772,11 @@ object GlobalDefinitions {
|
|||
lightgunship_weapon_system.FireModes += new FireModeDefinition
|
||||
lightgunship_weapon_system.FireModes.head.AmmoTypeIndices += 0
|
||||
lightgunship_weapon_system.FireModes.head.AmmoSlotIndex = 0
|
||||
lightgunship_weapon_system.FireModes.head.Magazine = 150
|
||||
lightgunship_weapon_system.FireModes.head.Magazine = 245
|
||||
lightgunship_weapon_system.FireModes += new FireModeDefinition
|
||||
lightgunship_weapon_system.FireModes(1).AmmoTypeIndices += 1
|
||||
lightgunship_weapon_system.FireModes(1).AmmoSlotIndex = 1
|
||||
lightgunship_weapon_system.FireModes(1).Magazine = 1 //TODO check
|
||||
lightgunship_weapon_system.FireModes(1).Magazine = 16
|
||||
|
||||
wasp_weapon_system.Size = EquipmentSize.VehicleWeapon
|
||||
wasp_weapon_system.AmmoTypes += wasp_gun_ammo
|
||||
|
|
@ -1770,7 +1788,7 @@ object GlobalDefinitions {
|
|||
wasp_weapon_system.FireModes += new FireModeDefinition
|
||||
wasp_weapon_system.FireModes(1).AmmoTypeIndices += 1
|
||||
wasp_weapon_system.FireModes(1).AmmoSlotIndex = 1
|
||||
wasp_weapon_system.FireModes(1).Magazine = 1 //TODO check
|
||||
wasp_weapon_system.FireModes(1).Magazine = 2
|
||||
|
||||
liberator_weapon_system.Size = EquipmentSize.VehicleWeapon
|
||||
liberator_weapon_system.AmmoTypes += bullet_35mm
|
||||
|
|
@ -1893,7 +1911,7 @@ object GlobalDefinitions {
|
|||
two_man_assault_buggy.Weapons += 2 -> chaingun_p
|
||||
two_man_assault_buggy.MountPoints += 1 -> 0
|
||||
two_man_assault_buggy.MountPoints += 2 -> 1
|
||||
two_man_assault_buggy.TrunkSize = InventoryTile.Tile1111
|
||||
two_man_assault_buggy.TrunkSize = InventoryTile.Tile1511
|
||||
two_man_assault_buggy.TrunkOffset = 30
|
||||
|
||||
skyguard.Seats += 0 -> new SeatDefinition()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,14 @@ import net.psforever.types.ExoSuitType
|
|||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
//trait Loadout {
|
||||
// def Label : String
|
||||
// def VisibleSlots : List[Loadout.SimplifiedEntry]
|
||||
// def Inventory : List[Loadout.SimplifiedEntry]
|
||||
// def ExoSuit : ExoSuitType.Value
|
||||
// def Subtype : Int
|
||||
//}
|
||||
|
||||
/**
|
||||
* From a `Player` their current exo-suit and their `Equipment`, retain a set of instructions to reconstruct this arrangement.<br>
|
||||
* <br>
|
||||
|
|
@ -31,36 +39,17 @@ import scala.annotation.tailrec
|
|||
* The fifth tab on an `order_terminal` window is for "Favorite" blueprints for `Loadout` entries.
|
||||
* The ten-long list is initialized with `FavoritesMessage` packets.
|
||||
* Specific entries are loaded or removed using `FavoritesRequest` packets.
|
||||
* @param player the player
|
||||
* @param label the name by which this inventory will be known when displayed in a Favorites list
|
||||
* @param visible_slots simplified representation of the `Equipment` that can see "seen" on the target
|
||||
* @param inventory simplified representation of the `Equipment` in the target's inventory or trunk
|
||||
* @param exosuit na
|
||||
* @param subtype na
|
||||
*/
|
||||
class Loadout(player : Player, private val label : String) {
|
||||
/** the exo-suit */
|
||||
private val exosuit : ExoSuitType.Value = player.ExoSuit
|
||||
/** the MAX specialization, to differentiate the three types of MAXes who all use the same exo-suit name */
|
||||
private val subtype =
|
||||
if(exosuit == ExoSuitType.MAX) {
|
||||
player.Holsters().head.Equipment.get.Definition match {
|
||||
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.nchev_scattercannon | GlobalDefinitions.vshev_quasar =>
|
||||
1
|
||||
case GlobalDefinitions.trhev_pounder | GlobalDefinitions.nchev_falcon | GlobalDefinitions.vshev_comet =>
|
||||
2
|
||||
case GlobalDefinitions.trhev_burster | GlobalDefinitions.nchev_sparrow | GlobalDefinitions.vshev_starfire =>
|
||||
3
|
||||
case _ =>
|
||||
0
|
||||
}
|
||||
}
|
||||
else {
|
||||
0
|
||||
}
|
||||
/** simplified representation of the holster `Equipment` */
|
||||
private val holsters : List[Loadout.SimplifiedEntry] =
|
||||
Loadout.packageSimplifications(player.Holsters())
|
||||
/** simplified representation of the inventory `Equipment` */
|
||||
private val inventory : List[Loadout.SimplifiedEntry] =
|
||||
Loadout.packageSimplifications(player.Inventory.Items.values.toList)
|
||||
|
||||
final case class Loadout(private val label : String,
|
||||
private val visible_slots : List[Loadout.SimplifiedEntry],
|
||||
private val inventory : List[Loadout.SimplifiedEntry],
|
||||
private val exosuit : ExoSuitType.Value,
|
||||
private val subtype : Int) {
|
||||
/**
|
||||
* The label by which this `Loadout` is called.
|
||||
* @return the label
|
||||
|
|
@ -89,7 +78,7 @@ class Loadout(player : Player, private val label : String) {
|
|||
* The `Equipment` in the `Player`'s holster slots when this `Loadout` is created.
|
||||
* @return a `List` of the holster item blueprints
|
||||
*/
|
||||
def Holsters : List[Loadout.SimplifiedEntry] = holsters
|
||||
def VisibleSlots : List[Loadout.SimplifiedEntry] = visible_slots
|
||||
|
||||
/**
|
||||
* The `Equipment` in the `Player`'s inventory region when this `Loadout` is created.
|
||||
|
|
@ -99,6 +88,28 @@ class Loadout(player : Player, private val label : String) {
|
|||
}
|
||||
|
||||
object Loadout {
|
||||
def apply(label : String, visible : List[SimplifiedEntry], inventory : List[SimplifiedEntry]) : Loadout = {
|
||||
new Loadout(label, visible, inventory, ExoSuitType.Standard, 0)
|
||||
}
|
||||
|
||||
def Create(player : Player, label : String) : Loadout = {
|
||||
new Loadout(
|
||||
label,
|
||||
packageSimplifications(player.Holsters()),
|
||||
packageSimplifications(player.Inventory.Items.values.toList),
|
||||
player.ExoSuit,
|
||||
determineSubtype(player)
|
||||
)
|
||||
}
|
||||
|
||||
def Create(vehicle : Vehicle, label : String) : Loadout = {
|
||||
Loadout(
|
||||
label,
|
||||
packageSimplifications(vehicle.Weapons.map({ case ((index, weapon)) => InventoryItem(weapon.Equipment.get, index) }).toList),
|
||||
packageSimplifications(vehicle.Trunk.Items.values.toList)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A basic `Trait` connecting all of the `Equipment` blueprints.
|
||||
*/
|
||||
|
|
@ -124,13 +135,13 @@ object Loadout {
|
|||
* @param tdef the `ToolDefinition` that describes this future object
|
||||
* @param ammo the blueprints to construct the correct number of ammunition slots in the `Tool`
|
||||
*/
|
||||
final case class ShorthandTool(tdef : ToolDefinition, ammo : List[ShorthandAmmotSlot]) extends Simplification
|
||||
final case class ShorthandTool(tdef : ToolDefinition, ammo : List[ShorthandAmmoSlot]) extends Simplification
|
||||
/**
|
||||
* The simplified form of a `Tool` `FireMode`
|
||||
* @param ammoIndex the index that points to the type of ammunition this slot currently uses
|
||||
* @param ammo a `ShorthandAmmoBox` object to load into that slot
|
||||
*/
|
||||
final case class ShorthandAmmotSlot(ammoIndex : Int, ammo : ShorthandAmmoBox)
|
||||
final case class ShorthandAmmoSlot(ammoIndex : Int, ammo : ShorthandAmmoBox)
|
||||
/**
|
||||
* The simplified form of a `ConstructionItem`.
|
||||
* @param cdef the `ConstructionItemDefinition` that describes this future object
|
||||
|
|
@ -147,6 +158,29 @@ object Loadout {
|
|||
*/
|
||||
final case class ShorthandKit(kdef : KitDefinition) extends Simplification
|
||||
|
||||
private def determineSubtype(player : Player) : Int = {
|
||||
if(player.ExoSuit == ExoSuitType.MAX) {
|
||||
player.Slot(2).Equipment match {
|
||||
case Some(item) =>
|
||||
item.Definition match {
|
||||
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.nchev_scattercannon | GlobalDefinitions.vshev_quasar =>
|
||||
1
|
||||
case GlobalDefinitions.trhev_pounder | GlobalDefinitions.nchev_falcon | GlobalDefinitions.vshev_comet =>
|
||||
2
|
||||
case GlobalDefinitions.trhev_burster | GlobalDefinitions.nchev_sparrow | GlobalDefinitions.vshev_starfire =>
|
||||
3
|
||||
case _ =>
|
||||
0
|
||||
}
|
||||
case None =>
|
||||
0
|
||||
}
|
||||
}
|
||||
else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded entry point for constructing simplified blueprints from holster slot equipment.
|
||||
* @param equipment the holster slots
|
||||
|
|
@ -165,6 +199,7 @@ object Loadout {
|
|||
equipment.map(entry => { SimplifiedEntry(buildSimplification(entry.obj), entry.start) })
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Traverse a `Player`'s holsters and transform occupied slots into simplified blueprints for the contents of that slot.
|
||||
* The holsters are fixed positions and can be unoccupied.
|
||||
|
|
@ -193,29 +228,30 @@ object Loadout {
|
|||
}
|
||||
|
||||
/**
|
||||
* Ammunition slots are internal connection points where `AmmoBox` units and their characteristics represent a `Tool`'s magazine.
|
||||
* Their simplification process has a layer of complexity that ensures that the content of the slot matches the type of content that should be in the slot.
|
||||
* If it does not, it extracts information about the slot from the `EquipmentDefinition` and sets the blueprints to that.
|
||||
* Ammunition slots are internal connection points where `AmmoBox` units represent the characteristics of a magazine.
|
||||
* Their simplification process has a layer of complexity that ensures that the content of the slot
|
||||
* matches the type of content that should be in the slot.
|
||||
* If it does not, it extracts information about the slot from the `EquipmentDefinition` and sets the blueprints.
|
||||
* @param iter an `Iterator`
|
||||
* @param list an updating `List` of simplified ammo slot blueprints;
|
||||
* empty, by default
|
||||
* @return a `List` of simplified ammo slot blueprints
|
||||
* @see `Tool.FireModeSlot`
|
||||
*/
|
||||
@tailrec private def recursiveFireModeSimplications(iter : Iterator[Tool.FireModeSlot], list : List[ShorthandAmmotSlot] = Nil) : List[ShorthandAmmotSlot] = {
|
||||
@tailrec private def recursiveFireModeSimplications(iter : Iterator[Tool.FireModeSlot], list : List[ShorthandAmmoSlot] = Nil) : List[ShorthandAmmoSlot] = {
|
||||
if(!iter.hasNext) {
|
||||
list
|
||||
}
|
||||
else {
|
||||
val entry = iter.next
|
||||
val fmodeSimp = if(entry.Box.AmmoType == entry.AmmoType) {
|
||||
ShorthandAmmotSlot(
|
||||
ShorthandAmmoSlot(
|
||||
entry.AmmoTypeIndex,
|
||||
ShorthandAmmoBox(entry.Box.Definition, entry.Box.Capacity)
|
||||
)
|
||||
}
|
||||
else {
|
||||
ShorthandAmmotSlot(
|
||||
ShorthandAmmoSlot(
|
||||
entry.AmmoTypeIndex,
|
||||
ShorthandAmmoBox(entry.Tool.AmmoTypes(entry.Definition.AmmoTypeIndices.head), 1)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -17,4 +17,11 @@ class OffhandEquipmentSlot(size : EquipmentSize.Value) extends EquipmentSlot {
|
|||
* @return the capacity for this slot
|
||||
*/
|
||||
override def Size_=(assignSize : EquipmentSize.Value) : EquipmentSize.Value = Size
|
||||
}
|
||||
}
|
||||
|
||||
object OffhandEquipmentSlot {
|
||||
/**
|
||||
* An `EquipmentSlot` that can not be manipulated because its size is `Blocked` permanently.
|
||||
*/
|
||||
final val BlockedSlot = new OffhandEquipmentSlot(EquipmentSize.Blocked)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,19 +3,20 @@ package net.psforever.objects
|
|||
|
||||
import net.psforever.objects.definition.{AvatarDefinition, ImplantDefinition}
|
||||
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
|
||||
import net.psforever.objects.inventory.{GridInventory, InventoryItem}
|
||||
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types._
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.mutable
|
||||
import scala.util.{Success, Try}
|
||||
|
||||
class Player(private val name : String,
|
||||
private val faction : PlanetSideEmpire.Value,
|
||||
private val sex : CharacterGender.Value,
|
||||
private val head : Int,
|
||||
private val voice : Int
|
||||
) extends PlanetSideGameObject {
|
||||
) extends PlanetSideGameObject with Container {
|
||||
private var alive : Boolean = false
|
||||
private var backpack : Boolean = false
|
||||
private var health : Int = 0
|
||||
|
|
@ -65,8 +66,8 @@ class Player(private val name : String,
|
|||
private var vehicleSeated : Option[PlanetSideGUID] = None
|
||||
private var vehicleOwned : Option[PlanetSideGUID] = None
|
||||
|
||||
private var continent : String = "home2" //actually, the zoneId
|
||||
private var playerDef : AvatarDefinition = Player.definition
|
||||
private var continent : String = "home2" //the zone id
|
||||
private val playerDef : AvatarDefinition = Player.definition //TODO could be a var
|
||||
|
||||
//SouNourS things
|
||||
/** Last medkituse. */
|
||||
|
|
@ -80,7 +81,7 @@ class Player(private val name : String,
|
|||
var PlanetsideAttribute : Array[Long] = Array.ofDim(120)
|
||||
|
||||
Player.SuitSetup(this, ExoSuit)
|
||||
fifthSlot.Equipment = new LockerContainer() //the fifth slot is the player's "locker"
|
||||
fifthSlot.Equipment = new LockerContainer //the fifth slot is the player's "locker"
|
||||
|
||||
def Name : String = name
|
||||
|
||||
|
|
@ -161,7 +162,9 @@ class Player(private val name : String,
|
|||
|
||||
def MaxArmor : Int = ExoSuitDefinition.Select(exosuit).MaxArmor
|
||||
|
||||
def Slot(slot : Int) : EquipmentSlot = {
|
||||
def VisibleSlots : Set[Int] = if(exosuit == ExoSuitType.MAX) { Set(2) } else { Set(0,1,2,3,4) }
|
||||
|
||||
override def Slot(slot : Int) : EquipmentSlot = {
|
||||
if(inventory.Offset <= slot && slot <= inventory.LastIndex) {
|
||||
inventory.Slot(slot)
|
||||
}
|
||||
|
|
@ -177,7 +180,7 @@ class Player(private val name : String,
|
|||
freeHand
|
||||
}
|
||||
else {
|
||||
new OffhandEquipmentSlot(EquipmentSize.Blocked)
|
||||
OffhandEquipmentSlot.BlockedSlot
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -238,7 +241,7 @@ class Player(private val name : String,
|
|||
}
|
||||
|
||||
def SaveLoadout(label : String, line : Int) : Unit = {
|
||||
loadouts(line) = Some(new Loadout(this, label))
|
||||
loadouts(line) = Some(Loadout.Create(this, label))
|
||||
}
|
||||
|
||||
def LoadLoadout(line : Int) : Option[Loadout] = loadouts(line)
|
||||
|
|
@ -298,6 +301,28 @@ class Player(private val name : String,
|
|||
}
|
||||
}
|
||||
|
||||
override def Collisions(dest : Int, width : Int, height : Int) : Try[List[InventoryItem]] = {
|
||||
if(-1 < dest && dest < 5) {
|
||||
holsters(dest).Equipment match {
|
||||
case Some(item) =>
|
||||
Success(List(InventoryItem(item, dest)))
|
||||
case None =>
|
||||
Success(List())
|
||||
}
|
||||
}
|
||||
else if(dest == Player.FreeHandSlot) {
|
||||
freeHand.Equipment match {
|
||||
case Some(item) =>
|
||||
Success(List(InventoryItem(item, dest)))
|
||||
case None =>
|
||||
Success(List())
|
||||
}
|
||||
}
|
||||
else {
|
||||
super.Collisions(dest, width, height)
|
||||
}
|
||||
}
|
||||
|
||||
def DrawnSlot : Int = drawnSlot
|
||||
|
||||
def DrawnSlot_=(slot : Int = Player.HandsDownSlot) : Int = {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects
|
|||
|
||||
import net.psforever.objects.definition.VehicleDefinition
|
||||
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
|
||||
import net.psforever.objects.inventory.{GridInventory, InventoryTile}
|
||||
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem, InventoryTile}
|
||||
import net.psforever.objects.mount.Mountable
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.vehicles.{AccessPermissionGroup, Seat, Utility, VehicleLockState}
|
||||
|
|
@ -27,7 +27,7 @@ import scala.collection.mutable
|
|||
* stores and unloads pertinent information about the `Vehicle`'s configuration;
|
||||
* used in the initialization process (`loadVehicleDefinition`)
|
||||
*/
|
||||
class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServerObject with Mountable {
|
||||
class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServerObject with Mountable with Container {
|
||||
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.TR
|
||||
private var owner : Option[PlanetSideGUID] = None
|
||||
private var health : Int = 1
|
||||
|
|
@ -337,6 +337,45 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ
|
|||
}
|
||||
}
|
||||
|
||||
def Inventory : GridInventory = trunk
|
||||
|
||||
def Find(obj : Equipment) : Option[Int] = Find(obj.GUID)
|
||||
|
||||
def Find(guid : PlanetSideGUID) : Option[Int] = {
|
||||
findInInventory(Inventory.Items.values.iterator, guid) match {
|
||||
case Some(index) =>
|
||||
Some(index)
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@tailrec private def findInInventory(iter : Iterator[InventoryItem], guid : PlanetSideGUID) : Option[Int] = {
|
||||
if(!iter.hasNext) {
|
||||
None
|
||||
}
|
||||
else {
|
||||
val item = iter.next
|
||||
if(item.obj.GUID == guid) {
|
||||
Some(item.start)
|
||||
}
|
||||
else {
|
||||
findInInventory(iter, guid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def VisibleSlots : Set[Int] = weapons.keySet
|
||||
|
||||
override def Slot(slot : Int) : EquipmentSlot = {
|
||||
if(Inventory.Offset <= slot && slot <= Inventory.LastIndex) {
|
||||
Inventory.Slot(slot)
|
||||
}
|
||||
else {
|
||||
OffhandEquipmentSlot.BlockedSlot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to the `Vehicle` `Trunk` space.
|
||||
* @return this `Vehicle` `Trunk`
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects
|
||||
package net.psforever.objects.avatar
|
||||
|
||||
/**
|
||||
* An `Enumeration` of all the avatar types in the game, paired with their object id as the `Value`.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.definition
|
||||
|
||||
import net.psforever.objects.avatar.Avatars
|
||||
import net.psforever.objects.definition.converter.AvatarConverter
|
||||
import net.psforever.objects.Avatars
|
||||
|
||||
/**
|
||||
* The definition for game objects that look like other people, and also for players.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.definition.converter
|
||||
|
||||
import net.psforever.objects.{EquipmentSlot, GlobalDefinitions, ImplantSlot, Player}
|
||||
import net.psforever.objects.{EquipmentSlot, ImplantSlot, Player}
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.packet.game.objectcreate.{BasicCharacterData, CharacterAppearanceData, CharacterData, Cosmetics, DetailedCharacterData, DrawnSlot, ImplantEffects, ImplantEntry, InternalSlot, InventoryData, PlacementData, RibbonBars, UniformStyle}
|
||||
import net.psforever.types.{GrenadeState, ImplantType}
|
||||
|
|
@ -164,14 +164,14 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
|
|||
else {
|
||||
val slot = iter.next
|
||||
if(slot.Active) {
|
||||
slot.Installed match {
|
||||
case Some(GlobalDefinitions.advanced_regen) =>
|
||||
slot.Implant match {
|
||||
case ImplantType.AdvancedRegen =>
|
||||
Some(ImplantEffects.RegenEffects)
|
||||
case Some(GlobalDefinitions.darklight_vision) =>
|
||||
case ImplantType.DarklightVision =>
|
||||
Some(ImplantEffects.DarklightEffects)
|
||||
case Some(GlobalDefinitions.personal_shield) =>
|
||||
case ImplantType.PersonalShield =>
|
||||
Some(ImplantEffects.PersonalShieldEffects)
|
||||
case Some(GlobalDefinitions.surge) =>
|
||||
case ImplantType.Surge =>
|
||||
Some(ImplantEffects.SurgeEffects)
|
||||
case _ =>
|
||||
recursiveMakeImplantEffects(iter)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
|||
false,
|
||||
obj.Cloaked,
|
||||
SpecificFormatData(obj),
|
||||
Some(InventoryData((MakeMountings(obj) ++ MakeTrunk(obj)).sortBy(_.parentSlot)))
|
||||
Some(InventoryData(MakeMountings(obj).sortBy(_.parentSlot)))
|
||||
)(SpecificFormatModifier)
|
||||
)
|
||||
}
|
||||
|
|
@ -47,18 +47,18 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
|||
}).toList
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param obj the `Player` game object
|
||||
* @return a list of all items that were in the inventory in decoded packet form
|
||||
*/
|
||||
private def MakeTrunk(obj : Vehicle) : List[InternalSlot] = {
|
||||
obj.Trunk.Items.map({
|
||||
case(_, item) =>
|
||||
val equip : Equipment = item.obj
|
||||
InventoryItemData(equip.Definition.ObjectId, equip.GUID, item.start, equip.Definition.Packet.ConstructorData(equip).get)
|
||||
}).toList
|
||||
}
|
||||
// /**
|
||||
// * na
|
||||
// * @param obj the `Player` game object
|
||||
// * @return a list of all items that were in the inventory in decoded packet form
|
||||
// */
|
||||
// private def MakeTrunk(obj : Vehicle) : List[InternalSlot] = {
|
||||
// obj.Trunk.Items.map({
|
||||
// case(_, item) =>
|
||||
// val equip : Equipment = item.obj
|
||||
// InventoryItemData(equip.Definition.ObjectId, equip.GUID, item.start, equip.Definition.Packet.ConstructorData(equip).get)
|
||||
// }).toList
|
||||
// }
|
||||
|
||||
// @tailrec private def recursiveMakeSeats(iter : Iterator[(Int, Seat)], list : List[InventoryItemData.InventoryItem] = Nil) : List[InventoryItemData.InventoryItem] = {
|
||||
// if(!iter.hasNext) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,170 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.inventory
|
||||
|
||||
import net.psforever.objects.{EquipmentSlot, OffhandEquipmentSlot}
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
|
||||
import scala.util.Try
|
||||
|
||||
/**
|
||||
* This object is capable of storing ("stowing") `Equipment` within itself.<br>
|
||||
* <br>
|
||||
* The following objects are considered item containers:
|
||||
* players (their own inventory),
|
||||
* players (their corpse's loot),
|
||||
* vehicles (their trunk), and
|
||||
* lockers (contents of the player's fifth slot).
|
||||
*/
|
||||
trait Container {
|
||||
/**
|
||||
* A(n imperfect) reference to a generalized pool of the contained objects.
|
||||
* Having access to all of the available positions is not required.
|
||||
* The entries in this reference should definitely include all unseen positions.
|
||||
* @see `VisibleSlots`
|
||||
*/
|
||||
def Inventory : GridInventory
|
||||
|
||||
/**
|
||||
* Given globally unique identifier, if the object using it is stowed, attempt to locate its slot.
|
||||
* All positions, `VisibleSlot` and `Inventory`, and wherever else, should be searchable.
|
||||
* @param guid the GUID of the `Equipment`
|
||||
* @return the index of the `EquipmentSlot`, or `None`
|
||||
*/
|
||||
def Find(guid : PlanetSideGUID) : Option[Int]
|
||||
|
||||
/**
|
||||
* A(n imperfect) reference to a generalized pool of the contained objects.<br>
|
||||
* <br>
|
||||
* Having access to all of the available positions is not required.
|
||||
* Only the positions that can be actively viewed by other clients are listed.
|
||||
* @see `Inventory`
|
||||
* @return all of the affected slot indices
|
||||
*/
|
||||
def VisibleSlots : Set[Int]
|
||||
|
||||
/**
|
||||
* Access to all stowable positions on this object by index.<br>
|
||||
* <br>
|
||||
* All positions, `VisibleSlot` and `Inventory`, and wherever else, should be reachable.
|
||||
* Regardless of the internal storage medium, the format of return is expected to be the same structure of object
|
||||
* as the most basic storage component for `Equipment`, namely, `EquipmentSlot` objects.
|
||||
* By default, it is expected to return an `EquipmentSlot` that can not be manipulated because it is `Blocked`.
|
||||
* @see `OffhandEquipmentSlot`
|
||||
* @param slotNum an index
|
||||
* @return the searchable position identified by that index
|
||||
*/
|
||||
def Slot(slotNum : Int) : EquipmentSlot = OffhandEquipmentSlot.BlockedSlot
|
||||
|
||||
/**
|
||||
* Given a region of "searchable unit positions" considered as stowable,
|
||||
* determine if any previously stowed items are contained within that region.<br>
|
||||
* <br>
|
||||
* Default usage, and recommended the continued inclusion of that use,
|
||||
* is defined in terms of `Equipment` being stowed in a `GridInventory`.
|
||||
* Where the `Equipment` object is defined by the dimensions `width` and `height`,
|
||||
* starting a search at `index` will search all positions within a grid-like range of numbers.
|
||||
* Under certain searching conditions, this range may be meaningless,
|
||||
* such as is the case when searching individual positions that are normal `EquipmentSlot` objects.
|
||||
* Regardless, the value collected indicates the potential of multiple objects being discovered and
|
||||
* maintains a reference to the object itself and the slot position where the object is located.
|
||||
* (As any object can be discovered within the range, that is important.)
|
||||
* @see `GridInventory.CheckCollisionsVar`
|
||||
* @param index the position to start searching
|
||||
* @param width the width of the searchable space
|
||||
* @param height the height of the serachable space
|
||||
* @return a list of objects that have been encountered within the searchable space
|
||||
*/
|
||||
def Collisions(index : Int, width : Int, height : Int) : Try[List[InventoryItem]] =
|
||||
Inventory.CheckCollisionsVar(index, width, height)
|
||||
}
|
||||
|
||||
//object Container {
|
||||
// type ValidContainer = PlanetSideServerObject with Container
|
||||
//
|
||||
// final case class GetMoveItem(where_src : Int, other : ValidContainer, where_other : Int, other_item : Option[Equipment])
|
||||
//
|
||||
// final case class GiveMoveItem(cont1 : ValidContainer, where_cont1 : Int, item : Option[Equipment], cont2 : ValidContainer, where_cont2 : Int, other_item : Option[Equipment])
|
||||
//
|
||||
//
|
||||
// final case class TakeMoveItem(source_index : Int, destination : ValidContainer, destination_index : Int)
|
||||
//
|
||||
// final case class TakeMoveItem2(item_guid : PlanetSideGUID, destination : ValidContainer, destination_index : Int)
|
||||
//
|
||||
// final case class GivingMoveItem(item : Equipment, source : ValidContainer, source_index : Int, destination : ValidContainer, destination_index : Int)
|
||||
//
|
||||
// final case class PutMoveItem(item : Equipment, target_index : Int, source : ValidContainer, source_index : Int)
|
||||
//
|
||||
// final case class DropMoveItem(item : Equipment, source : ValidContainer, source_index : Int)
|
||||
//
|
||||
// final case class ItemMoved(item : Equipment, location : ValidContainer, location_index : Int)
|
||||
//
|
||||
// final case class NoMoveItem(source : ValidContainer, source_index : Int)
|
||||
//}
|
||||
//
|
||||
//trait ContainerBehavior {
|
||||
// this : Actor =>
|
||||
//
|
||||
// def ContainableObject : Container.ValidContainer
|
||||
//
|
||||
// val containerBehavior : Receive = {
|
||||
// case Container.GetMoveItem(where_src, destination, where_dest, other_item) =>
|
||||
// val slot : EquipmentSlot = ContainableObject.Slot(where_src)
|
||||
// val equipment = slot.Equipment
|
||||
// slot.Equipment = None
|
||||
// sender ! Container.GiveMoveItem(ContainableObject, where_src, equipment, destination, where_dest, other_item)
|
||||
//
|
||||
// case Container.TakeMoveItem(source_index, destination, destination_index) =>
|
||||
// val slot : EquipmentSlot = ContainableObject.Slot(source_index)
|
||||
// val equipment : Option[Equipment] = slot.Equipment
|
||||
// slot.Equipment = None
|
||||
// sender ! (equipment match {
|
||||
// case Some(item) =>
|
||||
// Container.GivingMoveItem(item, ContainableObject, source_index, destination, destination_index)
|
||||
// case None =>
|
||||
// Container.NoMoveItem(ContainableObject, source_index)
|
||||
// })
|
||||
//
|
||||
// case Container.TakeMoveItem2(item_guid, destination, destination_index) =>
|
||||
// ContainableObject.Find(item_guid) match {
|
||||
// case Some(source_index) =>
|
||||
// val slot : EquipmentSlot = ContainableObject.Slot(source_index)
|
||||
// val equipment : Option[Equipment] = slot.Equipment
|
||||
// slot.Equipment = None
|
||||
// sender ! (equipment match {
|
||||
// case Some(item) =>
|
||||
// Container.GivingMoveItem(item, ContainableObject, source_index, destination, destination_index)
|
||||
// case None => ;
|
||||
// })
|
||||
//
|
||||
// case None =>
|
||||
// sender ! Container.NoMoveItem(ContainableObject, 65535)
|
||||
// }
|
||||
//
|
||||
// case Container.PutMoveItem(item, target_index, source, source_index) =>
|
||||
// val slot : EquipmentSlot = ContainableObject.Slot(target_index)
|
||||
// val equipment : Option[Equipment] = slot.Equipment
|
||||
// if( {
|
||||
// val tile = item.Definition.Tile
|
||||
// ContainableObject.Collisions(target_index, tile.Width, tile.Height) match {
|
||||
// case Success(Nil) => //no item swap
|
||||
// true
|
||||
// case Success(_ :: Nil) => //one item to swap
|
||||
// true
|
||||
// case Success(_) | scala.util.Failure(_) =>
|
||||
// false //abort when too many items at destination or other failure case
|
||||
// }
|
||||
// }) {
|
||||
// slot.Equipment = None
|
||||
// slot.Equipment = item
|
||||
// equipment match {
|
||||
// case Some(swapItem) =>
|
||||
// sender ! Container.GivingMoveItem(swapItem, ContainableObject, target_index, source, source_index)
|
||||
// case None => ;
|
||||
// }
|
||||
// sender ! Container.ItemMoved(item, ContainableObject, target_index)
|
||||
// }
|
||||
// else {
|
||||
// sender ! Container.DropMoveItem(item, source, source_index)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
|
@ -5,23 +5,27 @@ import akka.actor.Actor
|
|||
|
||||
/**
|
||||
* The logic governing `Mountable` objects that use the `TryMount` message.
|
||||
* This is a mix-in trait for combining the `Receive` logic.
|
||||
* @see `Seat`
|
||||
* @see `Mountable`
|
||||
* @param obj the `Mountable` object governed beholden to this logic
|
||||
*/
|
||||
abstract class MountableControl(obj : Mountable) extends Actor {
|
||||
def receive : Receive = {
|
||||
trait MountableBehavior {
|
||||
this : Actor =>
|
||||
|
||||
def MountableObject : Mountable
|
||||
|
||||
val mountableBehavior : Receive = {
|
||||
case Mountable.TryMount(user, seat_num) =>
|
||||
obj.Seat(seat_num) match {
|
||||
MountableObject.Seat(seat_num) match {
|
||||
case Some(seat) =>
|
||||
if((seat.Occupant = user).contains(user)) {
|
||||
sender ! Mountable.MountMessages(user, Mountable.CanMount(obj, seat_num))
|
||||
sender ! Mountable.MountMessages(user, Mountable.CanMount(MountableObject, seat_num))
|
||||
}
|
||||
else {
|
||||
sender ! Mountable.MountMessages(user, Mountable.CanNotMount(obj, seat_num))
|
||||
sender ! Mountable.MountMessages(user, Mountable.CanNotMount(MountableObject, seat_num))
|
||||
}
|
||||
case None =>
|
||||
sender ! Mountable.MountMessages(user, Mountable.CanNotMount(obj, seat_num))
|
||||
sender ! Mountable.MountMessages(user, Mountable.CanNotMount(MountableObject, seat_num))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,17 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.implantmech
|
||||
|
||||
import net.psforever.objects.mount.MountableControl
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.mount.MountableBehavior
|
||||
|
||||
/**
|
||||
* An `Actor` that handles messages being dispatched to a specific `ImplantTerminalMech`.
|
||||
* @param mech the "mech" object being governed
|
||||
*/
|
||||
class ImplantTerminalMechControl(mech : ImplantTerminalMech) extends MountableControl(mech) {
|
||||
override def receive : Receive = super[MountableControl].receive.orElse {
|
||||
class ImplantTerminalMechControl(mech : ImplantTerminalMech) extends Actor with MountableBehavior {
|
||||
override def MountableObject = mech
|
||||
|
||||
def receive : Receive = mountableBehavior.orElse {
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.packet.game.ItemTransactionMessage
|
||||
|
||||
class AirVehicleTerminalDefinition extends TerminalDefinition(43) {
|
||||
class AirVehicleTerminalDefinition extends VehicleTerminalDefinition(43) {
|
||||
vehicles = flight1Vehicles
|
||||
Name = "air_vehicle_terminal"
|
||||
|
||||
def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
||||
flight1Vehicles.get(msg.item_name) match {
|
||||
case Some(vehicle) =>
|
||||
Terminal.BuyVehicle(vehicle(), Nil)
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.packet.game.ItemTransactionMessage
|
||||
|
||||
class BFRTerminalDefinition extends TerminalDefinition(143) {
|
||||
class BFRTerminalDefinition extends VehicleTerminalDefinition(143) {
|
||||
vehicles = bfrVehicles
|
||||
Name = "bfr_terminal"
|
||||
|
||||
def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
||||
bfrVehicles.get(msg.item_name) match {
|
||||
case Some(vehicle) =>
|
||||
//Terminal.BuyVehicle(vehicle, Nil)
|
||||
Terminal.NoDeal()
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.packet.game.ItemTransactionMessage
|
||||
|
||||
class DropshipVehicleTerminalDefinition extends TerminalDefinition(263) {
|
||||
private val flightVehicles = flight1Vehicles ++ flight2Vehicles
|
||||
class DropshipVehicleTerminalDefinition extends VehicleTerminalDefinition(263) {
|
||||
vehicles = flight1Vehicles ++ flight2Vehicles
|
||||
Name = "dropship_vehicle_terminal"
|
||||
|
||||
def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
||||
flightVehicles.get(msg.item_name) match {
|
||||
case Some(vehicle) =>
|
||||
Terminal.BuyVehicle(vehicle(), Nil)
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,320 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.definition._
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.types.ExoSuitType
|
||||
|
||||
abstract class EquipmentTerminalDefinition(objId : Int) extends TerminalDefinition(objId) {
|
||||
Name = "equipment_terminal"
|
||||
}
|
||||
|
||||
object EquipmentTerminalDefinition {
|
||||
private[this] val log = org.log4s.getLogger("TerminalDefinition")
|
||||
|
||||
/**
|
||||
* A `Map` of information for changing exo-suits.
|
||||
* key - an identification string sent by the client
|
||||
* value - a `Tuple` containing exo-suit specifications
|
||||
*/
|
||||
val suits : Map[String, (ExoSuitType.Value, Int)] = Map(
|
||||
"standard_issue_armor" -> (ExoSuitType.Standard, 0),
|
||||
"lite_armor" -> (ExoSuitType.Agile, 0),
|
||||
"med_armor" -> (ExoSuitType.Reinforced, 0)
|
||||
//TODO max and infiltration suit
|
||||
)
|
||||
|
||||
import net.psforever.objects.GlobalDefinitions._
|
||||
/**
|
||||
* A `Map` of operations for producing the `AmmoBox` `Equipment` for infantry-held weaponry.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
val infantryAmmunition : Map[String, () => Equipment] = Map(
|
||||
"9mmbullet" -> MakeAmmoBox(bullet_9mm),
|
||||
"9mmbullet_AP" -> MakeAmmoBox(bullet_9mm_AP),
|
||||
"shotgun_shell" -> MakeAmmoBox(shotgun_shell),
|
||||
"shotgun_shell_AP" -> MakeAmmoBox(shotgun_shell_AP),
|
||||
"energy_cell" -> MakeAmmoBox(energy_cell),
|
||||
"anniversary_ammo" -> MakeAmmoBox(anniversary_ammo), //10mm multi-phase
|
||||
"rocket" -> MakeAmmoBox(rocket),
|
||||
"frag_cartridge" -> MakeAmmoBox(frag_cartridge),
|
||||
"jammer_cartridge" -> MakeAmmoBox(jammer_cartridge),
|
||||
"plasma_cartridge" -> MakeAmmoBox(plasma_cartridge),
|
||||
"ancient_ammo_combo" -> MakeAmmoBox(ancient_ammo_combo),
|
||||
"maelstrom_ammo" -> MakeAmmoBox(maelstrom_ammo),
|
||||
"striker_missile_ammo" -> MakeAmmoBox(striker_missile_ammo),
|
||||
"hunter_seeker_missile" -> MakeAmmoBox(hunter_seeker_missile), //phoenix missile
|
||||
"lancer_cartridge" -> MakeAmmoBox(lancer_cartridge),
|
||||
"bolt" -> MakeAmmoBox(bolt),
|
||||
"oicw_ammo" -> MakeAmmoBox(oicw_ammo), //scorpion missile
|
||||
"flamethrower_ammo" -> MakeAmmoBox(flamethrower_ammo)
|
||||
)
|
||||
/**
|
||||
* A `Map` of operations for producing the `AmmoBox` `Equipment` for infantry-held utilities.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
val supportAmmunition : Map[String, () => Equipment] = Map(
|
||||
"health_canister" -> MakeAmmoBox(health_canister),
|
||||
"armor_canister" -> MakeAmmoBox(armor_canister),
|
||||
"upgrade_canister" -> MakeAmmoBox(upgrade_canister)
|
||||
)
|
||||
/**
|
||||
* A `Map` of operations for producing the `AmmoBox` `Equipment` for vehicle-mounted weaponry.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
val vehicleAmmunition : Map[String, () => Equipment] = Map(
|
||||
"35mmbullet" -> MakeAmmoBox(bullet_35mm),
|
||||
"hellfire_ammo" -> MakeAmmoBox(hellfire_ammo),
|
||||
"liberator_bomb" -> MakeAmmoBox(liberator_bomb),
|
||||
"25mmbullet" -> MakeAmmoBox(bullet_25mm),
|
||||
"75mmbullet" -> MakeAmmoBox(bullet_75mm),
|
||||
"heavy_grenade_mortar" -> MakeAmmoBox(heavy_grenade_mortar),
|
||||
"reaver_rocket" -> MakeAmmoBox(reaver_rocket),
|
||||
"20mmbullet" -> MakeAmmoBox(bullet_20mm),
|
||||
"12mmbullet" -> MakeAmmoBox(bullet_12mm),
|
||||
"wasp_rocket_ammo" -> MakeAmmoBox(wasp_rocket_ammo),
|
||||
"wasp_gun_ammo" -> MakeAmmoBox(wasp_gun_ammo),
|
||||
"aphelion_laser_ammo" -> MakeAmmoBox(aphelion_laser_ammo),
|
||||
"aphelion_immolation_cannon_ammo" -> MakeAmmoBox(aphelion_immolation_cannon_ammo),
|
||||
"aphelion_plasma_rocket_ammo" -> MakeAmmoBox(aphelion_plasma_rocket_ammo),
|
||||
"aphelion_ppa_ammo" -> MakeAmmoBox(aphelion_ppa_ammo),
|
||||
"aphelion_starfire_ammo" -> MakeAmmoBox(aphelion_starfire_ammo),
|
||||
"skyguard_flak_cannon_ammo" -> MakeAmmoBox(skyguard_flak_cannon_ammo),
|
||||
"flux_cannon_thresher_battery" -> MakeAmmoBox(flux_cannon_thresher_battery),
|
||||
"fluxpod_ammo" -> MakeAmmoBox(fluxpod_ammo),
|
||||
"pulse_battery" -> MakeAmmoBox(pulse_battery),
|
||||
"heavy_rail_beam_battery" -> MakeAmmoBox(heavy_rail_beam_battery),
|
||||
"15mmbullet" -> MakeAmmoBox(bullet_15mm),
|
||||
"colossus_100mm_cannon_ammo" -> MakeAmmoBox(colossus_100mm_cannon_ammo),
|
||||
"colossus_burster_ammo" -> MakeAmmoBox(colossus_burster_ammo),
|
||||
"colossus_cluster_bomb_ammo" -> MakeAmmoBox(colossus_cluster_bomb_ammo),
|
||||
"colossus_chaingun_ammo" -> MakeAmmoBox(colossus_chaingun_ammo),
|
||||
"colossus_tank_cannon_ammo" -> MakeAmmoBox(colossus_tank_cannon_ammo),
|
||||
"105mmbullet" -> MakeAmmoBox(bullet_105mm),
|
||||
"gauss_cannon_ammo" -> MakeAmmoBox(gauss_cannon_ammo),
|
||||
"peregrine_dual_machine_gun_ammo" -> MakeAmmoBox(peregrine_dual_machine_gun_ammo),
|
||||
"peregrine_mechhammer_ammo" -> MakeAmmoBox(peregrine_mechhammer_ammo),
|
||||
"peregrine_particle_cannon_ammo" -> MakeAmmoBox(peregrine_particle_cannon_ammo),
|
||||
"peregrine_rocket_pod_ammo" -> MakeAmmoBox(peregrine_rocket_pod_ammo),
|
||||
"peregrine_sparrow_ammo" -> MakeAmmoBox(peregrine_sparrow_ammo),
|
||||
"150mmbullet" -> MakeAmmoBox(bullet_150mm)
|
||||
)
|
||||
/**
|
||||
* A `Map` of operations for producing the `Tool` `Equipment` for infantry weapons.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
val infantryWeapons : Map[String, () => Equipment] = Map(
|
||||
"ilc9" -> MakeTool(ilc9),
|
||||
"repeater" -> MakeTool(repeater),
|
||||
"isp" -> MakeTool(isp), //amp
|
||||
"beamer" -> MakeTool(beamer),
|
||||
"suppressor" -> MakeTool(suppressor),
|
||||
"anniversary_guna" -> MakeTool(anniversary_guna), //tr stinger
|
||||
"anniversary_gun" -> MakeTool(anniversary_gun), //nc spear
|
||||
"anniversary_gunb" -> MakeTool(anniversary_gunb), //vs eraser
|
||||
"cycler" -> MakeTool(cycler),
|
||||
"gauss" -> MakeTool(gauss),
|
||||
"pulsar" -> MakeTool(pulsar),
|
||||
"punisher" -> MakeTool(punisher),
|
||||
"flechette" -> MakeTool(flechette),
|
||||
"spiker" -> MakeTool(spiker),
|
||||
"frag_grenade" -> MakeTool(frag_grenade),
|
||||
"jammer_grenade" -> MakeTool(jammer_grenade),
|
||||
"plasma_grenade" -> MakeTool(plasma_grenade),
|
||||
"katana" -> MakeTool(katana),
|
||||
"chainblade" -> MakeTool(chainblade),
|
||||
"magcutter" -> MakeTool(magcutter),
|
||||
"forceblade" -> MakeTool(forceblade),
|
||||
"mini_chaingun" -> MakeTool(mini_chaingun),
|
||||
"r_shotgun" -> MakeTool(r_shotgun), //jackhammer
|
||||
"lasher" -> MakeTool(lasher),
|
||||
"maelstrom" -> MakeTool(maelstrom),
|
||||
"striker" -> MakeTool(striker),
|
||||
"hunterseeker" -> MakeTool(hunterseeker), //phoenix
|
||||
"lancer" -> MakeTool(lancer),
|
||||
"phoenix" -> MakeTool(phoenix), //decimator
|
||||
"rocklet" -> MakeTool(rocklet),
|
||||
"thumper" -> MakeTool(thumper),
|
||||
"radiator" -> MakeTool(radiator),
|
||||
"heavy_sniper" -> MakeTool(heavy_sniper), //hsr
|
||||
"bolt_driver" -> MakeTool(bolt_driver),
|
||||
"oicw" -> MakeTool(oicw), //scorpion
|
||||
"flamethrower" -> MakeTool(flamethrower)
|
||||
)
|
||||
/**
|
||||
* A `Map` of operations for producing the `Tool` `Equipment` for utilities.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
val supportWeapons : Map[String, () => Equipment] = Map(
|
||||
"medkit" -> MakeKit(medkit),
|
||||
"super_medkit" -> MakeKit(super_medkit),
|
||||
"super_armorkit" -> MakeKit(super_armorkit),
|
||||
"super_staminakit" -> MakeKit(super_staminakit),
|
||||
"medicalapplicator" -> MakeTool(medicalapplicator),
|
||||
"bank" -> MakeTool(bank, armor_canister),
|
||||
"nano_dispenser" -> MakeTool(nano_dispenser),
|
||||
//TODO "ace" -> MakeConstructionItem(ace),
|
||||
//TODO "advanced_ace" -> MakeConstructionItem(advanced_ace),
|
||||
"remote_electronics_kit" -> MakeSimpleItem(remote_electronics_kit),
|
||||
"trek" -> MakeTool(trek),
|
||||
"command_detonater" -> MakeSimpleItem(command_detonater),
|
||||
"flail_targeting_laser" -> MakeSimpleItem(flail_targeting_laser)
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new `Tool` from provided `EquipmentDefinition` objects.
|
||||
* @param tdef the `ToolDefinition` object
|
||||
* @return a partial function that, when called, creates the piece of `Equipment`
|
||||
*/
|
||||
private def MakeTool(tdef : ToolDefinition)() : Tool = MakeTool(tdef, Nil)
|
||||
|
||||
/**
|
||||
* Create a new `Tool` from provided `EquipmentDefinition` objects.
|
||||
* @param tdef the `ToolDefinition` object
|
||||
* @param adef an `AmmoBoxDefinition` object
|
||||
* @return a partial function that, when called, creates the piece of `Equipment`
|
||||
*/
|
||||
private def MakeTool(tdef : ToolDefinition, adef : AmmoBoxDefinition)() : Tool = MakeTool(tdef, List(adef))
|
||||
|
||||
/**
|
||||
* Create a new `Tool` from provided `EquipmentDefinition` objects.
|
||||
* Only use this function to create default `Tools` with the default parameters.
|
||||
* For example, loadouts can retain `Tool` information that utilizes alternate, valid ammunition types;
|
||||
* and, this method function will not construct a complete object if provided that information.
|
||||
* @param tdef the `ToolDefinition` object
|
||||
* @param adefs a `List` of `AmmoBoxDefinition` objects
|
||||
* @return a curried function that, when called, creates the piece of `Equipment`
|
||||
* @see `GlobalDefinitions`
|
||||
* @see `OrderTerminalDefinition.BuildSimplifiedPattern`
|
||||
*/
|
||||
private def MakeTool(tdef : ToolDefinition, adefs : List[AmmoBoxDefinition])() : Tool = {
|
||||
val obj = Tool(tdef)
|
||||
adefs match {
|
||||
case _ :: _ =>
|
||||
LoadAmmunitionIntoWeapon(obj, adefs)
|
||||
case Nil => ; //as-is
|
||||
}
|
||||
obj
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a weapon, and custom ammunition profiles, attempt to load those boxes of ammunition into the weapon.<br>
|
||||
* <br>
|
||||
* This is a customization function that should normally go unused.
|
||||
* All of the information necessary to generate a `Tool` from a `Terminal` request should be available on the `ToolDefinition` object.
|
||||
* The ammunition information, regardless of "customization," must satisfy the type limits of the original definition.
|
||||
* As thus, to introduce very strange ammunition to a give `Tool`,
|
||||
* either the definition must be modified or a different definition must be used.
|
||||
* The custom ammunition is organized into order of ammunition slots based on the `FireModeDefinition` objects.
|
||||
* That is:
|
||||
* the first custom element is processed by the first ammunition slot;
|
||||
* the second custom element is processed by the second ammunition slot; and, so forth.
|
||||
* @param weapon the `Tool` object
|
||||
* @param adefs a sequential `List` of ammunition to be loaded into weapon
|
||||
* @see `AmmoBoxDefinition`
|
||||
* @see `FireModeDefinition`
|
||||
*/
|
||||
private def LoadAmmunitionIntoWeapon(weapon : Tool, adefs : List[AmmoBoxDefinition]) : Unit = {
|
||||
val definition = weapon.Definition
|
||||
(0 until math.min(weapon.MaxAmmoSlot, adefs.length)).foreach(index => {
|
||||
val ammoSlot = weapon.AmmoSlots(index)
|
||||
adefs.lift(index) match {
|
||||
case Some(aType) =>
|
||||
ammoSlot.AllAmmoTypes.indexOf(aType.AmmoType) match {
|
||||
case -1 =>
|
||||
log.warn(s"terminal plans do not match definition: can not feed ${aType.AmmoType} ammunition into Tool (${definition.ObjectId} @ ammo $index)")
|
||||
case n =>
|
||||
ammoSlot.AmmoTypeIndex = n
|
||||
ammoSlot.Box = MakeAmmoBox(aType, Some(definition.FireModes(index).Magazine)) //make new internal magazine, full
|
||||
}
|
||||
case None => ;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new `AmmoBox` from provided `EquipmentDefinition` objects.
|
||||
* @param adef the `AmmoBoxDefinition` object
|
||||
* @param capacity optional number of rounds in this `AmmoBox`, deviating from the `EquipmentDefinition`;
|
||||
* necessary for constructing the magazine (`AmmoSlot`) of `Tool`s
|
||||
* @return a curried function that, when called, creates the piece of `Equipment`
|
||||
* @see `GlobalDefinitions`
|
||||
*/
|
||||
private def MakeAmmoBox(adef : AmmoBoxDefinition, capacity : Option[Int] = None)() : AmmoBox = {
|
||||
capacity match {
|
||||
case Some(cap) =>
|
||||
AmmoBox(adef, cap)
|
||||
case None =>
|
||||
AmmoBox(adef)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new `Kit` from provided `EquipmentDefinition` objects.
|
||||
* @param kdef the `KitDefinition` object
|
||||
* @return a curried function that, when called, creates the piece of `Equipment`
|
||||
* @see `GlobalDefinitions`
|
||||
*/
|
||||
private def MakeKit(kdef : KitDefinition)() : Kit = Kit(kdef)
|
||||
|
||||
/**
|
||||
* Create a new `SimpleItem` from provided `EquipmentDefinition` objects.
|
||||
* @param sdef the `SimpleItemDefinition` object
|
||||
* @return a curried function that, when called, creates the piece of `Equipment`
|
||||
* @see `GlobalDefinitions`
|
||||
*/
|
||||
private def MakeSimpleItem(sdef : SimpleItemDefinition)() : SimpleItem = SimpleItem(sdef)
|
||||
|
||||
/**
|
||||
* Create a new `ConstructionItem` from provided `EquipmentDefinition` objects.
|
||||
* @param cdef the `ConstructionItemDefinition` object
|
||||
* @return a curried function that, when called, creates the piece of `Equipment`
|
||||
* @see `GlobalDefinitions`
|
||||
*/
|
||||
private def MakeConstructionItem(cdef : ConstructionItemDefinition)() : ConstructionItem = ConstructionItem(cdef)
|
||||
|
||||
/**
|
||||
* Accept a simplified blueprint for some piece of `Equipment` and create an actual piece of `Equipment` based on it.
|
||||
* Used specifically for the reconstruction of `Equipment` via an `Loadout`.
|
||||
* @param entry the simplified blueprint
|
||||
* @return some `Equipment` object
|
||||
* @see `TerminalDefinition.MakeTool`<br>
|
||||
* `TerminalDefinition.MakeAmmoBox`<br>
|
||||
* `TerminalDefinition.MakeSimpleItem`<br>
|
||||
* `TerminalDefinition.MakeConstructionItem`<br>
|
||||
* `TerminalDefinition.MakeKit`
|
||||
*/
|
||||
def BuildSimplifiedPattern(entry : Loadout.Simplification) : Equipment = {
|
||||
import net.psforever.objects.Loadout._
|
||||
entry match {
|
||||
case obj : ShorthandTool =>
|
||||
val ammo : List[AmmoBoxDefinition] = obj.ammo.map(fmode => { fmode.ammo.adef })
|
||||
val tool = Tool(obj.tdef)
|
||||
//makes Tools where an ammo slot may have one of its alternate ammo types
|
||||
(0 until tool.MaxAmmoSlot).foreach(index => {
|
||||
val slot = tool.AmmoSlots(index)
|
||||
slot.AmmoTypeIndex += obj.ammo(index).ammoIndex
|
||||
slot.Box = MakeAmmoBox(ammo(index), Some(obj.ammo(index).ammo.capacity))
|
||||
})
|
||||
tool
|
||||
|
||||
case obj : ShorthandAmmoBox =>
|
||||
MakeAmmoBox(obj.adef, Some(obj.capacity))
|
||||
|
||||
case obj : ShorthandConstructionItem =>
|
||||
MakeConstructionItem(obj.cdef)
|
||||
|
||||
case obj : ShorthandSimpleItem =>
|
||||
MakeSimpleItem(obj.sdef)
|
||||
|
||||
case obj : ShorthandKit =>
|
||||
MakeKit(obj.kdef)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.packet.game.ItemTransactionMessage
|
||||
|
||||
class GroundVehicleTerminalDefinition extends TerminalDefinition(386) {
|
||||
class GroundVehicleTerminalDefinition extends VehicleTerminalDefinition(386) {
|
||||
vehicles = groundVehicles
|
||||
Name = "ground_vehicle_terminal"
|
||||
|
||||
def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
||||
groundVehicles.get(msg.item_name) match {
|
||||
case Some(vehicle) =>
|
||||
Terminal.BuyVehicle(vehicle(), Nil)
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ import net.psforever.packet.game.objectcreate.ObjectClass
|
|||
* attached as a child of the visible implant terminal component - the "implant_terminal_mech."
|
||||
*/
|
||||
class ImplantTerminalInterfaceDefinition extends TerminalDefinition(ObjectClass.implant_terminal_interface) {
|
||||
Packet = new ImplantTerminalInterfaceConverter
|
||||
Name = "implante_terminal_interface"
|
||||
|
||||
private val implants : Map[String, ImplantDefinition] = Map (
|
||||
"advanced_regen" -> GlobalDefinitions.advanced_regen,
|
||||
"targeting" -> GlobalDefinitions.targeting,
|
||||
|
|
@ -27,8 +30,6 @@ class ImplantTerminalInterfaceDefinition extends TerminalDefinition(ObjectClass.
|
|||
"silent_run" -> GlobalDefinitions.silent_run,
|
||||
"surge" -> GlobalDefinitions.surge
|
||||
)
|
||||
Packet = new ImplantTerminalInterfaceConverter
|
||||
Name = "implante_terminal_interface"
|
||||
|
||||
def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
||||
implants.get(msg.item_name) match {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import net.psforever.objects.Loadout.Simplification
|
||||
import net.psforever.objects.{Player, Tool}
|
||||
import net.psforever.objects.definition._
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.inventory.InventoryItem
|
||||
import net.psforever.packet.game.ItemTransactionMessage
|
||||
import net.psforever.objects.serverobject.terminals.EquipmentTerminalDefinition._
|
||||
|
||||
import scala.annotation.switch
|
||||
|
||||
|
|
@ -15,7 +14,7 @@ import scala.annotation.switch
|
|||
* `Buy` and `Sell` `Equipment` items and `AmmoBox` items.
|
||||
* Change `ExoSuitType` and retrieve `Loadout` entries.
|
||||
*/
|
||||
class OrderTerminalDefinition extends TerminalDefinition(612) {
|
||||
class OrderTerminalDefinition extends EquipmentTerminalDefinition(612) {
|
||||
Name = "order_terminal"
|
||||
|
||||
/**
|
||||
|
|
@ -91,7 +90,7 @@ class OrderTerminalDefinition extends TerminalDefinition(612) {
|
|||
if(msg.item_page == 4) { //Favorites tab
|
||||
player.LoadLoadout(msg.unk1) match {
|
||||
case Some(loadout) =>
|
||||
val holsters = loadout.Holsters.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) })
|
||||
val holsters = loadout.VisibleSlots.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) })
|
||||
val inventory = loadout.Inventory.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) })
|
||||
Terminal.InfantryLoadout(loadout.ExoSuit, loadout.Subtype, holsters, inventory)
|
||||
case None =>
|
||||
|
|
@ -102,43 +101,4 @@ class OrderTerminalDefinition extends TerminalDefinition(612) {
|
|||
Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept a simplified blueprint for some piece of `Equipment` and create an actual piece of `Equipment` based on it.
|
||||
* Used specifically for the reconstruction of `Equipment` via an `Loadout`.
|
||||
* @param entry the simplified blueprint
|
||||
* @return some `Equipment` object
|
||||
* @see `TerminalDefinition.MakeTool`<br>
|
||||
* `TerminalDefinition.MakeAmmoBox`<br>
|
||||
* `TerminalDefinition.MakeSimpleItem`<br>
|
||||
* `TerminalDefinition.MakeConstructionItem`<br>
|
||||
* `TerminalDefinition.MakeKit`
|
||||
*/
|
||||
private def BuildSimplifiedPattern(entry : Simplification) : Equipment = {
|
||||
import net.psforever.objects.Loadout._
|
||||
entry match {
|
||||
case obj : ShorthandTool =>
|
||||
val ammo : List[AmmoBoxDefinition] = obj.ammo.map(fmode => { fmode.ammo.adef })
|
||||
val tool = Tool(obj.tdef)
|
||||
//makes Tools where an ammo slot may have one of its alternate ammo types
|
||||
(0 until tool.MaxAmmoSlot).foreach(index => {
|
||||
val slot = tool.AmmoSlots(index)
|
||||
slot.AmmoTypeIndex += obj.ammo(index).ammoIndex
|
||||
slot.Box = MakeAmmoBox(ammo(index), Some(obj.ammo(index).ammo.capacity))
|
||||
})
|
||||
tool
|
||||
|
||||
case obj : ShorthandAmmoBox =>
|
||||
MakeAmmoBox(obj.adef, Some(obj.capacity))
|
||||
|
||||
case obj : ShorthandConstructionItem =>
|
||||
MakeConstructionItem(obj.cdef)
|
||||
|
||||
case obj : ShorthandSimpleItem =>
|
||||
MakeSimpleItem(obj.sdef)
|
||||
|
||||
case obj : ShorthandKit =>
|
||||
MakeKit(obj.kdef)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,9 +168,10 @@ object Terminal {
|
|||
/**
|
||||
* Provide a vehicle that was constructed for the player.
|
||||
* @param vehicle the vehicle
|
||||
* @param loadout the vehicle's trunk contents
|
||||
* @param weapons the vehicle's mounted armament
|
||||
* @param inventory the vehicle's trunk contents
|
||||
*/
|
||||
final case class BuyVehicle(vehicle : Vehicle, loadout: List[Any]) extends Exchange
|
||||
final case class BuyVehicle(vehicle : Vehicle, weapons : List[InventoryItem], inventory : List[InventoryItem]) extends Exchange
|
||||
|
||||
/**
|
||||
* Recover a former exo-suit and `Equipment` configuration that the `Player` possessed.
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.definition._
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.packet.game.ItemTransactionMessage
|
||||
import net.psforever.types.ExoSuitType
|
||||
|
||||
/**
|
||||
* The basic definition for any `Terminal`.
|
||||
* @param objectId the object's identifier number
|
||||
*/
|
||||
abstract class TerminalDefinition(objectId : Int) extends ObjectDefinition(objectId) {
|
||||
private[this] val log = org.log4s.getLogger("TerminalDefinition")
|
||||
abstract class TerminalDefinition(objectId : Int) extends net.psforever.objects.definition.ObjectDefinition(objectId) {
|
||||
Name = "terminal"
|
||||
|
||||
/**
|
||||
|
|
@ -23,359 +19,10 @@ abstract class TerminalDefinition(objectId : Int) extends ObjectDefinition(objec
|
|||
/**
|
||||
* The unimplemented functionality for this `Terminal`'s `TransactionType.Sell` activity.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal()
|
||||
|
||||
/**
|
||||
* A `Map` of information for changing exo-suits.
|
||||
* key - an identification string sent by the client
|
||||
* value - a `Tuple` containing exo-suit specifications
|
||||
*/
|
||||
protected val suits : Map[String, (ExoSuitType.Value, Int)] = Map(
|
||||
"standard_issue_armor" -> (ExoSuitType.Standard, 0),
|
||||
"lite_armor" -> (ExoSuitType.Agile, 0),
|
||||
"med_armor" -> (ExoSuitType.Reinforced, 0)
|
||||
//TODO max and infiltration suit
|
||||
)
|
||||
|
||||
import net.psforever.objects.GlobalDefinitions._
|
||||
/**
|
||||
* A `Map` of operations for producing the `AmmoBox` `Equipment` for infantry-held weaponry.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val infantryAmmunition : Map[String, ()=>Equipment] = Map(
|
||||
"9mmbullet" -> MakeAmmoBox(bullet_9mm),
|
||||
"9mmbullet_AP" -> MakeAmmoBox(bullet_9mm_AP),
|
||||
"shotgun_shell" -> MakeAmmoBox(shotgun_shell),
|
||||
"shotgun_shell_AP" -> MakeAmmoBox(shotgun_shell_AP),
|
||||
"energy_cell" -> MakeAmmoBox(energy_cell),
|
||||
"anniversary_ammo" -> MakeAmmoBox(anniversary_ammo), //10mm multi-phase
|
||||
"rocket" -> MakeAmmoBox(rocket),
|
||||
"frag_cartridge" -> MakeAmmoBox(frag_cartridge),
|
||||
"jammer_cartridge" -> MakeAmmoBox(jammer_cartridge),
|
||||
"plasma_cartridge" -> MakeAmmoBox(plasma_cartridge),
|
||||
"ancient_ammo_combo" -> MakeAmmoBox(ancient_ammo_combo),
|
||||
"maelstrom_ammo" -> MakeAmmoBox(maelstrom_ammo),
|
||||
"striker_missile_ammo" -> MakeAmmoBox(striker_missile_ammo),
|
||||
"hunter_seeker_missile" -> MakeAmmoBox(hunter_seeker_missile), //phoenix missile
|
||||
"lancer_cartridge" -> MakeAmmoBox(lancer_cartridge),
|
||||
"bolt" -> MakeAmmoBox(bolt),
|
||||
"oicw_ammo" -> MakeAmmoBox(oicw_ammo), //scorpion missile
|
||||
"flamethrower_ammo" -> MakeAmmoBox(flamethrower_ammo)
|
||||
)
|
||||
|
||||
/**
|
||||
* A `Map` of operations for producing the `AmmoBox` `Equipment` for infantry-held utilities.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val supportAmmunition : Map[String, ()=>Equipment] = Map(
|
||||
"health_canister" -> MakeAmmoBox(health_canister),
|
||||
"armor_canister" -> MakeAmmoBox(armor_canister),
|
||||
"upgrade_canister" -> MakeAmmoBox(upgrade_canister)
|
||||
)
|
||||
|
||||
/**
|
||||
* A `Map` of operations for producing the `AmmoBox` `Equipment` for vehicle-mounted weaponry.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val vehicleAmmunition : Map[String, ()=>Equipment] = Map(
|
||||
"35mmbullet" -> MakeAmmoBox(bullet_35mm),
|
||||
"hellfire_ammo" -> MakeAmmoBox(hellfire_ammo),
|
||||
"liberator_bomb" -> MakeAmmoBox(liberator_bomb),
|
||||
"25mmbullet" -> MakeAmmoBox(bullet_25mm),
|
||||
"75mmbullet" -> MakeAmmoBox(bullet_75mm),
|
||||
"heavy_grenade_mortar" -> MakeAmmoBox(heavy_grenade_mortar),
|
||||
"reaver_rocket" -> MakeAmmoBox(reaver_rocket),
|
||||
"20mmbullet" -> MakeAmmoBox(bullet_20mm),
|
||||
"12mmbullet" -> MakeAmmoBox(bullet_12mm),
|
||||
"wasp_rocket_ammo" -> MakeAmmoBox(wasp_rocket_ammo),
|
||||
"wasp_gun_ammo" -> MakeAmmoBox(wasp_gun_ammo),
|
||||
"aphelion_laser_ammo" -> MakeAmmoBox(aphelion_laser_ammo),
|
||||
"aphelion_immolation_cannon_ammo" -> MakeAmmoBox(aphelion_immolation_cannon_ammo),
|
||||
"aphelion_plasma_rocket_ammo" -> MakeAmmoBox(aphelion_plasma_rocket_ammo),
|
||||
"aphelion_ppa_ammo" -> MakeAmmoBox(aphelion_ppa_ammo),
|
||||
"aphelion_starfire_ammo" -> MakeAmmoBox(aphelion_starfire_ammo),
|
||||
"skyguard_flak_cannon_ammo" -> MakeAmmoBox(skyguard_flak_cannon_ammo),
|
||||
"flux_cannon_thresher_battery" -> MakeAmmoBox(flux_cannon_thresher_battery),
|
||||
"fluxpod_ammo" -> MakeAmmoBox(fluxpod_ammo),
|
||||
"pulse_battery" -> MakeAmmoBox(pulse_battery),
|
||||
"heavy_rail_beam_battery" -> MakeAmmoBox(heavy_rail_beam_battery),
|
||||
"15mmbullet" -> MakeAmmoBox(bullet_15mm),
|
||||
"colossus_100mm_cannon_ammo" -> MakeAmmoBox(colossus_100mm_cannon_ammo),
|
||||
"colossus_burster_ammo" -> MakeAmmoBox(colossus_burster_ammo),
|
||||
"colossus_cluster_bomb_ammo" -> MakeAmmoBox(colossus_cluster_bomb_ammo),
|
||||
"colossus_chaingun_ammo" -> MakeAmmoBox(colossus_chaingun_ammo),
|
||||
"colossus_tank_cannon_ammo" -> MakeAmmoBox(colossus_tank_cannon_ammo),
|
||||
"105mmbullet" -> MakeAmmoBox(bullet_105mm),
|
||||
"gauss_cannon_ammo" -> MakeAmmoBox(gauss_cannon_ammo),
|
||||
"peregrine_dual_machine_gun_ammo" -> MakeAmmoBox(peregrine_dual_machine_gun_ammo),
|
||||
"peregrine_mechhammer_ammo" -> MakeAmmoBox(peregrine_mechhammer_ammo),
|
||||
"peregrine_particle_cannon_ammo" -> MakeAmmoBox(peregrine_particle_cannon_ammo),
|
||||
"peregrine_rocket_pod_ammo" -> MakeAmmoBox(peregrine_rocket_pod_ammo),
|
||||
"peregrine_sparrow_ammo" -> MakeAmmoBox(peregrine_sparrow_ammo),
|
||||
"150mmbullet" -> MakeAmmoBox(bullet_150mm)
|
||||
)
|
||||
|
||||
/**
|
||||
* A `Map` of operations for producing the `Tool` `Equipment` for infantry weapons.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val infantryWeapons : Map[String, ()=>Equipment] = Map(
|
||||
"ilc9" -> MakeTool(ilc9),
|
||||
"repeater" -> MakeTool(repeater),
|
||||
"isp" -> MakeTool(isp), //amp
|
||||
"beamer" -> MakeTool(beamer),
|
||||
"suppressor" -> MakeTool(suppressor),
|
||||
"anniversary_guna" -> MakeTool(anniversary_guna), //tr stinger
|
||||
"anniversary_gun" -> MakeTool(anniversary_gun), //nc spear
|
||||
"anniversary_gunb" -> MakeTool(anniversary_gunb), //vs eraser
|
||||
"cycler" -> MakeTool(cycler),
|
||||
"gauss" -> MakeTool(gauss),
|
||||
"pulsar" -> MakeTool(pulsar),
|
||||
"punisher" -> MakeTool(punisher),
|
||||
"flechette" -> MakeTool(flechette),
|
||||
"spiker" -> MakeTool(spiker),
|
||||
"frag_grenade" -> MakeTool(frag_grenade),
|
||||
"jammer_grenade" -> MakeTool(jammer_grenade),
|
||||
"plasma_grenade" -> MakeTool(plasma_grenade),
|
||||
"katana" -> MakeTool(katana),
|
||||
"chainblade" -> MakeTool(chainblade),
|
||||
"magcutter" -> MakeTool(magcutter),
|
||||
"forceblade" -> MakeTool(forceblade),
|
||||
"mini_chaingun" -> MakeTool(mini_chaingun),
|
||||
"r_shotgun" -> MakeTool(r_shotgun), //jackhammer
|
||||
"lasher" -> MakeTool(lasher),
|
||||
"maelstrom" -> MakeTool(maelstrom),
|
||||
"striker" -> MakeTool(striker),
|
||||
"hunterseeker" -> MakeTool(hunterseeker), //phoenix
|
||||
"lancer" -> MakeTool(lancer),
|
||||
"phoenix" -> MakeTool(phoenix), //decimator
|
||||
"rocklet" -> MakeTool(rocklet),
|
||||
"thumper" -> MakeTool(thumper),
|
||||
"radiator" -> MakeTool(radiator),
|
||||
"heavy_sniper" -> MakeTool(heavy_sniper), //hsr
|
||||
"bolt_driver" -> MakeTool(bolt_driver),
|
||||
"oicw" -> MakeTool(oicw), //scorpion
|
||||
"flamethrower" -> MakeTool(flamethrower)
|
||||
)
|
||||
|
||||
/**
|
||||
* A `Map` of operations for producing the `Tool` `Equipment` for utilities.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val supportWeapons : Map[String, ()=>Equipment] = Map(
|
||||
"medkit" -> MakeKit(medkit),
|
||||
"super_medkit" -> MakeKit(super_medkit),
|
||||
"super_armorkit" -> MakeKit(super_armorkit),
|
||||
"super_staminakit" -> MakeKit(super_staminakit),
|
||||
"medicalapplicator" -> MakeTool(medicalapplicator),
|
||||
"bank" -> MakeTool(bank, armor_canister),
|
||||
"nano_dispenser" -> MakeTool(nano_dispenser),
|
||||
//TODO "ace" -> MakeConstructionItem(ace),
|
||||
//TODO "advanced_ace" -> MakeConstructionItem(advanced_ace),
|
||||
"remote_electronics_kit" -> MakeSimpleItem(remote_electronics_kit),
|
||||
"trek" -> MakeTool(trek),
|
||||
"command_detonater" -> MakeSimpleItem(command_detonater),
|
||||
"flail_targeting_laser" -> MakeSimpleItem(flail_targeting_laser)
|
||||
)
|
||||
|
||||
/**
|
||||
* A `Map` of operations for producing a ground-based `Vehicle`.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val groundVehicles : Map[String, ()=>Vehicle] = Map(
|
||||
"quadassault" -> MakeVehicle(quadassault),
|
||||
"fury" -> MakeVehicle(fury),
|
||||
"quadstealth" -> MakeVehicle(quadstealth),
|
||||
"ant" -> MakeVehicle(ant),
|
||||
"ams" -> MakeVehicle(ams),
|
||||
"mediumtransport" -> MakeVehicle(mediumtransport),
|
||||
"two_man_assault_buggy" -> MakeVehicle(two_man_assault_buggy),
|
||||
"skyguard" -> MakeVehicle(skyguard),
|
||||
"lightning" -> MakeVehicle(lightning),
|
||||
"threemanheavybuggy" -> MakeVehicle(threemanheavybuggy),
|
||||
"battlewagon" -> MakeVehicle(battlewagon),
|
||||
"apc_tr" -> MakeVehicle(apc_tr),
|
||||
"prowler" -> MakeVehicle(prowler),
|
||||
"twomanheavybuggy" -> MakeVehicle(twomanheavybuggy),
|
||||
"thunderer" -> MakeVehicle(thunderer),
|
||||
"apc_nc" -> MakeVehicle(apc_nc),
|
||||
"vanguard" -> MakeVehicle(vanguard),
|
||||
"twomanhoverbuggy" -> MakeVehicle(twomanhoverbuggy),
|
||||
"aurora" -> MakeVehicle(aurora),
|
||||
"apc_vs" -> MakeVehicle(apc_vs),
|
||||
"magrider" -> MakeVehicle(magrider),
|
||||
"flail" -> MakeVehicle(flail),
|
||||
"switchblade" -> MakeVehicle(switchblade),
|
||||
"router" -> MakeVehicle(router)
|
||||
)
|
||||
|
||||
/**
|
||||
* A `Map` of operations for producing most flight-based `Vehicle`.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val flight1Vehicles : Map[String, ()=>Vehicle] = Map(
|
||||
"mosquito" -> MakeVehicle(mosquito),
|
||||
"lightgunship" -> MakeVehicle(lightgunship),
|
||||
"wasp" -> MakeVehicle(wasp),
|
||||
"phantasm" -> MakeVehicle(phantasm),
|
||||
"vulture" -> MakeVehicle(vulture),
|
||||
"liberator" -> MakeVehicle(liberator)
|
||||
)
|
||||
|
||||
/**
|
||||
* A `Map` of operations for producing a flight-based `Vehicle` specific to the dropship terminal.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val flight2Vehicles : Map[String, ()=>Vehicle] = Map(
|
||||
"dropship" -> MakeVehicle(dropship),
|
||||
"galaxy_gunship" -> MakeVehicle(galaxy_gunship),
|
||||
"lodestar" -> MakeVehicle(lodestar)
|
||||
)
|
||||
|
||||
/**
|
||||
* A `Map` of operations for producing a ground-based `Vehicle` specific to the bfr terminal.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val bfrVehicles : Map[String, ()=>Vehicle] = Map(
|
||||
// "colossus_gunner" -> (()=>Unit),
|
||||
// "colossus_flight" -> (()=>Unit),
|
||||
// "peregrine_gunner" -> (()=>Unit),
|
||||
// "peregrine_flight" -> (()=>Unit),
|
||||
// "aphelion_gunner" -> (()=>Unit),
|
||||
// "aphelion_flight" -> (()=>Unit)
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new `Tool` from provided `EquipmentDefinition` objects.
|
||||
* @param tdef the `ToolDefinition` object
|
||||
* @return a partial function that, when called, creates the piece of `Equipment`
|
||||
*/
|
||||
protected def MakeTool(tdef : ToolDefinition)() : Tool = MakeTool(tdef, Nil)
|
||||
|
||||
/**
|
||||
* Create a new `Tool` from provided `EquipmentDefinition` objects.
|
||||
* @param tdef the `ToolDefinition` object
|
||||
* @param adef an `AmmoBoxDefinition` object
|
||||
* @return a partial function that, when called, creates the piece of `Equipment`
|
||||
*/
|
||||
protected def MakeTool(tdef : ToolDefinition, adef : AmmoBoxDefinition)() : Tool = MakeTool(tdef, List(adef))
|
||||
|
||||
/**
|
||||
* Create a new `Tool` from provided `EquipmentDefinition` objects.
|
||||
* Only use this function to create default `Tools` with the default parameters.
|
||||
* For example, loadouts can retain `Tool` information that utilizes alternate, valid ammunition types;
|
||||
* and, this method function will not construct a complete object if provided that information.
|
||||
* @param tdef the `ToolDefinition` object
|
||||
* @param adefs a `List` of `AmmoBoxDefinition` objects
|
||||
* @return a curried function that, when called, creates the piece of `Equipment`
|
||||
* @see `GlobalDefinitions`
|
||||
* @see `OrderTerminalDefinition.BuildSimplifiedPattern`
|
||||
*/
|
||||
protected def MakeTool(tdef : ToolDefinition, adefs : List[AmmoBoxDefinition])() : Tool = {
|
||||
val obj = Tool(tdef)
|
||||
adefs match {
|
||||
case _ :: _ =>
|
||||
LoadAmmunitionIntoWeapon(obj, adefs)
|
||||
case Nil => ; //as-is
|
||||
}
|
||||
obj
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a weapon, and custom ammunition profiles, attempt to load those boxes of ammunition into the weapon.<br>
|
||||
* <br>
|
||||
* This is a customization function that should normally go unused.
|
||||
* All of the information necessary to generate a `Tool` from a `Terminal` request should be available on the `ToolDefinition` object.
|
||||
* The ammunition information, regardless of "customization," must satisfy the type limits of the original definition.
|
||||
* As thus, to introduce very strange ammunition to a give `Tool`,
|
||||
* either the definition must be modified or a different definition must be used.
|
||||
* The custom ammunition is organized into order of ammunition slots based on the `FireModeDefinition` objects.
|
||||
* That is:
|
||||
* the first custom element is processed by the first ammunition slot;
|
||||
* the second custom element is processed by the second ammunition slot; and, so forth.
|
||||
* @param weapon the `Tool` object
|
||||
* @param adefs a sequential `List` of ammunition to be loaded into weapon
|
||||
* @see `AmmoBoxDefinition`
|
||||
* @see `FireModeDefinition`
|
||||
*/
|
||||
private def LoadAmmunitionIntoWeapon(weapon : Tool, adefs : List[AmmoBoxDefinition]) : Unit = {
|
||||
val definition = weapon.Definition
|
||||
(0 until math.min(weapon.MaxAmmoSlot, adefs.length)).foreach(index => {
|
||||
val ammoSlot = weapon.AmmoSlots(index)
|
||||
adefs.lift(index) match {
|
||||
case Some(aType) =>
|
||||
ammoSlot.AllAmmoTypes.indexOf(aType.AmmoType) match {
|
||||
case -1 =>
|
||||
log.warn(s"terminal plans do not match definition: can not feed ${aType.AmmoType} ammunition into Tool (${definition.ObjectId} @ ammo $index)")
|
||||
case n =>
|
||||
ammoSlot.AmmoTypeIndex = n
|
||||
ammoSlot.Box = MakeAmmoBox(aType, Some(definition.FireModes(index).Magazine)) //make new internal magazine, full
|
||||
}
|
||||
case None => ;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new `AmmoBox` from provided `EquipmentDefinition` objects.
|
||||
* @param adef the `AmmoBoxDefinition` object
|
||||
* @param capacity optional number of rounds in this `AmmoBox`, deviating from the `EquipmentDefinition`;
|
||||
* necessary for constructing the magazine (`AmmoSlot`) of `Tool`s
|
||||
* @return a curried function that, when called, creates the piece of `Equipment`
|
||||
* @see `GlobalDefinitions`
|
||||
*/
|
||||
protected def MakeAmmoBox(adef : AmmoBoxDefinition, capacity : Option[Int] = None)() : AmmoBox = {
|
||||
capacity match {
|
||||
case Some(cap) =>
|
||||
AmmoBox(adef, cap)
|
||||
case None =>
|
||||
AmmoBox(adef)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new `Kit` from provided `EquipmentDefinition` objects.
|
||||
* @param kdef the `KitDefinition` object
|
||||
* @return a curried function that, when called, creates the piece of `Equipment`
|
||||
* @see `GlobalDefinitions`
|
||||
*/
|
||||
protected def MakeKit(kdef : KitDefinition)() : Kit = Kit(kdef)
|
||||
|
||||
/**
|
||||
* Create a new `SimpleItem` from provided `EquipmentDefinition` objects.
|
||||
* @param sdef the `SimpleItemDefinition` object
|
||||
* @return a curried function that, when called, creates the piece of `Equipment`
|
||||
* @see `GlobalDefinitions`
|
||||
*/
|
||||
protected def MakeSimpleItem(sdef : SimpleItemDefinition)() : SimpleItem = SimpleItem(sdef)
|
||||
|
||||
/**
|
||||
* Create a new `ConstructionItem` from provided `EquipmentDefinition` objects.
|
||||
* @param cdef the `ConstructionItemDefinition` object
|
||||
* @return a curried function that, when called, creates the piece of `Equipment`
|
||||
* @see `GlobalDefinitions`
|
||||
*/
|
||||
protected def MakeConstructionItem(cdef : ConstructionItemDefinition)() : ConstructionItem = ConstructionItem(cdef)
|
||||
|
||||
/**
|
||||
* Create a new `Vehicle` from provided `VehicleDefinition` objects.
|
||||
* @param vdef the `VehicleDefinition` object
|
||||
* @return a curried function that, when called, creates the `Vehicle`
|
||||
* @see `GlobalDefinitions`
|
||||
*/
|
||||
protected def MakeVehicle(vdef : VehicleDefinition)() : Vehicle = Vehicle(vdef)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.packet.game.ItemTransactionMessage
|
||||
|
||||
class VehicleTerminalCombinedDefinition extends TerminalDefinition(952) {
|
||||
private val vehicles = groundVehicles ++ flight1Vehicles
|
||||
class VehicleTerminalCombinedDefinition extends VehicleTerminalDefinition(952) {
|
||||
vehicles = groundVehicles ++ flight1Vehicles
|
||||
Name = "vehicle_terminal_combined"
|
||||
|
||||
def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
||||
vehicles.get(msg.item_name) match {
|
||||
case Some(vehicle) =>
|
||||
Terminal.BuyVehicle(vehicle(), Nil)
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,487 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import net.psforever.objects.definition.VehicleDefinition
|
||||
import net.psforever.objects.{Player, Vehicle}
|
||||
import net.psforever.objects.inventory.InventoryItem
|
||||
import net.psforever.packet.game.ItemTransactionMessage
|
||||
|
||||
abstract class VehicleTerminalDefinition(objId : Int) extends TerminalDefinition(objId) {
|
||||
protected var vehicles : Map[String, ()=>Vehicle] = Map()
|
||||
Name = "vehicle_terminal"
|
||||
|
||||
import net.psforever.objects.GlobalDefinitions._
|
||||
import VehicleTerminalDefinition.MakeVehicle
|
||||
/**
|
||||
* A `Map` of operations for producing a ground-based `Vehicle`.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val groundVehicles : Map[String, () => Vehicle] = Map(
|
||||
"quadassault" -> MakeVehicle(quadassault),
|
||||
"fury" -> MakeVehicle(fury),
|
||||
"quadstealth" -> MakeVehicle(quadstealth),
|
||||
"ant" -> MakeVehicle(ant),
|
||||
"ams" -> MakeVehicle(ams),
|
||||
"mediumtransport" -> MakeVehicle(mediumtransport),
|
||||
"two_man_assault_buggy" -> MakeVehicle(two_man_assault_buggy),
|
||||
"skyguard" -> MakeVehicle(skyguard),
|
||||
"lightning" -> MakeVehicle(lightning),
|
||||
"threemanheavybuggy" -> MakeVehicle(threemanheavybuggy),
|
||||
"battlewagon" -> MakeVehicle(battlewagon),
|
||||
"apc_tr" -> MakeVehicle(apc_tr),
|
||||
"prowler" -> MakeVehicle(prowler),
|
||||
"twomanheavybuggy" -> MakeVehicle(twomanheavybuggy),
|
||||
"thunderer" -> MakeVehicle(thunderer),
|
||||
"apc_nc" -> MakeVehicle(apc_nc),
|
||||
"vanguard" -> MakeVehicle(vanguard),
|
||||
"twomanhoverbuggy" -> MakeVehicle(twomanhoverbuggy),
|
||||
"aurora" -> MakeVehicle(aurora),
|
||||
"apc_vs" -> MakeVehicle(apc_vs),
|
||||
"magrider" -> MakeVehicle(magrider),
|
||||
"flail" -> MakeVehicle(flail),
|
||||
"switchblade" -> MakeVehicle(switchblade),
|
||||
"router" -> MakeVehicle(router)
|
||||
)
|
||||
|
||||
/**
|
||||
* A `Map` of operations for producing most flight-based `Vehicle`.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val flight1Vehicles : Map[String, ()=>Vehicle] = Map(
|
||||
"mosquito" -> MakeVehicle(mosquito),
|
||||
"lightgunship" -> MakeVehicle(lightgunship),
|
||||
"wasp" -> MakeVehicle(wasp),
|
||||
"phantasm" -> MakeVehicle(phantasm),
|
||||
"vulture" -> MakeVehicle(vulture),
|
||||
"liberator" -> MakeVehicle(liberator)
|
||||
)
|
||||
|
||||
/**
|
||||
* A `Map` of operations for producing a flight-based `Vehicle` specific to the dropship terminal.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val flight2Vehicles : Map[String, ()=>Vehicle] = Map(
|
||||
"dropship" -> MakeVehicle(dropship),
|
||||
"galaxy_gunship" -> MakeVehicle(galaxy_gunship),
|
||||
"lodestar" -> MakeVehicle(lodestar)
|
||||
)
|
||||
|
||||
/**
|
||||
* A `Map` of operations for producing a ground-based `Vehicle` specific to the bfr terminal.
|
||||
* key - an identification string sent by the client
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val bfrVehicles : Map[String, ()=>Vehicle] = Map(
|
||||
// "colossus_gunner" -> (()=>Unit),
|
||||
// "colossus_flight" -> (()=>Unit),
|
||||
// "peregrine_gunner" -> (()=>Unit),
|
||||
// "peregrine_flight" -> (()=>Unit),
|
||||
// "aphelion_gunner" -> (()=>Unit),
|
||||
// "aphelion_flight" -> (()=>Unit)
|
||||
)
|
||||
|
||||
import net.psforever.objects.{Loadout => _Loadout} //distinguish from Terminal.Loadout message
|
||||
import _Loadout._
|
||||
/**
|
||||
* A `Map` of the default contents of a `Vehicle` inventory, called the trunk.
|
||||
* key - an identification string sent by the client (for the vehicle)
|
||||
* value - a curried function that builds the object
|
||||
*/
|
||||
protected val trunk : Map[String, _Loadout] = {
|
||||
val ammo_12mm = ShorthandAmmoBox(bullet_12mm, bullet_12mm.Capacity)
|
||||
val ammo_15mm = ShorthandAmmoBox(bullet_15mm, bullet_15mm.Capacity)
|
||||
val ammo_25mm = ShorthandAmmoBox(bullet_25mm, bullet_25mm.Capacity)
|
||||
val ammo_35mm = ShorthandAmmoBox(bullet_35mm, bullet_35mm.Capacity)
|
||||
val ammo_20mm = ShorthandAmmoBox(bullet_20mm, bullet_20mm.Capacity)
|
||||
val ammo_75mm = ShorthandAmmoBox(bullet_75mm, bullet_75mm.Capacity)
|
||||
val ammo_mortar = ShorthandAmmoBox(heavy_grenade_mortar, heavy_grenade_mortar.Capacity)
|
||||
val ammo_flux = ShorthandAmmoBox(flux_cannon_thresher_battery, flux_cannon_thresher_battery.Capacity)
|
||||
val ammo_bomb = ShorthandAmmoBox(liberator_bomb, liberator_bomb.Capacity)
|
||||
Map(
|
||||
//"quadstealth" -> _Loadout("default_quadstealth", List(), List()),
|
||||
"quadassault" -> _Loadout("default_quadassault", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_12mm, 30),
|
||||
SimplifiedEntry(ammo_12mm, 34),
|
||||
SimplifiedEntry(ammo_12mm, 74),
|
||||
SimplifiedEntry(ammo_12mm, 78)
|
||||
)
|
||||
),
|
||||
{
|
||||
val ammo = ShorthandAmmoBox(hellfire_ammo, hellfire_ammo.Capacity)
|
||||
"fury" -> _Loadout("default_fury", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo, 30),
|
||||
SimplifiedEntry(ammo, 34),
|
||||
SimplifiedEntry(ammo, 74),
|
||||
SimplifiedEntry(ammo, 78)
|
||||
)
|
||||
)
|
||||
},
|
||||
//"ant" -> _Loadout("default_ant", List(), List()),
|
||||
//"ams" -> _Loadout("default_ams", List(), List()),
|
||||
"two_man_assault_buggy" -> _Loadout("default_two_man_assault_buggy", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_12mm, 30),
|
||||
SimplifiedEntry(ammo_12mm, 34),
|
||||
SimplifiedEntry(ammo_12mm, 38),
|
||||
SimplifiedEntry(ammo_12mm, 90),
|
||||
SimplifiedEntry(ammo_12mm, 94),
|
||||
SimplifiedEntry(ammo_12mm, 98)
|
||||
)
|
||||
),
|
||||
{
|
||||
val ammo = ShorthandAmmoBox(skyguard_flak_cannon_ammo, skyguard_flak_cannon_ammo.Capacity)
|
||||
"skyguard" -> _Loadout("default_skyguard", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_12mm, 30),
|
||||
SimplifiedEntry(ammo_12mm, 34),
|
||||
SimplifiedEntry(ammo_12mm, 38),
|
||||
SimplifiedEntry(ammo, 90),
|
||||
SimplifiedEntry(ammo, 94),
|
||||
SimplifiedEntry(ammo, 98)
|
||||
)
|
||||
)
|
||||
},
|
||||
"threemanheavybuggy" -> _Loadout("default_threemanheavybuggy", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_12mm, 30),
|
||||
SimplifiedEntry(ammo_12mm, 34),
|
||||
SimplifiedEntry(ammo_12mm, 38),
|
||||
SimplifiedEntry(ammo_mortar, 90),
|
||||
SimplifiedEntry(ammo_mortar, 94),
|
||||
SimplifiedEntry(ammo_mortar, 98)
|
||||
)
|
||||
),
|
||||
{
|
||||
val ammo = ShorthandAmmoBox(firebird_missile, firebird_missile.Capacity)
|
||||
"twomanheavybuggy" -> _Loadout("default_twomanheavybuggy", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo, 30),
|
||||
SimplifiedEntry(ammo, 34),
|
||||
SimplifiedEntry(ammo, 38),
|
||||
SimplifiedEntry(ammo, 90),
|
||||
SimplifiedEntry(ammo, 94),
|
||||
SimplifiedEntry(ammo, 98)
|
||||
)
|
||||
)
|
||||
},
|
||||
"twomanhoverbuggy" -> _Loadout("default_twomanhoverbuggy", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_flux, 30),
|
||||
SimplifiedEntry(ammo_flux, 34),
|
||||
SimplifiedEntry(ammo_flux, 38),
|
||||
SimplifiedEntry(ammo_flux, 90),
|
||||
SimplifiedEntry(ammo_flux, 94),
|
||||
SimplifiedEntry(ammo_flux, 98)
|
||||
)
|
||||
),
|
||||
"mediumtransport" -> _Loadout("default_mediumtransport", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_20mm, 30),
|
||||
SimplifiedEntry(ammo_20mm, 34),
|
||||
SimplifiedEntry(ammo_20mm, 38),
|
||||
SimplifiedEntry(ammo_20mm, 90),
|
||||
SimplifiedEntry(ammo_20mm, 94),
|
||||
SimplifiedEntry(ammo_20mm, 98),
|
||||
SimplifiedEntry(ammo_20mm, 150),
|
||||
SimplifiedEntry(ammo_20mm, 154),
|
||||
SimplifiedEntry(ammo_20mm, 158)
|
||||
)
|
||||
),
|
||||
"battlewagon" -> _Loadout("default_battlewagon", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_15mm, 30),
|
||||
SimplifiedEntry(ammo_15mm, 34),
|
||||
SimplifiedEntry(ammo_15mm, 38),
|
||||
SimplifiedEntry(ammo_15mm, 90),
|
||||
SimplifiedEntry(ammo_15mm, 94),
|
||||
SimplifiedEntry(ammo_15mm, 98),
|
||||
SimplifiedEntry(ammo_15mm, 150),
|
||||
SimplifiedEntry(ammo_15mm, 154),
|
||||
SimplifiedEntry(ammo_15mm, 158)
|
||||
)
|
||||
),
|
||||
{
|
||||
val ammo = ShorthandAmmoBox(gauss_cannon_ammo, gauss_cannon_ammo.Capacity)
|
||||
"thunderer" -> _Loadout("default_thunderer", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo, 30),
|
||||
SimplifiedEntry(ammo, 34),
|
||||
SimplifiedEntry(ammo, 38),
|
||||
SimplifiedEntry(ammo, 90),
|
||||
SimplifiedEntry(ammo, 94),
|
||||
SimplifiedEntry(ammo, 98),
|
||||
SimplifiedEntry(ammo, 150),
|
||||
SimplifiedEntry(ammo, 154),
|
||||
SimplifiedEntry(ammo, 158)
|
||||
)
|
||||
)
|
||||
},
|
||||
{
|
||||
val ammo = ShorthandAmmoBox(fluxpod_ammo, fluxpod_ammo.Capacity)
|
||||
"aurora" -> _Loadout("default_aurora", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo, 30),
|
||||
SimplifiedEntry(ammo, 34),
|
||||
SimplifiedEntry(ammo, 38),
|
||||
SimplifiedEntry(ammo, 90),
|
||||
SimplifiedEntry(ammo, 94),
|
||||
SimplifiedEntry(ammo, 98),
|
||||
SimplifiedEntry(ammo, 150),
|
||||
SimplifiedEntry(ammo, 154),
|
||||
SimplifiedEntry(ammo, 158)
|
||||
)
|
||||
)
|
||||
},
|
||||
"apc_tr" -> _Loadout("default_apc_tr", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_75mm, 30),
|
||||
SimplifiedEntry(ammo_75mm, 34),
|
||||
SimplifiedEntry(ammo_75mm, 38),
|
||||
SimplifiedEntry(ammo_75mm, 42),
|
||||
SimplifiedEntry(ammo_75mm, 46),
|
||||
SimplifiedEntry(ammo_75mm, 110),
|
||||
SimplifiedEntry(ammo_75mm, 114),
|
||||
SimplifiedEntry(ammo_75mm, 118),
|
||||
SimplifiedEntry(ammo_75mm, 122),
|
||||
SimplifiedEntry(ammo_12mm, 126),
|
||||
SimplifiedEntry(ammo_12mm, 190),
|
||||
SimplifiedEntry(ammo_12mm, 194),
|
||||
SimplifiedEntry(ammo_12mm, 198),
|
||||
SimplifiedEntry(ammo_12mm, 202),
|
||||
SimplifiedEntry(ammo_15mm, 206),
|
||||
SimplifiedEntry(ammo_15mm, 270),
|
||||
SimplifiedEntry(ammo_15mm, 274),
|
||||
SimplifiedEntry(ammo_15mm, 278),
|
||||
SimplifiedEntry(ammo_15mm, 282),
|
||||
SimplifiedEntry(ammo_15mm, 286)
|
||||
)
|
||||
),
|
||||
"apc_nc" -> _Loadout("default_apc_nc", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_75mm, 30),
|
||||
SimplifiedEntry(ammo_75mm, 34),
|
||||
SimplifiedEntry(ammo_75mm, 38),
|
||||
SimplifiedEntry(ammo_75mm, 42),
|
||||
SimplifiedEntry(ammo_75mm, 46),
|
||||
SimplifiedEntry(ammo_75mm, 110),
|
||||
SimplifiedEntry(ammo_75mm, 114),
|
||||
SimplifiedEntry(ammo_75mm, 118),
|
||||
SimplifiedEntry(ammo_75mm, 122),
|
||||
SimplifiedEntry(ammo_12mm, 126),
|
||||
SimplifiedEntry(ammo_12mm, 190),
|
||||
SimplifiedEntry(ammo_12mm, 194),
|
||||
SimplifiedEntry(ammo_12mm, 198),
|
||||
SimplifiedEntry(ammo_12mm, 202),
|
||||
SimplifiedEntry(ammo_20mm, 206),
|
||||
SimplifiedEntry(ammo_20mm, 270),
|
||||
SimplifiedEntry(ammo_20mm, 274),
|
||||
SimplifiedEntry(ammo_20mm, 278),
|
||||
SimplifiedEntry(ammo_20mm, 282),
|
||||
SimplifiedEntry(ammo_20mm, 286)
|
||||
)
|
||||
),
|
||||
"apc_vs" -> _Loadout("default_apc_vs", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_75mm, 30),
|
||||
SimplifiedEntry(ammo_75mm, 34),
|
||||
SimplifiedEntry(ammo_75mm, 38),
|
||||
SimplifiedEntry(ammo_75mm, 42),
|
||||
SimplifiedEntry(ammo_75mm, 46),
|
||||
SimplifiedEntry(ammo_75mm, 110),
|
||||
SimplifiedEntry(ammo_75mm, 114),
|
||||
SimplifiedEntry(ammo_75mm, 118),
|
||||
SimplifiedEntry(ammo_75mm, 122),
|
||||
SimplifiedEntry(ammo_12mm, 126),
|
||||
SimplifiedEntry(ammo_12mm, 190),
|
||||
SimplifiedEntry(ammo_12mm, 194),
|
||||
SimplifiedEntry(ammo_12mm, 198),
|
||||
SimplifiedEntry(ammo_12mm, 202),
|
||||
SimplifiedEntry(ammo_flux, 206),
|
||||
SimplifiedEntry(ammo_flux, 270),
|
||||
SimplifiedEntry(ammo_flux, 274),
|
||||
SimplifiedEntry(ammo_flux, 278),
|
||||
SimplifiedEntry(ammo_flux, 282),
|
||||
SimplifiedEntry(ammo_flux, 286)
|
||||
)
|
||||
),
|
||||
"lightning" -> _Loadout("default_lightning", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_25mm, 30),
|
||||
SimplifiedEntry(ammo_25mm, 34),
|
||||
SimplifiedEntry(ammo_25mm, 38),
|
||||
SimplifiedEntry(ammo_75mm, 90),
|
||||
SimplifiedEntry(ammo_75mm, 94),
|
||||
SimplifiedEntry(ammo_75mm, 98)
|
||||
)
|
||||
),
|
||||
{
|
||||
val ammo = ShorthandAmmoBox(bullet_105mm, bullet_105mm.Capacity)
|
||||
"prowler" -> _Loadout("default_prowler", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_15mm, 30),
|
||||
SimplifiedEntry(ammo_15mm, 34),
|
||||
SimplifiedEntry(ammo_15mm, 38),
|
||||
SimplifiedEntry(ammo, 90),
|
||||
SimplifiedEntry(ammo, 94),
|
||||
SimplifiedEntry(ammo, 98)
|
||||
)
|
||||
)
|
||||
},
|
||||
{
|
||||
val ammo = ShorthandAmmoBox(bullet_150mm, bullet_150mm.Capacity)
|
||||
"vanguard" -> _Loadout("default_vanguard", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_20mm, 30),
|
||||
SimplifiedEntry(ammo_20mm, 34),
|
||||
SimplifiedEntry(ammo_20mm, 38),
|
||||
SimplifiedEntry(ammo, 90),
|
||||
SimplifiedEntry(ammo, 94),
|
||||
SimplifiedEntry(ammo, 98)
|
||||
)
|
||||
)
|
||||
},
|
||||
{
|
||||
val ammo1 = ShorthandAmmoBox(pulse_battery, pulse_battery.Capacity)
|
||||
val ammo2 = ShorthandAmmoBox(heavy_rail_beam_battery, heavy_rail_beam_battery.Capacity)
|
||||
"magrider" -> _Loadout("default_magrider", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo1, 30),
|
||||
SimplifiedEntry(ammo1, 34),
|
||||
SimplifiedEntry(ammo1, 38),
|
||||
SimplifiedEntry(ammo2, 90),
|
||||
SimplifiedEntry(ammo2, 94),
|
||||
SimplifiedEntry(ammo2, 98)
|
||||
)
|
||||
)
|
||||
},
|
||||
//"flail" -> _Loadout("default_flail", List(), List()),
|
||||
//"switchblade" -> _Loadout("default_switchblade", List(), List()),
|
||||
//"router" -> _Loadout("default_router", List(), List()),
|
||||
"mosquito" -> _Loadout("default_mosquito", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_12mm, 30),
|
||||
SimplifiedEntry(ammo_12mm, 34),
|
||||
SimplifiedEntry(ammo_12mm, 74),
|
||||
SimplifiedEntry(ammo_12mm, 78)
|
||||
)
|
||||
),
|
||||
{
|
||||
val ammo = ShorthandAmmoBox(reaver_rocket, reaver_rocket.Capacity)
|
||||
"lightgunship" -> _Loadout("default_lightgunship", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo, 30),
|
||||
SimplifiedEntry(ammo, 34),
|
||||
SimplifiedEntry(ammo, 38),
|
||||
SimplifiedEntry(ammo, 90),
|
||||
SimplifiedEntry(ammo_20mm, 94),
|
||||
SimplifiedEntry(ammo_20mm, 98)
|
||||
)
|
||||
)
|
||||
},
|
||||
{
|
||||
val ammo1 = ShorthandAmmoBox(wasp_rocket_ammo, wasp_rocket_ammo.Capacity)
|
||||
val ammo2 = ShorthandAmmoBox(wasp_gun_ammo, wasp_gun_ammo.Capacity)
|
||||
"wasp" -> _Loadout("default_wasp", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo1, 30),
|
||||
SimplifiedEntry(ammo1, 34),
|
||||
SimplifiedEntry(ammo2, 74),
|
||||
SimplifiedEntry(ammo2, 78)
|
||||
)
|
||||
)
|
||||
},
|
||||
"liberator" -> _Loadout("default_liberator", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_35mm, 30),
|
||||
SimplifiedEntry(ammo_35mm, 34),
|
||||
SimplifiedEntry(ammo_25mm, 38),
|
||||
SimplifiedEntry(ammo_25mm, 90),
|
||||
SimplifiedEntry(ammo_bomb, 94),
|
||||
SimplifiedEntry(ammo_bomb, 98),
|
||||
SimplifiedEntry(ammo_bomb, 150),
|
||||
SimplifiedEntry(ammo_bomb, 154),
|
||||
SimplifiedEntry(ammo_bomb, 158)
|
||||
)
|
||||
),
|
||||
"vulture" -> _Loadout("default_vulture", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_35mm, 30),
|
||||
SimplifiedEntry(ammo_35mm, 34),
|
||||
SimplifiedEntry(ammo_35mm, 38),
|
||||
SimplifiedEntry(ammo_25mm, 42),
|
||||
SimplifiedEntry(ammo_25mm, 94),
|
||||
SimplifiedEntry(ammo_bomb, 98),
|
||||
SimplifiedEntry(ammo_bomb, 102),
|
||||
SimplifiedEntry(ammo_bomb, 106)
|
||||
) //TODO confirm
|
||||
),
|
||||
"dropship" -> _Loadout("default_dropship", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_20mm, 30),
|
||||
SimplifiedEntry(ammo_20mm, 34),
|
||||
SimplifiedEntry(ammo_20mm, 38),
|
||||
SimplifiedEntry(ammo_20mm, 42),
|
||||
SimplifiedEntry(ammo_20mm, 94),
|
||||
SimplifiedEntry(ammo_20mm, 98),
|
||||
SimplifiedEntry(ammo_20mm, 102),
|
||||
SimplifiedEntry(ammo_20mm, 106),
|
||||
SimplifiedEntry(ammo_20mm, 158),
|
||||
SimplifiedEntry(ammo_20mm, 162),
|
||||
SimplifiedEntry(ammo_20mm, 166),
|
||||
SimplifiedEntry(ammo_20mm, 170)
|
||||
)
|
||||
),
|
||||
"galaxy_gunship" -> _Loadout("galaxy_gunship", List(),
|
||||
List(
|
||||
SimplifiedEntry(ammo_35mm, 30),
|
||||
SimplifiedEntry(ammo_35mm, 34),
|
||||
SimplifiedEntry(ammo_35mm, 38),
|
||||
SimplifiedEntry(ammo_35mm, 42),
|
||||
SimplifiedEntry(ammo_35mm, 102),
|
||||
SimplifiedEntry(ammo_35mm, 106),
|
||||
SimplifiedEntry(ammo_35mm, 110),
|
||||
SimplifiedEntry(ammo_35mm, 114),
|
||||
SimplifiedEntry(ammo_mortar, 174),
|
||||
SimplifiedEntry(ammo_mortar, 178),
|
||||
SimplifiedEntry(ammo_mortar, 182),
|
||||
SimplifiedEntry(ammo_mortar, 186)
|
||||
)
|
||||
)
|
||||
//"phantasm" -> _Loadout("default_phantasm", List(), List()),
|
||||
//"lodestar" -> _Loadout("default_lodestar", List(), List()),
|
||||
)
|
||||
}
|
||||
|
||||
def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
||||
vehicles.get(msg.item_name) match {
|
||||
case Some(vehicle) =>
|
||||
val (weapons, inventory) = trunk.get(msg.item_name) match {
|
||||
case Some(loadout) =>
|
||||
(
|
||||
loadout.VisibleSlots.map(entry => { InventoryItem(EquipmentTerminalDefinition.BuildSimplifiedPattern(entry.item), entry.index) }),
|
||||
loadout.Inventory.map(entry => { InventoryItem(EquipmentTerminalDefinition.BuildSimplifiedPattern(entry.item), entry.index) })
|
||||
)
|
||||
case None =>
|
||||
(List.empty, List.empty)
|
||||
}
|
||||
Terminal.BuyVehicle(vehicle(), weapons, inventory)
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object VehicleTerminalDefinition {
|
||||
/**
|
||||
* Create a new `Vehicle` from provided `VehicleDefinition` objects.
|
||||
* @param vdef the `VehicleDefinition` object
|
||||
* @return a curried function that, when called, creates the `Vehicle`
|
||||
* @see `GlobalDefinitions`
|
||||
*/
|
||||
protected def MakeVehicle(vdef : VehicleDefinition)() : Vehicle = Vehicle(vdef)
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.vehicles
|
||||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.Vehicle
|
||||
import net.psforever.objects.mount.MountableControl
|
||||
import net.psforever.objects.mount.MountableBehavior
|
||||
|
||||
/**
|
||||
* An `Actor` that handles messages being dispatched to a specific `Vehicle`.<br>
|
||||
|
|
@ -11,8 +12,10 @@ import net.psforever.objects.mount.MountableControl
|
|||
* The latter is applicable only when the specific vehicle is being deconstructed.
|
||||
* @param vehicle the `Vehicle` object being governed
|
||||
*/
|
||||
class VehicleControl(private val vehicle : Vehicle) extends MountableControl(vehicle) {
|
||||
override def receive : Receive = super[MountableControl].receive.orElse {
|
||||
class VehicleControl(private val vehicle : Vehicle) extends Actor with MountableBehavior {
|
||||
override def MountableObject = vehicle
|
||||
|
||||
def receive : Receive = mountableBehavior.orElse {
|
||||
case Vehicle.PrepareForDeletion =>
|
||||
context.become(Disabled)
|
||||
|
||||
|
|
|
|||
|
|
@ -446,7 +446,7 @@ object GamePacketOpcode extends Enumeration {
|
|||
case 0x69 => game.AvatarFirstTimeEventMessage.decode
|
||||
case 0x6a => noDecoder(AggravatedDamageMessage)
|
||||
case 0x6b => game.TriggerSoundMessage.decode
|
||||
case 0x6c => noDecoder(LootItemMessage)
|
||||
case 0x6c => game.LootItemMessage.decode
|
||||
case 0x6d => noDecoder(VehicleSubStateMessage)
|
||||
case 0x6e => noDecoder(SquadMembershipRequest)
|
||||
case 0x6f => noDecoder(SquadMembershipResponse)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.packet.game
|
||||
|
||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param item_guid the item being taken
|
||||
* @param target_guid what is taking the item;
|
||||
* in general, usually the player who is doing the taking
|
||||
*/
|
||||
final case class LootItemMessage(item_guid : PlanetSideGUID,
|
||||
target_guid : PlanetSideGUID
|
||||
) extends PlanetSideGamePacket {
|
||||
type Packet = LootItemMessage
|
||||
def opcode = GamePacketOpcode.LootItemMessage
|
||||
def encode = LootItemMessage.encode(this)
|
||||
}
|
||||
|
||||
object LootItemMessage extends Marshallable[LootItemMessage] {
|
||||
implicit val codec : Codec[LootItemMessage] = (
|
||||
("item_guid" | PlanetSideGUID.codec) ::
|
||||
("target_guid" | PlanetSideGUID.codec)
|
||||
).as[LootItemMessage]
|
||||
}
|
||||
27
common/src/test/scala/game/LootItemMessageTest.scala
Normal file
27
common/src/test/scala/game/LootItemMessageTest.scala
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package game
|
||||
|
||||
import org.specs2.mutable._
|
||||
import net.psforever.packet._
|
||||
import net.psforever.packet.game._
|
||||
import scodec.bits._
|
||||
|
||||
class LootItemMessageTest extends Specification {
|
||||
val string = hex"6C DD0D 5C14"
|
||||
|
||||
"decode" in {
|
||||
PacketCoding.DecodePacket(string).require match {
|
||||
case LootItemMessage(item_guid, target_guid) =>
|
||||
item_guid mustEqual PlanetSideGUID(3549)
|
||||
target_guid mustEqual PlanetSideGUID(5212)
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"encode" in {
|
||||
val msg = LootItemMessage(PlanetSideGUID(3549),PlanetSideGUID(5212))
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
pkt mustEqual string
|
||||
}
|
||||
}
|
||||
71
common/src/test/scala/objects/ContainerTest.scala
Normal file
71
common/src/test/scala/objects/ContainerTest.scala
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
|
||||
import net.psforever.objects.{GlobalDefinitions, OffhandEquipmentSlot, Tool}
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import org.specs2.mutable._
|
||||
|
||||
import scala.util.Success
|
||||
|
||||
class ContainerTest extends Specification {
|
||||
"Container" should {
|
||||
"construct" in {
|
||||
val obj = new ContainerTest.CObject
|
||||
obj.VisibleSlots mustEqual (0 until 9).toSet
|
||||
obj.Inventory.Size mustEqual 0
|
||||
obj.Inventory.Capacity mustEqual 9
|
||||
obj.Find(PlanetSideGUID(0)) mustEqual None
|
||||
obj.Slot(0) mustEqual OffhandEquipmentSlot.BlockedSlot
|
||||
obj.Collisions(0, 2, 2) mustEqual Success(List())
|
||||
}
|
||||
|
||||
"Collisions can Find items in Inventory (default behavior)" in {
|
||||
val obj = new ContainerTest.CObject
|
||||
val weapon = Tool(GlobalDefinitions.beamer)
|
||||
weapon.GUID = PlanetSideGUID(1)
|
||||
|
||||
obj.Inventory += 0 -> weapon
|
||||
obj.Find(PlanetSideGUID(1)) match {
|
||||
case Some(index) =>
|
||||
obj.Inventory.Items(index).obj mustEqual weapon
|
||||
case None =>
|
||||
ko
|
||||
}
|
||||
obj.Collisions(1,1,1) match {
|
||||
case Success(items) =>
|
||||
items.length mustEqual 1
|
||||
items.head.obj mustEqual weapon
|
||||
case _ =>;
|
||||
ko
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ContainerTest {
|
||||
class CObject extends Container {
|
||||
private val inv = GridInventory(3, 3)
|
||||
|
||||
def Inventory : GridInventory = inv
|
||||
|
||||
def Find(guid : PlanetSideGUID) : Option[Int] = {
|
||||
Inventory.Items.find({
|
||||
case((_, item)) =>
|
||||
if(item.obj.HasGUID) {
|
||||
item.obj.GUID == guid
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
}) match {
|
||||
case Some((index, _)) =>
|
||||
Some(index)
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
def VisibleSlots :Set[Int] = Set[Int](0,1,2, 3,4,5, 6,7,8)
|
||||
}
|
||||
}
|
||||
148
common/src/test/scala/objects/EquipmentSlotTest.scala
Normal file
148
common/src/test/scala/objects/EquipmentSlotTest.scala
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import net.psforever.objects.{EquipmentSlot, OffhandEquipmentSlot, Tool}
|
||||
import net.psforever.objects.equipment.EquipmentSize
|
||||
import net.psforever.objects.GlobalDefinitions.{beamer, repeater, suppressor}
|
||||
import org.specs2.mutable._
|
||||
|
||||
class EquipmentSlotTest extends Specification {
|
||||
"EquipmentSlot" should {
|
||||
"construct" in {
|
||||
val obj = new EquipmentSlot()
|
||||
obj.Size mustEqual EquipmentSize.Blocked
|
||||
obj.Equipment mustEqual None
|
||||
}
|
||||
|
||||
"construct with a default size" in {
|
||||
val obj = EquipmentSlot(EquipmentSize.Pistol)
|
||||
obj.Size mustEqual EquipmentSize.Pistol
|
||||
}
|
||||
|
||||
"change size" in {
|
||||
val obj = new EquipmentSlot()
|
||||
obj.Size mustEqual EquipmentSize.Blocked
|
||||
obj.Size = EquipmentSize.Pistol
|
||||
obj.Size mustEqual EquipmentSize.Pistol
|
||||
}
|
||||
|
||||
"hold equipment" in {
|
||||
val obj = new EquipmentSlot()
|
||||
val equipment = Tool(beamer)
|
||||
obj.Equipment = None
|
||||
|
||||
beamer.Size mustEqual EquipmentSize.Pistol
|
||||
obj.Size = EquipmentSize.Pistol
|
||||
obj.Equipment = equipment
|
||||
obj.Equipment match {
|
||||
case Some(item) =>
|
||||
item.Definition mustEqual beamer
|
||||
case None =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"put down previously held equipment" in {
|
||||
val obj = EquipmentSlot(EquipmentSize.Pistol)
|
||||
obj.Equipment = Tool(beamer)
|
||||
|
||||
obj.Equipment match {
|
||||
case Some(item) =>
|
||||
item.Definition mustEqual beamer
|
||||
case None =>
|
||||
ko
|
||||
}
|
||||
obj.Equipment = None
|
||||
obj.Equipment match {
|
||||
case Some(_) =>
|
||||
ko
|
||||
case None =>
|
||||
ok
|
||||
}
|
||||
}
|
||||
|
||||
"not change size when holding equipment" in {
|
||||
val obj = new EquipmentSlot()
|
||||
obj.Size mustEqual EquipmentSize.Blocked
|
||||
obj.Size = EquipmentSize.Pistol
|
||||
obj.Equipment = Tool(beamer)
|
||||
obj.Equipment match {
|
||||
case Some(_) => ;
|
||||
case None => ko
|
||||
}
|
||||
|
||||
obj.Size mustEqual EquipmentSize.Pistol
|
||||
obj.Size = EquipmentSize.Rifle
|
||||
obj.Size mustEqual EquipmentSize.Pistol
|
||||
}
|
||||
|
||||
"not hold wrong-sized equipment" in {
|
||||
val obj = new EquipmentSlot()
|
||||
val equipment = Tool(suppressor)
|
||||
obj.Equipment = None
|
||||
|
||||
beamer.Size mustEqual EquipmentSize.Pistol
|
||||
obj.Size = EquipmentSize.Pistol
|
||||
obj.Equipment = equipment
|
||||
obj.Equipment mustEqual None
|
||||
}
|
||||
|
||||
"not switch to holding a second item in place of a first one" in {
|
||||
val obj = EquipmentSlot(EquipmentSize.Pistol)
|
||||
obj.Equipment = Tool(beamer)
|
||||
|
||||
obj.Equipment match {
|
||||
case Some(item) =>
|
||||
item.Definition mustEqual beamer
|
||||
case None =>
|
||||
ko
|
||||
}
|
||||
repeater.Size mustEqual EquipmentSize.Pistol
|
||||
obj.Equipment = Tool(repeater) //also a pistol
|
||||
obj.Equipment match {
|
||||
case Some(item) =>
|
||||
item.Definition mustEqual beamer
|
||||
case None =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"OffhandEquipmentSLot" should {
|
||||
"construct" in {
|
||||
val obj = new OffhandEquipmentSlot(EquipmentSize.Pistol)
|
||||
obj.Size mustEqual EquipmentSize.Pistol
|
||||
obj.Equipment mustEqual None
|
||||
}
|
||||
|
||||
"hold equipment" in {
|
||||
val obj = new OffhandEquipmentSlot(EquipmentSize.Pistol)
|
||||
val equipment = Tool(beamer)
|
||||
obj.Equipment = None
|
||||
|
||||
beamer.Size mustEqual EquipmentSize.Pistol
|
||||
obj.Equipment = equipment
|
||||
obj.Equipment match {
|
||||
case Some(item) =>
|
||||
item.Definition mustEqual beamer
|
||||
case None =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"not change size after being constructed" in {
|
||||
//see above test "EquipmentSlot should/not change size when holding equipment"
|
||||
val obj = new OffhandEquipmentSlot(EquipmentSize.Pistol)
|
||||
obj.Equipment mustEqual None
|
||||
|
||||
obj.Size mustEqual EquipmentSize.Pistol
|
||||
obj.Size = EquipmentSize.Rifle
|
||||
obj.Size mustEqual EquipmentSize.Pistol
|
||||
}
|
||||
|
||||
"special Blocked size default" in {
|
||||
OffhandEquipmentSlot.BlockedSlot.Size mustEqual EquipmentSize.Blocked
|
||||
OffhandEquipmentSlot.BlockedSlot.Equipment mustEqual None
|
||||
}
|
||||
}
|
||||
}
|
||||
196
common/src/test/scala/objects/LoadoutTest.scala
Normal file
196
common/src/test/scala/objects/LoadoutTest.scala
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import net.psforever.objects._
|
||||
import net.psforever.types.{CharacterGender, ExoSuitType, PlanetSideEmpire}
|
||||
import net.psforever.objects.GlobalDefinitions._
|
||||
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
|
||||
import org.specs2.mutable._
|
||||
|
||||
class LoadoutTest extends Specification {
|
||||
def CreatePlayer() : Player = {
|
||||
val
|
||||
player = Player("TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 41, 1)
|
||||
player.Slot(0).Equipment = Tool(beamer)
|
||||
player.Slot(2).Equipment = Tool(suppressor)
|
||||
player.Slot(4).Equipment = Tool(forceblade)
|
||||
player.Slot(6).Equipment = AmmoBox(bullet_9mm)
|
||||
player.Slot(9).Equipment = AmmoBox(bullet_9mm)
|
||||
player.Slot(12).Equipment = AmmoBox(bullet_9mm)
|
||||
player.Slot(33).Equipment = AmmoBox(bullet_9mm_AP)
|
||||
player.Slot(36).Equipment = AmmoBox(energy_cell)
|
||||
player.Slot(39).Equipment = SimpleItem(remote_electronics_kit)
|
||||
player
|
||||
}
|
||||
|
||||
"Player Loadout" should {
|
||||
"test sample player" in {
|
||||
val obj : Player = CreatePlayer()
|
||||
obj.Holsters()(0).Equipment.get.Definition mustEqual beamer
|
||||
obj.Holsters()(2).Equipment.get.Definition mustEqual suppressor
|
||||
obj.Holsters()(4).Equipment.get.Definition mustEqual forceblade
|
||||
obj.Slot(6).Equipment.get.Definition mustEqual bullet_9mm
|
||||
obj.Slot(9).Equipment.get.Definition mustEqual bullet_9mm
|
||||
obj.Slot(12).Equipment.get.Definition mustEqual bullet_9mm
|
||||
obj.Slot(33).Equipment.get.Definition mustEqual bullet_9mm_AP
|
||||
obj.Slot(36).Equipment.get.Definition mustEqual energy_cell
|
||||
obj.Slot(39).Equipment.get.Definition mustEqual remote_electronics_kit
|
||||
}
|
||||
|
||||
"do not load, if never saved" in {
|
||||
CreatePlayer().LoadLoadout(0) mustEqual None
|
||||
}
|
||||
|
||||
"save but incorrect load" in {
|
||||
val obj : Player = CreatePlayer()
|
||||
obj.SaveLoadout("test", 0)
|
||||
|
||||
obj.LoadLoadout(1) mustEqual None
|
||||
}
|
||||
|
||||
"save and load" in {
|
||||
val obj : Player = CreatePlayer()
|
||||
obj.Slot(0).Equipment.get.asInstanceOf[Tool].Magazine = 1 //non-standard but legal
|
||||
obj.Slot(2).Equipment.get.asInstanceOf[Tool].AmmoSlot.Magazine = 100 //non-standard (and out of range, real=25)
|
||||
obj.SaveLoadout("test", 0)
|
||||
|
||||
obj.LoadLoadout(0) match {
|
||||
case Some(items) =>
|
||||
items.Label mustEqual "test"
|
||||
items.ExoSuit mustEqual obj.ExoSuit
|
||||
items.Subtype mustEqual 0
|
||||
|
||||
items.VisibleSlots.length mustEqual 3
|
||||
val holsters = items.VisibleSlots.sortBy(_.index)
|
||||
holsters.head.index mustEqual 0
|
||||
holsters.head.item.asInstanceOf[Loadout.ShorthandTool].tdef mustEqual beamer
|
||||
holsters.head.item.asInstanceOf[Loadout.ShorthandTool].ammo.head.ammo.capacity mustEqual 1
|
||||
holsters(1).index mustEqual 2
|
||||
holsters(1).item.asInstanceOf[Loadout.ShorthandTool].tdef mustEqual suppressor
|
||||
holsters(1).item.asInstanceOf[Loadout.ShorthandTool].ammo.head.ammo.capacity mustEqual 100
|
||||
holsters(2).index mustEqual 4
|
||||
holsters(2).item.asInstanceOf[Loadout.ShorthandTool].tdef mustEqual forceblade
|
||||
|
||||
items.Inventory.length mustEqual 6
|
||||
val inventory = items.Inventory.sortBy(_.index)
|
||||
inventory.head.index mustEqual 6
|
||||
inventory.head.item.asInstanceOf[Loadout.ShorthandAmmoBox].adef mustEqual bullet_9mm
|
||||
inventory(1).index mustEqual 9
|
||||
inventory(1).item.asInstanceOf[Loadout.ShorthandAmmoBox].adef mustEqual bullet_9mm
|
||||
inventory(2).index mustEqual 12
|
||||
inventory(2).item.asInstanceOf[Loadout.ShorthandAmmoBox].adef mustEqual bullet_9mm
|
||||
inventory(3).index mustEqual 33
|
||||
inventory(3).item.asInstanceOf[Loadout.ShorthandAmmoBox].adef mustEqual bullet_9mm_AP
|
||||
inventory(4).index mustEqual 36
|
||||
inventory(4).item.asInstanceOf[Loadout.ShorthandAmmoBox].adef mustEqual energy_cell
|
||||
inventory(5).index mustEqual 39
|
||||
inventory(5).item.asInstanceOf[Loadout.ShorthandSimpleItem].sdef mustEqual remote_electronics_kit
|
||||
case None =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"save without inventory contents" in {
|
||||
val obj : Player = CreatePlayer()
|
||||
obj.Inventory.Clear()
|
||||
obj.SaveLoadout("test", 0)
|
||||
|
||||
obj.LoadLoadout(0) match {
|
||||
case Some(items) =>
|
||||
items.Label mustEqual "test"
|
||||
items.ExoSuit mustEqual obj.ExoSuit
|
||||
items.Subtype mustEqual 0
|
||||
items.VisibleSlots.length mustEqual 3
|
||||
items.Inventory.length mustEqual 0 //empty
|
||||
case None =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"save without visible slot contents" in {
|
||||
val obj : Player = CreatePlayer()
|
||||
obj.Slot(0).Equipment = None
|
||||
obj.Slot(2).Equipment = None
|
||||
obj.Slot(4).Equipment = None
|
||||
obj.SaveLoadout("test", 0)
|
||||
|
||||
obj.LoadLoadout(0) match {
|
||||
case Some(items) =>
|
||||
items.Label mustEqual "test"
|
||||
items.ExoSuit mustEqual obj.ExoSuit
|
||||
items.Subtype mustEqual 0
|
||||
items.VisibleSlots.length mustEqual 0 //empty
|
||||
items.Inventory.length mustEqual 6
|
||||
case None =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"save (a construction item) and load" in {
|
||||
val obj : Player = CreatePlayer()
|
||||
obj.Inventory.Clear()
|
||||
obj.Slot(6).Equipment = ConstructionItem(advanced_ace)
|
||||
obj.SaveLoadout("test", 0)
|
||||
|
||||
obj.LoadLoadout(0) match {
|
||||
case Some(items) =>
|
||||
items.Inventory.length mustEqual 1
|
||||
items.Inventory.head.index mustEqual 6
|
||||
items.Inventory.head.item.asInstanceOf[Loadout.ShorthandConstructionItem].cdef mustEqual advanced_ace
|
||||
case None =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"save (a kit) and load" in {
|
||||
val obj : Player = CreatePlayer()
|
||||
obj.Inventory.Clear()
|
||||
obj.Slot(6).Equipment = Kit(medkit)
|
||||
obj.SaveLoadout("test", 0)
|
||||
|
||||
obj.LoadLoadout(0) match {
|
||||
case Some(items) =>
|
||||
items.Inventory.length mustEqual 1
|
||||
items.Inventory.head.index mustEqual 6
|
||||
items.Inventory.head.item.asInstanceOf[Loadout.ShorthandKit].kdef mustEqual medkit
|
||||
case None =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"save, load, delete" in {
|
||||
val obj : Player = CreatePlayer()
|
||||
obj.SaveLoadout("test", 0)
|
||||
|
||||
obj.LoadLoadout(0) match {
|
||||
case None =>
|
||||
ko
|
||||
case Some(_) => ; //good; keep going
|
||||
}
|
||||
obj.DeleteLoadout(0)
|
||||
obj.LoadLoadout(0) mustEqual None
|
||||
}
|
||||
|
||||
"distinguish MAX subtype information" in {
|
||||
val obj : Player = CreatePlayer()
|
||||
val slot = obj.Slot(2)
|
||||
slot.Equipment = None //only an unequipped slot can have its Equipment Size changed (Rifle -> Max)
|
||||
Player.SuitSetup(obj, ExoSuitType.MAX)
|
||||
obj.SaveLoadout("generic", 0) //weaponless
|
||||
slot.Equipment = None
|
||||
slot.Equipment = Tool(trhev_dualcycler)
|
||||
obj.SaveLoadout("cycler", 1)
|
||||
slot.Equipment = None
|
||||
slot.Equipment = Tool(trhev_pounder)
|
||||
obj.SaveLoadout("pounder", 2)
|
||||
slot.Equipment = None
|
||||
slot.Equipment = Tool(trhev_burster)
|
||||
obj.SaveLoadout("burster", 3)
|
||||
|
||||
obj.LoadLoadout(0).get.Subtype mustEqual 0
|
||||
obj.LoadLoadout(1).get.Subtype mustEqual 1
|
||||
obj.LoadLoadout(2).get.Subtype mustEqual 2
|
||||
obj.LoadLoadout(3).get.Subtype mustEqual 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import akka.actor.{ActorRef, Props}
|
||||
import akka.actor.{Actor, ActorRef, Props}
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.definition.{ObjectDefinition, SeatDefinition}
|
||||
import net.psforever.objects.mount.{Mountable, MountableControl}
|
||||
import net.psforever.objects.mount.{Mountable, MountableBehavior}
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.vehicles.Seat
|
||||
import net.psforever.types.{CharacterGender, PlanetSideEmpire}
|
||||
|
|
@ -83,5 +83,9 @@ object MountableTest {
|
|||
def Definition : ObjectDefinition = null //eh whatever
|
||||
}
|
||||
|
||||
class MountableTestControl(obj : Mountable) extends MountableControl(obj)
|
||||
class MountableTestControl(obj : Mountable) extends Actor with MountableBehavior {
|
||||
override def MountableObject = obj
|
||||
|
||||
def receive : Receive = mountableBehavior
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
package objects.terminal
|
||||
|
||||
import akka.actor.ActorRef
|
||||
import net.psforever.objects.{GlobalDefinitions, Player, Tool}
|
||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
||||
import net.psforever.objects.serverobject.terminals.Terminal
|
||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||
import net.psforever.types.{CharacterGender, PlanetSideEmpire, TransactionType}
|
||||
|
|
@ -24,7 +24,14 @@ class AirVehicleTerminalTest extends Specification {
|
|||
reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true
|
||||
val reply2 = reply.asInstanceOf[Terminal.BuyVehicle]
|
||||
reply2.vehicle.Definition mustEqual GlobalDefinitions.lightgunship
|
||||
reply2.loadout mustEqual Nil //TODO
|
||||
reply2.weapons mustEqual Nil
|
||||
reply2.inventory.length mustEqual 6
|
||||
reply2.inventory.head.obj.Definition mustEqual GlobalDefinitions.reaver_rocket
|
||||
reply2.inventory(1).obj.Definition mustEqual GlobalDefinitions.reaver_rocket
|
||||
reply2.inventory(2).obj.Definition mustEqual GlobalDefinitions.reaver_rocket
|
||||
reply2.inventory(3).obj.Definition mustEqual GlobalDefinitions.reaver_rocket
|
||||
reply2.inventory(4).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
reply2.inventory(5).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
}
|
||||
|
||||
"player can not buy a fake vehicle ('reaver')" in {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,20 @@ class DropshipVehicleTerminalTest extends Specification {
|
|||
reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true
|
||||
val reply2 = reply.asInstanceOf[Terminal.BuyVehicle]
|
||||
reply2.vehicle.Definition mustEqual GlobalDefinitions.dropship
|
||||
reply2.loadout mustEqual Nil //TODO
|
||||
reply2.weapons mustEqual Nil
|
||||
reply2.inventory.length mustEqual 12
|
||||
reply2.inventory.head.obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
reply2.inventory(1).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
reply2.inventory(2).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
reply2.inventory(3).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
reply2.inventory(4).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
reply2.inventory(5).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
reply2.inventory(6).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
reply2.inventory(7).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
reply2.inventory(8).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
reply2.inventory(9).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
reply2.inventory(10).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
reply2.inventory(11).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
}
|
||||
|
||||
"player can not buy a fake vehicle ('galaxy')" in {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,14 @@ class GroundVehicleTerminalTest extends Specification {
|
|||
reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true
|
||||
val reply2 = reply.asInstanceOf[Terminal.BuyVehicle]
|
||||
reply2.vehicle.Definition mustEqual GlobalDefinitions.two_man_assault_buggy
|
||||
reply2.loadout mustEqual Nil //TODO
|
||||
reply2.weapons mustEqual Nil
|
||||
reply2.inventory.length mustEqual 6
|
||||
reply2.inventory.head.obj.Definition mustEqual GlobalDefinitions.bullet_12mm
|
||||
reply2.inventory(1).obj.Definition mustEqual GlobalDefinitions.bullet_12mm
|
||||
reply2.inventory(2).obj.Definition mustEqual GlobalDefinitions.bullet_12mm
|
||||
reply2.inventory(3).obj.Definition mustEqual GlobalDefinitions.bullet_12mm
|
||||
reply2.inventory(4).obj.Definition mustEqual GlobalDefinitions.bullet_12mm
|
||||
reply2.inventory(5).obj.Definition mustEqual GlobalDefinitions.bullet_12mm
|
||||
}
|
||||
|
||||
"player can not buy a fake vehicle ('harasser')" in {
|
||||
|
|
|
|||
|
|
@ -99,7 +99,14 @@ class VehicleTerminalControl1Test extends ActorTest() {
|
|||
assert(reply2.response.isInstanceOf[Terminal.BuyVehicle])
|
||||
val reply3 = reply2.response.asInstanceOf[Terminal.BuyVehicle]
|
||||
assert(reply3.vehicle.Definition == GlobalDefinitions.two_man_assault_buggy)
|
||||
assert(reply3.loadout == Nil) //TODO
|
||||
assert(reply3.weapons == Nil)
|
||||
assert(reply3.inventory.length == 6) //TODO
|
||||
assert(reply3.inventory.head.obj.Definition == GlobalDefinitions.bullet_12mm)
|
||||
assert(reply3.inventory(1).obj.Definition == GlobalDefinitions.bullet_12mm)
|
||||
assert(reply3.inventory(2).obj.Definition == GlobalDefinitions.bullet_12mm)
|
||||
assert(reply3.inventory(3).obj.Definition == GlobalDefinitions.bullet_12mm)
|
||||
assert(reply3.inventory(4).obj.Definition == GlobalDefinitions.bullet_12mm)
|
||||
assert(reply3.inventory(5).obj.Definition == GlobalDefinitions.bullet_12mm)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,14 @@ class VehicleTerminalCombinedTest extends Specification {
|
|||
reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true
|
||||
val reply2 = reply.asInstanceOf[Terminal.BuyVehicle]
|
||||
reply2.vehicle.Definition mustEqual GlobalDefinitions.two_man_assault_buggy
|
||||
reply2.loadout mustEqual Nil //TODO
|
||||
reply2.weapons mustEqual Nil
|
||||
reply2.inventory.length mustEqual 6
|
||||
reply2.inventory.head.obj.Definition mustEqual GlobalDefinitions.bullet_12mm
|
||||
reply2.inventory(1).obj.Definition mustEqual GlobalDefinitions.bullet_12mm
|
||||
reply2.inventory(2).obj.Definition mustEqual GlobalDefinitions.bullet_12mm
|
||||
reply2.inventory(3).obj.Definition mustEqual GlobalDefinitions.bullet_12mm
|
||||
reply2.inventory(4).obj.Definition mustEqual GlobalDefinitions.bullet_12mm
|
||||
reply2.inventory(5).obj.Definition mustEqual GlobalDefinitions.bullet_12mm
|
||||
}
|
||||
|
||||
"player can buy a flying vehicle, the reaver ('lightgunship')" in {
|
||||
|
|
@ -34,7 +41,14 @@ class VehicleTerminalCombinedTest extends Specification {
|
|||
reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true
|
||||
val reply2 = reply.asInstanceOf[Terminal.BuyVehicle]
|
||||
reply2.vehicle.Definition mustEqual GlobalDefinitions.lightgunship
|
||||
reply2.loadout mustEqual Nil //TODO
|
||||
reply2.weapons mustEqual Nil
|
||||
reply2.inventory.length mustEqual 6
|
||||
reply2.inventory.head.obj.Definition mustEqual GlobalDefinitions.reaver_rocket
|
||||
reply2.inventory(1).obj.Definition mustEqual GlobalDefinitions.reaver_rocket
|
||||
reply2.inventory(2).obj.Definition mustEqual GlobalDefinitions.reaver_rocket
|
||||
reply2.inventory(3).obj.Definition mustEqual GlobalDefinitions.reaver_rocket
|
||||
reply2.inventory(4).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
reply2.inventory(5).obj.Definition mustEqual GlobalDefinitions.bullet_20mm
|
||||
}
|
||||
|
||||
"player can not buy a fake vehicle ('harasser')" in {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import services.ServiceManager.Lookup
|
|||
import net.psforever.objects._
|
||||
import net.psforever.objects.equipment._
|
||||
import net.psforever.objects.guid.{GUIDTask, Task, TaskResolver}
|
||||
import net.psforever.objects.inventory.{GridInventory, InventoryItem}
|
||||
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
|
||||
import net.psforever.objects.mount.Mountable
|
||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
|
|
@ -61,7 +61,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case Some(tplayer) =>
|
||||
tplayer.VehicleSeated match {
|
||||
case Some(vehicle_guid) =>
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(tplayer.GUID, 0, true))
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(tplayer.GUID, 0, true, vehicle_guid))
|
||||
case None => ;
|
||||
}
|
||||
tplayer.VehicleOwned match {
|
||||
|
|
@ -288,8 +288,15 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(PacketCoding.CreateGamePacket(0, DismountVehicleMsg(guid, unk1, unk2)))
|
||||
}
|
||||
|
||||
case VehicleResponse.KickPassenger(unk1, unk2) =>
|
||||
case VehicleResponse.KickPassenger(unk1, unk2, vehicle_guid) =>
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, DismountVehicleMsg(guid, unk1, unk2)))
|
||||
if(guid == player.GUID) {
|
||||
continent.GUID(vehicle_guid) match {
|
||||
case Some(obj : Vehicle) =>
|
||||
UnAccessContents(obj)
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
case VehicleResponse.LoadVehicle(vehicle, vtype, vguid, vdata) =>
|
||||
//this is not be suitable for vehicles with people who are seated in it before it spawns (if that is possible)
|
||||
|
|
@ -308,9 +315,48 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(vehicle_guid, seat_group, permission)))
|
||||
}
|
||||
|
||||
case VehicleResponse.StowEquipment(vehicle_guid, slot, item_type, item_guid, item_data) =>
|
||||
if(player.GUID != guid) {
|
||||
//TODO prefer ObjectAttachMessage, but how to force ammo pools to update properly?
|
||||
sendResponse(PacketCoding.CreateGamePacket(0,
|
||||
ObjectCreateDetailedMessage(item_type, item_guid, ObjectCreateMessageParent(vehicle_guid, slot), item_data)
|
||||
))
|
||||
// sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(vehicle_guid, item_guid, slot)))
|
||||
}
|
||||
|
||||
case VehicleResponse.UnloadVehicle(vehicle_guid) =>
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectDeleteMessage(vehicle_guid, 0)))
|
||||
|
||||
case VehicleResponse.UnstowEquipment(item_guid) =>
|
||||
if(player.GUID != guid) {
|
||||
//TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly?
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectDeleteMessage(item_guid, 0)))
|
||||
// sendResponse(PacketCoding.CreateGamePacket(0, ObjectDetachMessage(vehicle_guid, item_guid, Vector3(0f, 0f, 0f), 0f, 0f, 0f)))
|
||||
//...
|
||||
// continent.GUID(vehicle_guid) match {
|
||||
// case Some(veh : Vehicle) =>
|
||||
// veh.PassengerInSeat(player) match {
|
||||
// case Some(seat_num) =>
|
||||
// veh.Seat(seat_num).get.ControlledWeapon match {
|
||||
// case Some(weapon_num) =>
|
||||
// veh.Weapons.get(weapon_num) match {
|
||||
// case Some(mount) =>
|
||||
// mount.Equipment match {
|
||||
// case Some(wep : Tool) =>
|
||||
// val ammo = wep.AmmoSlot
|
||||
// sendResponse(PacketCoding.CreateGamePacket(0, InventoryStateMessage(ammo.Box.GUID, wep.GUID, ammo.Magazine)))
|
||||
// case _ => ;
|
||||
// }
|
||||
// case _ => ;
|
||||
// }
|
||||
// case _ => ;
|
||||
// }
|
||||
// case _ => ;
|
||||
// }
|
||||
// case _ => ;
|
||||
// }
|
||||
}
|
||||
|
||||
case VehicleResponse.VehicleState(vehicle_guid, unk1, pos, ang, vel, unk2, unk3, unk4, wheel_direction, unk5, unk6) =>
|
||||
if(player.GUID != guid) {
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, VehicleStateMessage(vehicle_guid, unk1, pos, ang, vel, unk2, unk3, unk4, wheel_direction, unk5, unk6)))
|
||||
|
|
@ -374,18 +420,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
obj.WeaponControlledFromSeat(seat_num) match {
|
||||
case Some(weapon : Tool) =>
|
||||
//update mounted weapon belonging to seat
|
||||
val magazine = weapon.AmmoSlots(weapon.FireModeIndex).Box //update the magazine in the weapon, specifically
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, InventoryStateMessage(magazine.GUID, 0, weapon.GUID, weapon.Magazine.toLong)))
|
||||
//update all related ammunition objects in trunk
|
||||
obj.Trunk.Items
|
||||
.filter({ case ((_, item)) => item.obj.isInstanceOf[AmmoBox] && item.obj.asInstanceOf[AmmoBox].AmmoType == weapon.AmmoType })
|
||||
.foreach({ case ((_, item)) =>
|
||||
val box = item.obj.asInstanceOf[AmmoBox]
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, InventoryStateMessage(box.GUID, 0, obj_guid, box.Capacity.toLong)))
|
||||
})
|
||||
weapon.AmmoSlots.foreach(slot => { //update the magazine(s) in the weapon, specifically
|
||||
val magazine = slot.Box
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, InventoryStateMessage(magazine.GUID, 0, weapon.GUID, magazine.Capacity.toLong)))
|
||||
})
|
||||
case _ => ; //no weapons to update
|
||||
}
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(obj_guid, player_guid, seat_num)))
|
||||
AccessContents(obj)
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.MountVehicle(player_guid, obj_guid, seat_num))
|
||||
|
||||
case Mountable.CanMount(obj : Mountable, seat_num) =>
|
||||
|
|
@ -431,7 +473,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
afterHolsters.foreach({elem => tplayer.Slot(elem.start).Equipment = elem.obj })
|
||||
val finalInventory = fillEmptyHolsters(tplayer.Holsters().iterator, toInventory ++ beforeInventory)
|
||||
//draw holsters
|
||||
(0 until 5).foreach({index =>
|
||||
tplayer.VisibleSlots.foreach({index =>
|
||||
tplayer.Slot(index).Equipment match {
|
||||
case Some(obj) =>
|
||||
val definition = obj.Definition
|
||||
|
|
@ -675,16 +717,34 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(PacketCoding.CreateGamePacket(0, ItemTransactionResultMessage(terminal_guid, TransactionType.Sell, false)))
|
||||
}
|
||||
|
||||
|
||||
case Terminal.BuyVehicle(vehicle, loadout) =>
|
||||
case Terminal.BuyVehicle(vehicle, weapons, trunk) =>
|
||||
continent.Map.TerminalToSpawnPad.get(msg.terminal_guid.guid) match {
|
||||
case Some(pad_guid) =>
|
||||
val pad = continent.GUID(pad_guid).get.asInstanceOf[VehicleSpawnPad]
|
||||
vehicle.Faction = tplayer.Faction
|
||||
vehicle.Position = pad.Position
|
||||
vehicle.Orientation = pad.Orientation
|
||||
//default loadout, weapons
|
||||
log.info(s"default weapons: ${weapons.size}")
|
||||
val vWeapons = vehicle.Weapons
|
||||
weapons.foreach(entry => {
|
||||
val index = entry.start
|
||||
vWeapons.get(index) match {
|
||||
case Some(slot) =>
|
||||
slot.Equipment = None
|
||||
slot.Equipment = entry.obj
|
||||
case None =>
|
||||
log.warn(s"applying default loadout to $vehicle, can not find a mounted weapon @ $index")
|
||||
}
|
||||
})
|
||||
//default loadout, trunk
|
||||
log.info(s"default trunk: ${trunk.size}")
|
||||
val vTrunk = vehicle.Trunk
|
||||
vTrunk.Clear()
|
||||
trunk.foreach(entry => { vTrunk += entry.start -> entry.obj })
|
||||
taskResolver ! RegisterNewVehicle(vehicle, pad)
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Learn, true)))
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, true)))
|
||||
|
||||
case None =>
|
||||
log.error(s"$tplayer wanted to spawn a vehicle, but there was no spawn pad associated with terminal ${msg.terminal_guid} to accept it")
|
||||
}
|
||||
|
|
@ -993,14 +1053,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
player.Certifications += CertificationType.Phantasm
|
||||
AwardBattleExperiencePoints(player, 1000000L)
|
||||
// player.ExoSuit = ExoSuitType.MAX //TODO strange issue; divide number above by 10 when uncommenting
|
||||
player.Slot(0).Equipment = Tool(beamer)
|
||||
player.Slot(0).Equipment = Tool(GlobalDefinitions.StandardPistol(player.Faction))
|
||||
player.Slot(2).Equipment = Tool(suppressor)
|
||||
player.Slot(4).Equipment = Tool(forceblade)
|
||||
player.Slot(4).Equipment = Tool(GlobalDefinitions.StandardMelee(player.Faction))
|
||||
player.Slot(6).Equipment = AmmoBox(bullet_9mm)
|
||||
player.Slot(9).Equipment = AmmoBox(bullet_9mm)
|
||||
player.Slot(12).Equipment = AmmoBox(bullet_9mm)
|
||||
player.Slot(33).Equipment = AmmoBox(bullet_9mm_AP)
|
||||
player.Slot(36).Equipment = AmmoBox(energy_cell)
|
||||
player.Slot(36).Equipment = AmmoBox(GlobalDefinitions.StandardPistolAmmo(player.Faction))
|
||||
player.Slot(39).Equipment = SimpleItem(remote_electronics_kit)
|
||||
player.Slot(5).Equipment.get.asInstanceOf[LockerContainer].Inventory += 0 -> SimpleItem(remote_electronics_kit)
|
||||
//TODO end temp player character auto-loading
|
||||
|
|
@ -1346,75 +1406,106 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
log.info("ObjectDelete: " + msg)
|
||||
|
||||
case msg @ MoveItemMessage(item_guid, source_guid, destination_guid, dest, unk1) =>
|
||||
player.Find(item_guid) match {
|
||||
case Some(index) =>
|
||||
val indexSlot = player.Slot(index)
|
||||
var itemOpt : Option[Equipment] = indexSlot.Equipment
|
||||
//use this to short circuit
|
||||
val item = itemOpt.get
|
||||
val destSlot = player.Slot(dest)
|
||||
val destItem = if((-1 < dest && dest < 5) || dest == Player.FreeHandSlot) {
|
||||
destSlot.Equipment match {
|
||||
case Some(found) =>
|
||||
Some(InventoryItem(found, dest))
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
else {
|
||||
val tile = item.Definition.Tile
|
||||
player.Inventory.CheckCollisionsVar(dest, tile.Width, tile.Height) match {
|
||||
case Success(Nil) => None //no item swap
|
||||
case Success(entry :: Nil) => Some(entry) //one item to swap
|
||||
case Success(_) | scala.util.Failure(_) => itemOpt = None; None //abort item move altogether
|
||||
}
|
||||
}
|
||||
if(itemOpt.isDefined) {
|
||||
log.info(s"MoveItem: $item_guid moved from $source_guid @ $index to $source_guid @ $dest")
|
||||
indexSlot.Equipment = None
|
||||
destItem match {
|
||||
//do we have a swap item?
|
||||
case Some(entry) => //yes, swap
|
||||
val item2 = entry.obj
|
||||
player.Slot(entry.start).Equipment = None //remove item2 to make room for item
|
||||
destSlot.Equipment = item //in case dest and index could block each other
|
||||
(indexSlot.Equipment = entry.obj) match {
|
||||
case Some(_) => //item and item2 swapped places successfully
|
||||
log.info(s"MoveItem: ${item2.GUID} swapped to $source_guid @ $index")
|
||||
//we must shuffle items around cleanly to avoid causing icons to "disappear"
|
||||
if(index == Player.FreeHandSlot) {
|
||||
//temporarily put in safe location, A -> C
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectDetachMessage(player.GUID, item.GUID, Vector3(0f, 0f, 0f), 0f, 0f, 0f))) //ground
|
||||
}
|
||||
else {
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(player.GUID, item.GUID, Player.FreeHandSlot))) //free hand
|
||||
}
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(player.GUID, item2.GUID, index))) //B -> A
|
||||
if(0 <= index && index < 5) {
|
||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentInHand(player.GUID, index, item2))
|
||||
}
|
||||
|
||||
case None => //item2 does not fit; drop on ground
|
||||
val pos = player.Position
|
||||
val playerOrient = player.Orientation
|
||||
val orient : Vector3 = Vector3(0f, 0f, playerOrient.z)
|
||||
continent.Actor ! Zone.DropItemOnGround(item2, pos, orient)
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectDetachMessage(player.GUID, item2.GUID, pos, 0f, 0f, playerOrient.z))) //ground
|
||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentOnGround(player.GUID, pos, orient, item2))
|
||||
(continent.GUID(source_guid), continent.GUID(destination_guid), continent.GUID(item_guid)) match {
|
||||
case (Some(source : Container), Some(destination : Container), Some(item : Equipment)) =>
|
||||
source.Find(item_guid) match {
|
||||
case Some(index) =>
|
||||
val indexSlot = source.Slot(index)
|
||||
val destSlot = destination.Slot(dest)
|
||||
val destItem = destSlot.Equipment
|
||||
if( {
|
||||
val tile = item.Definition.Tile
|
||||
destination.Collisions(dest, tile.Width, tile.Height) match {
|
||||
case Success(Nil) =>
|
||||
destItem.isEmpty //no item swap; abort if encountering an unexpected item
|
||||
case Success(entry :: Nil) =>
|
||||
destItem.contains(entry.obj) //one item to swap; abort if destination item is missing or is wrong
|
||||
case Success(_) | scala.util.Failure(_) =>
|
||||
false //abort when too many items at destination or other failure case
|
||||
}
|
||||
} && indexSlot.Equipment.contains(item)) {
|
||||
log.info(s"MoveItem: $item_guid moved from $source_guid @ $index to $destination_guid @ $dest")
|
||||
indexSlot.Equipment = None
|
||||
destItem match { //do we have a swap item?
|
||||
case Some(item2) => //yes, swap
|
||||
destSlot.Equipment = None //remove item2 to make room for item
|
||||
destSlot.Equipment = item
|
||||
(indexSlot.Equipment = item2) match {
|
||||
case Some(_) => //item and item2 swapped places successfully
|
||||
log.info(s"MoveItem: ${item2.GUID} swapped to $source_guid @ $index")
|
||||
//cleanly shuffle items around to avoid losing icons
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectDetachMessage(source_guid, item_guid, Vector3(0f, 0f, 0f), 0f, 0f, 0f))) //ground; A -> C
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(source_guid, item2.GUID, index))) //B -> A
|
||||
source match {
|
||||
case (obj : Vehicle) =>
|
||||
val player_guid = player.GUID
|
||||
vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player_guid, item_guid))
|
||||
vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.StowEquipment(player_guid, source_guid, index, item2))
|
||||
//TODO visible slot verification, in the case of BFR arms
|
||||
case (_ : Player) =>
|
||||
if(source.VisibleSlots.contains(index)) {
|
||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentInHand(source_guid, index, item2))
|
||||
}
|
||||
case _ => ;
|
||||
//TODO something?
|
||||
}
|
||||
|
||||
case None => //just move item over
|
||||
destSlot.Equipment = item
|
||||
}
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(source_guid, item_guid, dest)))
|
||||
if(0 <= dest && dest < 5) {
|
||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentInHand(player.GUID, dest, item))
|
||||
}
|
||||
case None => //item2 does not fit; drop on ground
|
||||
val pos = source.Position
|
||||
val sourceOrientZ = source.Orientation.z
|
||||
val orient : Vector3 = Vector3(0f, 0f, sourceOrientZ)
|
||||
continent.Actor ! Zone.DropItemOnGround(item2, pos, orient)
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectDetachMessage(source_guid, item2.GUID, pos, 0f, 0f, sourceOrientZ))) //ground
|
||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentOnGround(player.GUID, pos, orient, item2))
|
||||
}
|
||||
|
||||
case None => //just move item over
|
||||
destSlot.Equipment = item
|
||||
source match {
|
||||
case (obj : Vehicle) =>
|
||||
vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player.GUID, item_guid))
|
||||
//TODO visible slot verification, in the case of BFR arms
|
||||
case _ => ;
|
||||
//TODO something?
|
||||
}
|
||||
|
||||
}
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(destination_guid, item_guid, dest)))
|
||||
destination match {
|
||||
case (obj : Vehicle) =>
|
||||
vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.StowEquipment(player.GUID, destination_guid, dest, item))
|
||||
//TODO visible slot verification, in the case of BFR arms
|
||||
case (_ : Player) =>
|
||||
if(destination.VisibleSlots.contains(dest)) {
|
||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentInHand(destination_guid, dest, item))
|
||||
}
|
||||
case _ => ;
|
||||
//TODO something?
|
||||
}
|
||||
}
|
||||
else if(indexSlot.Equipment.nonEmpty) {
|
||||
log.error(s"MoveItem: wanted to move $item_guid, but unexpected item ${indexSlot.Equipment.get} at origin")
|
||||
}
|
||||
else {
|
||||
log.error(s"MoveItem: wanted to move $item_guid, but unexpected item(s) at destination")
|
||||
}
|
||||
case _ =>
|
||||
log.error(s"MoveItem: wanted to move $item_guid, but could not find it")
|
||||
}
|
||||
case None =>
|
||||
log.info(s"MoveItem: $source_guid wanted to move the item $item_guid but could not find it")
|
||||
|
||||
case (None, _, _) =>
|
||||
log.error(s"MoveItem: wanted to move $item_guid from $source_guid, but could not find source")
|
||||
case (_, None, _) =>
|
||||
log.error(s"MoveItem: wanted to move $item_guid from $source_guid to $destination_guid, but could not find destination")
|
||||
case (_, _, None) =>
|
||||
log.error(s"MoveItem: wanted to move $item_guid, but could not find it")
|
||||
case _ =>
|
||||
log.error(s"MoveItem: wanted to move $item_guid from $source_guid to $destination_guid, but multiple problems were encountered")
|
||||
}
|
||||
|
||||
case msg @ LootItemMessage(item_guid, target_guid) =>
|
||||
log.info("LootItem: " + msg)
|
||||
|
||||
case msg @ ChangeAmmoMessage(item_guid, unk1) =>
|
||||
log.info("ChangeAmmo: " + msg)
|
||||
|
||||
|
|
@ -1463,14 +1554,35 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
case Some(obj : Vehicle) =>
|
||||
if(obj.Faction == player.Faction) {
|
||||
player.Slot(player.DrawnSlot).Equipment match {
|
||||
val equipment = player.Slot(player.DrawnSlot).Equipment
|
||||
if(equipment match {
|
||||
case Some(tool : Tool) =>
|
||||
if(tool.Definition == GlobalDefinitions.nano_dispenser) {
|
||||
//TODO repairing behavior
|
||||
tool.Definition match {
|
||||
case GlobalDefinitions.nano_dispenser | GlobalDefinitions.remote_electronics_kit => false
|
||||
case _ => true
|
||||
}
|
||||
case Some(_) | None =>
|
||||
//TODO trunk access
|
||||
case _ => true
|
||||
}) {
|
||||
//access to trunk
|
||||
if(obj.AccessingTrunk.isEmpty) {
|
||||
obj.AccessingTrunk = player.GUID
|
||||
AccessContents(obj)
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType)))
|
||||
}
|
||||
else {
|
||||
log.info(s"UseItem: $player can not cut in line while player ${obj.AccessingTrunk.get} is using $obj's trunk")
|
||||
}
|
||||
}
|
||||
else if(equipment.isDefined) {
|
||||
equipment.get.Definition match {
|
||||
case GlobalDefinitions.nano_dispenser =>
|
||||
//TODO repairing behavior
|
||||
|
||||
case GlobalDefinitions.remote_electronics_kit =>
|
||||
//TODO hacking behavior
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1487,8 +1599,17 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case None => ;
|
||||
}
|
||||
|
||||
case msg @ UnuseItemMessage(player_guid, item) =>
|
||||
case msg @ UnuseItemMessage(player_guid, object_guid) =>
|
||||
log.info("UnuseItem: " + msg)
|
||||
continent.GUID(object_guid) match {
|
||||
case Some(obj : Vehicle) =>
|
||||
if(obj.AccessingTrunk.contains(player.GUID)) {
|
||||
obj.AccessingTrunk = None
|
||||
UnAccessContents(obj)
|
||||
}
|
||||
|
||||
case _ =>;
|
||||
}
|
||||
|
||||
case msg @ DeployObjectMessage(guid, unk1, pos, roll, pitch, yaw, unk2) =>
|
||||
log.info("DeployObject: " + msg)
|
||||
|
|
@ -1559,12 +1680,17 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
//TODO optimize this later
|
||||
log.info(s"DismountVehicleMsg: $msg")
|
||||
if(player.GUID == player_guid) {
|
||||
//normally disembarking from a seat
|
||||
val previouslySeated = player.VehicleSeated
|
||||
player.VehicleSeated = None
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, DismountVehicleMsg(player_guid, unk1, unk2)))
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DismountVehicle(player_guid, unk1, unk2))
|
||||
//common warning for this section
|
||||
def dismountWarning(msg : String) : Unit = {
|
||||
log.warn(s"$msg; some vehicle might not know that a player is no longer sitting in it")
|
||||
}
|
||||
//normally disembarking from a seat
|
||||
player.VehicleSeated match {
|
||||
//find vehicle seat and disembark it
|
||||
previouslySeated match {
|
||||
case Some(obj_guid) =>
|
||||
continent.GUID(obj_guid) match {
|
||||
case Some(obj : Mountable) =>
|
||||
|
|
@ -1580,6 +1706,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case (veh : Vehicle) =>
|
||||
if(seats.count(seat => seat.isOccupied) == 0) {
|
||||
vehicleService ! VehicleServiceMessage.DelayedVehicleDeconstruction(veh, continent, 600L) //start vehicle decay (10m)
|
||||
UnAccessContents(veh)
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
|
|
@ -1593,10 +1720,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case None =>
|
||||
dismountWarning(s"DismountVehicleMsg: player $player_guid not considered seated in a mountable entity")
|
||||
}
|
||||
//should be safe
|
||||
player.VehicleSeated = None
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, DismountVehicleMsg(player_guid, unk1, unk2)))
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DismountVehicle(player_guid, unk1, unk2))
|
||||
}
|
||||
else {
|
||||
//kicking someone else out of a seat; need to own that seat
|
||||
|
|
@ -1612,7 +1735,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case Some(seat) =>
|
||||
seat.Occupant = None
|
||||
tplayer.VehicleSeated = None
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(player_guid, unk1, unk2))
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(player_guid, unk1, unk2, vehicle_guid))
|
||||
if(seats.count(seat => seat.isOccupied) == 0) {
|
||||
vehicleService ! VehicleServiceMessage.DelayedVehicleDeconstruction(obj, continent, 600L) //start vehicle decay (10m)
|
||||
}
|
||||
|
|
@ -1673,7 +1796,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
if(vehicle.SeatPermissionGroup(seat_num).contains(group) && tplayer != player) {
|
||||
seat.Occupant = None
|
||||
tplayer.VehicleSeated = None
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(tplayer.GUID, 4, false))
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(tplayer.GUID, 4, false, object_guid))
|
||||
}
|
||||
case None => ;
|
||||
}
|
||||
|
|
@ -1944,9 +2067,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
TaskResolver.GiveTask(
|
||||
new Task() {
|
||||
private val localVehicle = obj
|
||||
private val localPad = pad.Actor
|
||||
private val localAnnounce = vehicleService
|
||||
private val localSession : String = sessionId.toString
|
||||
private val localPad = pad.Actor
|
||||
private val localPlayer = player
|
||||
private val localVehicleService = vehicleService
|
||||
private val localZone = continent
|
||||
|
|
@ -2137,6 +2260,32 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
}
|
||||
|
||||
def AccessContents(vehicle : Vehicle) : Unit = {
|
||||
vehicleService ! Service.Join(s"${vehicle.Actor}")
|
||||
val parent_guid = vehicle.GUID
|
||||
vehicle.Trunk.Items.foreach({
|
||||
case ((_, entry)) =>
|
||||
val obj = entry.obj
|
||||
val obj_def = obj.Definition
|
||||
sendResponse(PacketCoding.CreateGamePacket(0,
|
||||
ObjectCreateDetailedMessage(
|
||||
obj_def.ObjectId,
|
||||
obj.GUID,
|
||||
ObjectCreateMessageParent(parent_guid, entry.start),
|
||||
obj_def.Packet.DetailedConstructorData(obj).get
|
||||
)
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
def UnAccessContents(vehicle : Vehicle) : Unit = {
|
||||
vehicleService ! Service.Leave(Some(s"${vehicle.Actor}"))
|
||||
vehicle.Trunk.Items.foreach({
|
||||
case ((_, entry)) =>
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectDeleteMessage(entry.obj.GUID, 0)))
|
||||
})
|
||||
}
|
||||
|
||||
def failWithError(error : String) = {
|
||||
log.error(error)
|
||||
sendResponse(PacketCoding.CreateControlPacket(ConnectionClose()))
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ object Service {
|
|||
final val defaultPlayerGUID : PlanetSideGUID = PlanetSideGUID(0)
|
||||
|
||||
final case class Join(channel : String)
|
||||
final case class Leave()
|
||||
final case class Leave(channel : Option[String] = None)
|
||||
final case class LeaveAll()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,12 +18,18 @@ class AvatarService extends Actor {
|
|||
case Service.Join(channel) =>
|
||||
val path = s"/$channel/Avatar"
|
||||
val who = sender()
|
||||
|
||||
log.info(s"$who has joined $path")
|
||||
|
||||
AvatarEvents.subscribe(who, path)
|
||||
case Service.Leave() =>
|
||||
|
||||
case Service.Leave(None) =>
|
||||
AvatarEvents.unsubscribe(sender())
|
||||
|
||||
case Service.Leave(Some(channel)) =>
|
||||
val path = s"/$channel/Avatar"
|
||||
val who = sender()
|
||||
log.info(s"$who has left $path")
|
||||
AvatarEvents.unsubscribe(sender(), path)
|
||||
|
||||
case Service.LeaveAll() =>
|
||||
AvatarEvents.unsubscribe(sender())
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,16 @@ class LocalService extends Actor {
|
|||
val who = sender()
|
||||
log.info(s"$who has joined $path")
|
||||
LocalEvents.subscribe(who, path)
|
||||
case Service.Leave() =>
|
||||
|
||||
case Service.Leave(None) =>
|
||||
LocalEvents.unsubscribe(sender())
|
||||
|
||||
case Service.Leave(Some(channel)) =>
|
||||
val path = s"/$channel/Local"
|
||||
val who = sender()
|
||||
log.info(s"$who has left $path")
|
||||
LocalEvents.unsubscribe(who, path)
|
||||
|
||||
case Service.LeaveAll() =>
|
||||
LocalEvents.unsubscribe(sender())
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package services.vehicle
|
||||
|
||||
import net.psforever.objects.Vehicle
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.packet.game.objectcreate.ConstructorData
|
||||
|
|
@ -13,10 +14,12 @@ object VehicleAction {
|
|||
final case class Awareness(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID) extends Action
|
||||
final case class ChildObjectState(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, pitch : Float, yaw : Float) extends Action
|
||||
final case class DismountVehicle(player_guid : PlanetSideGUID, unk1 : Int, unk2 : Boolean) extends Action
|
||||
final case class KickPassenger(player_guid : PlanetSideGUID, unk1 : Int, unk2 : Boolean) extends Action
|
||||
final case class KickPassenger(player_guid : PlanetSideGUID, unk1 : Int, unk2 : Boolean, vehicle_guid : PlanetSideGUID) extends Action
|
||||
final case class LoadVehicle(player_guid : PlanetSideGUID, vehicle : Vehicle, vtype : Int, vguid : PlanetSideGUID, vdata : ConstructorData) extends Action
|
||||
final case class MountVehicle(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, seat : Int) extends Action
|
||||
final case class SeatPermissions(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, seat_group : Int, permission : Long) extends Action
|
||||
final case class StowEquipment(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, slot : Int, item : Equipment) extends Action
|
||||
final case class UnloadVehicle(player_guid : PlanetSideGUID, continent : Zone, vehicle : Vehicle) extends Action
|
||||
final case class UnstowEquipment(player_guid : PlanetSideGUID, item_guid : PlanetSideGUID) extends Action
|
||||
final case class VehicleState(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, unk1 : Int, pos : Vector3, ang : Vector3, vel : Option[Vector3], unk2 : Option[Int], unk3 : Int, unk4 : Int, wheel_direction : Int, unk5 : Boolean, unk6 : Boolean) extends Action
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,12 @@ object VehicleResponse {
|
|||
final case class Awareness(vehicle_guid : PlanetSideGUID) extends Response
|
||||
final case class ChildObjectState(object_guid : PlanetSideGUID, pitch : Float, yaw : Float) extends Response
|
||||
final case class DismountVehicle(unk1 : Int, unk2 : Boolean) extends Response
|
||||
final case class KickPassenger(unk1 : Int, unk2 : Boolean) extends Response
|
||||
final case class KickPassenger(unk1 : Int, unk2 : Boolean, vehicle_guid : PlanetSideGUID) extends Response
|
||||
final case class LoadVehicle(vehicle : Vehicle, vtype : Int, vguid : PlanetSideGUID, vdata : ConstructorData) extends Response
|
||||
final case class MountVehicle(object_guid : PlanetSideGUID, seat : Int) extends Response
|
||||
final case class SeatPermissions(vehicle_guid : PlanetSideGUID, seat_group : Int, permission : Long) extends Response
|
||||
final case class StowEquipment(vehicle_guid : PlanetSideGUID, slot : Int, itype : Int, iguid : PlanetSideGUID, idata : ConstructorData) extends Response
|
||||
final case class UnloadVehicle(vehicle_guid : PlanetSideGUID) extends Response
|
||||
final case class UnstowEquipment(item_guid : PlanetSideGUID) extends Response
|
||||
final case class VehicleState(vehicle_guid : PlanetSideGUID, unk1 : Int, pos : Vector3, ang : Vector3, vel : Option[Vector3], unk2 : Option[Int], unk3 : Int, unk4 : Int, wheel_direction : Int, unk5 : Boolean, unk6 : Boolean) extends Response
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,12 +22,18 @@ class VehicleService extends Actor {
|
|||
case Service.Join(channel) =>
|
||||
val path = s"/$channel/Vehicle"
|
||||
val who = sender()
|
||||
|
||||
log.info(s"$who has joined $path")
|
||||
|
||||
VehicleEvents.subscribe(who, path)
|
||||
case Service.Leave() =>
|
||||
|
||||
case Service.Leave(None) =>
|
||||
VehicleEvents.unsubscribe(sender())
|
||||
|
||||
case Service.Leave(Some(channel)) =>
|
||||
val path = s"/$channel/Vehicle"
|
||||
val who = sender()
|
||||
log.info(s"$who has left $path")
|
||||
VehicleEvents.unsubscribe(who, path)
|
||||
|
||||
case Service.LeaveAll() =>
|
||||
VehicleEvents.unsubscribe(sender())
|
||||
|
||||
|
|
@ -45,9 +51,9 @@ class VehicleService extends Actor {
|
|||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.DismountVehicle(unk1, unk2))
|
||||
)
|
||||
case VehicleAction.KickPassenger(player_guid, unk1, unk2) =>
|
||||
case VehicleAction.KickPassenger(player_guid, unk1, unk2, vehicle_guid) =>
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.KickPassenger(unk1, unk2))
|
||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.KickPassenger(unk1, unk2, vehicle_guid))
|
||||
)
|
||||
case VehicleAction.LoadVehicle(player_guid, vehicle, vtype, vguid, vdata) =>
|
||||
VehicleEvents.publish(
|
||||
|
|
@ -61,6 +67,15 @@ class VehicleService extends Actor {
|
|||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.SeatPermissions(vehicle_guid, seat_group, permission))
|
||||
)
|
||||
case VehicleAction.StowEquipment(player_guid, vehicle_guid, slot, item) =>
|
||||
val definition = item.Definition
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.StowEquipment(vehicle_guid, slot, definition.ObjectId, item.GUID, definition.Packet.DetailedConstructorData(item).get))
|
||||
)
|
||||
case VehicleAction.UnstowEquipment(player_guid, item_guid) =>
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.UnstowEquipment(item_guid))
|
||||
)
|
||||
case VehicleAction.VehicleState(player_guid, vehicle_guid, unk1, pos, ang, vel, unk2, unk3, unk4, wheel_direction, unk5, unk6) =>
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.VehicleState(vehicle_guid, unk1, pos, ang, vel, unk2, unk3, unk4, wheel_direction, unk5, unk6))
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class DeconstructionActor extends Actor {
|
|||
seat.Occupant = None
|
||||
tplayer.VehicleSeated = None
|
||||
if(tplayer.HasGUID) {
|
||||
context.parent ! VehicleServiceMessage(zone_id, VehicleAction.KickPassenger(tplayer.GUID, 4, false))
|
||||
context.parent ! VehicleServiceMessage(zone_id, VehicleAction.KickPassenger(tplayer.GUID, 4, false, vehicle.GUID))
|
||||
}
|
||||
case None => ;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue