mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-02-19 06:33:38 +00:00
test Harasser to demonstrate synched vehicle actions: mounting, disembarking, driving, gunning, changing access permissions, changing ownership, kicking passengers, deconstructing
This commit is contained in:
parent
211eb838aa
commit
8f658aa688
36 changed files with 1820 additions and 470 deletions
|
|
@ -1228,17 +1228,86 @@ object GlobalDefinitions {
|
|||
fury_weapon_systema.FireModes.head.AmmoSlotIndex = 0
|
||||
fury_weapon_systema.FireModes.head.Magazine = 2
|
||||
|
||||
val
|
||||
quadassault_weapon_system = ToolDefinition(ObjectClass.quadassault_weapon_system)
|
||||
quadassault_weapon_system.Size = EquipmentSize.VehicleWeapon
|
||||
quadassault_weapon_system.AmmoTypes += Ammo.bullet_12mm
|
||||
quadassault_weapon_system.FireModes += new FireModeDefinition
|
||||
quadassault_weapon_system.FireModes.head.AmmoTypeIndices += 0
|
||||
quadassault_weapon_system.FireModes.head.AmmoSlotIndex = 0
|
||||
quadassault_weapon_system.FireModes.head.Magazine = 100
|
||||
|
||||
val
|
||||
chaingun_p = ToolDefinition(ObjectClass.chaingun_p)
|
||||
chaingun_p.Size = EquipmentSize.VehicleWeapon
|
||||
chaingun_p.AmmoTypes += Ammo.bullet_12mm
|
||||
chaingun_p.FireModes += new FireModeDefinition
|
||||
chaingun_p.FireModes.head.AmmoTypeIndices += 0
|
||||
chaingun_p.FireModes.head.AmmoSlotIndex = 0
|
||||
chaingun_p.FireModes.head.Magazine = 150
|
||||
|
||||
val
|
||||
fury = VehicleDefinition(ObjectClass.fury)
|
||||
fury.Seats += 0 -> new SeatDefinition()
|
||||
fury.Seats(0).Bailable = true
|
||||
fury.Seats(0).ControlledWeapon = Some(1)
|
||||
fury.Seats(0).ControlledWeapon = 1
|
||||
fury.MountPoints += 0 -> 0
|
||||
fury.MountPoints += 2 -> 0
|
||||
fury.Weapons += 1 -> fury_weapon_systema
|
||||
fury.TrunkSize = InventoryTile(11, 11)
|
||||
fury.TrunkOffset = 30
|
||||
|
||||
val
|
||||
quadassault = VehicleDefinition(ObjectClass.quadassault)
|
||||
quadassault.Seats += 0 -> new SeatDefinition()
|
||||
quadassault.Seats(0).Bailable = true
|
||||
quadassault.Seats(0).ControlledWeapon = 1
|
||||
quadassault.MountPoints += 0 -> 0
|
||||
quadassault.MountPoints += 2 -> 0
|
||||
quadassault.Weapons += 1 -> quadassault_weapon_system
|
||||
quadassault.TrunkSize = InventoryTile(11, 11)
|
||||
quadassault.TrunkOffset = 30
|
||||
|
||||
val
|
||||
quadstealth = VehicleDefinition(ObjectClass.quadstealth)
|
||||
quadstealth.CanCloak = true
|
||||
quadstealth.Seats += 0 -> new SeatDefinition()
|
||||
quadstealth.Seats(0).Bailable = true
|
||||
quadstealth.MountPoints += 0 -> 0
|
||||
quadstealth.MountPoints += 2 -> 0
|
||||
quadstealth.CanCloak = true
|
||||
quadstealth.TrunkSize = InventoryTile(11, 11)
|
||||
quadstealth.TrunkOffset = 30
|
||||
|
||||
val
|
||||
two_man_assault_buggy = VehicleDefinition(ObjectClass.two_man_assault_buggy)
|
||||
two_man_assault_buggy.Seats += 0 -> new SeatDefinition()
|
||||
two_man_assault_buggy.Seats(0).Bailable = true
|
||||
two_man_assault_buggy.Seats += 1 -> new SeatDefinition()
|
||||
two_man_assault_buggy.Seats(1).Bailable = true
|
||||
two_man_assault_buggy.Seats(1).ControlledWeapon = 2
|
||||
two_man_assault_buggy.MountPoints += 1 -> 0
|
||||
two_man_assault_buggy.MountPoints += 2 -> 1
|
||||
two_man_assault_buggy.Weapons += 2 -> chaingun_p
|
||||
two_man_assault_buggy.TrunkSize = InventoryTile(11, 11)
|
||||
two_man_assault_buggy.TrunkOffset = 30
|
||||
|
||||
val
|
||||
phantasm = VehicleDefinition(ObjectClass.phantasm)
|
||||
phantasm.CanCloak = true
|
||||
phantasm.Seats += 0 -> new SeatDefinition()
|
||||
phantasm.Seats += 1 -> new SeatDefinition()
|
||||
phantasm.Seats(1).Bailable = true
|
||||
phantasm.Seats += 2 -> new SeatDefinition()
|
||||
phantasm.Seats(2).Bailable = true
|
||||
phantasm.Seats += 3 -> new SeatDefinition()
|
||||
phantasm.Seats(3).Bailable = true
|
||||
phantasm.Seats += 4 -> new SeatDefinition()
|
||||
phantasm.Seats(4).Bailable = true
|
||||
phantasm.MountPoints += 1 -> 0 //TODO add and check all
|
||||
phantasm.TrunkSize = InventoryTile(11, 8)
|
||||
phantasm.TrunkOffset = 30 //TODO check
|
||||
|
||||
val
|
||||
order_terminal = new OrderTerminalDefinition
|
||||
val
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ package net.psforever.objects
|
|||
import net.psforever.objects.definition.VehicleDefinition
|
||||
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
|
||||
import net.psforever.objects.inventory.GridInventory
|
||||
import net.psforever.objects.vehicles.{Seat, Utility, VehicleLockState}
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.vehicles.{AccessPermissionGroup, Seat, Utility, VehicleLockState}
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.packet.game.objectcreate.DriveState
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.mutable
|
||||
|
||||
/**
|
||||
|
|
@ -17,29 +19,31 @@ import scala.collection.mutable
|
|||
* All infantry seating, all mounted weapons, and the trunk space are considered part of the same index hierarchy.
|
||||
* Generally, all seating is declared first - the driver and passengers and and gunners.
|
||||
* Following that are the mounted weapons and other utilities.
|
||||
* Trunk space starts being indexed afterwards.
|
||||
* The first seat is always the op;erator (driver/pilot).
|
||||
* "Passengers" are seats that are not the operator and are not in control of a mounted weapon.
|
||||
* "Gunners" are seats that are not the operator and ARE in control of a mounted weapon.
|
||||
* (The operator can be in control of a weapon - that is the whole point of a turret.)<br>
|
||||
* Trunk space starts being indexed afterwards.<br>
|
||||
* <br>
|
||||
* Having said all that, to keep it simple, infantry seating, mounted weapons, and utilities are stored in separate `Map`s.
|
||||
* @param vehicleDef the vehicle's definition entry'
|
||||
* To keep it simple, infantry seating, mounted weapons, and utilities are stored separately.
|
||||
* @param vehicleDef the vehicle's definition entry';
|
||||
* stores and unloads pertinent information about the `Vehicle`'s configuration;
|
||||
* used in the initialization process (`loadVehicleDefinition`)
|
||||
*/
|
||||
class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideGameObject {
|
||||
class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServerObject {
|
||||
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.TR
|
||||
private var owner : Option[PlanetSideGUID] = None
|
||||
private var health : Int = 1
|
||||
private var shields : Int = 0
|
||||
private var deployed : DriveState.Value = DriveState.Mobile
|
||||
private var decal : Int = 0
|
||||
private var trunkLockState : VehicleLockState.Value = VehicleLockState.Locked
|
||||
private var trunkAccess : Option[PlanetSideGUID] = None
|
||||
private var jammered : Boolean = false
|
||||
private var cloaked : Boolean = false
|
||||
|
||||
private val seats : mutable.HashMap[Int, Seat] = mutable.HashMap()
|
||||
private val weapons : mutable.HashMap[Int, EquipmentSlot] = mutable.HashMap()
|
||||
/**
|
||||
* Permissions control who gets to access different parts of the vehicle;
|
||||
* the groups are Driver (seat), Gunner (seats), Passenger (seats), and the Trunk
|
||||
*/
|
||||
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 val trunk : GridInventory = GridInventory()
|
||||
|
||||
|
|
@ -68,8 +72,15 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideGame
|
|||
}
|
||||
|
||||
def Owner_=(owner : Option[PlanetSideGUID]) : Option[PlanetSideGUID] = {
|
||||
this.owner = owner
|
||||
owner
|
||||
owner match {
|
||||
case Some(_) =>
|
||||
if(Definition.CanBeOwned) {
|
||||
this.owner = owner
|
||||
}
|
||||
case None =>
|
||||
this.owner = None
|
||||
}
|
||||
Owner
|
||||
}
|
||||
|
||||
def Health : Int = {
|
||||
|
|
@ -98,15 +109,15 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideGame
|
|||
vehicleDef.MaxShields
|
||||
}
|
||||
|
||||
def Configuration : DriveState.Value = {
|
||||
def Drive : DriveState.Value = {
|
||||
this.deployed
|
||||
}
|
||||
|
||||
def Configuration_=(deploy : DriveState.Value) : DriveState.Value = {
|
||||
def Drive_=(deploy : DriveState.Value) : DriveState.Value = {
|
||||
if(vehicleDef.Deployment) {
|
||||
this.deployed = deploy
|
||||
}
|
||||
Configuration
|
||||
Drive
|
||||
}
|
||||
|
||||
def Decal : Int = {
|
||||
|
|
@ -118,6 +129,20 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideGame
|
|||
decal
|
||||
}
|
||||
|
||||
def Jammered : Boolean = jammered
|
||||
|
||||
def Jammered_=(jamState : Boolean) : Boolean = {
|
||||
jammered = jamState
|
||||
Jammered
|
||||
}
|
||||
|
||||
def Cloaked : Boolean = cloaked
|
||||
|
||||
def Cloaked_=(isCloaked : Boolean) : Boolean = {
|
||||
cloaked = isCloaked
|
||||
Cloaked
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the index of an entry mounting point, return the infantry-accessible `Seat` associated with it.
|
||||
* @param mountPoint an index representing the seat position / mounting point
|
||||
|
|
@ -127,6 +152,60 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideGame
|
|||
vehicleDef.MountPoints.get(mountPoint)
|
||||
}
|
||||
|
||||
/**
|
||||
* What are the access permissions for a position on this vehicle, seats or trunk?
|
||||
* @param group the group index
|
||||
* @return what sort of access permission exist for this group
|
||||
*/
|
||||
def PermissionGroup(group : Int) : Option[VehicleLockState.Value] = {
|
||||
reindexPermissionsGroup(group) match {
|
||||
case Some(index) =>
|
||||
Some(groupPermissions(index))
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the access permissions for a position on this vehicle, seats or trunk.
|
||||
* @param group the group index
|
||||
* @param level the new permission for this group
|
||||
* @return the new access permission for this group;
|
||||
* `None`, if the group does not exist or the level of permission was not changed
|
||||
*/
|
||||
def PermissionGroup(group : Int, level : Long) : Option[VehicleLockState.Value] = {
|
||||
reindexPermissionsGroup(group) match {
|
||||
case Some(index) =>
|
||||
val current = groupPermissions(index)
|
||||
val next = try { VehicleLockState(level.toInt) } catch { case _ : Exception => groupPermissions(index) }
|
||||
if(current != next) {
|
||||
groupPermissions(index) = next
|
||||
PermissionGroup(index)
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When the access permission group is communicated via `PlanetsideAttributeMessage`, the index is between 10 and 13.
|
||||
* Internally, permission groups are stored as an `Array`, so the respective re-indexing plots 10 -> 0 and 13 -> 3.
|
||||
* @param group the group index
|
||||
* @return the modified group index
|
||||
*/
|
||||
private def reindexPermissionsGroup(group : Int) : Option[Int] = if(group > 9 && group < 14) {
|
||||
Some(group - 10)
|
||||
}
|
||||
else if(group > -1 && group < 4) {
|
||||
Some(group)
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the seat at the index.
|
||||
* The specified "seat" can only accommodate a player as opposed to weapon mounts which share the same indexing system.
|
||||
|
|
@ -146,7 +225,26 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideGame
|
|||
seats.values.toList
|
||||
}
|
||||
|
||||
def Weapons : mutable.HashMap[Int, EquipmentSlot] = weapons
|
||||
def SeatPermissionGroup(seatNumber : Int) : Option[AccessPermissionGroup.Value] = {
|
||||
if(seatNumber == 0) {
|
||||
Some(AccessPermissionGroup.Driver)
|
||||
}
|
||||
else {
|
||||
Seat(seatNumber) match {
|
||||
case Some(seat) =>
|
||||
seat.ControlledWeapon match {
|
||||
case Some(_) =>
|
||||
Some(AccessPermissionGroup.Gunner)
|
||||
case None =>
|
||||
Some(AccessPermissionGroup.Passenger)
|
||||
}
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def Weapons : Map[Int, EquipmentSlot] = weapons
|
||||
|
||||
/**
|
||||
* Get the weapon at the index.
|
||||
|
|
@ -164,20 +262,25 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideGame
|
|||
}
|
||||
|
||||
/**
|
||||
* Given a player who may be a passenger, retrieve an index where this player is seated.
|
||||
* Given a player who may be an occupant, retrieve an number of the seat where this player is sat.
|
||||
* @param player the player
|
||||
* @return a seat by index, or `None` if the `player` is not actually seated in this `Vehicle`
|
||||
* @return a seat number, or `None` if the `player` is not actually seated in this vehicle
|
||||
*/
|
||||
def PassengerInSeat(player : Player) : Option[Int] = {
|
||||
var outSeat : Option[Int] = None
|
||||
val GUID = player.GUID
|
||||
for((seatNumber, seat) <- this.seats) {
|
||||
val occupant : Option[PlanetSideGUID] = seat.Occupant
|
||||
if(occupant.isDefined && occupant.get == GUID) {
|
||||
outSeat = Some(seatNumber)
|
||||
def PassengerInSeat(player : Player) : Option[Int] = recursivePassengerInSeat(seats.iterator, player)
|
||||
|
||||
@tailrec private def recursivePassengerInSeat(iter : Iterator[(Int, Seat)], player : Player) : Option[Int] = {
|
||||
if(!iter.hasNext) {
|
||||
None
|
||||
}
|
||||
else {
|
||||
val (seatNumber, seat) = iter.next
|
||||
if(seat.Occupant.contains(player)) {
|
||||
Some(seatNumber)
|
||||
}
|
||||
else {
|
||||
recursivePassengerInSeat(iter, player)
|
||||
}
|
||||
}
|
||||
outSeat
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -267,7 +370,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideGame
|
|||
*/
|
||||
def CanAccessTrunk(player : Player) : Boolean = {
|
||||
if(trunkAccess.isEmpty || trunkAccess.contains(player.GUID)) {
|
||||
trunkLockState match {
|
||||
groupPermissions(3) match {
|
||||
case VehicleLockState.Locked => //only the owner
|
||||
owner.isEmpty || (owner.isDefined && player.GUID == owner.get)
|
||||
case VehicleLockState.Group => //anyone in the owner's squad or platoon
|
||||
|
|
@ -285,19 +388,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideGame
|
|||
* Check access to the `Trunk`.
|
||||
* @return the current access value for the `Vehicle` `Trunk`
|
||||
*/
|
||||
def TrunkLockState : VehicleLockState.Value = {
|
||||
this.trunkLockState
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the access value for the trunk.
|
||||
* @param lockState the new access value for the `Vehicle` `Trunk`
|
||||
* @return the current access value for the `Vehicle` `Trunk` after the change
|
||||
*/
|
||||
def TrunkLockState_=(lockState : VehicleLockState.Value) : VehicleLockState.Value = {
|
||||
this.trunkLockState = lockState
|
||||
lockState
|
||||
}
|
||||
def TrunkLockState : VehicleLockState.Value = groupPermissions(3)
|
||||
|
||||
/**
|
||||
* This is the definition entry that is used to store and unload pertinent information about the `Vehicle`.
|
||||
|
|
@ -316,22 +407,52 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideGame
|
|||
|
||||
object Vehicle {
|
||||
/**
|
||||
* Overloaded constructor.
|
||||
* @param vehicleDef the vehicle's definition entry
|
||||
* @return a `Vwehicle` object
|
||||
* A basic `Trait` connecting all of the actionable `Vehicle` response messages.
|
||||
*/
|
||||
def apply(vehicleDef : VehicleDefinition) : Vehicle = {
|
||||
new Vehicle(vehicleDef)
|
||||
}
|
||||
sealed trait Exchange
|
||||
|
||||
/**
|
||||
* Message that carries the result of the processed request message back to the original user (`player`).
|
||||
* @param player the player who sent this request message
|
||||
* @param response the result of the processed request
|
||||
*/
|
||||
final case class VehicleMessages(player : Player, response : Exchange)
|
||||
|
||||
/**
|
||||
* The `Vehicle` will become unresponsive to player activity.
|
||||
* Usually, it does this to await deconstruction and clean-up
|
||||
* @see `VehicleControl`
|
||||
*/
|
||||
final case class PrepareForDeletion()
|
||||
|
||||
/**
|
||||
* This player wants to sit down in an available(?) seat.
|
||||
* @param seat_num the seat where the player is trying to occupy;
|
||||
* this is NOT the entry mount point index;
|
||||
* make certain to convert!
|
||||
* @param player the `Player` object
|
||||
*/
|
||||
final case class TrySeatPlayer(seat_num : Int, player : Player)
|
||||
/**
|
||||
* The recipient player of this packet is being allowed to sit in the assigned seat.
|
||||
* @param vehicle the `Vehicle` object that generated this message
|
||||
* @param seat_num the seat that the player will occupy
|
||||
*/
|
||||
final case class CanSeatPlayer(vehicle : Vehicle, seat_num : Int) extends Exchange
|
||||
/**
|
||||
* The recipient player of this packet is not allowed to sit in the requested seat.
|
||||
* @param vehicle the `Vehicle` object that generated this message
|
||||
* @param seat_num the seat that the player can not occupy
|
||||
*/
|
||||
final case class CannotSeatPlayer(vehicle : Vehicle, seat_num : Int) extends Exchange
|
||||
|
||||
/**
|
||||
* Overloaded constructor.
|
||||
* @param vehicleDef the vehicle's definition entry
|
||||
* @return a `Vwehicle` object
|
||||
* @return a `Vehicle` object
|
||||
*/
|
||||
def apply(guid : PlanetSideGUID, vehicleDef : VehicleDefinition) : Vehicle = {
|
||||
val obj = new Vehicle(vehicleDef)
|
||||
obj.GUID = guid
|
||||
obj
|
||||
def apply(vehicleDef : VehicleDefinition) : Vehicle = {
|
||||
new Vehicle(vehicleDef)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -344,16 +465,13 @@ object Vehicle {
|
|||
//general stuff
|
||||
vehicle.Health = vdef.MaxHealth
|
||||
//create weapons
|
||||
for((num, definition) <- vdef.Weapons) {
|
||||
vehicle.weapons = vdef.Weapons.map({case (num, definition) =>
|
||||
val slot = EquipmentSlot(EquipmentSize.VehicleWeapon)
|
||||
slot.Equipment = Tool(definition)
|
||||
vehicle.weapons += num -> slot
|
||||
vehicle
|
||||
}
|
||||
num -> slot
|
||||
}).toMap
|
||||
//create seats
|
||||
for((num, seatDef) <- vdef.Seats) {
|
||||
vehicle.seats += num -> Seat(seatDef, vehicle)
|
||||
}
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -37,8 +37,12 @@ class SeatDefinition extends BasicDefinition {
|
|||
this.weaponMount
|
||||
}
|
||||
|
||||
def ControlledWeapon_=(seat : Option[Int]) : Option[Int] = {
|
||||
this.weaponMount = seat
|
||||
def ControlledWeapon_=(wep : Int) : Option[Int] = {
|
||||
ControlledWeapon_=(Some(wep))
|
||||
}
|
||||
|
||||
def ControlledWeapon_=(wep : Option[Int]) : Option[Int] = {
|
||||
this.weaponMount = wep
|
||||
ControlledWeapon
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@ class VehicleDefinition(objectId : Int) extends ObjectDefinition(objectId) {
|
|||
private var deployment : Boolean = false
|
||||
private val utilities : mutable.ArrayBuffer[Int] = mutable.ArrayBuffer[Int]()
|
||||
private var trunkSize : InventoryTile = InventoryTile.None
|
||||
private var trunkOffset: Int = 0
|
||||
private var trunkOffset : Int = 0
|
||||
private var canCloak : Boolean = false
|
||||
private var canBeOwned : Boolean = true
|
||||
Name = "vehicle"
|
||||
Packet = new VehicleConverter
|
||||
|
||||
|
|
@ -44,6 +46,20 @@ class VehicleDefinition(objectId : Int) extends ObjectDefinition(objectId) {
|
|||
|
||||
def MountPoints : mutable.HashMap[Int, Int] = mountPoints
|
||||
|
||||
def CanBeOwned : Boolean = canBeOwned
|
||||
|
||||
def CanBeOwned_=(ownable : Boolean) : Boolean = {
|
||||
canBeOwned = ownable
|
||||
CanBeOwned
|
||||
}
|
||||
|
||||
def CanCloak : Boolean = canCloak
|
||||
|
||||
def CanCloak_=(cloakable : Boolean) : Boolean = {
|
||||
canCloak = cloakable
|
||||
CanCloak
|
||||
}
|
||||
|
||||
def Weapons : mutable.HashMap[Int, ToolDefinition] = weapons
|
||||
|
||||
def Deployment : Boolean = deployment
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@
|
|||
package net.psforever.objects.definition.converter
|
||||
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.{EquipmentSlot, Vehicle}
|
||||
import net.psforever.objects.Vehicle
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.packet.game.objectcreate.{InventoryItemData, _}
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
||||
class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
||||
|
|
@ -19,47 +18,66 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
|||
PlacementData(obj.Position, obj.Orientation, obj.Velocity),
|
||||
obj.Faction,
|
||||
0,
|
||||
if(obj.Owner.isDefined) { obj.Owner.get } else { PlanetSideGUID(0) } //this is the owner field, right?
|
||||
PlanetSideGUID(0) //if(obj.Owner.isDefined) { obj.Owner.get } else { PlanetSideGUID(0) } //TODO is this really Owner?
|
||||
),
|
||||
0,
|
||||
obj.Health / obj.MaxHealth * 255, //TODO not precise
|
||||
false, false,
|
||||
DriveState.Mobile,
|
||||
false,
|
||||
obj.Drive,
|
||||
false,
|
||||
false,
|
||||
obj.Cloaked,
|
||||
SpecificFormatData(obj),
|
||||
Some(InventoryData(MakeMountings(obj).sortBy(_.parentSlot)))
|
||||
Some(InventoryData((MakeMountings(obj) ++ MakeTrunk(obj)).sortBy(_.parentSlot)))
|
||||
)(SpecificFormatModifier)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* For an object with a list of weapon mountings, convert those weapons into data as if found in an `0x17` packet.
|
||||
* @param obj the Vehicle game object
|
||||
* @return the converted data
|
||||
* 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] = recursiveMakeMountings(obj.Weapons.iterator)
|
||||
|
||||
@tailrec private def recursiveMakeMountings(iter : Iterator[(Int,EquipmentSlot)], list : List[InventoryItemData.InventoryItem] = Nil) : List[InventoryItemData.InventoryItem] = {
|
||||
if(!iter.hasNext) {
|
||||
list
|
||||
}
|
||||
else {
|
||||
val (index, slot) = iter.next
|
||||
if(slot.Equipment.isDefined) {
|
||||
private def MakeMountings(obj : Vehicle) : List[InventoryItemData.InventoryItem] = {
|
||||
obj.Weapons.map({
|
||||
case((index, slot)) =>
|
||||
val equip : Equipment = slot.Equipment.get
|
||||
recursiveMakeMountings(
|
||||
iter,
|
||||
list :+ InventoryItemData(equip.Definition.ObjectId, equip.GUID, index, equip.Definition.Packet.ConstructorData(equip).get)
|
||||
)
|
||||
}
|
||||
else {
|
||||
recursiveMakeMountings(iter, list)
|
||||
}
|
||||
}
|
||||
InventoryItemData(equip.Definition.ObjectId, equip.GUID, index, 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) {
|
||||
// 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 SpecificFormatModifier : VehicleFormat.Value = VehicleFormat.Normal
|
||||
|
||||
protected def SpecificFormatData(obj : Vehicle) : Option[SpecificVehicleData] = None
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ object EquipmentSize extends Enumeration {
|
|||
Rifle, //6x3 and 9x3
|
||||
Max, //max weapon only
|
||||
VehicleWeapon, //vehicle-mounted weapons
|
||||
BFRArmWeapon, //duel arm weapons for bfr
|
||||
BFRGunnerWeapon, //gunner seat for bfr
|
||||
Inventory, //reserved
|
||||
Any
|
||||
= Value
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.inventory
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
|
||||
trait AccessibleInventory {
|
||||
def Inventory : GridInventory
|
||||
|
||||
def CanAccess(who : Player) : Boolean
|
||||
def Access(who : PlanetSideGUID) : Boolean
|
||||
def Unaccess : Boolean
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ class CertTerminalDefinition extends TerminalDefinition(171) {
|
|||
*/
|
||||
private val certificationList : Map[String, (CertificationType.Value, Int)] = Map(
|
||||
"medium_assault" -> (CertificationType.MediumAssault, 2),
|
||||
"reinforced_armo" -> (CertificationType.ReinforcedExoSuit, 3),
|
||||
"reinforced_armor" -> (CertificationType.ReinforcedExoSuit, 3),
|
||||
"quad_all" -> (CertificationType.ATV, 1),
|
||||
"switchblade" -> (CertificationType.Switchblade, 1),
|
||||
"harasser" -> (CertificationType.Harasser, 1),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.vehicles
|
||||
|
||||
/**
|
||||
* An `Enumeration` of various permission groups that control access to aspects of a vehicle.<br>
|
||||
* - `Driver` is a seat that is always seat number 0.<br>
|
||||
* - `Gunner` is a seat that is not the `Driver` and controls a mounted weapon.<br>
|
||||
* - `Passenger` is a seat that is not the `Driver` and does not have control of a mounted weapon.<br>
|
||||
* - `Trunk` represnts access to the vehicle's internal storage space.<br>
|
||||
* Organized to replicate the `PlanetsideAttributeMessage` value used for that given access level.
|
||||
* In their respective `PlanetsideAttributeMessage` packet, the groups are indexed in the same order as 10 through 13.
|
||||
*/
|
||||
object AccessPermissionGroup extends Enumeration {
|
||||
type Type = Value
|
||||
|
||||
val
|
||||
Driver,
|
||||
Gunner,
|
||||
Passenger,
|
||||
Trunk
|
||||
= Value
|
||||
}
|
||||
|
|
@ -2,33 +2,22 @@
|
|||
package net.psforever.objects.vehicles
|
||||
|
||||
import net.psforever.objects.definition.SeatDefinition
|
||||
import net.psforever.objects.{Player, Vehicle}
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
import net.psforever.objects.Player
|
||||
|
||||
/**
|
||||
* Server-side support for a slot that infantry players can occupy, ostensibly called a "seat" and treated like a "seat."
|
||||
* (Players can sit in it.)
|
||||
* @param seatDef the Definition that constructs this item and maintains some of its immutable fields
|
||||
* @param vehicle the vehicle where this seat is installed
|
||||
* @param seatDef the Definition that constructs this item and maintains some of its unchanging fields
|
||||
*/
|
||||
class Seat(private val seatDef : SeatDefinition, private val vehicle : Vehicle) {
|
||||
private var occupant : Option[PlanetSideGUID] = None
|
||||
private var lockState : VehicleLockState.Value = VehicleLockState.Empire
|
||||
|
||||
/**
|
||||
* The faction association of this `Seat` is tied directly to the connected `Vehicle`.
|
||||
* @return the faction association
|
||||
*/
|
||||
def Faction : PlanetSideEmpire.Value = {
|
||||
vehicle.Faction
|
||||
}
|
||||
class Seat(private val seatDef : SeatDefinition) {
|
||||
private var occupant : Option[Player] = None
|
||||
// private var lockState : VehicleLockState.Value = VehicleLockState.Empire
|
||||
|
||||
/**
|
||||
* Is this seat occupied?
|
||||
* @return the GUID of the player sitting in this seat, or `None` if it is left vacant
|
||||
*/
|
||||
def Occupant : Option[PlanetSideGUID] = {
|
||||
def Occupant : Option[Player] = {
|
||||
this.occupant
|
||||
}
|
||||
|
||||
|
|
@ -38,10 +27,12 @@ class Seat(private val seatDef : SeatDefinition, private val vehicle : Vehicle)
|
|||
* @param player the player who wants to sit, or `None` if the occupant is getting up
|
||||
* @return the GUID of the player sitting in this seat, or `None` if it is left vacant
|
||||
*/
|
||||
def Occupant_=(player : Option[Player]) : Option[PlanetSideGUID] = {
|
||||
def Occupant_=(player : Player) : Option[Player] = Occupant_=(Some(player))
|
||||
|
||||
def Occupant_=(player : Option[Player]) : Option[Player] = {
|
||||
if(player.isDefined) {
|
||||
if(this.occupant.isEmpty) {
|
||||
this.occupant = Some(player.get.GUID)
|
||||
this.occupant = player
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -58,14 +49,14 @@ class Seat(private val seatDef : SeatDefinition, private val vehicle : Vehicle)
|
|||
this.occupant.isDefined
|
||||
}
|
||||
|
||||
def SeatLockState : VehicleLockState.Value = {
|
||||
this.lockState
|
||||
}
|
||||
|
||||
def SeatLockState_=(lockState : VehicleLockState.Value) : VehicleLockState.Value = {
|
||||
this.lockState = lockState
|
||||
SeatLockState
|
||||
}
|
||||
// def SeatLockState : VehicleLockState.Value = {
|
||||
// this.lockState
|
||||
// }
|
||||
//
|
||||
// def SeatLockState_=(lockState : VehicleLockState.Value) : VehicleLockState.Value = {
|
||||
// this.lockState = lockState
|
||||
// SeatLockState
|
||||
// }
|
||||
|
||||
def ArmorRestriction : SeatArmorRestriction.Value = {
|
||||
seatDef.ArmorRestriction
|
||||
|
|
@ -79,25 +70,6 @@ class Seat(private val seatDef : SeatDefinition, private val vehicle : Vehicle)
|
|||
seatDef.ControlledWeapon
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a player, can they access this `Seat` under its current restrictions and permissions.
|
||||
* @param player the player who wants to sit
|
||||
* @return `true` if the player can sit down in this `Seat`; `false`, otherwise
|
||||
*/
|
||||
def CanUseSeat(player : Player) : Boolean = {
|
||||
var access : Boolean = false
|
||||
val owner : Option[PlanetSideGUID] = vehicle.Owner
|
||||
lockState match {
|
||||
case VehicleLockState.Locked =>
|
||||
access = owner.isEmpty || (owner.isDefined && player.GUID == owner.get)
|
||||
case VehicleLockState.Group =>
|
||||
access = Faction == player.Faction //TODO this is not correct
|
||||
case VehicleLockState.Empire =>
|
||||
access = Faction == player.Faction
|
||||
}
|
||||
access
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the string representation to provide additional information.
|
||||
* @return the string output
|
||||
|
|
@ -110,11 +82,10 @@ class Seat(private val seatDef : SeatDefinition, private val vehicle : Vehicle)
|
|||
object Seat {
|
||||
/**
|
||||
* Overloaded constructor.
|
||||
* @param vehicle the vehicle where this seat is installed
|
||||
* @return a `Seat` object
|
||||
*/
|
||||
def apply(seatDef : SeatDefinition, vehicle : Vehicle) : Seat = {
|
||||
new Seat(seatDef, vehicle)
|
||||
def apply(seatDef : SeatDefinition) : Seat = {
|
||||
new Seat(seatDef)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -122,13 +93,12 @@ object Seat {
|
|||
* @return the string output
|
||||
*/
|
||||
def toString(obj : Seat) : String = {
|
||||
val weaponStr = if(obj.ControlledWeapon.isDefined) { " (gunner)" } else { "" }
|
||||
val seatStr = if(obj.isOccupied) {
|
||||
"occupied by %d".format(obj.Occupant.get.guid)
|
||||
s", occupied by player ${obj.Occupant.get.GUID}"
|
||||
}
|
||||
else {
|
||||
"unoccupied"
|
||||
""
|
||||
}
|
||||
s"{Seat$weaponStr: $seatStr}"
|
||||
s"seat$seatStr"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ package net.psforever.objects.vehicles
|
|||
object SeatArmorRestriction extends Enumeration {
|
||||
type Type = Value
|
||||
|
||||
val MaxOnly,
|
||||
val
|
||||
MaxOnly,
|
||||
NoMax,
|
||||
NoReinforcedOrMax
|
||||
= Value
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.vehicles
|
||||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.Vehicle
|
||||
|
||||
/**
|
||||
* An `Actor` that handles messages being dispatched to a specific `Vehicle`.<br>
|
||||
* <br>
|
||||
* Vehicle-controlling actors have two behavioral states - responsive and "`Disabled`."
|
||||
* 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 {
|
||||
def receive : Receive = {
|
||||
case Vehicle.PrepareForDeletion =>
|
||||
context.become(Disabled)
|
||||
|
||||
case Vehicle.TrySeatPlayer(seat_num, player) =>
|
||||
vehicle.Seat(seat_num) match {
|
||||
case Some(seat) =>
|
||||
if((seat.Occupant = player).contains(player)) {
|
||||
sender ! Vehicle.VehicleMessages(player, Vehicle.CanSeatPlayer(vehicle, seat_num))
|
||||
}
|
||||
else {
|
||||
sender ! Vehicle.VehicleMessages(player, Vehicle.CannotSeatPlayer(vehicle, seat_num))
|
||||
}
|
||||
case None =>
|
||||
sender ! Vehicle.VehicleMessages(player, Vehicle.CannotSeatPlayer(vehicle, seat_num))
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
def Disabled : Receive = {
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,12 +3,12 @@ package net.psforever.objects.vehicles
|
|||
|
||||
/**
|
||||
* An `Enumeration` of various access states for vehicle components, such as the seats and the trunk.
|
||||
* Organized to replicate the `PlanetsideAttributeMessage` value used for that given access level.
|
||||
*/
|
||||
object VehicleLockState extends Enumeration {
|
||||
type Type = Value
|
||||
|
||||
val Empire, //owner's whole faction
|
||||
Group, //owner's squad/platoon only
|
||||
Locked //owner only
|
||||
= Value
|
||||
val Locked = Value(0) //owner only
|
||||
val Group = Value(1) //owner's squad/platoon only
|
||||
val Empire = Value(3) //owner's whole faction
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package net.psforever.objects.zones
|
|||
import akka.actor.{ActorContext, ActorRef, Props}
|
||||
import akka.routing.RandomPool
|
||||
import net.psforever.objects.serverobject.doors.Base
|
||||
import net.psforever.objects.{PlanetSideGameObject, Player}
|
||||
import net.psforever.objects.{PlanetSideGameObject, Player, Vehicle}
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.guid.NumberPoolHub
|
||||
import net.psforever.objects.guid.actor.UniqueNumberSystem
|
||||
|
|
@ -14,6 +14,7 @@ import net.psforever.packet.GamePacket
|
|||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
/**
|
||||
|
|
@ -49,6 +50,10 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
|||
private val equipmentOnGround : ListBuffer[Equipment] = ListBuffer[Equipment]()
|
||||
/** Used by the `Zone` to coordinate `Equipment` dropping and collection requests. */
|
||||
private var ground : ActorRef = ActorRef.noSender
|
||||
/** */
|
||||
private var vehicles : List[Vehicle] = List[Vehicle]()
|
||||
/** */
|
||||
private var transport : ActorRef = ActorRef.noSender
|
||||
|
||||
private var bases : List[Base] = List()
|
||||
|
||||
|
|
@ -69,6 +74,7 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
|||
implicit val guid : NumberPoolHub = this.guid //passed into builderObject.Build implicitly
|
||||
accessor = context.actorOf(RandomPool(25).props(Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystem.AllocateNumberPoolActors(guid))), s"$Id-uns")
|
||||
ground = context.actorOf(Props(classOf[ZoneGroundActor], equipmentOnGround), s"$Id-ground")
|
||||
transport = context.actorOf(Props(classOf[ZoneVehicleActor], this), s"$Id-vehicles")
|
||||
|
||||
Map.LocalObjects.foreach({ builderObject =>
|
||||
builderObject.Build
|
||||
|
|
@ -165,6 +171,37 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
|||
*/
|
||||
def EquipmentOnGround : List[Equipment] = equipmentOnGround.toList
|
||||
|
||||
def Vehicles : List[Vehicle] = vehicles
|
||||
|
||||
def AddVehicle(vehicle : Vehicle) : List[Vehicle] = {
|
||||
vehicles = vehicles :+ vehicle
|
||||
Vehicles
|
||||
}
|
||||
|
||||
def RemoveVehicle(vehicle : Vehicle) : List[Vehicle] = {
|
||||
vehicles = recursiveFindVehicle(vehicles.iterator, vehicle) match {
|
||||
case Some(index) =>
|
||||
vehicles.take(index) ++ vehicles.drop(index + 1)
|
||||
case None => ;
|
||||
vehicles
|
||||
}
|
||||
Vehicles
|
||||
}
|
||||
|
||||
@tailrec private def recursiveFindVehicle(iter : Iterator[Vehicle], target : Vehicle, index : Int = 0) : Option[Int] = {
|
||||
if(!iter.hasNext) {
|
||||
None
|
||||
}
|
||||
else {
|
||||
if(iter.next.equals(target)) {
|
||||
Some(index)
|
||||
}
|
||||
else {
|
||||
recursiveFindVehicle(iter, target, index + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Coordinate `Equipment` that has been dropped on the ground or to-be-dropped on the ground.
|
||||
* @return synchronized reference to the ground
|
||||
|
|
@ -175,6 +212,8 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
|||
*/
|
||||
def Ground : ActorRef = ground
|
||||
|
||||
def Transport : ActorRef = transport
|
||||
|
||||
def MakeBases(num : Int) : List[Base] = {
|
||||
bases = (0 to num).map(id => new Base(id)).toList
|
||||
bases
|
||||
|
|
@ -250,6 +289,10 @@ object Zone {
|
|||
*/
|
||||
final case class ItemFromGround(player : Player, item : Equipment)
|
||||
|
||||
final case class SpawnVehicle(vehicle : Vehicle)
|
||||
|
||||
final case class DespawnVehicle(vehicle : Vehicle)
|
||||
|
||||
/**
|
||||
* Message to report the packet messages that initialize the client.
|
||||
* @param list a `List` of `GamePacket` messages
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.zones
|
||||
|
||||
import akka.actor.Actor
|
||||
|
||||
/**
|
||||
* Synchronize management of the list of `Vehicles` maintained by some `Zone`.
|
||||
* @param zone the `Zone` object
|
||||
*/
|
||||
class ZoneVehicleActor(zone : Zone) extends Actor {
|
||||
//private[this] val log = org.log4s.getLogger
|
||||
|
||||
def receive : Receive = {
|
||||
case Zone.SpawnVehicle(vehicle) =>
|
||||
zone.AddVehicle(vehicle)
|
||||
|
||||
case Zone.DespawnVehicle(vehicle) =>
|
||||
zone.RemoveVehicle(vehicle)
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import scodec.Codec
|
|||
import scodec.codecs._
|
||||
|
||||
/**
|
||||
* Attribute Type:<br>
|
||||
* Players/General:<br>
|
||||
* Server to client : <br>
|
||||
* `0 - health`<br>
|
||||
* `1 - healthMax`<br>
|
||||
|
|
@ -86,7 +86,19 @@ import scodec.codecs._
|
|||
* `78 - Cavern Kills. Value is the number of kills`<br>
|
||||
* `106 - Custom Head`
|
||||
* Client to Server : <br>
|
||||
* `106 - Custom Head`
|
||||
* `106 - Custom Head`<br>
|
||||
* <br>
|
||||
* Vehicles:<br>
|
||||
* 0 - Vehicle health<br>
|
||||
* 10 - Driver seat permissions (0 = Locked, 1 = Group, 3 = Empire)<br>
|
||||
* 11 - Gunner seat(s) permissions (same)<br>
|
||||
* 12 - Passenger seat(s) permissions (same) <br>
|
||||
* 13 - Trunk permissions (same)<br>
|
||||
* 21 - Asserts first time event eligibility / makes owner if no owner is assigned<br>
|
||||
* 22 - Toggles gunner and passenger mount points (1 = hides, 0 = reveals; this also locks their permissions)<br>
|
||||
* 68 - ???<br>
|
||||
* 80 - Damage vehicle (unknown value)<br>
|
||||
* 113 - ???
|
||||
* @param player_guid the player
|
||||
* @param attribute_type na
|
||||
* @param attribute_value na
|
||||
|
|
|
|||
|
|
@ -803,6 +803,7 @@ object ObjectClass {
|
|||
case ObjectClass.battlewagon_weapon_systemd => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.bolt_driver => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.chainblade => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.chaingun_p => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.colossus_burster => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.colossus_burster_left => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.colossus_burster_right => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
|
|
@ -918,7 +919,6 @@ object ObjectClass {
|
|||
case ObjectClass.cannon_dropship_20mm => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.chaingun_12mm => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.chaingun_15mm => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.chaingun_p => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.cycler_v2 => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.cycler_v3 => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.cycler_v4 => ConstructorData.genericCodec(WeaponData.codec, "weapon")
|
||||
|
|
@ -1080,6 +1080,7 @@ object ObjectClass {
|
|||
// case ObjectClass.aphelion_starfire_right => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.bolt_driver => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.chainblade => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
// case ObjectClass.chaingun_p => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
// case ObjectClass.colossus_burster => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
// case ObjectClass.colossus_burster_left => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
// case ObjectClass.colossus_burster_right => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
|
|
@ -1144,7 +1145,6 @@ object ObjectClass {
|
|||
case ObjectClass.advanced_missile_launcher_t => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.chaingun_12mm => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.chaingun_15mm => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.chaingun_p => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.cycler_v2 => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.cycler_v3 => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
case ObjectClass.cycler_v4 => DroppedItemData.genericCodec(WeaponData.codec, "weapon")
|
||||
|
|
|
|||
|
|
@ -281,7 +281,8 @@ class ConverterTest extends Specification {
|
|||
|
||||
val hellfire_ammo_box = AmmoBox(PlanetSideGUID(432), hellfire_ammo)
|
||||
|
||||
val fury = Vehicle(PlanetSideGUID(413), fury_def)
|
||||
val fury = Vehicle(fury_def)
|
||||
fury.GUID = PlanetSideGUID(413)
|
||||
fury.Faction = PlanetSideEmpire.VS
|
||||
fury.Position = Vector3(3674.8438f, 2732f, 91.15625f)
|
||||
fury.Orientation = Vector3(0.0f, 0.0f, 90.0f)
|
||||
|
|
|
|||
103
common/src/test/scala/objects/VehicleTest.scala
Normal file
103
common/src/test/scala/objects/VehicleTest.scala
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import net.psforever.objects.{GlobalDefinitions, Vehicle}
|
||||
import net.psforever.objects.definition.SeatDefinition
|
||||
import net.psforever.objects.vehicles.{Seat, SeatArmorRestriction, VehicleLockState}
|
||||
import org.specs2.mutable._
|
||||
|
||||
class VehicleTest extends Specification {
|
||||
|
||||
"SeatDefinition" should {
|
||||
val seat = new SeatDefinition
|
||||
seat.ArmorRestriction = SeatArmorRestriction.MaxOnly
|
||||
seat.Bailable = true
|
||||
seat.ControlledWeapon = 5
|
||||
|
||||
"define (default)" in {
|
||||
val t_seat = new SeatDefinition
|
||||
t_seat.ArmorRestriction mustEqual SeatArmorRestriction.NoMax
|
||||
t_seat.Bailable mustEqual false
|
||||
t_seat.ControlledWeapon mustEqual None
|
||||
}
|
||||
|
||||
"define (custom)" in {
|
||||
seat.ArmorRestriction mustEqual SeatArmorRestriction.MaxOnly
|
||||
seat.Bailable mustEqual true
|
||||
seat.ControlledWeapon mustEqual Some(5)
|
||||
}
|
||||
}
|
||||
|
||||
"VehicleDefinition" should {
|
||||
"define" in {
|
||||
val fury = GlobalDefinitions.fury
|
||||
fury.CanBeOwned mustEqual true
|
||||
fury.CanCloak mustEqual false
|
||||
fury.Seats.size mustEqual 1
|
||||
fury.Seats(0).Bailable mustEqual true
|
||||
fury.Seats(0).ControlledWeapon mustEqual Some(1)
|
||||
fury.MountPoints.size mustEqual 2
|
||||
fury.MountPoints.get(0) mustEqual Some(0)
|
||||
fury.MountPoints.get(1) mustEqual None
|
||||
fury.MountPoints.get(2) mustEqual Some(0)
|
||||
fury.Weapons.size mustEqual 1
|
||||
fury.Weapons.get(0) mustEqual None
|
||||
fury.Weapons.get(1) mustEqual Some(GlobalDefinitions.fury_weapon_systema)
|
||||
fury.TrunkSize.width mustEqual 11
|
||||
fury.TrunkSize.height mustEqual 11
|
||||
fury.TrunkOffset mustEqual 30
|
||||
}
|
||||
}
|
||||
|
||||
"Seat" should {
|
||||
val seat_def = new SeatDefinition
|
||||
seat_def.ArmorRestriction = SeatArmorRestriction.MaxOnly
|
||||
seat_def.Bailable = true
|
||||
seat_def.ControlledWeapon = 5
|
||||
|
||||
"construct" in {
|
||||
val seat = new Seat(seat_def)
|
||||
seat.ArmorRestriction mustEqual SeatArmorRestriction.MaxOnly
|
||||
seat.Bailable mustEqual true
|
||||
seat.ControlledWeapon mustEqual Some(5)
|
||||
seat.isOccupied mustEqual false
|
||||
seat.Occupant mustEqual None
|
||||
}
|
||||
}
|
||||
|
||||
"Vehicle" should {
|
||||
"construct" in {
|
||||
Vehicle(GlobalDefinitions.fury)
|
||||
ok
|
||||
}
|
||||
|
||||
"construct (detailed)" in {
|
||||
val fury_vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
fury_vehicle.Owner mustEqual None
|
||||
fury_vehicle.Seats.size mustEqual 1
|
||||
fury_vehicle.Seats.head.ArmorRestriction mustEqual SeatArmorRestriction.NoMax
|
||||
fury_vehicle.Seats.head.isOccupied mustEqual false
|
||||
fury_vehicle.Seats.head.Occupant mustEqual None
|
||||
fury_vehicle.Seats.head.Bailable mustEqual true
|
||||
fury_vehicle.Seats.head.ControlledWeapon mustEqual Some(1)
|
||||
fury_vehicle.PermissionGroup(0) mustEqual Some(VehicleLockState.Locked) //driver
|
||||
fury_vehicle.PermissionGroup(1) mustEqual Some(VehicleLockState.Empire) //gunner
|
||||
fury_vehicle.PermissionGroup(2) mustEqual Some(VehicleLockState.Empire) //passenger
|
||||
fury_vehicle.PermissionGroup(3) mustEqual Some(VehicleLockState.Locked) //trunk
|
||||
fury_vehicle.Weapons.size mustEqual 1
|
||||
fury_vehicle.Weapons.get(0) mustEqual None
|
||||
fury_vehicle.Weapons.get(1).isDefined mustEqual true
|
||||
fury_vehicle.Weapons(1).Equipment.isDefined mustEqual true
|
||||
fury_vehicle.Weapons(1).Equipment.get.Definition mustEqual GlobalDefinitions.fury.Weapons(1)
|
||||
fury_vehicle.WeaponControlledFromSeat(0) mustEqual fury_vehicle.Weapons(1).Equipment
|
||||
fury_vehicle.Trunk.Width mustEqual 11
|
||||
fury_vehicle.Trunk.Height mustEqual 11
|
||||
fury_vehicle.Trunk.Offset mustEqual 30
|
||||
fury_vehicle.GetSeatFromMountPoint(0) mustEqual Some(0)
|
||||
fury_vehicle.GetSeatFromMountPoint(1) mustEqual None
|
||||
fury_vehicle.GetSeatFromMountPoint(2) mustEqual Some(0)
|
||||
fury_vehicle.Decal mustEqual 0
|
||||
fury_vehicle.Health mustEqual fury_vehicle.Definition.MaxHealth
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue