mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
commit
27d86af015
|
|
@ -12,7 +12,7 @@ import net.psforever.objects.serverobject.locks.IFFLockDefinition
|
|||
import net.psforever.objects.serverobject.mblocker.LockerDefinition
|
||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPadDefinition
|
||||
import net.psforever.objects.serverobject.terminals._
|
||||
import net.psforever.objects.vehicles.SeatArmorRestriction
|
||||
import net.psforever.objects.vehicles.{SeatArmorRestriction, UtilityType}
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
|
||||
object GlobalDefinitions {
|
||||
|
|
@ -486,6 +486,10 @@ object GlobalDefinitions {
|
|||
*/
|
||||
val order_terminal = new OrderTerminalDefinition
|
||||
|
||||
val order_terminala = new OrderTerminalABDefinition(613)
|
||||
|
||||
val order_terminalb = new OrderTerminalABDefinition(614)
|
||||
|
||||
val cert_terminal = new CertTerminalDefinition
|
||||
|
||||
val implant_terminal_mech = new ImplantTerminalMechDefinition
|
||||
|
|
@ -2343,6 +2347,8 @@ object GlobalDefinitions {
|
|||
ams.Seats(0).ArmorRestriction = SeatArmorRestriction.NoReinforcedOrMax
|
||||
ams.MountPoints += 1 -> 0
|
||||
ams.MountPoints += 2 -> 0
|
||||
ams.Utilities += 3 -> UtilityType.order_terminala
|
||||
ams.Utilities += 4 -> UtilityType.order_terminalb
|
||||
ams.Packet = utilityConverter
|
||||
|
||||
val variantConverter = new VariantVehicleConverter
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import net.psforever.packet.game.objectcreate.DriveState
|
|||
import net.psforever.types.PlanetSideEmpire
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.mutable
|
||||
|
||||
/**
|
||||
* The server-side support object that represents a vehicle.<br>
|
||||
|
|
@ -23,7 +22,15 @@ import scala.collection.mutable
|
|||
* Following that are the mounted weapons and other utilities.
|
||||
* Trunk space starts being indexed afterwards.<br>
|
||||
* <br>
|
||||
* To keep it simple, infantry seating, mounted weapons, and utilities are stored separately.
|
||||
* To keep it simple, infantry seating, mounted weapons, and utilities are stored separately.<br>
|
||||
* <br>
|
||||
* Vehicles maintain a `Map` of `Utility` objects in given index positions.
|
||||
* Positive indices and zero are considered "represented" and must be assigned a globally unique identifier
|
||||
* and must be present in the containing vehicle's `ObjectCreateMessage` packet.
|
||||
* The index is the seat position, reflecting the position in the zero-index inventory.
|
||||
* Negative indices are expected to be excluded from this conversion.
|
||||
* The value of the negative index does not have a specific meaning.
|
||||
* @see `Vehicle.EquipmentUtilities`
|
||||
* @param vehicleDef the vehicle's definition entry';
|
||||
* stores and unloads pertinent information about the `Vehicle`'s configuration;
|
||||
* used in the initialization process (`loadVehicleDefinition`)
|
||||
|
|
@ -49,7 +56,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ
|
|||
private val groupPermissions : Array[VehicleLockState.Value] = Array(VehicleLockState.Locked, VehicleLockState.Empire, VehicleLockState.Empire, VehicleLockState.Locked)
|
||||
private var seats : Map[Int, Seat] = Map.empty
|
||||
private var weapons : Map[Int, EquipmentSlot] = Map.empty
|
||||
private val utilities : mutable.ArrayBuffer[Utility] = mutable.ArrayBuffer()
|
||||
private var utilities : Map[Int, Utility] = Map()
|
||||
private val trunk : GridInventory = GridInventory()
|
||||
|
||||
//init
|
||||
|
|
@ -325,16 +332,21 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ
|
|||
}
|
||||
}
|
||||
|
||||
def Utilities : mutable.ArrayBuffer[Utility] = utilities
|
||||
def Utilities : Map[Int, Utility] = utilities
|
||||
|
||||
/**
|
||||
* Get a referenece ot a certain `Utility` attached to this `Vehicle`.
|
||||
* @param utilNumber the attachment number of the `Utility`
|
||||
* @return the `Utility` or `None` (if invalid)
|
||||
*/
|
||||
def Utility(utilNumber : Int) : Option[Utility] = {
|
||||
def Utility(utilNumber : Int) : Option[PlanetSideServerObject] = {
|
||||
if(utilNumber >= 0 && utilNumber < this.utilities.size) {
|
||||
Some(this.utilities(utilNumber))
|
||||
this.utilities.get(utilNumber) match {
|
||||
case Some(util) =>
|
||||
Some(util())
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
else {
|
||||
None
|
||||
|
|
@ -489,6 +501,14 @@ object Vehicle {
|
|||
new Vehicle(vehicleDef)
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a `Map` of `Utility` objects, only return the objects with a positive or zero-index position.
|
||||
* @return a map of applicable utilities
|
||||
*/
|
||||
def EquipmentUtilities(utilities : Map[Int, Utility]) : Map[Int, Utility] = {
|
||||
utilities.filter({ case(index : Int, _ : Utility) => index > -1 })
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the `*Definition` that was provided to this object to initialize its fields and settings.
|
||||
* @param vehicle the `Vehicle` being initialized
|
||||
|
|
@ -506,10 +526,8 @@ object Vehicle {
|
|||
}).toMap
|
||||
//create seats
|
||||
vehicle.seats = vdef.Seats.map({ case(num, definition) => num -> Seat(definition)}).toMap
|
||||
for(i <- vdef.Utilities) {
|
||||
//TODO utilies must be loaded and wired on a case-by-case basis?
|
||||
vehicle.Utilities += Utility.Select(i, vehicle)
|
||||
}
|
||||
//create utilities
|
||||
vehicle.utilities = vdef.Utilities.map({ case(num, util) => num -> Utility(util, vehicle) }).toMap
|
||||
//trunk
|
||||
vdef.TrunkSize match {
|
||||
case InventoryTile.None => ;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package net.psforever.objects.definition
|
|||
|
||||
import net.psforever.objects.definition.converter.VehicleConverter
|
||||
import net.psforever.objects.inventory.InventoryTile
|
||||
import net.psforever.objects.vehicles.UtilityType
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
|
|
@ -20,7 +21,7 @@ class VehicleDefinition(objectId : Int) extends ObjectDefinition(objectId) {
|
|||
/* key - seat index (where this weapon attaches during object construction), value - the weapon on an EquipmentSlot */
|
||||
private val weapons : mutable.HashMap[Int, ToolDefinition] = mutable.HashMap[Int, ToolDefinition]()
|
||||
private var deployment : Boolean = false
|
||||
private val utilities : mutable.ArrayBuffer[Int] = mutable.ArrayBuffer[Int]()
|
||||
private val utilities : mutable.HashMap[Int, UtilityType.Value] = mutable.HashMap()
|
||||
private var trunkSize : InventoryTile = InventoryTile.None
|
||||
private var trunkOffset : Int = 0
|
||||
private var canCloak : Boolean = false
|
||||
|
|
@ -69,7 +70,7 @@ class VehicleDefinition(objectId : Int) extends ObjectDefinition(objectId) {
|
|||
Deployment
|
||||
}
|
||||
|
||||
def Utilities : mutable.ArrayBuffer[Int] = utilities
|
||||
def Utilities : mutable.HashMap[Int, UtilityType.Value] = utilities
|
||||
|
||||
def TrunkSize : InventoryTile = trunkSize
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.definition.converter
|
||||
|
||||
import net.psforever.objects.serverobject.terminals.Terminal
|
||||
import net.psforever.packet.game.objectcreate.CommonTerminalData
|
||||
|
||||
import scala.util.{Success, Try}
|
||||
|
||||
class TerminalConverter extends ObjectCreateConverter[Terminal]() {
|
||||
override def ConstructorData(obj : Terminal) : Try[CommonTerminalData] = { Success(CommonTerminalData(obj.Faction)) }
|
||||
}
|
||||
|
|
@ -29,55 +29,28 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
|||
false,
|
||||
obj.Cloaked,
|
||||
SpecificFormatData(obj),
|
||||
Some(InventoryData(MakeMountings(obj).sortBy(_.parentSlot)))
|
||||
Some(InventoryData((MakeUtilities(obj) ++ MakeMountings(obj)).sortBy(_.parentSlot)))
|
||||
)(SpecificFormatModifier)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param obj the `Player` game object
|
||||
* @return a list of all tools that were in the mounted weapon slots in decoded packet form
|
||||
*/
|
||||
|
||||
private def MakeMountings(obj : Vehicle) : List[InventoryItemData.InventoryItem] = {
|
||||
obj.Weapons.map({
|
||||
case((index, slot)) =>
|
||||
val equip : Equipment = slot.Equipment.get
|
||||
InventoryItemData(equip.Definition.ObjectId, equip.GUID, index, equip.Definition.Packet.ConstructorData(equip).get)
|
||||
val equipDef = equip.Definition
|
||||
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.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) {
|
||||
// list
|
||||
// }
|
||||
// else {
|
||||
// val (index, seat) = iter.next
|
||||
// seat.Occupant match {
|
||||
// case Some(avatar) =>
|
||||
// val definition = avatar.Definition
|
||||
// recursiveMakeSeats(
|
||||
// iter,
|
||||
// list :+ InventoryItemData(definition.ObjectId, avatar.GUID, index, definition.Packet.ConstructorData(avatar).get)
|
||||
// )
|
||||
// case None =>
|
||||
// recursiveMakeSeats(iter, list)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
protected def MakeUtilities(obj : Vehicle) : List[InventoryItemData.InventoryItem] = {
|
||||
Vehicle.EquipmentUtilities(obj.Utilities).map({
|
||||
case(index, utilContainer) =>
|
||||
val util = utilContainer()
|
||||
val utilDef = util.Definition
|
||||
InventoryItemData(utilDef.ObjectId, util.GUID, index, utilDef.Packet.ConstructorData(util).get)
|
||||
}).toList
|
||||
}
|
||||
|
||||
protected def SpecificFormatModifier : VehicleFormat.Value = VehicleFormat.Normal
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.guid
|
||||
|
||||
import net.psforever.objects.vehicles.Utility
|
||||
|
||||
/**
|
||||
* The basic compiled tasks for assigning (registering) and revoking (unregistering) globally unique identifiers.<br>
|
||||
* <br>
|
||||
|
|
@ -149,8 +151,9 @@ object GUIDTask {
|
|||
def RegisterVehicle(vehicle : Vehicle)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
||||
import net.psforever.objects.inventory.InventoryItem
|
||||
val weaponTasks = vehicle.Weapons.map({ case(_ : Int, entry : EquipmentSlot) => RegisterEquipment(entry.Equipment.get)}).toList
|
||||
val utilTasks = Vehicle.EquipmentUtilities(vehicle.Utilities).map({case (_ : Int, util : Utility) => RegisterObjectTask(util())}).toList
|
||||
val inventoryTasks = vehicle.Trunk.Items.map({ case((_ : Int, entry : InventoryItem)) => RegisterEquipment(entry.obj)})
|
||||
TaskResolver.GiveTask(RegisterObjectTask(vehicle).task, weaponTasks ++ inventoryTasks)
|
||||
TaskResolver.GiveTask(RegisterObjectTask(vehicle).task, weaponTasks ++ utilTasks ++ inventoryTasks)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -252,8 +255,9 @@ object GUIDTask {
|
|||
def UnregisterVehicle(vehicle : Vehicle)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
||||
import net.psforever.objects.inventory.InventoryItem
|
||||
val weaponTasks = vehicle.Weapons.map({ case(_ : Int, entry : EquipmentSlot) => UnregisterTool(entry.Equipment.get.asInstanceOf[Tool]) }).toList
|
||||
val utilTasks = Vehicle.EquipmentUtilities(vehicle.Utilities).map({case (_ : Int, util : Utility) => UnregisterObjectTask(util())}).toList
|
||||
val inventoryTasks = vehicle.Trunk.Items.map({ case((_ : Int, entry : InventoryItem)) => UnregisterEquipment(entry.obj)})
|
||||
TaskResolver.GiveTask(UnregisterObjectTask(vehicle).task, weaponTasks ++ inventoryTasks)
|
||||
TaskResolver.GiveTask(UnregisterObjectTask(vehicle).task, weaponTasks ++ utilTasks ++ inventoryTasks)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,10 +4,27 @@ package net.psforever.objects.serverobject.terminals
|
|||
import net.psforever.objects._
|
||||
import net.psforever.objects.definition._
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.packet.game.ItemTransactionMessage
|
||||
import net.psforever.types.ExoSuitType
|
||||
|
||||
import scala.annotation.switch
|
||||
|
||||
abstract class EquipmentTerminalDefinition(objId : Int) extends TerminalDefinition(objId) {
|
||||
Name = "equipment_terminal"
|
||||
|
||||
/**
|
||||
* Process a `TransactionType.Sell` action by the user.
|
||||
* There is no specific tab associated with this action.
|
||||
* It is a common button on the terminal interface window.
|
||||
* Additionally, the equipment to be sold ia almost always in the player's `FreeHand` slot.
|
||||
* Selling `Equipment` is always permitted.
|
||||
* @param player the player
|
||||
* @param msg the original packet carrying the request
|
||||
* @return an actionable message that explains how to process the request
|
||||
*/
|
||||
override def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
||||
Terminal.SellEquipment()
|
||||
}
|
||||
}
|
||||
|
||||
object EquipmentTerminalDefinition {
|
||||
|
|
@ -22,7 +39,15 @@ object EquipmentTerminalDefinition {
|
|||
"standard_issue_armor" -> (ExoSuitType.Standard, 0),
|
||||
"lite_armor" -> (ExoSuitType.Agile, 0),
|
||||
"med_armor" -> (ExoSuitType.Reinforced, 0),
|
||||
"stealth_armor" -> (ExoSuitType.Infiltration, 0),
|
||||
"stealth_armor" -> (ExoSuitType.Infiltration, 0)
|
||||
)
|
||||
|
||||
/**
|
||||
* A `Map` of information for changing mechanized assault exo-suits.
|
||||
* key - an identification string sent by the client
|
||||
* value - a `Tuple` containing exo-suit specifications
|
||||
*/
|
||||
val maxSuits : Map[String, (ExoSuitType.Value, Int)] = Map(
|
||||
"trhev_antiaircraft" -> (ExoSuitType.MAX, 3),
|
||||
"trhev_antipersonnel" -> (ExoSuitType.MAX, 1),
|
||||
"trhev_antivehicular" -> (ExoSuitType.MAX, 2),
|
||||
|
|
@ -337,4 +362,57 @@ object EquipmentTerminalDefinition {
|
|||
MakeKit(obj.kdef)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a `TransactionType.Buy` action by the user.
|
||||
* Either attempt to purchase equipment or attempt to switch directly to a different exo-suit.
|
||||
* @param page0Stock the `Equipment` items and `AmmoBox` items available on the first tab
|
||||
* @param page2Stock the `Equipment` items and `AmmoBox` items available on the third tab
|
||||
* @param exosuits the exo-suit types (and subtypes) available on the second tab
|
||||
* @param player the player
|
||||
* @param msg the original packet carrying the request
|
||||
* @return an actionable message that explains how to process the request
|
||||
*/
|
||||
def Buy(page0Stock : Map[String, ()=>Equipment],
|
||||
page2Stock : Map[String, ()=>Equipment],
|
||||
exosuits : Map[String, (ExoSuitType.Value, Int)])
|
||||
(player : Player, msg : ItemTransactionMessage): Terminal.Exchange = {
|
||||
(msg.item_page : @switch) match {
|
||||
case 0 => //Weapon tab
|
||||
page0Stock.get(msg.item_name) match {
|
||||
case Some(item) =>
|
||||
Terminal.BuyEquipment(item())
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
case 2 => //Support tab
|
||||
page2Stock.get(msg.item_name) match {
|
||||
case Some(item) =>
|
||||
Terminal.BuyEquipment(item())
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
case 3 => //Vehicle tab
|
||||
vehicleAmmunition.get(msg.item_name) match {
|
||||
case Some(item) =>
|
||||
Terminal.BuyEquipment(item())
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
case 1 => //Armor tab
|
||||
exosuits.get(msg.item_name) match {
|
||||
case Some((suit, subtype)) =>
|
||||
Terminal.BuyExosuit(suit, subtype)
|
||||
case None =>
|
||||
maxAmmo.get(msg.item_name) match {
|
||||
case Some(item) =>
|
||||
Terminal.BuyEquipment(item())
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import akka.actor.ActorContext
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.inventory.InventoryItem
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.packet.game.ItemTransactionMessage
|
||||
import net.psforever.objects.serverobject.terminals.EquipmentTerminalDefinition._
|
||||
import net.psforever.types.ExoSuitType
|
||||
|
||||
/**
|
||||
* The definition for any `Terminal` that is of a type "ams_order_terminal".
|
||||
* As the name indicates, paired on the flanks of an advanced mobile spawn vehicle.<br>
|
||||
* <br>
|
||||
* `Buy` and `Sell` `Equipment` items and `AmmoBox` items.
|
||||
* Change `ExoSuitType` and retrieve `Loadout` entries.
|
||||
* Changing into mechanized assault exo-suits (MAXes) is not permitted.
|
||||
*/
|
||||
class OrderTerminalABDefinition(object_id : Int) extends EquipmentTerminalDefinition(object_id) {
|
||||
if(object_id == 613) {
|
||||
Name = "order_terminala"
|
||||
}
|
||||
else if(object_id == 614) {
|
||||
Name = "order_terminalb"
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("terminal must be either object id 613 or object id 614")
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Equipment` available from this `Terminal` on specific pages.
|
||||
*/
|
||||
private val buyFunc : (Player, ItemTransactionMessage)=>Terminal.Exchange =
|
||||
EquipmentTerminalDefinition.Buy(
|
||||
infantryAmmunition ++ infantryWeapons,
|
||||
supportAmmunition ++ supportWeapons,
|
||||
suits
|
||||
)
|
||||
|
||||
override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = buyFunc(player, msg)
|
||||
|
||||
/**
|
||||
* Process a `TransactionType.InfantryLoadout` action by the user.
|
||||
* `Loadout` objects are blueprints composed of exo-suit specifications and simplified `Equipment`-to-slot mappings.
|
||||
* If a valid loadout is found, its data is transformed back into actual `Equipment` for return to the user.
|
||||
* Loadouts that would suit the player into a mechanized assault exo-suit are not permitted.
|
||||
* @param player the player
|
||||
* @param msg the original packet carrying the request
|
||||
* @return an actionable message that explains how to process the request
|
||||
*/
|
||||
override def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
||||
if(msg.item_page == 4) { //Favorites tab
|
||||
player.LoadLoadout(msg.unk1) match {
|
||||
case Some(loadout) =>
|
||||
if(loadout.ExoSuit != ExoSuitType.MAX) {
|
||||
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)
|
||||
}
|
||||
else {
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
else {
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object OrderTerminalABDefinition {
|
||||
/**
|
||||
* Assemble some logic for a provided object.
|
||||
* @param obj an `Amenity` object;
|
||||
* anticipating a `Terminal` object using this same definition
|
||||
* @param context hook to the local `Actor` system
|
||||
*/
|
||||
def Setup(obj : Amenity, context : ActorContext) : Unit = {
|
||||
import akka.actor.{ActorRef, Props}
|
||||
if(obj.Actor == ActorRef.noSender) {
|
||||
obj.Actor = context.actorOf(Props(classOf[TerminalControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,15 +2,14 @@
|
|||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
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
|
||||
|
||||
/**
|
||||
* The definition for any `Terminal` that is of a type "order_terminal".
|
||||
* This kind of "order_terminal" is applicable to facilities.<br>
|
||||
* <br>
|
||||
* `Buy` and `Sell` `Equipment` items and `AmmoBox` items.
|
||||
* Change `ExoSuitType` and retrieve `Loadout` entries.
|
||||
*/
|
||||
|
|
@ -20,68 +19,12 @@ class OrderTerminalDefinition extends EquipmentTerminalDefinition(612) {
|
|||
/**
|
||||
* The `Equipment` available from this `Terminal` on specific pages.
|
||||
*/
|
||||
private val page0Stock : Map[String, ()=>Equipment] = infantryAmmunition ++ infantryWeapons
|
||||
private val page2Stock : Map[String, ()=>Equipment] = supportAmmunition ++ supportWeapons
|
||||
private val buyFunc : (Player, ItemTransactionMessage)=>Terminal.Exchange = EquipmentTerminalDefinition.Buy(
|
||||
infantryAmmunition ++ infantryWeapons,
|
||||
supportAmmunition ++ supportWeapons,
|
||||
suits ++ maxSuits)
|
||||
|
||||
/**
|
||||
* Process a `TransactionType.Buy` action by the user.
|
||||
* Either attempt to purchase equipment or attempt to switch directly to a different exo-suit.
|
||||
* @param player the player
|
||||
* @param msg the original packet carrying the request
|
||||
* @return an actionable message that explains how to process the request
|
||||
*/
|
||||
def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
||||
(msg.item_page : @switch) match {
|
||||
case 0 => //Weapon tab
|
||||
page0Stock.get(msg.item_name) match {
|
||||
case Some(item) =>
|
||||
Terminal.BuyEquipment(item())
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
case 2 => //Support tab
|
||||
page2Stock.get(msg.item_name) match {
|
||||
case Some(item) =>
|
||||
Terminal.BuyEquipment(item())
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
case 3 => //Vehicle tab
|
||||
vehicleAmmunition.get(msg.item_name) match {
|
||||
case Some(item) =>
|
||||
Terminal.BuyEquipment(item())
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
case 1 => //Armor tab
|
||||
suits.get(msg.item_name) match {
|
||||
case Some((suit, subtype)) =>
|
||||
Terminal.BuyExosuit(suit, subtype)
|
||||
case None =>
|
||||
maxAmmo.get(msg.item_name) match {
|
||||
case Some(item) =>
|
||||
Terminal.BuyEquipment(item())
|
||||
case None =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a `TransactionType.Sell` action by the user.
|
||||
* There is no specific `order_terminal` tab associated with this action.
|
||||
* Additionally, the equipment to be sold ia almost always in the player's `FreeHand` slot.
|
||||
* Selling `Equipment` is always permitted.
|
||||
* @param player the player
|
||||
* @param msg the original packet carrying the request
|
||||
* @return an actionable message that explains how to process the request
|
||||
*/
|
||||
override def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
||||
Terminal.SellEquipment()
|
||||
}
|
||||
override def Buy(player: Player, msg : ItemTransactionMessage) : Terminal.Exchange = buyFunc(player, msg)
|
||||
|
||||
/**
|
||||
* Process a `TransactionType.InfantryLoadout` action by the user.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.definition.converter.TerminalConverter
|
||||
import net.psforever.packet.game.ItemTransactionMessage
|
||||
|
||||
/**
|
||||
|
|
@ -10,6 +11,7 @@ import net.psforever.packet.game.ItemTransactionMessage
|
|||
*/
|
||||
abstract class TerminalDefinition(objectId : Int) extends net.psforever.objects.definition.ObjectDefinition(objectId) {
|
||||
Name = "terminal"
|
||||
Packet = new TerminalConverter
|
||||
|
||||
/**
|
||||
* The unimplemented functionality for this `Terminal`'s `TransactionType.Buy` and `TransactionType.Learn` activity.
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.vehicles
|
||||
|
||||
import net.psforever.objects.Vehicle
|
||||
|
||||
/**
|
||||
* A `Utility` designed to simulate the NTU-distributive functions of an ANT.
|
||||
* @param objectId the object id that is associated with this sort of `Utility`
|
||||
* @param vehicle the `Vehicle` to which this `Utility` is attached
|
||||
*/
|
||||
class ANTResourceUtility(objectId : Int, vehicle : Vehicle) extends Utility(objectId, vehicle) {
|
||||
private var currentNTU : Int = 0
|
||||
|
||||
def NTU : Int = currentNTU
|
||||
|
||||
def NTU_=(ntu : Int) : Int = {
|
||||
currentNTU = ntu
|
||||
currentNTU = math.max(math.min(currentNTU, MaxNTU), 0)
|
||||
NTU
|
||||
}
|
||||
|
||||
def MaxNTU : Int = ANTResourceUtility.MaxNTU
|
||||
}
|
||||
|
||||
object ANTResourceUtility {
|
||||
private val MaxNTU : Int = 300 //TODO what should this value be?
|
||||
|
||||
def apply(objectId : Int, vehicle : Vehicle) : ANTResourceUtility = {
|
||||
new ANTResourceUtility(objectId, vehicle)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,104 +1,103 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.vehicles
|
||||
|
||||
import net.psforever.objects.entity.IdentifiableEntity
|
||||
import net.psforever.objects.Vehicle
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
|
||||
import scala.annotation.switch
|
||||
import akka.actor.ActorContext
|
||||
import net.psforever.objects.{GlobalDefinitions, Vehicle}
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.objects.serverobject.terminals.{OrderTerminalABDefinition, Terminal}
|
||||
|
||||
/**
|
||||
* A `Utility` represents an unknown but functional entity that is attached to a `Vehicle` and is not a weapon or a seat.
|
||||
* This is a placeholder solution until a better system is established.
|
||||
* @param objectId the object id that is associated with this sort of `Utility`
|
||||
* @param vehicle the `Vehicle` to which this `Utility` is attached
|
||||
* An `Enumeration` of the available vehicular utilities.<br>
|
||||
* <br>
|
||||
* These values are used to connect `Amenity` objects and their extra logic encapsulated in this class
|
||||
* with information in the `VehicleDefinition` object for that kind of vehicle.
|
||||
* @see `Vehicle.LoadDefinition`
|
||||
* @see `VehicleDefinition.Utilities`
|
||||
*/
|
||||
class Utility(val objectId : Int, vehicle : Vehicle) extends IdentifiableEntity {
|
||||
private var active : Boolean = false
|
||||
object UtilityType extends Enumeration {
|
||||
type Type = Value
|
||||
val
|
||||
order_terminala,
|
||||
order_terminalb
|
||||
= Value
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a specific functional extension that is a component of a certain `Vehicle` object.<br>
|
||||
* <br>
|
||||
* A `Utility` object is a variation of an `Amenity` object that might be found in a `Building` object.
|
||||
* The object itself is stored inside the `Utility` as if it were a container.
|
||||
* `Amenity` objects are required because they are to be owned by the `vehicle` for purposes of faction affinity.
|
||||
* Only specific kinds of objects count for being `Utility` contents/objects.
|
||||
* Additional "setup" logic can be supplied that will be called when the owner vehicle's control `Actor` is created.
|
||||
* Ostensibly, the purpose of the additional logic, when it is called,
|
||||
* is to initialize a control `Actor` for the contained object.
|
||||
* This `Actor` is expected by other logic.
|
||||
* @see `Vehicle.LoadDefinition`
|
||||
* @see `VehicleDefinition.Utilities`
|
||||
* @param util the type of the `Amenity` object to be created
|
||||
* @param vehicle the owner of this object
|
||||
* @see `Amenity.Owner`
|
||||
*/
|
||||
class Utility(util : UtilityType.Value, vehicle : Vehicle) {
|
||||
private val obj : Amenity = Utility.BuildUtilityFunc(util)
|
||||
obj.Owner = vehicle
|
||||
private val setupFunc : Utility.UtilLogic = Utility.SelectUtilitySetupFunc(util)
|
||||
|
||||
/**
|
||||
* The faction association of this `Utility` is tied directly to the connected `Vehicle`.
|
||||
* @return the faction association
|
||||
* Access the contained object in this `Utility`.
|
||||
* @return the contained `Amenity` object
|
||||
*/
|
||||
def Faction : PlanetSideEmpire.Value = {
|
||||
vehicle.Faction
|
||||
}
|
||||
def apply() : Amenity = obj
|
||||
|
||||
/**
|
||||
* An "active" `Utility` can be used by players; an "inactive" one can not be used in its current state.
|
||||
* @return whether this `Utility` is active.
|
||||
* Run the setup code that was provided in the object constructor parameters.
|
||||
* While it is expected to construct an `Actor`, that is not required.
|
||||
* @param context an `ActorContext` potentially useful for the function
|
||||
*/
|
||||
def ActiveState : Boolean = {
|
||||
this.active
|
||||
}
|
||||
def Setup(implicit context : ActorContext) : Unit = setupFunc(obj, context)
|
||||
|
||||
/**
|
||||
* Change the "active" state of this `Utility`.
|
||||
* @param state the new active state
|
||||
* @return the current active state after being changed
|
||||
* Recover the original value used to initialize this object.
|
||||
* @return the type of the `Amenity` object that was created
|
||||
*/
|
||||
def ActiveState_=(state : Boolean) : Boolean = {
|
||||
this.active = state
|
||||
state
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the string representation to provide additional information.
|
||||
* @return the string output
|
||||
*/
|
||||
override def toString : String = {
|
||||
Utility.toString(this)
|
||||
}
|
||||
def UtilType : UtilityType.Value = util
|
||||
}
|
||||
|
||||
object Utility {
|
||||
type UtilLogic = (Amenity, ActorContext)=>Unit
|
||||
|
||||
/**
|
||||
* An overloaded constructor.
|
||||
* @param objectId the object id the is associated with this sort of `Utility`
|
||||
* @param vehicle the `Vehicle` to which this `Utility` is attached
|
||||
* Overloaded constructor.
|
||||
* @param util the type of the `Amenity` object to be created
|
||||
* @param vehicle the owner of this object
|
||||
* @return a `Utility` object
|
||||
*/
|
||||
def apply(objectId : Int, vehicle : Vehicle) : Utility = {
|
||||
new Utility(objectId, vehicle)
|
||||
def apply(util : UtilityType.Value, vehicle : Vehicle) : Utility = {
|
||||
new Utility(util, vehicle)
|
||||
}
|
||||
|
||||
/**
|
||||
* An overloaded constructor.
|
||||
* @param objectId the object id the is associated with this sort of `Utility`
|
||||
* @param vehicle the `Vehicle` to which this `Utility` is attached
|
||||
* @return a `Utility` object
|
||||
* Create the called-out object.
|
||||
* @param util the type of the `Amenity` object
|
||||
* @return the `Amenity` object
|
||||
*/
|
||||
def apply(guid : PlanetSideGUID, objectId : Int, vehicle : Vehicle) : Utility = {
|
||||
val obj = new Utility(objectId, vehicle)
|
||||
obj.GUID = guid
|
||||
obj
|
||||
private def BuildUtilityFunc(util : UtilityType.Value) : Amenity = util match {
|
||||
case UtilityType.order_terminala =>
|
||||
Terminal(GlobalDefinitions.order_terminala)
|
||||
case UtilityType.order_terminalb =>
|
||||
Terminal(GlobalDefinitions.order_terminalb)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create one of a specific type of utilities.
|
||||
* @param objectId the object id that is associated with this sort of `Utility`
|
||||
* @param vehicle the `Vehicle` to which this `Utility` is attached
|
||||
* @return a permitted `Utility` object
|
||||
* Provide the called-out object's logic.
|
||||
* @param util the type of the `Amenity` object
|
||||
* @return the `Amenity` object
|
||||
*/
|
||||
def Select(objectId : Int, vehicle : Vehicle) : Utility = {
|
||||
(objectId : @switch) match {
|
||||
case 60 => //this is the object id of an ANT
|
||||
ANTResourceUtility(objectId, vehicle)
|
||||
|
||||
case 49 | 519 | 613 | 614 => //ams parts
|
||||
Utility(objectId, vehicle)
|
||||
|
||||
case _ =>
|
||||
throw new IllegalArgumentException(s"the requested objectID #$objectId is not accepted as a valid Utility")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a fixed string representation.
|
||||
* @return the string output
|
||||
*/
|
||||
def toString(obj : Utility) : String = {
|
||||
s"{utility-${obj.objectId}}"
|
||||
private def SelectUtilitySetupFunc(util : UtilityType.Value) : UtilLogic = util match {
|
||||
case UtilityType.order_terminala =>
|
||||
OrderTerminalABDefinition.Setup
|
||||
case UtilityType.order_terminalb =>
|
||||
OrderTerminalABDefinition.Setup
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects.vehicles
|
|||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.Vehicle
|
||||
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
||||
import net.psforever.objects.serverobject.mount.MountableBehavior
|
||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||
|
||||
/**
|
||||
|
|
@ -13,10 +13,13 @@ import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffi
|
|||
* 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 Actor
|
||||
class VehicleControl(vehicle : Vehicle) extends Actor
|
||||
with FactionAffinityBehavior.Check
|
||||
with MountableBehavior.Mount
|
||||
with MountableBehavior.Dismount {
|
||||
//make control actors belonging to utilities when making control actor belonging to vehicle
|
||||
vehicle.Utilities.foreach({case (_, util) => util.Setup })
|
||||
|
||||
def MountableObject = vehicle //do not add type!
|
||||
|
||||
def FactionObject : FactionAffinity = vehicle
|
||||
|
|
@ -27,6 +30,13 @@ class VehicleControl(private val vehicle : Vehicle) extends Actor
|
|||
.orElse(mountBehavior)
|
||||
.orElse(dismountBehavior)
|
||||
.orElse {
|
||||
case FactionAffinity.ConvertFactionAffinity(faction) =>
|
||||
val originalAffinity = vehicle.Faction
|
||||
if(originalAffinity != (vehicle.Faction = faction)) {
|
||||
vehicle.Utilities.foreach({ case(_ : Int, util : Utility) => util().Actor forward FactionAffinity.ConfirmFactionAffinity() })
|
||||
}
|
||||
sender ! FactionAffinity.AssertFactionAffinity(vehicle, faction)
|
||||
|
||||
case Vehicle.PrepareForDeletion =>
|
||||
context.become(Disabled)
|
||||
|
||||
|
|
|
|||
|
|
@ -365,6 +365,7 @@ object ObjectClass {
|
|||
final val vulture = 986
|
||||
final val wasp = 997
|
||||
//other
|
||||
final val ams_order_terminal = 48
|
||||
final val ams_respawn_tube = 49
|
||||
final val avatar = 121
|
||||
final val bfr_rearm_terminal = 142
|
||||
|
|
@ -950,6 +951,7 @@ object ObjectClass {
|
|||
//vehicles?
|
||||
case ObjectClass.orbital_shuttle => ConstructorData.genericCodec(OrbitalShuttleData.codec, "HART")
|
||||
//other
|
||||
case ObjectClass.ams_order_terminal => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal")
|
||||
case ObjectClass.ams_respawn_tube => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal")
|
||||
case ObjectClass.bfr_rearm_terminal => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal")
|
||||
case ObjectClass.implant_terminal_interface => ConstructorData.genericCodec(CommonTerminalData.codec, "implant terminal")
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import net.psforever.objects.GlobalDefinitions.remote_electronics_kit
|
||||
import net.psforever.objects.definition.converter.{ACEConverter, CharacterSelectConverter, REKConverter}
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.definition._
|
||||
import net.psforever.objects.equipment.CItem.{DeployedItem, Unit}
|
||||
import net.psforever.objects.equipment._
|
||||
import net.psforever.objects.inventory.InventoryTile
|
||||
import net.psforever.objects.serverobject.terminals.Terminal
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.packet.game.objectcreate._
|
||||
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
import scala.util.Success
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
class ConverterTest extends Specification {
|
||||
"AmmoBox" should {
|
||||
|
|
@ -275,8 +277,28 @@ class ConverterTest extends Specification {
|
|||
}
|
||||
}
|
||||
|
||||
"Vehicle" should {
|
||||
"Terminal" should {
|
||||
"convert to packet" in {
|
||||
val obj = Terminal(GlobalDefinitions.order_terminala)
|
||||
|
||||
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
||||
case Failure(err) =>
|
||||
err.isInstanceOf[NoSuchMethodException] mustEqual true
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
|
||||
obj.Definition.Packet.ConstructorData(obj) match {
|
||||
case Success(pkt) =>
|
||||
pkt mustEqual CommonTerminalData(PlanetSideEmpire.NEUTRAL, 0)
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Vehicle" should {
|
||||
"convert to packet (1)" in {
|
||||
val hellfire_ammo = AmmoBoxDefinition(Ammo.hellfire_ammo.id)
|
||||
|
||||
val fury_weapon_systema_def = ToolDefinition(ObjectClass.fury_weapon_systema)
|
||||
|
|
@ -311,5 +333,16 @@ class ConverterTest extends Specification {
|
|||
fury.Definition.Packet.ConstructorData(fury).isSuccess mustEqual true
|
||||
ok //TODO write more of this test
|
||||
}
|
||||
|
||||
"convert to packet (2)" in {
|
||||
val
|
||||
ams = Vehicle(GlobalDefinitions.ams)
|
||||
ams.GUID = PlanetSideGUID(413)
|
||||
ams.Utilities(3)().GUID = PlanetSideGUID(414)
|
||||
ams.Utilities(4)().GUID = PlanetSideGUID(415)
|
||||
|
||||
ams.Definition.Packet.ConstructorData(ams).isSuccess mustEqual true
|
||||
ok //TODO write more of this test
|
||||
}
|
||||
}
|
||||
}
|
||||
71
common/src/test/scala/objects/UtilityTest.scala
Normal file
71
common/src/test/scala/objects/UtilityTest.scala
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Props}
|
||||
import net.psforever.objects.{GlobalDefinitions, Vehicle}
|
||||
import net.psforever.objects.serverobject.terminals.Terminal
|
||||
import net.psforever.objects.vehicles._
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import org.specs2.mutable._
|
||||
|
||||
import scala.concurrent.duration.Duration
|
||||
|
||||
class UtilityTest extends Specification {
|
||||
"Utility" should {
|
||||
"create an order_terminala object" in {
|
||||
val obj = Utility(UtilityType.order_terminala, UtilityTest.vehicle)
|
||||
obj.UtilType mustEqual UtilityType.order_terminala
|
||||
obj().isInstanceOf[Terminal] mustEqual true
|
||||
obj().asInstanceOf[Terminal].Definition.ObjectId mustEqual 613
|
||||
obj().asInstanceOf[Terminal].Actor == ActorRef.noSender
|
||||
}
|
||||
|
||||
"create an order_terminalb object" in {
|
||||
val obj = Utility(UtilityType.order_terminalb, UtilityTest.vehicle)
|
||||
obj.UtilType mustEqual UtilityType.order_terminalb
|
||||
obj().isInstanceOf[Terminal] mustEqual true
|
||||
obj().asInstanceOf[Terminal].Definition.ObjectId mustEqual 614
|
||||
obj().asInstanceOf[Terminal].Actor == ActorRef.noSender
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Utility1Test extends ActorTest() {
|
||||
"Utility" should {
|
||||
"wire an order_terminala Actor" in {
|
||||
val obj = Utility(UtilityType.order_terminala, UtilityTest.vehicle)
|
||||
obj().GUID = PlanetSideGUID(1)
|
||||
assert(obj().Actor == ActorRef.noSender)
|
||||
|
||||
system.actorOf(Props(classOf[UtilityTest.SetupControl], obj), "test") ! ""
|
||||
receiveOne(Duration.create(100, "ms")) //consume and discard
|
||||
assert(obj().Actor != ActorRef.noSender)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Utility2Test extends ActorTest() {
|
||||
"Utility" should {
|
||||
"wire an order_terminalb Actor" in {
|
||||
val obj = Utility(UtilityType.order_terminalb, UtilityTest.vehicle)
|
||||
obj().GUID = PlanetSideGUID(1)
|
||||
assert(obj().Actor == ActorRef.noSender)
|
||||
|
||||
system.actorOf(Props(classOf[UtilityTest.SetupControl], obj), "test") ! ""
|
||||
receiveOne(Duration.create(100, "ms")) //consume and discard
|
||||
assert(obj().Actor != ActorRef.noSender)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object UtilityTest {
|
||||
val vehicle = Vehicle(GlobalDefinitions.quadstealth)
|
||||
|
||||
class SetupControl(obj : Utility) extends Actor {
|
||||
def receive : Receive = {
|
||||
case _ =>
|
||||
obj.Setup(context)
|
||||
sender ! ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ package objects
|
|||
|
||||
import akka.actor.Props
|
||||
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
|
||||
import net.psforever.objects.definition.SeatDefinition
|
||||
import net.psforever.objects.definition.{SeatDefinition, VehicleDefinition}
|
||||
import net.psforever.objects.serverobject.mount.Mountable
|
||||
import net.psforever.objects.vehicles._
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
|
|
@ -256,6 +256,26 @@ class VehicleTest extends Specification {
|
|||
harasser_vehicle.WeaponControlledFromSeat(0) mustEqual None
|
||||
harasser_vehicle.WeaponControlledFromSeat(1) mustEqual chaingun_p
|
||||
}
|
||||
|
||||
"can filter utilities with indices that are natural numbers" in {
|
||||
val objDef = VehicleDefinition(1)
|
||||
objDef.Utilities += -1 -> UtilityType.order_terminala
|
||||
objDef.Utilities += 0 -> UtilityType.order_terminalb
|
||||
objDef.Utilities += 2 -> UtilityType.order_terminalb
|
||||
val obj = Vehicle(objDef)
|
||||
|
||||
obj.Utilities.size mustEqual 3
|
||||
obj.Utilities(-1).UtilType mustEqual UtilityType.order_terminala
|
||||
obj.Utilities(0).UtilType mustEqual UtilityType.order_terminalb
|
||||
obj.Utilities.get(1) mustEqual None
|
||||
obj.Utilities(2).UtilType mustEqual UtilityType.order_terminalb
|
||||
|
||||
val filteredMap = Vehicle.EquipmentUtilities(obj.Utilities)
|
||||
filteredMap.size mustEqual 2
|
||||
filteredMap.get(-1) mustEqual None
|
||||
filteredMap(0).UtilType mustEqual UtilityType.order_terminalb
|
||||
filteredMap(2).UtilType mustEqual UtilityType.order_terminalb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.terminal
|
||||
|
||||
import akka.actor.ActorRef
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
import net.psforever.objects.serverobject.terminals.{OrderTerminalABDefinition, Terminal}
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||
import net.psforever.types._
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
class OrderTerminalABTest extends Specification {
|
||||
"OrderTerminalAB" should {
|
||||
"define (a)" in {
|
||||
val a = new OrderTerminalABDefinition(613)
|
||||
a.ObjectId mustEqual 613
|
||||
a.Name mustEqual "order_terminala"
|
||||
}
|
||||
|
||||
"define (b)" in {
|
||||
val b = new OrderTerminalABDefinition(614)
|
||||
b.ObjectId mustEqual 614
|
||||
b.Name mustEqual "order_terminalb"
|
||||
}
|
||||
|
||||
"define (invalid)" in {
|
||||
var id : Int = (math.random * Int.MaxValue).toInt
|
||||
if(id == 613) {
|
||||
id += 2
|
||||
}
|
||||
else if(id == 614) {
|
||||
id += 1
|
||||
}
|
||||
|
||||
new OrderTerminalABDefinition(id) must throwA[IllegalArgumentException]
|
||||
}
|
||||
}
|
||||
|
||||
"Order_Terminal" should {
|
||||
val terminal = Terminal(GlobalDefinitions.order_terminala)
|
||||
terminal.Owner = new Building(0, Zone.Nowhere)
|
||||
terminal.Owner.Faction = PlanetSideEmpire.TR
|
||||
|
||||
"construct" in {
|
||||
terminal.Actor mustEqual ActorRef.noSender
|
||||
}
|
||||
|
||||
"player can buy different armor ('lite_armor')" in {
|
||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
||||
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0))
|
||||
|
||||
terminal.Request(player, msg) mustEqual Terminal.BuyExosuit(ExoSuitType.Agile)
|
||||
}
|
||||
|
||||
"player can buy max armor ('trhev_antiaircraft')" in {
|
||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
||||
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "trhev_antiaircraft", 0, PlanetSideGUID(0))
|
||||
|
||||
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
|
||||
}
|
||||
//TODO loudout tests
|
||||
|
||||
"player can not load max loadout" in {
|
||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
||||
player.SaveLoadout("test1", 0)
|
||||
player.ExoSuit = ExoSuitType.MAX
|
||||
player.SaveLoadout("test2", 1)
|
||||
|
||||
val msg1 = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.InfantryLoadout, 4, "", 0, PlanetSideGUID(0))
|
||||
terminal.Request(player, msg1) mustEqual Terminal.InfantryLoadout(ExoSuitType.Standard, 0, Nil, Nil)
|
||||
|
||||
val msg2 = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.InfantryLoadout, 4, "", 1, PlanetSideGUID(0))
|
||||
terminal.Request(player, msg2) mustEqual Terminal.NoDeal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2097,8 +2097,24 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
|
||||
case msg @ DeployRequestMessage(player_guid, entity, unk1, unk2, unk3, pos) =>
|
||||
//if you try to deploy, can not undeploy
|
||||
log.info("DeployRequest: " + msg)
|
||||
//LOCAL FUNCTIONALITY ONLY FOR THIS BRANCH
|
||||
val player_guid = player.GUID
|
||||
if(unk1 == 2) { // deploy AMS
|
||||
//sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(entity,49,1))) // TODO : ANT ? With increment when loading NTU ?
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, DeployRequestMessage(player_guid, entity, unk1, unk2, unk3, Vector3(0f, 0f, 0f))))
|
||||
Thread.sleep(1000) // 2 seconds
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, DeployRequestMessage(player_guid, entity, 3, unk2, unk3, Vector3(0f, 0f, 0f))))
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(entity, 10, 1)))
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(entity, 11, 1)))
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(entity, 12, 1)))
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(entity, 13, 1)))
|
||||
}
|
||||
else if(unk1 == 1) { // undeploy AMS
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, DeployRequestMessage(player_guid, entity, unk1, unk2, unk3, Vector3(0f, 0f, 0f))))
|
||||
Thread.sleep(1000) // 2 seconds
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, DeployRequestMessage(player_guid, entity, 0, unk2, unk3, Vector3(0f, 0f, 0f))))
|
||||
}
|
||||
|
||||
case msg @ AvatarGrenadeStateMessage(player_guid, state) =>
|
||||
log.info("AvatarGrenadeStateMessage: " + msg)
|
||||
|
|
|
|||
Loading…
Reference in a new issue