Building:

Replaces class object/serverobject/door/Base.scala.  It performs nearly the exact same purpose but now has a list of owned objects called Amenities.  Buildings are now a PlanetSideServerObject (PSSO), which allows them to have accept a *Control Actor and possess FactionAffinity.

FoundationBuilder:
FoundationBuilder : Building :: ServerObjectBuilder : [T <: PlanetSideServerObject]

Amenity:
Most PSSO's now accept Amenity as their parent in class hierarchy.  Flagged PSSO's like Building and Vehicle are, on the other hand, capable of becoming the owner for these Amenity PSSOs, which allows them to inherit the same FactionAffinity.

FactionAffinity:
A trait that connects objects that are intended to communicate PlanetSideEmpire values.

MountableBhevaior:
Split between Mount and Dismount behavior.  Passes appropriate messages to ensure coherent workflows.

Control Actors:
FactionAffinityBehavior and MountableBehavior are PartialFunctions that get processed in series.

VehicleControl:
Distinguished behavior allowed between an operational vehicle and a deactivated one.

WSA:
Tightened up DismountVehicleMsg handling code, since MountableBehavior has been enhanced.

Minor:
Shotgun shell stacking goes from 32 to 16.  Various PSSO classes now have reliable Definition objects.

Tests:
We now have 1012 tests, some of them useful.
This commit is contained in:
FateJH 2018-01-26 15:32:08 -05:00
parent 8c02f8d519
commit eefe4d2e20
56 changed files with 1362 additions and 425 deletions

View file

@ -9,6 +9,8 @@ import net.psforever.objects.equipment._
import net.psforever.objects.inventory.InventoryTile
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMechDefinition
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.types.PlanetSideEmpire
@ -498,9 +500,9 @@ object GlobalDefinitions {
val vehicle_terminal_combined = new VehicleTerminalCombinedDefinition
val spawn_pad = new ObjectDefinition(800) { Name = "spawn_pad" }
val spawn_pad = new VehicleSpawnPadDefinition
val mb_locker = new ObjectDefinition(524) { Name = "mb_locker" }
val mb_locker = new LockerDefinition
val lock_external = new IFFLockDefinition
@ -827,10 +829,10 @@ object GlobalDefinitions {
bullet_9mm_AP.Capacity = 50
bullet_9mm_AP.Tile = InventoryTile.Tile33
shotgun_shell.Capacity = 32
shotgun_shell.Capacity = 16
shotgun_shell.Tile = InventoryTile.Tile33
shotgun_shell_AP.Capacity = 32
shotgun_shell_AP.Capacity = 16
shotgun_shell_AP.Tile = InventoryTile.Tile33
energy_cell.Capacity = 50

View file

@ -8,6 +8,12 @@ import net.psforever.packet.game.PlanetSideGUID
import scala.annotation.tailrec
/**
* The companion of a `Locker` that is carried with a player
* masquerading as their sixth `EquipmentSlot` object and a sub-inventory item.
* The `Player` class refers to it as the "fifth slot" as its permanent slot number is encoded as `0x85`.
* The inventory of this object is accessed using a game world `Locker` object (`mb_locker`).
*/
class LockerContainer extends Equipment with Container {
private val inventory = GridInventory(30, 20)

View file

@ -4,6 +4,7 @@ package net.psforever.objects
import net.psforever.objects.definition.{AvatarDefinition, ImplantDefinition}
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.types._
@ -16,7 +17,7 @@ class Player(private val name : String,
private val sex : CharacterGender.Value,
private val head : Int,
private val voice : Int
) extends PlanetSideGameObject with Container {
) extends PlanetSideGameObject with FactionAffinity with Container {
private var alive : Boolean = false
private var backpack : Boolean = false
private var health : Int = 0

View file

@ -4,8 +4,9 @@ package net.psforever.objects
import net.psforever.objects.definition.VehicleDefinition
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem, InventoryTile}
import net.psforever.objects.mount.Mountable
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.vehicles.{AccessPermissionGroup, Seat, Utility, VehicleLockState}
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.packet.game.objectcreate.DriveState
@ -27,7 +28,10 @@ import scala.collection.mutable
* stores and unloads pertinent information about the `Vehicle`'s configuration;
* used in the initialization process (`loadVehicleDefinition`)
*/
class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServerObject with Mountable with Container {
class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServerObject
with FactionAffinity
with Mountable
with Container {
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.TR
private var owner : Option[PlanetSideGUID] = None
private var health : Int = 1
@ -63,7 +67,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ
this.faction
}
def Faction_=(faction : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = {
override def Faction_=(faction : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = {
this.faction = faction
faction
}
@ -465,11 +469,17 @@ object Vehicle {
/**
* The `Vehicle` will become unresponsive to player activity.
* Usually, it does this to await deconstruction and clean-up
* Usually, it does this to await deconstruction and clean-up.
* @see `VehicleControl`
*/
final case class PrepareForDeletion()
/**
* The `Vehicle` will resume previous unresponsiveness to player activity.
* @see `VehicleControl`
*/
final case class Reactivate()
/**
* Overloaded constructor.
* @param vehicleDef the vehicle's definition entry

View file

@ -1,31 +0,0 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.mount
import akka.actor.Actor
/**
* The logic governing `Mountable` objects that use the `TryMount` message.
* This is a mix-in trait for combining the `Receive` logic.
* @see `Seat`
* @see `Mountable`
*/
trait MountableBehavior {
this : Actor =>
def MountableObject : Mountable
val mountableBehavior : Receive = {
case Mountable.TryMount(user, seat_num) =>
MountableObject.Seat(seat_num) match {
case Some(seat) =>
if((seat.Occupant = user).contains(user)) {
sender ! Mountable.MountMessages(user, Mountable.CanMount(MountableObject, seat_num))
}
else {
sender ! Mountable.MountMessages(user, Mountable.CanNotMount(MountableObject, seat_num))
}
case None =>
sender ! Mountable.MountMessages(user, Mountable.CanNotMount(MountableObject, seat_num))
}
}
}

View file

@ -3,12 +3,13 @@ package net.psforever.objects.serverobject
import akka.actor.ActorRef
import net.psforever.objects.PlanetSideGameObject
import net.psforever.objects.serverobject.affinity.FactionAffinity
/**
* An object layered on top of the standard game object class that maintains an internal `ActorRef`.
* A measure of synchronization can be managed using this `Actor`.
*/
abstract class PlanetSideServerObject extends PlanetSideGameObject {
abstract class PlanetSideServerObject extends PlanetSideGameObject with FactionAffinity {
private var actor = ActorRef.noSender
/**

View file

@ -0,0 +1,35 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.affinity
import net.psforever.types.PlanetSideEmpire
/**
* Keep track of the allegiance of the object in terms of its association to a `PlanetSideEmpire` value.
*/
trait FactionAffinity {
def Faction : PlanetSideEmpire.Value
def Faction_=(fac : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = Faction
}
object FactionAffinity {
/**
* Message that makes the server object transmit IFF feedback.
* @see AssertFactionAffinity
*/
final case class ConfirmFactionAffinity()
/**
* Message that makes the server object change allegiance to the specified faction value.
* Transmit IFF feedback when done.
* @param faction the allegiance to which to change
*/
final case class ConvertFactionAffinity(faction : PlanetSideEmpire.Value)
/**
* Message that responds to an IFF feedback request.
* Transmit IFF feedback when done.
* @see ConfirmFactionAffinity
* @param obj the governed object
* @param faction the allegiance to which the object belongs
*/
final case class AssertFactionAffinity(obj : FactionAffinity, faction : PlanetSideEmpire.Value)
}

View file

@ -0,0 +1,42 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.affinity
import akka.actor.Actor
object FactionAffinityBehavior {
/**
* A `trait` for inheritance of common implementable methods.
*/
sealed trait BasicAffinity {
def FactionObject : FactionAffinity
}
/**
* The logic governing `FactionAffinity` objects that use the `ConvertFactionAffinity` message.
* This is a mix-in trait for combining with existing `Receive` logic.
*/
trait Convert extends BasicAffinity {
this : Actor =>
val convertBehavior : Receive = {
case FactionAffinity.ConvertFactionAffinity(faction) =>
FactionObject.Faction = faction
sender ! FactionAffinity.AssertFactionAffinity(FactionObject, faction)
}
}
/**
* The logic governing `FactionAffinity` objects that use the `ConfirmFactionAffinity` message.
* A case exists to catch `AssertFactionAffinity` messages for the same ends though they should not be used this way.
* This is a mix-in trait for combining with existing `Receive` logic.
*/
trait Check extends BasicAffinity {
this : Actor =>
val checkBehavior : Receive = {
case FactionAffinity.ConfirmFactionAffinity() | FactionAffinity.AssertFactionAffinity(_, _) =>
sender ! FactionAffinity.AssertFactionAffinity(FactionObject, FactionObject.Faction)
}
}
}

View file

@ -1,21 +0,0 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.doors
import net.psforever.types.PlanetSideEmpire
/**
* A temporary class to represent "facilities" and "structures."
* @param id the map id of the base
*/
class Base(private val id : Int) {
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
def Id : Int = id
def Faction : PlanetSideEmpire.Value = faction
def Faction_=(emp : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = {
faction = emp
Faction
}
}

View file

@ -1,8 +1,8 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.doors
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.Player
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.packet.game.UseItemMessage
import net.psforever.types.Vector3
@ -10,7 +10,7 @@ import net.psforever.types.Vector3
* A structure-owned server object that is a "door" that can open and can close.
* @param ddef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
*/
class Door(private val ddef : DoorDefinition) extends PlanetSideServerObject {
class Door(private val ddef : DoorDefinition) extends Amenity {
private var openState : Option[Player] = None
/** a vector in the direction of the "outside" of a room;
* typically, any locking utility is on that same "outside" */

View file

@ -2,13 +2,16 @@
package net.psforever.objects.serverobject.doors
import akka.actor.Actor
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
/**
* An `Actor` that handles messages being dispatched to a specific `Door`.
* @param door the `Door` object being governed
*/
class DoorControl(door : Door) extends Actor {
def receive : Receive = {
class DoorControl(door : Door) extends Actor with FactionAffinityBehavior.Check {
def FactionObject : FactionAffinity = door
def receive : Receive = checkBehavior.orElse {
case Door.Use(player, msg) =>
sender ! Door.DoorMessage(player, msg, door.Use(player, msg))

View file

@ -3,8 +3,8 @@ package net.psforever.objects.serverobject.implantmech
import net.psforever.objects.Player
import net.psforever.objects.definition.ObjectDefinition
import net.psforever.objects.mount.Mountable
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.objects.vehicles.Seat
/**
@ -12,7 +12,7 @@ import net.psforever.objects.vehicles.Seat
* For the most part, it merely implements the support data structures indicated by `Mountable`.
* @param idef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
*/
class ImplantTerminalMech(private val idef : ImplantTerminalMechDefinition) extends PlanetSideServerObject with Mountable {
class ImplantTerminalMech(private val idef : ImplantTerminalMechDefinition) extends Amenity with Mountable {
private val seats : Map[Int, Seat] = Map( 0 -> new Seat(idef.Seats(0)) )
def Seats : Map[Int, Seat] = seats

View file

@ -2,16 +2,23 @@
package net.psforever.objects.serverobject.implantmech
import akka.actor.Actor
import net.psforever.objects.mount.MountableBehavior
import net.psforever.objects.serverobject.mount.MountableBehavior
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
/**
* An `Actor` that handles messages being dispatched to a specific `ImplantTerminalMech`.
* @param mech the "mech" object being governed
*/
class ImplantTerminalMechControl(mech : ImplantTerminalMech) extends Actor with MountableBehavior {
override def MountableObject = mech
class ImplantTerminalMechControl(mech : ImplantTerminalMech) extends Actor with FactionAffinityBehavior.Check
with MountableBehavior.Mount with MountableBehavior.Dismount {
def MountableObject = mech //do not add type!
def receive : Receive = mountableBehavior.orElse {
case _ => ;
}
def FactionObject : FactionAffinity = mech
def receive : Receive = checkBehavior
.orElse(mountBehavior)
.orElse(dismountBehavior)
.orElse {
case _ => ;
}
}

View file

@ -2,7 +2,7 @@
package net.psforever.objects.serverobject.locks
import net.psforever.objects.Player
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.types.Vector3
@ -15,7 +15,7 @@ import net.psforever.types.Vector3
* The `IFFLock` is ideally associated with a server map object - a `Door` - to which it acts as a gatekeeper.
* @param idef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
*/
class IFFLock(private val idef : IFFLockDefinition) extends PlanetSideServerObject {
class IFFLock(private val idef : IFFLockDefinition) extends Amenity {
/**
* An entry that maintains a reference to the `Player`, and the player's GUID and location when the message was received.
*/

View file

@ -3,14 +3,17 @@ package net.psforever.objects.serverobject.locks
import akka.actor.Actor
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
/**
* An `Actor` that handles messages being dispatched to a specific `IFFLock`.
* @param lock the `IFFLock` object being governed
* @see `CommonMessages`
*/
class IFFLockControl(lock : IFFLock) extends Actor {
def receive : Receive = {
class IFFLockControl(lock : IFFLock) extends Actor with FactionAffinityBehavior.Check {
def FactionObject : FactionAffinity = lock
def receive : Receive = checkBehavior.orElse {
case CommonMessages.Hack(player) =>
lock.HackedBy = player

View file

@ -1,19 +1,18 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.mblocker
import akka.actor.ActorContext
import akka.actor.{ActorContext, Props}
import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.definition.ObjectDefinition
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.structures.Amenity
class Locker extends PlanetSideServerObject {
def Definition : ObjectDefinition = GlobalDefinitions.mb_locker
class Locker extends Amenity {
def Definition : LockerDefinition = GlobalDefinitions.mb_locker
}
object Locker {
/**
* Overloaded constructor.
* @return a `VehicleSpawnPad` object
* @return the `Locker` object
*/
def apply() : Locker = {
new Locker()
@ -28,6 +27,7 @@ object Locker {
*/
def Constructor(id : Int, context : ActorContext) : Locker = {
val obj = Locker()
obj.Actor = context.actorOf(Props(classOf[LockerControl], obj), s"${obj.Definition.Name}_$id")
obj
}
}

View file

@ -0,0 +1,17 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.mblocker
import akka.actor.Actor
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
/**
* An `Actor` that handles messages being dispatched to a specific `Locker`.
* @param locker the `Locker` object being governed
*/
class LockerControl(locker : Locker) extends Actor with FactionAffinityBehavior.Check {
def FactionObject : FactionAffinity = locker
def receive : Receive = checkBehavior.orElse {
case _ => ;
}
}

View file

@ -0,0 +1,12 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.mblocker
import net.psforever.objects.definition.ObjectDefinition
/**
* The definition for any `Locker`.
* Object Id 524.
*/
class LockerDefinition extends ObjectDefinition(524) {
Name = "mb_locker"
}

View file

@ -1,5 +1,5 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.mount
package net.psforever.objects.serverobject.mount
import akka.actor.ActorRef
import net.psforever.objects.Player
@ -62,6 +62,8 @@ object Mountable {
*/
final case class TryMount(player : Player, seat_num : Int)
final case class TryDismount(player : Player, seat_num : Int)
/**
* A basic `Trait` connecting all of the actionable `Mountable` response messages.
*/
@ -89,4 +91,19 @@ object Mountable {
* @param seat_num the seat index
*/
final case class CanNotMount(obj : Mountable, seat_num : Int) extends Exchange
/**
* Message sent in response to the player succeeding to disembark a `Mountable` object.
* The player was previously seated at the given index.
* @param obj the `Mountable` object
* @param seat_num the seat index
*/
final case class CanDismount(obj : Mountable, seat_num : Int) extends Exchange
/**
* Message sent in response to the player failing to disembark a `Mountable` object.
* The player is still seated at the given index.
* @param obj the `Mountable` object
* @param seat_num the seat index
*/
final case class CanNotDismount(obj : Mountable, seat_num : Int) extends Exchange
}

View file

@ -0,0 +1,68 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.mount
import akka.actor.Actor
import net.psforever.objects.entity.{Identifiable, WorldEntity}
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.types.Vector3
object MountableBehavior {
/**
* The logic governing `Mountable` objects that use the `TryMount` message.
* This is a mix-in trait for combining with existing `Receive` logic.
* @see `Seat`
* @see `Mountable`
*/
trait Mount {
this : Actor =>
def MountableObject : Mountable with Identifiable with WorldEntity with FactionAffinity
val mountBehavior : Receive = {
case Mountable.TryMount(user, seat_num) =>
val obj = MountableObject
obj.Seat(seat_num) match {
case Some(seat) =>
if(user.Faction == obj.Faction && (seat.Occupant = user).contains(user)) {
user.VehicleSeated = obj.GUID
sender ! Mountable.MountMessages(user, Mountable.CanMount(obj, seat_num))
}
else {
sender ! Mountable.MountMessages(user, Mountable.CanNotMount(obj, seat_num))
}
case None =>
sender ! Mountable.MountMessages(user, Mountable.CanNotMount(obj, seat_num))
}
}
}
/**
* The logic governing `Mountable` objects that use the `TryDismount` message.
* This is a mix-in trait for combining with existing `Receive` logic.
* @see `Seat`
* @see `Mountable`
*/
trait Dismount {
this : Actor =>
def MountableObject : Mountable with Identifiable with WorldEntity with FactionAffinity
val dismountBehavior : Receive = {
case Mountable.TryDismount(user, seat_num) =>
val obj = MountableObject
obj.Seat(seat_num) match {
case Some(seat) =>
if(seat.Bailable || obj.Velocity.isEmpty || Vector3.MagnitudeSquared(obj.Velocity.get).toInt == 0) {
seat.Occupant = None
user.VehicleSeated = None
sender ! Mountable.MountMessages(user, Mountable.CanDismount(obj, seat_num))
}
else {
sender ! Mountable.MountMessages(user, Mountable.CanNotDismount(obj, seat_num))
}
case None =>
sender ! Mountable.MountMessages(user, Mountable.CanNotDismount(obj, seat_num))
}
}
}
}

View file

@ -2,6 +2,7 @@
package net.psforever.objects.serverobject.pad
import akka.actor.{Actor, ActorRef, Cancellable}
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.{DefaultCancellable, Player, Vehicle}
import net.psforever.types.Vector3
@ -29,7 +30,7 @@ import scala.concurrent.duration._
* 3. a callback location for sending messages.
* @param pad the `VehicleSpawnPad` object being governed
*/
class VehicleSpawnControl(pad : VehicleSpawnPad) extends Actor {
class VehicleSpawnControl(pad : VehicleSpawnPad) extends Actor with FactionAffinityBehavior.Check {
/** an executor for progressing a vehicle order through the normal spawning logic */
private var process : Cancellable = DefaultCancellable.obj
/** a list of vehicle orders that have been submitted for this spawn pad */
@ -41,8 +42,9 @@ class VehicleSpawnControl(pad : VehicleSpawnPad) extends Actor {
private[this] val log = org.log4s.getLogger
private[this] def trace(msg : String) : Unit = log.trace(msg)
def FactionObject : FactionAffinity = pad
def receive : Receive = {
def receive : Receive = checkBehavior.orElse {
case VehicleSpawnPad.VehicleOrder(player, vehicle) =>
trace(s"order from $player for $vehicle received")
orders = orders :+ VehicleSpawnControl.OrderEntry(player, vehicle, sender)

View file

@ -2,8 +2,7 @@
package net.psforever.objects.serverobject.pad
import net.psforever.objects.{Player, Vehicle}
import net.psforever.objects.definition.ObjectDefinition
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.packet.game.PlanetSideGUID
/**
@ -16,8 +15,8 @@ import net.psforever.packet.game.PlanetSideGUID
* @param spDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
* @see `VehicleSpawnControl`
*/
class VehicleSpawnPad(spDef : ObjectDefinition) extends PlanetSideServerObject {
def Definition : ObjectDefinition = spDef
class VehicleSpawnPad(spDef : VehicleSpawnPadDefinition) extends Amenity {
def Definition : VehicleSpawnPadDefinition = spDef
}
object VehicleSpawnPad {
@ -83,7 +82,7 @@ object VehicleSpawnPad {
* @param spDef the spawn pad's definition entry
* @return a `VehicleSpawnPad` object
*/
def apply(spDef : ObjectDefinition) : VehicleSpawnPad = {
def apply(spDef : VehicleSpawnPadDefinition) : VehicleSpawnPad = {
new VehicleSpawnPad(spDef)
}

View file

@ -0,0 +1,12 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.pad
import net.psforever.objects.definition.ObjectDefinition
/**
* The definition for any `VehicleSpawnPad`.
* Object Id 800.
*/
class VehicleSpawnPadDefinition extends ObjectDefinition(800) {
Name = "spawn_pad"
}

View file

@ -0,0 +1,60 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.structures
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.types.PlanetSideEmpire
/**
* Amenities are elements of the game that belong to other elements of the game.<br>
* <br>
* Normal `PlanetSideServerObject` entities (server objects) tend to have properties that are completely internalized.
* An `Amenity` is a server object that maintains a fixed association with another server object.
* This association strips away at the internalization and redirects a reference to some properties somewhere else.
* An `Amenity` object belongs to its `Owner` object;
* the `Amenity` objects looks to its `Owner` object for some of its properties.
* @see `FactionAffinity`
*/
abstract class Amenity extends PlanetSideServerObject {
private var owner : PlanetSideServerObject = Building.NoBuilding
def Faction : PlanetSideEmpire.Value = Owner.Faction
/**
* Reference the object that is in direct association with (is superior to) this one.
* @return the object associated as this object's "owner"
*/
def Owner : PlanetSideServerObject = owner
/**
* Set an object to have a direct association with (be superior to) this one.
* @see `Amenity.AmenityTarget`
* @param obj the object trying to become associated as this object's "owner"
* @tparam T a validation of the type of object that can be an owner
* @return the object associated as this object's "owner"
*/
def Owner_=[T : Amenity.AmenityTarget](obj : T) : PlanetSideServerObject = {
owner = obj.asInstanceOf[PlanetSideServerObject]
Owner
}
}
object Amenity {
/**
* A `trait` for validating the type of object that can be allowed to become an `Amenity` object's `Owner`.<br>
* <br>
* The `Owner` defaults to a type of `PlanetSideServerObject` in reference type;
* but, that distinction is mainly to allow for a common ancestor with appropriate methods.
* Only certain types of `PlanetSideServerObject` are formally allowed to be owners.
* In execution, the `T` is the type of object that implicitly converts into an acceptable type of sub-object.
* The companion object maintains the hardcoded conversions.
* If such an implicit conversion does not exist, the assignment is unacceptable at compile time.
* @tparam T the permitted type of object
*/
sealed trait AmenityTarget[T]
object AmenityTarget {
import net.psforever.objects.Vehicle
implicit object BuildingTarget extends AmenityTarget[Building] { }
implicit object VehicleTarget extends AmenityTarget[Vehicle] { }
}
}

View file

@ -0,0 +1,56 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.structures
import akka.actor.ActorContext
import net.psforever.objects.definition.ObjectDefinition
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.types.PlanetSideEmpire
class Building(private val id : Int, private val zone : Zone) extends PlanetSideServerObject {
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
private var amenities : List[Amenity] = List.empty
GUID = PlanetSideGUID(0)
def Id : Int = id
def Faction : PlanetSideEmpire.Value = faction
override def Faction_=(fac : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = {
faction = fac
Faction
}
def Amenities : List[Amenity] = amenities
def Amenities_=(obj : Amenity) : List[Amenity] = {
amenities = amenities :+ obj
obj.Owner = this
amenities
}
def Zone : Zone = zone
def Definition: ObjectDefinition = Building.BuildingDefinition
}
object Building {
final val NoBuilding : Building = new Building(0, Zone.Nowhere) {
override def Faction_=(faction : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
override def Amenities_=(obj : Amenity) : List[Amenity] = Nil
}
final val BuildingDefinition : ObjectDefinition = new ObjectDefinition(0) { Name = "building" }
def apply(id : Int, zone : Zone) : Building = {
new Building(id, zone)
}
def Structure(id : Int, zone : Zone, context : ActorContext) : Building = {
import akka.actor.Props
val obj = new Building(id, zone)
obj.Actor = context.actorOf(Props(classOf[BuildingControl], obj), s"$id-building")
obj
}
}

View file

@ -0,0 +1,20 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.structures
import akka.actor.Actor
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
class BuildingControl(building : Building) extends Actor with FactionAffinityBehavior.Check {
def FactionObject : FactionAffinity = building
def receive : Receive = checkBehavior.orElse {
case FactionAffinity.ConvertFactionAffinity(faction) =>
val originalAffinity = building.Faction
if(originalAffinity != (building.Faction = faction)) {
building.Amenities.foreach(_.Actor forward FactionAffinity.ConfirmFactionAffinity())
}
sender ! FactionAffinity.AssertFactionAffinity(building, faction)
case _ => ;
}
}

View file

@ -0,0 +1,30 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.structures
import akka.actor.ActorContext
import net.psforever.objects.zones.Zone
/**
* Defer establishment of a `Building` object until the location for the object is correct (in the correct zone)
* and a `context` in the proper `Actor` hierarchy of that zone exists in scope.
* @see `ServerObjectBuilder`
* @see `Building`
* @param constructor a curried function that eventually constructs a `Building` object
*/
class FoundationBuilder(private val constructor : (Int, Zone, ActorContext)=>Building) {
def Build(id : Int, zone : Zone)(implicit context : ActorContext = null) : Building = {
val obj : Building = constructor(id, zone, context)
obj
}
}
object FoundationBuilder {
/**
* Overloaded constructor.
* @param constructor a curried function that eventually constructs a `Building` object
* @return a `FoundationBuilder` object
*/
def apply(constructor : (Int, Zone, ActorContext)=>Building) : FoundationBuilder = {
new FoundationBuilder(constructor)
}
}

View file

@ -2,7 +2,7 @@
package net.psforever.objects.serverobject.terminals
import net.psforever.objects.Player
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
import net.psforever.types.{TransactionType, Vector3}
@ -10,7 +10,7 @@ import net.psforever.types.{TransactionType, Vector3}
* A structure-owned server object that is a "terminal" that can be accessed for amenities and services.
* @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
*/
class Terminal(tdef : TerminalDefinition) extends PlanetSideServerObject {
class Terminal(tdef : TerminalDefinition) extends Amenity {
/** An entry that maintains a reference to the `Player`, and the player's GUID and location when the message was received. */
private var hackedBy : Option[(Player, PlanetSideGUID, Vector3)] = None
@ -65,18 +65,23 @@ class Terminal(tdef : TerminalDefinition) extends PlanetSideServerObject {
* @return an actionable message that explains what resulted from interacting with this `Terminal`
*/
def Request(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
msg.transaction_type match {
case TransactionType.Buy | TransactionType.Learn =>
tdef.Buy(player, msg)
if(Faction == player.Faction || HackedBy.isDefined) {
msg.transaction_type match {
case TransactionType.Buy | TransactionType.Learn =>
tdef.Buy(player, msg)
case TransactionType.Sell =>
tdef.Sell(player, msg)
case TransactionType.Sell =>
tdef.Sell(player, msg)
case TransactionType.InfantryLoadout =>
tdef.Loadout(player, msg)
case TransactionType.InfantryLoadout =>
tdef.Loadout(player, msg)
case _ =>
Terminal.NoDeal()
case _ =>
Terminal.NoDeal()
}
}
else {
Terminal.NoDeal()
}
}

View file

@ -2,13 +2,16 @@
package net.psforever.objects.serverobject.terminals
import akka.actor.Actor
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
/**
* An `Actor` that handles messages being dispatched to a specific `Terminal`.
* @param term the `Terminal` object being governed
*/
class TerminalControl(term : Terminal) extends Actor {
def receive : Receive = {
class TerminalControl(term : Terminal) extends Actor with FactionAffinityBehavior.Check {
def FactionObject : FactionAffinity = term
def receive : Receive = checkBehavior.orElse {
case Terminal.Request(player, msg) =>
sender ! Terminal.TerminalMessage(player, msg, term.Request(player, msg))

View file

@ -3,7 +3,8 @@ package net.psforever.objects.vehicles
import akka.actor.Actor
import net.psforever.objects.Vehicle
import net.psforever.objects.mount.MountableBehavior
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
/**
* An `Actor` that handles messages being dispatched to a specific `Vehicle`.<br>
@ -12,17 +13,32 @@ import net.psforever.objects.mount.MountableBehavior
* 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 with MountableBehavior {
override def MountableObject = vehicle
class VehicleControl(private val vehicle : Vehicle) extends Actor
with FactionAffinityBehavior.Check
with MountableBehavior.Mount
with MountableBehavior.Dismount {
def MountableObject = vehicle //do not add type!
def receive : Receive = mountableBehavior.orElse {
case Vehicle.PrepareForDeletion =>
context.become(Disabled)
def FactionObject : FactionAffinity = vehicle
case _ => ;
}
def receive : Receive = Enabled
def Disabled : Receive = {
case _ => ;
}
def Enabled : Receive = checkBehavior
.orElse(mountBehavior)
.orElse(dismountBehavior)
.orElse {
case Vehicle.PrepareForDeletion =>
context.become(Disabled)
case _ => ;
}
def Disabled : Receive = checkBehavior
.orElse(dismountBehavior)
.orElse {
case Vehicle.Reactivate =>
context.become(Enabled)
case _ => ;
}
}

View file

@ -3,19 +3,20 @@ 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, Vehicle}
import net.psforever.objects.equipment.Equipment
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.actor.UniqueNumberSystem
import net.psforever.objects.guid.selector.RandomSelector
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.objects.serverobject.structures.{Amenity, Building}
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
import scala.collection.immutable.{Map => PairMap}
/**
* A server object representing the one-landmass planets as well as the individual subterranean caverns.<br>
@ -55,7 +56,7 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
/** */
private var transport : ActorRef = ActorRef.noSender
private var bases : List[Base] = List()
private var buildings : PairMap[Int, Building] = PairMap.empty[Int, Building]
/**
* Establish the basic accessible conditions necessary for a functional `Zone`.<br>
@ -79,8 +80,8 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
Map.LocalObjects.foreach({ builderObject =>
builderObject.Build
})
MakeBases(Map.LocalBases)
MakeBuildings(context)
AssignAmenities()
}
}
@ -217,13 +218,20 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
def Transport : ActorRef = transport
def MakeBases(num : Int) : List[Base] = {
bases = (1 to num).map(id => new Base(id)).toList
bases
def Building(id : Int) : Option[Building] = {
buildings.get(id)
}
def Base(id : Int) : Option[Base] = {
bases.lift(id)
private def MakeBuildings(implicit context : ActorContext) : PairMap[Int, Building] = {
val buildingList = Map.LocalBuildings
buildings = buildingList.map({case(building_id, constructor) => building_id -> constructor.Build(building_id, this) })
buildings
}
private def AssignAmenities() : Unit = {
Map.ObjectToBuilding.foreach({ case(object_guid, building_id) =>
buildings(building_id).Amenities = guid(object_guid).get.asInstanceOf[Amenity]
})
}
/**
@ -264,6 +272,8 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
}
object Zone {
final val Nowhere : Zone = new Zone("nowhere", new ZoneMap("nowhere"), 99)
/**
* Message to initialize the `Zone`.
* @see `Zone.Init(implicit ActorContext)`

View file

@ -2,6 +2,8 @@
package net.psforever.objects.zones
import akka.actor.Actor
import net.psforever.objects.PlanetSideGameObject
import org.log4s.Logger
/**
* na
@ -20,14 +22,16 @@ class ZoneActor(zone : Zone) extends Actor {
}
def ZoneSetupCheck(): Unit = {
import ZoneActor._
def guid(id : Int) = zone.GUID(id)
val map = zone.Map
val slog = org.log4s.getLogger(s"zone/${zone.Id}/sanity")
val validateObject : (Int, (PlanetSideGameObject)=>Boolean, String) => Boolean = ValidateObject(guid, slog)
//check base to object associations
map.ObjectToBase.foreach({ case((object_guid, base_id)) =>
if(zone.Base(base_id).isEmpty) {
slog.error(s"expected a base #$base_id")
map.ObjectToBuilding.foreach({ case((object_guid, base_id)) =>
if(zone.Building(base_id).isEmpty) {
slog.error(s"expected a building at id #$base_id")
}
if(guid(object_guid).isEmpty) {
slog.error(s"expected object id $object_guid to exist, but it did not")
@ -35,74 +39,80 @@ class ZoneActor(zone : Zone) extends Actor {
})
//check door to lock association
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.serverobject.locks.IFFLock
map.DoorToLock.foreach({ case((door_guid, lock_guid)) =>
try {
if(!guid(door_guid).get.isInstanceOf[Door]) {
slog.error(s"expected id $door_guid to be a door, but it was not")
}
}
catch {
case _ : Exception =>
slog.error(s"expected a door at id $door_guid but no object is initialized")
}
try {
if(!guid(lock_guid).get.isInstanceOf[IFFLock]) {
slog.error(s"expected id $lock_guid to be an IFF locks but it was not")
}
}
catch {
case _ : Exception =>
slog.error(s"expected an IFF locks at id $lock_guid but no object is initialized")
}
validateObject(door_guid, DoorCheck, "door")
validateObject(lock_guid, LockCheck, "IFF lock")
})
//check vehicle terminal to spawn pad association
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
import net.psforever.objects.serverobject.terminals.Terminal
map.TerminalToSpawnPad.foreach({ case ((term_guid, pad_guid)) =>
try {
if(!guid(term_guid).get.isInstanceOf[Terminal]) { //TODO check is vehicle terminal
slog.error(s"expected id $term_guid to be a terminal, but it was not")
}
}
catch {
case _ : Exception =>
slog.error(s"expected a terminal at id $term_guid but no object is initialized")
}
try {
if(!guid(pad_guid).get.isInstanceOf[VehicleSpawnPad]) {
slog.error(s"expected id $pad_guid to be a spawn pad, but it was not")
}
}
catch {
case _ : Exception =>
slog.error(s"expected a spawn pad at id $pad_guid but no object is initialized")
}
validateObject(term_guid, TerminalCheck, "vehicle terminal")
validateObject(pad_guid, VehicleSpawnPadCheck, "vehicle spawn pad")
})
//check implant terminal mech to implant terminal interface association
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
map.TerminalToInterface.foreach({case ((mech_guid, interface_guid)) =>
try {
if(!guid(mech_guid).get.isInstanceOf[ImplantTerminalMech]) {
slog.error(s"expected id $mech_guid to be an implant terminal mech, but it was not")
}
}
catch {
case _ : Exception =>
slog.error(s"expected a implant terminal mech at id $mech_guid but no object is initialized")
}
try {
if(!guid(interface_guid).get.isInstanceOf[Terminal]) { //TODO check is implant terminal
slog.error(s"expected id $interface_guid to be an implant terminal interface, but it was not")
}
}
catch {
case _ : Exception =>
slog.error(s"expected a implant terminal interface at id $interface_guid but no object is initialized")
}
validateObject(mech_guid, ImplantMechCheck, "implant terminal mech")
validateObject(interface_guid, TerminalCheck, "implant terminal interface")
})
}
}
object ZoneActor {
/**
* Recover an object from a collection and perform any number of validating tests upon it.
* If the object fails any tests, log an error.
* @param guid access to an association between unique numbers and objects using some of those unique numbers
* @param elog a contraction of "error log;"
* accepts `String` data
* @param object_guid the unique indentifier being checked against the `guid` access point
* @param test a test for the discovered object;
* expects at least `Type` checking
* @param description an explanation of how the object, if not discovered, should be identified
* @return `true` if the object was discovered and validates correctly;
* `false` if the object failed any tests
*/
def ValidateObject(guid : (Int)=>Option[PlanetSideGameObject], elog : Logger)
(object_guid : Int, test : (PlanetSideGameObject)=>Boolean, description : String) : Boolean = {
try {
if(!test(guid(object_guid).get)) {
elog.error(s"expected id $object_guid to be a $description, but it was not")
false
}
else {
true
}
}
catch {
case _ : Exception =>
elog.error(s"expected a $description at id $object_guid but no object is initialized")
false
}
}
def LockCheck(obj : PlanetSideGameObject) : Boolean = {
import net.psforever.objects.serverobject.locks.IFFLock
obj.isInstanceOf[IFFLock]
}
def DoorCheck(obj : PlanetSideGameObject) : Boolean = {
import net.psforever.objects.serverobject.doors.Door
obj.isInstanceOf[Door]
}
def TerminalCheck(obj : PlanetSideGameObject) : Boolean = {
import net.psforever.objects.serverobject.terminals.Terminal
obj.isInstanceOf[Terminal]
}
def ImplantMechCheck(obj : PlanetSideGameObject) : Boolean = {
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
obj.isInstanceOf[ImplantTerminalMech]
}
def VehicleSpawnPadCheck(obj : PlanetSideGameObject) : Boolean = {
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
obj.isInstanceOf[VehicleSpawnPad]
}
}

View file

@ -1,6 +1,7 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.zones
import net.psforever.objects.serverobject.structures.FoundationBuilder
import net.psforever.objects.serverobject.ServerObjectBuilder
/**
@ -29,7 +30,7 @@ class ZoneMap(private val name : String) {
private var linkTerminalInterface : Map[Int, Int] = Map()
private var linkDoorLock : Map[Int, Int] = Map()
private var linkObjectBase : Map[Int, Int] = Map()
private var numBases : Int = 0
private var buildings : Map[Int, FoundationBuilder] = Map()
def Name : String = name
@ -49,19 +50,19 @@ class ZoneMap(private val name : String) {
localObjects = localObjects :+ obj
}
def LocalBases : Int = numBases
def LocalBuildings : Map[Int, FoundationBuilder] = buildings
def LocalBases_=(num : Int) : Int = {
if(num > 0) {
numBases = num
def LocalBuilding(building_id : Int, constructor : FoundationBuilder) : Int = {
if(building_id > 0) {
buildings = buildings ++ Map(building_id -> constructor)
}
LocalBases
buildings.size
}
def ObjectToBase : Map[Int, Int] = linkObjectBase
def ObjectToBuilding : Map[Int, Int] = linkObjectBase
def ObjectToBase(object_guid : Int, base_id : Int) : Unit = {
linkObjectBase = linkObjectBase ++ Map(object_guid -> base_id)
def ObjectToBuilding(object_guid : Int, building_id : Int) : Unit = {
linkObjectBase = linkObjectBase ++ Map(object_guid -> building_id)
}
def DoorToLock : Map[Int, Int] = linkDoorLock

View file

@ -0,0 +1,169 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{ActorRef, Props}
import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.definition.ObjectDefinition
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.doors.{Door, DoorControl}
import net.psforever.objects.serverobject.structures.{Amenity, Building, BuildingControl}
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable.Specification
import scala.concurrent.duration.Duration
class AmenityTest extends Specification {
class AmenityObject extends Amenity {
def Definition : ObjectDefinition = null
}
"Amenity" should {
"construct" in {
val ao = new AmenityObject()
ao.Owner mustEqual Building.NoBuilding
}
"can be owned by a building" in {
val ao = new AmenityObject()
val bldg = Building(10, Zone.Nowhere)
ao.Owner = bldg
ao.Owner mustEqual bldg
}
"be owned by a vehicle" in {
import net.psforever.objects.Vehicle
val ao = new AmenityObject()
val veh = Vehicle(GlobalDefinitions.quadstealth)
ao.Owner = veh
ao.Owner mustEqual veh
}
"not be owned by an unexpected object" in {
val ao = new AmenityObject()
//ao.Owner = net.psforever.objects.serverobject.mblocker.Locker() //will not compile
ok
}
"confer faction allegiance through ownership" in {
//see FactionAffinityTest
val ao = new AmenityObject()
val bldg = Building(10, Zone.Nowhere)
ao.Owner = bldg
bldg.Faction mustEqual PlanetSideEmpire.NEUTRAL
ao.Faction mustEqual PlanetSideEmpire.NEUTRAL
bldg.Faction = PlanetSideEmpire.TR
bldg.Faction mustEqual PlanetSideEmpire.TR
ao.Faction mustEqual PlanetSideEmpire.TR
}
}
}
class BuildingTest extends Specification {
"Building" should {
"construct" in {
val bldg = Building(10, Zone.Nowhere)
bldg.Id mustEqual 10
bldg.Actor mustEqual ActorRef.noSender
bldg.Amenities mustEqual Nil
bldg.Zone mustEqual Zone.Nowhere
bldg.Faction mustEqual PlanetSideEmpire.NEUTRAL
}
"change faction affinity" in {
val bldg = Building(10, Zone.Nowhere)
bldg.Faction mustEqual PlanetSideEmpire.NEUTRAL
bldg.Faction = PlanetSideEmpire.TR
bldg.Faction mustEqual PlanetSideEmpire.TR
}
"keep track of amenities" in {
val bldg = Building(10, Zone.Nowhere)
val door1 = Door(GlobalDefinitions.door)
val door2 = Door(GlobalDefinitions.door)
bldg.Amenities mustEqual Nil
bldg.Amenities = door2
bldg.Amenities mustEqual List(door2)
bldg.Amenities = door1
bldg.Amenities mustEqual List(door2, door1)
door1.Owner mustEqual bldg
door2.Owner mustEqual bldg
}
}
}
class BuildingControl1Test extends ActorTest {
"Building Control" should {
"construct" in {
val bldg = Building(10, Zone.Nowhere)
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "test")
assert(bldg.Actor != ActorRef.noSender)
}
}
}
class BuildingControl2Test extends ActorTest {
"Building Control" should {
"convert and assert faction affinity on convert request" in {
val bldg = Building(10, Zone.Nowhere)
bldg.Faction = PlanetSideEmpire.TR
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "test")
assert(bldg.Faction == PlanetSideEmpire.TR)
bldg.Actor ! FactionAffinity.ConvertFactionAffinity(PlanetSideEmpire.VS)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[FactionAffinity.AssertFactionAffinity])
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].obj == bldg)
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].faction == PlanetSideEmpire.VS)
assert(bldg.Faction == PlanetSideEmpire.VS)
}
}
}
class BuildingControl3Test extends ActorTest {
"Building Control" should {
"convert and assert faction affinity on convert request, and for each of its amenities" in {
val bldg = Building(10, Zone.Nowhere)
bldg.Faction = PlanetSideEmpire.TR
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "building-test")
val door1 = Door(GlobalDefinitions.door)
door1.GUID = PlanetSideGUID(1)
door1.Actor = system.actorOf(Props(classOf[DoorControl], door1), "door1-test")
val door2 = Door(GlobalDefinitions.door)
door2.GUID = PlanetSideGUID(2)
door2.Actor = system.actorOf(Props(classOf[DoorControl], door2), "door2-test")
bldg.Amenities = door2
bldg.Amenities = door1
assert(bldg.Faction == PlanetSideEmpire.TR)
assert(bldg.Amenities.length == 2)
assert(bldg.Amenities.head == door2)
assert(bldg.Amenities(1) == door1)
bldg.Actor ! FactionAffinity.ConvertFactionAffinity(PlanetSideEmpire.VS)
val reply = receiveN(3, Duration.create(500, "ms"))
assert(reply.length == 3)
var building_count = 0
var door_count = 0
reply.foreach(item => {
assert(item.isInstanceOf[FactionAffinity.AssertFactionAffinity])
val item2 = item.asInstanceOf[FactionAffinity.AssertFactionAffinity]
item2.obj match {
case _ : Building =>
building_count += 1
case _ : Door =>
door_count += 1
case _ =>
assert(false)
}
assert(item2.faction == PlanetSideEmpire.VS)
})
assert(building_count == 1 && door_count == 2)
}
}
}

View file

@ -1,9 +1,11 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{ActorRef, Props}
import akka.actor.{ActorRef, ActorSystem, Props}
import net.psforever.objects.{GlobalDefinitions, Player}
import net.psforever.objects.serverobject.doors.{Door, DoorControl}
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{PlanetSideGUID, UseItemMessage}
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
import org.specs2.mutable.Specification
@ -11,6 +13,8 @@ import org.specs2.mutable.Specification
import scala.concurrent.duration.Duration
class DoorTest extends Specification {
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
"Door" should {
"construct" in {
Door(GlobalDefinitions.door)
@ -24,7 +28,6 @@ class DoorTest extends Specification {
}
"be opened and closed (1; manual)" in {
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val door = Door(GlobalDefinitions.door)
door.isOpen mustEqual false
door.Open mustEqual None
@ -39,7 +42,6 @@ class DoorTest extends Specification {
}
"be opened and closed (2; toggle)" in {
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val msg = UseItemMessage(PlanetSideGUID(6585), 0, PlanetSideGUID(372), 4294967295L, false, Vector3(5.0f,0.0f,0.0f), Vector3(0.0f,0.0f,0.0f), 11, 25, 0, 364)
val door = Door(GlobalDefinitions.door)
door.Open mustEqual None
@ -85,9 +87,7 @@ class DoorControl1Test extends ActorTest() {
class DoorControl2Test extends ActorTest() {
"DoorControl" should {
"open on use" in {
val door = Door(GlobalDefinitions.door)
door.Actor = system.actorOf(Props(classOf[DoorControl], door), "door")
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val (player, door) = DoorControlTest.SetUpAgents(PlanetSideEmpire.TR)
val msg = UseItemMessage(PlanetSideGUID(1), 0, PlanetSideGUID(2), 0L, false, Vector3(0f,0f,0f),Vector3(0f,0f,0f),0,0,0,0L) //faked
assert(door.Open.isEmpty)
@ -106,8 +106,7 @@ class DoorControl2Test extends ActorTest() {
class DoorControl3Test extends ActorTest() {
"DoorControl" should {
"do nothing if given garbage" in {
val door = Door(GlobalDefinitions.door)
door.Actor = system.actorOf(Props(classOf[DoorControl], door), "door")
val (_, door) = DoorControlTest.SetUpAgents(PlanetSideEmpire.TR)
assert(door.Open.isEmpty)
door.Actor ! "trash"
@ -117,3 +116,13 @@ class DoorControl3Test extends ActorTest() {
}
}
}
object DoorControlTest {
def SetUpAgents(faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, Door) = {
val door = Door(GlobalDefinitions.door)
door.Actor = system.actorOf(Props(classOf[DoorControl], door), "door")
door.Owner = new Building(0, Zone.Nowhere)
door.Owner.Faction = faction
(Player("test", faction, CharacterGender.Male, 0, 0), door)
}
}

View file

@ -0,0 +1,131 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{Actor, ActorSystem, Props}
import net.psforever.objects.{GlobalDefinitions, Vehicle}
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.zones.Zone
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable.Specification
import scala.concurrent.duration.Duration
class FactionAffinityTest extends Specification {
"FactionAffinity" should {
"construct (basic)" in {
val obj = new FactionAffinity { def Faction = PlanetSideEmpire.TR }
obj.Faction mustEqual PlanetSideEmpire.TR
}
"construct (part of)" in {
val obj = new Door(GlobalDefinitions.door)
obj.Faction mustEqual PlanetSideEmpire.NEUTRAL
}
"can not change affinity directly (basic)" in {
val obj = new FactionAffinity { def Faction = PlanetSideEmpire.TR }
(obj.Faction = PlanetSideEmpire.NC) mustEqual PlanetSideEmpire.TR
}
"can not change affinity directly (part of)" in {
val obj = new Door(GlobalDefinitions.door)
(obj.Faction = PlanetSideEmpire.TR) mustEqual PlanetSideEmpire.NEUTRAL
}
"inherits affinity from owner 1" in {
val obj = new Door(GlobalDefinitions.door)
obj.Owner.Faction mustEqual PlanetSideEmpire.NEUTRAL
(obj.Faction = PlanetSideEmpire.TR) mustEqual PlanetSideEmpire.NEUTRAL
}
"inherits affinity from owner 2" in {
val obj = new Door(GlobalDefinitions.door)
val bldg = new Building(1, Zone.Nowhere)
obj.Owner = bldg
obj.Faction mustEqual PlanetSideEmpire.NEUTRAL
bldg.Faction = PlanetSideEmpire.TR
obj.Faction mustEqual PlanetSideEmpire.TR
bldg.Faction = PlanetSideEmpire.NC
obj.Faction mustEqual PlanetSideEmpire.NC
}
}
}
class FactionAffinity1Test extends ActorTest() {
"FactionAffinity" should {
"assert affinity on confirm request" in {
val obj = FactionAffinityTest.SetUpAgent
obj.Faction = PlanetSideEmpire.VS //object is a type that can be changed directly
assert(obj.Faction == PlanetSideEmpire.VS)
obj.Actor ! FactionAffinity.ConfirmFactionAffinity()
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[FactionAffinity.AssertFactionAffinity])
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].obj == obj)
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].faction == PlanetSideEmpire.VS)
}
}
}
class FactionAffinity2Test extends ActorTest() {
"FactionAffinity" should {
"assert affinity on assert request" in {
val obj = FactionAffinityTest.SetUpAgent
obj.Faction = PlanetSideEmpire.VS //object is a type that can be changed directly
assert(obj.Faction == PlanetSideEmpire.VS)
obj.Actor ! FactionAffinity.AssertFactionAffinity(obj, PlanetSideEmpire.NEUTRAL)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[FactionAffinity.AssertFactionAffinity])
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].obj == obj)
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].faction == PlanetSideEmpire.VS)
}
}
}
class FactionAffinity3Test extends ActorTest() {
"FactionAffinity" should {
"convert and assert affinity on convert request" in {
val obj = FactionAffinityTest.SetUpAgent
obj.Faction = PlanetSideEmpire.VS //object is a type that can be changed directly
assert(obj.Faction == PlanetSideEmpire.VS)
obj.Actor ! FactionAffinity.ConvertFactionAffinity(PlanetSideEmpire.TR)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[FactionAffinity.AssertFactionAffinity])
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].obj == obj)
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].faction == PlanetSideEmpire.TR)
assert(obj.Faction == PlanetSideEmpire.TR)
}
}
}
object FactionAffinityTest {
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
private class AffinityControl(obj : FactionAffinity) extends Actor
with FactionAffinityBehavior.Check
with FactionAffinityBehavior.Convert {
override def FactionObject = obj
def receive = checkBehavior.orElse(convertBehavior).orElse { case _ => }
}
def SetUpAgent(implicit system : ActorSystem) = {
val obj = new Vehicle(GlobalDefinitions.quadstealth)
obj.Actor = system.actorOf(Props(classOf[FactionAffinityTest.AffinityControl], obj), "test")
obj
}
def FreeFactionObject : FactionAffinity = new FactionAffinity() {
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
def Faction : PlanetSideEmpire.Value = faction
override def Faction_=(fac : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = {
faction = fac
faction
}
}
}

View file

@ -1,10 +1,13 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{ActorRef, Props}
import akka.actor.{ActorRef, ActorSystem, Props}
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.{GlobalDefinitions, Player}
import net.psforever.objects.serverobject.locks.{IFFLock, IFFLockControl}
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalControl, TerminalDefinition}
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.types.{CharacterGender, PlanetSideEmpire}
import org.specs2.mutable.Specification
@ -33,9 +36,7 @@ class IFFLockControl1Test extends ActorTest() {
class IFFLockControl2Test extends ActorTest() {
"IFFLockControl" should {
"can hack" in {
val lock = IFFLock(GlobalDefinitions.lock_external)
lock.Actor = system.actorOf(Props(classOf[IFFLockControl], lock), "lock-control")
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val (player, lock) = IFFLockControlTest.SetUpAgents(PlanetSideEmpire.TR)
player.GUID = PlanetSideGUID(1)
assert(lock.HackedBy.isEmpty)
@ -49,9 +50,7 @@ class IFFLockControl2Test extends ActorTest() {
class IFFLockControl3Test extends ActorTest() {
"IFFLockControl" should {
"can hack" in {
val lock = IFFLock(GlobalDefinitions.lock_external)
lock.Actor = system.actorOf(Props(classOf[IFFLockControl], lock), "lock-control")
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val (player, lock) = IFFLockControlTest.SetUpAgents(PlanetSideEmpire.TR)
player.GUID = PlanetSideGUID(1)
assert(lock.HackedBy.isEmpty)
@ -64,3 +63,13 @@ class IFFLockControl3Test extends ActorTest() {
}
}
}
object IFFLockControlTest {
def SetUpAgents(faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, IFFLock) = {
val lock = IFFLock(GlobalDefinitions.lock_external)
lock.Actor = system.actorOf(Props(classOf[IFFLockControl], lock), "lock-control")
lock.Owner = new Building(0, Zone.Nowhere)
lock.Owner.Faction = faction
(Player("test", faction, CharacterGender.Male, 0, 0), lock)
}
}

View file

@ -0,0 +1,36 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{ActorRef, Props}
import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.mblocker.{Locker, LockerControl}
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable._
class LockerTest extends Specification {
"LockerDefinition" should {
"define" in {
GlobalDefinitions.mb_locker.ObjectId mustEqual 524
GlobalDefinitions.mb_locker.Name mustEqual "mb_locker"
}
}
"Locker" should {
"construct" in {
val locker = new Locker()
locker.Actor mustEqual ActorRef.noSender
}
}
}
class LockerControlTest extends ActorTest {
"LockerControl" should {
"construct" in {
val locker = new Locker()
locker.Actor = system.actorOf(Props(classOf[LockerControl], locker), "test")
locker.Actor ! FactionAffinity.ConfirmFactionAffinity()
expectMsg(FactionAffinity.AssertFactionAffinity(locker, PlanetSideEmpire.NEUTRAL))
}
}
}

View file

@ -4,9 +4,10 @@ package objects
import akka.actor.{Actor, ActorRef, Props}
import net.psforever.objects.Player
import net.psforever.objects.definition.{ObjectDefinition, SeatDefinition}
import net.psforever.objects.mount.{Mountable, MountableBehavior}
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.vehicles.Seat
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.types.{CharacterGender, PlanetSideEmpire}
import scala.concurrent.duration.Duration
@ -80,12 +81,15 @@ object MountableTest {
None
}
}
def Definition : ObjectDefinition = null //eh whatever
GUID = PlanetSideGUID(1)
//eh whatever
def Faction = PlanetSideEmpire.TR
def Definition : ObjectDefinition = null
}
class MountableTestControl(obj : Mountable) extends Actor with MountableBehavior {
class MountableTestControl(obj : PlanetSideServerObject with Mountable) extends Actor with MountableBehavior.Mount with MountableBehavior.Dismount {
override def MountableObject = obj
def receive : Receive = mountableBehavior
def receive : Receive = mountBehavior.orElse(dismountBehavior)
}
}

View file

@ -5,10 +5,26 @@ import akka.actor.{Actor, Props}
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.objects.serverobject.ServerObjectBuilder
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder}
import net.psforever.objects.zones.Zone
import net.psforever.types.Vector3
import scala.concurrent.duration.Duration
class BuildingBuilderTest extends ActorTest {
"Building object" should {
"build" in {
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuildingTestActor], 10, Zone.Nowhere), "building")
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[Building])
assert(reply.asInstanceOf[Building].Id == 10)
assert(reply.asInstanceOf[Building].Zone == Zone.Nowhere)
}
}
}
class DoorObjectBuilderTest1 extends ActorTest {
import net.psforever.objects.serverobject.doors.Door
"Door object" should {
@ -150,4 +166,11 @@ object ServerObjectBuilderTest {
sender ! builder.Build(context, hub)
}
}
class BuildingTestActor(building_id : Int, zone : Zone) extends Actor {
def receive : Receive = {
case _ =>
sender ! FoundationBuilder(Building.Structure).Build(building_id, zone)(context)
}
}
}

View file

@ -1,9 +1,11 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{ActorRef, Props}
import akka.actor.{ActorRef, ActorSystem, Props}
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.vehicles.VehicleControl
import net.psforever.objects.zones.Zone
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
@ -40,22 +42,20 @@ class VehicleSpawnControl1Test extends ActorTest() {
class VehicleSpawnControl2Test extends ActorTest() {
"VehicleSpawnControl" should {
"spawn a vehicle" in {
val obj = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
obj.Actor = system.actorOf(Props(classOf[VehicleSpawnControl], obj), "door")
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val (player, pad) = VehicleSpawnPadControl.SetUpAgents(PlanetSideEmpire.TR)
player.Spawn
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
vehicle.GUID = PlanetSideGUID(1)
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle")
obj.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle)
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle)
val reply = receiveOne(Duration.create(10000, "ms"))
assert(reply == VehicleSpawnPad.ConcealPlayer) //explicit: isInstanceOf does not work
val reply2 = receiveOne(Duration.create(10000, "ms"))
assert(reply2.isInstanceOf[VehicleSpawnPad.LoadVehicle])
assert(reply2.asInstanceOf[VehicleSpawnPad.LoadVehicle].vehicle == vehicle)
assert(reply2.asInstanceOf[VehicleSpawnPad.LoadVehicle].pad == obj)
assert(reply2.asInstanceOf[VehicleSpawnPad.LoadVehicle].pad == pad)
player.VehicleOwned = Some(vehicle.GUID)
val reply3 = receiveOne(Duration.create(10000, "ms"))
@ -78,14 +78,12 @@ class VehicleSpawnControl2Test extends ActorTest() {
class VehicleSpawnControl3Test extends ActorTest() {
"VehicleSpawnControl" should {
"not spawn a vehicle if player is dead" in {
val obj = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
obj.Actor = system.actorOf(Props(classOf[VehicleSpawnControl], obj), "door")
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val (player, pad) = VehicleSpawnPadControl.SetUpAgents(PlanetSideEmpire.TR)
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
vehicle.GUID = PlanetSideGUID(1)
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle")
obj.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle)
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle)
val reply = receiveOne(Duration.create(5000, "ms"))
assert(reply == null)
}
@ -95,16 +93,24 @@ class VehicleSpawnControl3Test extends ActorTest() {
class VehicleSpawnControl4Test extends ActorTest() {
"VehicleSpawnControl" should {
"not spawn a vehicle if vehicle Actor is missing" in {
val obj = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
obj.Actor = system.actorOf(Props(classOf[VehicleSpawnControl], obj), "door")
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val (player, pad) = VehicleSpawnPadControl.SetUpAgents(PlanetSideEmpire.TR)
player.Spawn
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
vehicle.GUID = PlanetSideGUID(1)
obj.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle)
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle)
val reply = receiveOne(Duration.create(5000, "ms"))
assert(reply == null)
}
}
}
object VehicleSpawnPadControl {
def SetUpAgents(faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, VehicleSpawnPad) = {
val pad = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
pad.Actor = system.actorOf(Props(classOf[VehicleSpawnControl], pad), "test-pad")
pad.Owner = new Building(0, Zone.Nowhere)
pad.Owner.Faction = faction
(Player("test", faction, CharacterGender.Male, 0, 0), pad)
}
}

View file

@ -1,13 +1,17 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.Props
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
import net.psforever.objects.definition.SeatDefinition
import net.psforever.objects.vehicles.{AccessPermissionGroup, Seat, SeatArmorRestriction, VehicleLockState}
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.vehicles._
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.types.{CharacterGender, ExoSuitType, PlanetSideEmpire}
import org.specs2.mutable._
import scala.concurrent.duration.Duration
class VehicleTest extends Specification {
"SeatDefinition" should {
@ -254,3 +258,49 @@ class VehicleTest extends Specification {
}
}
}
class VehicleControl1Test extends ActorTest {
"Vehicle Control" should {
"deactivate and stop handling mount messages" in {
val player1 = Player("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
player1.GUID = PlanetSideGUID(1)
val player2 = Player("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
vehicle.GUID = PlanetSideGUID(3)
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
vehicle.Actor ! Mountable.TryMount(player1, 0)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[Mountable.MountMessages])
vehicle.Actor ! Vehicle.PrepareForDeletion
vehicle.Actor ! Mountable.TryMount(player2, 1)
expectNoMsg(Duration.create(200, "ms"))
}
}
}
class VehicleControl2Test extends ActorTest {
"Vehicle Control" should {
"reactivate and resume handling mount messages" in {
val player1 = Player("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
player1.GUID = PlanetSideGUID(1)
val player2 = Player("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
player2.GUID = PlanetSideGUID(2)
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
vehicle.GUID = PlanetSideGUID(3)
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
vehicle.Actor ! Mountable.TryMount(player1, 0)
receiveOne(Duration.create(100, "ms")) //discard
vehicle.Actor ! Vehicle.PrepareForDeletion
vehicle.Actor ! Mountable.TryMount(player2, 1)
expectNoMsg(Duration.create(200, "ms"))
vehicle.Actor ! Vehicle.Reactivate
vehicle.Actor ! Mountable.TryMount(player2, 1)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[Mountable.MountMessages])
}
}
}

View file

@ -1,39 +1,44 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.ActorRef
import akka.actor.{ActorContext, ActorRef}
import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.equipment.Equipment
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder}
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.objects.{GlobalDefinitions, Vehicle}
import org.specs2.mutable.Specification
class ZoneTest extends Specification {
def test(a: Int, b : Zone, c : ActorContext) : Building = { Building.NoBuilding }
"ZoneMap" should {
//TODO these are temporary tests as the current ZoneMap is a kludge
"construct" in {
new ZoneMap("map13")
ok
}
"references bases by a positive building id (defaults to 0)" in {
def test(a: Int, b : Zone, c : ActorContext) : Building = { Building.NoBuilding }
val map = new ZoneMap("map13")
map.LocalBases mustEqual 0
map.LocalBases = 10
map.LocalBases mustEqual 10
map.LocalBases = -1
map.LocalBases mustEqual 10
map.LocalBuildings mustEqual Map.empty
map.LocalBuilding(10, FoundationBuilder(test))
map.LocalBuildings.keySet.contains(10) mustEqual true
map.LocalBuilding(-1, FoundationBuilder(test))
map.LocalBuildings.keySet.contains(10) mustEqual true
map.LocalBuildings.keySet.contains(-1) mustEqual false
}
"associates objects to bases (doesn't check numbers)" in {
val map = new ZoneMap("map13")
map.ObjectToBase mustEqual Nil
map.ObjectToBase(1, 2)
map.ObjectToBase mustEqual List((1, 2))
map.ObjectToBase(3, 4)
map.ObjectToBase mustEqual List((1, 2), (3, 4))
map.ObjectToBuilding mustEqual Nil
map.ObjectToBuilding(1, 2)
map.ObjectToBuilding mustEqual Map(1 -> 2)
map.ObjectToBuilding(3, 4)
map.ObjectToBuilding mustEqual Map(1 -> 2, 3 -> 4)
}
"associates doors to door locks (doesn't check numbers)" in {
@ -65,11 +70,10 @@ class ZoneTest extends Specification {
}
val map13 = new ZoneMap("map13")
map13.LocalBases = 10
map13.LocalBuilding(10, FoundationBuilder(test))
class TestObject extends IdentifiableEntity
"Zone" should {
//TODO these are temporary tests as the current Zone is a kludge
"construct" in {
val zone = new Zone("home3", map13, 13)
zone.GUID mustEqual ActorRef.noSender

View file

@ -2,8 +2,10 @@
package objects.terminal
import akka.actor.ActorRef
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.{GlobalDefinitions, Player}
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
import net.psforever.types.{CharacterGender, PlanetSideEmpire, TransactionType}
import org.specs2.mutable.Specification
@ -11,6 +13,9 @@ import org.specs2.mutable.Specification
class AirVehicleTerminalTest extends Specification {
"Air_Vehicle_Terminal" should {
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val terminal = Terminal(GlobalDefinitions.air_vehicle_terminal)
terminal.Owner = new Building(0, Zone.Nowhere)
terminal.Owner.Faction = PlanetSideEmpire.TR
"construct" in {
val terminal = Terminal(GlobalDefinitions.air_vehicle_terminal)
@ -18,8 +23,8 @@ class AirVehicleTerminalTest extends Specification {
}
"player can buy a reaver ('lightgunship')" in {
val terminal = Terminal(GlobalDefinitions.air_vehicle_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "lightgunship", 0, PlanetSideGUID(0))
val reply = terminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.BuyVehicle]
@ -35,7 +40,6 @@ class AirVehicleTerminalTest extends Specification {
}
"player can not buy a fake vehicle ('reaver')" in {
val terminal = Terminal(GlobalDefinitions.ground_vehicle_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "reaver", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()

View file

@ -2,7 +2,9 @@
package objects.terminal
import akka.actor.ActorRef
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.zones.Zone
import net.psforever.objects.{GlobalDefinitions, Player}
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
import net.psforever.types._
@ -11,6 +13,9 @@ import org.specs2.mutable.Specification
class CertTerminalTest extends Specification {
"Cert_Terminal" should {
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val terminal = Terminal(GlobalDefinitions.cert_terminal)
terminal.Owner = new Building(0, Zone.Nowhere)
terminal.Owner.Faction = PlanetSideEmpire.TR
"construct" in {
val terminal = Terminal(GlobalDefinitions.cert_terminal)
@ -18,27 +23,23 @@ class CertTerminalTest extends Specification {
}
"player can learn a certification ('medium_assault')" in {
val terminal = Terminal(GlobalDefinitions.cert_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "medium_assault", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.LearnCertification(CertificationType.MediumAssault, 2)
}
"player can not learn a fake certification ('juggling')" in {
val terminal = Terminal(GlobalDefinitions.cert_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "juggling", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
}
"player can forget a certification ('medium_assault')" in {
val terminal = Terminal(GlobalDefinitions.cert_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "medium_assault", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.SellCertification(CertificationType.MediumAssault, 2)
}
"player can not forget a fake certification ('juggling')" in {
val terminal = Terminal(GlobalDefinitions.cert_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "juggling", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()

View file

@ -2,8 +2,10 @@
package objects.terminal
import akka.actor.ActorRef
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.{GlobalDefinitions, Player}
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
import net.psforever.types.{CharacterGender, PlanetSideEmpire, TransactionType}
import org.specs2.mutable.Specification
@ -11,6 +13,9 @@ import org.specs2.mutable.Specification
class DropshipVehicleTerminalTest extends Specification {
"Dropship_Vehicle_Terminal" should {
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val terminal = Terminal(GlobalDefinitions.dropship_vehicle_terminal)
terminal.Owner = new Building(0, Zone.Nowhere)
terminal.Owner.Faction = PlanetSideEmpire.TR
"construct" in {
val terminal = Terminal(GlobalDefinitions.dropship_vehicle_terminal)
@ -18,8 +23,8 @@ class DropshipVehicleTerminalTest extends Specification {
}
"player can buy a galaxy ('dropship')" in {
val terminal = Terminal(GlobalDefinitions.dropship_vehicle_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "dropship", 0, PlanetSideGUID(0))
val reply = terminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.BuyVehicle]
@ -41,7 +46,6 @@ class DropshipVehicleTerminalTest extends Specification {
}
"player can not buy a fake vehicle ('galaxy')" in {
val terminal = Terminal(GlobalDefinitions.dropship_vehicle_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "galaxy", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()

View file

@ -2,8 +2,10 @@
package objects.terminal
import akka.actor.ActorRef
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.{GlobalDefinitions, Player}
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
import net.psforever.types.{CharacterGender, PlanetSideEmpire, TransactionType}
import org.specs2.mutable.Specification
@ -11,6 +13,9 @@ import org.specs2.mutable.Specification
class GroundVehicleTerminalTest extends Specification {
"Ground_Vehicle_Terminal" should {
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val terminal = Terminal(GlobalDefinitions.ground_vehicle_terminal)
terminal.Owner = new Building(0, Zone.Nowhere)
terminal.Owner.Faction = PlanetSideEmpire.TR
"construct" in {
val terminal = Terminal(GlobalDefinitions.ground_vehicle_terminal)
@ -18,8 +23,8 @@ class GroundVehicleTerminalTest extends Specification {
}
"player can buy a harasser ('two_man_assault_buggy')" in {
val terminal = Terminal(GlobalDefinitions.ground_vehicle_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "two_man_assault_buggy", 0, PlanetSideGUID(0))
val reply = terminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.BuyVehicle]
@ -35,7 +40,6 @@ class GroundVehicleTerminalTest extends Specification {
}
"player can not buy a fake vehicle ('harasser')" in {
val terminal = Terminal(GlobalDefinitions.ground_vehicle_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "harasser", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()

View file

@ -2,8 +2,10 @@
package objects.terminal
import akka.actor.ActorRef
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.{GlobalDefinitions, Player}
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
import net.psforever.types.{CharacterGender, PlanetSideEmpire, TransactionType}
import org.specs2.mutable.Specification
@ -11,6 +13,9 @@ import org.specs2.mutable.Specification
class ImplantTerminalInterfaceTest extends Specification {
"Implant_Terminal_Interface" should {
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val terminal = Terminal(GlobalDefinitions.implant_terminal_interface)
terminal.Owner = new Building(0, Zone.Nowhere)
terminal.Owner.Faction = PlanetSideEmpire.TR
"construct" in {
val terminal = Terminal(GlobalDefinitions.implant_terminal_interface)
@ -18,8 +23,8 @@ class ImplantTerminalInterfaceTest extends Specification {
}
"player can learn an implant ('darklight_vision')" in {
val terminal = Terminal(GlobalDefinitions.implant_terminal_interface)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "darklight_vision", 0, PlanetSideGUID(0))
val reply = terminal.Request(player, msg)
reply.isInstanceOf[Terminal.LearnImplant] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.LearnImplant]
@ -27,15 +32,14 @@ class ImplantTerminalInterfaceTest extends Specification {
}
"player can not learn a fake implant ('aimbot')" in {
val terminal = Terminal(GlobalDefinitions.implant_terminal_interface)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "aimbot", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
}
"player can surrender an implant ('darklight_vision')" in {
val terminal = Terminal(GlobalDefinitions.implant_terminal_interface)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "darklight_vision", 0, PlanetSideGUID(0))
val reply = terminal.Request(player, msg)
reply.isInstanceOf[Terminal.SellImplant] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.SellImplant]

View file

@ -1,13 +1,13 @@
// Copyright (c) 2017 PSForever
package objects.terminal
import akka.actor.{ActorRef, Props}
import akka.actor.{ActorRef, ActorSystem, Props}
import net.psforever.objects.definition.SeatDefinition
import net.psforever.objects.mount.Mountable
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.implantmech.{ImplantTerminalMech, ImplantTerminalMechControl}
import net.psforever.objects.vehicles.Seat
import net.psforever.objects.{GlobalDefinitions, Player}
import net.psforever.types.{CharacterGender, PlanetSideEmpire}
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
import objects.ActorTest
import org.specs2.mutable.Specification
@ -68,43 +68,101 @@ class ImplantTerminalMechControl1Test extends ActorTest() {
class ImplantTerminalMechControl2Test extends ActorTest() {
"ImplantTerminalMechControl" should {
"let a player mount" in {
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val obj = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech)
obj.Actor = system.actorOf(Props(classOf[ImplantTerminalMechControl], obj), "mech")
val (player, mech) = ImplantTerminalMechTest.SetUpAgents(PlanetSideEmpire.TR)
val msg = Mountable.TryMount(player, 0)
obj.Actor ! msg
val reply = receiveOne(Duration.create(100, "ms"))
mech.Actor ! msg
val reply = receiveOne(Duration.create(200, "ms"))
assert(reply.isInstanceOf[Mountable.MountMessages])
val reply2 = reply.asInstanceOf[Mountable.MountMessages]
assert(reply2.player == player)
assert(reply2.response.isInstanceOf[Mountable.CanMount])
val reply3 = reply2.response.asInstanceOf[Mountable.CanMount]
assert(reply3.obj == obj)
assert(reply3.obj == mech)
assert(reply3.seat_num == 0)
}
}
}
class ImplantTerminalMechControl3Test extends ActorTest() {
import net.psforever.types.CharacterGender
"ImplantTerminalMechControl" should {
"block a player from mounting" in {
val player1 = Player("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val (player1, mech) = ImplantTerminalMechTest.SetUpAgents(PlanetSideEmpire.TR)
val player2 = Player("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val obj = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech)
obj.Actor = system.actorOf(Props(classOf[ImplantTerminalMechControl], obj), "mech")
obj.Actor ! Mountable.TryMount(player1, 0)
mech.Actor ! Mountable.TryMount(player1, 0)
receiveOne(Duration.create(100, "ms")) //consume reply
obj.Actor ! Mountable.TryMount(player2, 0)
mech.Actor ! Mountable.TryMount(player2, 0)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[Mountable.MountMessages])
val reply2 = reply.asInstanceOf[Mountable.MountMessages]
assert(reply2.player == player2)
assert(reply2.response.isInstanceOf[Mountable.CanNotMount])
val reply3 = reply2.response.asInstanceOf[Mountable.CanNotMount]
assert(reply3.obj == obj)
assert(reply3.obj == mech)
assert(reply3.seat_num == 0)
}
}
}
class ImplantTerminalMechControl4Test extends ActorTest() {
"ImplantTerminalMechControl" should {
"dismount player after mounting" in {
val (player, mech) = ImplantTerminalMechTest.SetUpAgents(PlanetSideEmpire.TR)
mech.Actor ! Mountable.TryMount(player, 0)
receiveOne(Duration.create(100, "ms")) //consume reply
assert(mech.Seat(0).get.isOccupied)
mech.Actor ! Mountable.TryDismount(player, 0)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[Mountable.MountMessages])
val reply2 = reply.asInstanceOf[Mountable.MountMessages]
assert(reply2.player == player)
assert(reply2.response.isInstanceOf[Mountable.CanDismount])
val reply3 = reply2.response.asInstanceOf[Mountable.CanDismount]
assert(reply3.obj == mech)
assert(reply3.seat_num == 0)
assert(!mech.Seat(0).get.isOccupied)
}
}
}
class ImplantTerminalMechControl5Test extends ActorTest() {
"ImplantTerminalMechControl" should {
"block a player from dismounting" in {
val (player, mech) = ImplantTerminalMechTest.SetUpAgents(PlanetSideEmpire.TR)
mech.Actor ! Mountable.TryMount(player, 0)
receiveOne(Duration.create(100, "ms")) //consume reply
assert(mech.Seat(0).get.isOccupied)
mech.Velocity = Vector3(1,0,0) //makes no sense, but it works as the "seat" is not bailable
mech.Actor ! Mountable.TryDismount(player, 0)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[Mountable.MountMessages])
val reply2 = reply.asInstanceOf[Mountable.MountMessages]
assert(reply2.player == player)
assert(reply2.response.isInstanceOf[Mountable.CanNotDismount])
val reply3 = reply2.response.asInstanceOf[Mountable.CanNotDismount]
assert(reply3.obj == mech)
assert(reply3.seat_num == 0)
assert(mech.Seat(0).get.isOccupied)
}
}
}
object ImplantTerminalMechTest {
def SetUpAgents(faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, ImplantTerminalMech) = {
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.PlanetSideGUID
val terminal = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech)
terminal.Actor = system.actorOf(Props(classOf[ImplantTerminalMechControl], terminal), "mech")
terminal.Owner = new Building(0, Zone.Nowhere)
terminal.Owner.Faction = faction
terminal.GUID = PlanetSideGUID(1)
(Player("test", faction, CharacterGender.Male, 0, 0), terminal)
}
}

View file

@ -2,7 +2,9 @@
package objects.terminal
import akka.actor.ActorRef
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.zones.Zone
import net.psforever.objects.{AmmoBox, GlobalDefinitions, Player, Tool}
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
import net.psforever.types._
@ -11,6 +13,9 @@ import org.specs2.mutable.Specification
class OrderTerminalTest extends Specification {
"Order_Terminal" should {
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val terminal = Terminal(GlobalDefinitions.order_terminal)
terminal.Owner = new Building(0, Zone.Nowhere)
terminal.Owner.Faction = PlanetSideEmpire.TR
"construct" in {
val terminal = Terminal(GlobalDefinitions.order_terminal)
@ -18,7 +23,6 @@ class OrderTerminalTest extends Specification {
}
"player can buy a box of ammunition ('9mmbullet_AP')" in {
val terminal = Terminal(GlobalDefinitions.order_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "9mmbullet_AP", 0, PlanetSideGUID(0))
val reply = terminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true
@ -29,7 +33,6 @@ class OrderTerminalTest extends Specification {
}
"player can buy a weapon ('suppressor')" in {
val terminal = Terminal(GlobalDefinitions.order_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "suppressor", 0, PlanetSideGUID(0))
val reply = terminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true
@ -39,7 +42,6 @@ class OrderTerminalTest extends Specification {
}
"player can buy a box of vehicle ammunition ('105mmbullet')" in {
val terminal = Terminal(GlobalDefinitions.order_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 3, "105mmbullet", 0, PlanetSideGUID(0))
val reply = terminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true
@ -50,7 +52,6 @@ class OrderTerminalTest extends Specification {
}
"player can buy a support tool ('bank')" in {
val terminal = Terminal(GlobalDefinitions.order_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 2, "bank", 0, PlanetSideGUID(0))
val reply = terminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true
@ -60,14 +61,12 @@ class OrderTerminalTest extends Specification {
}
"player can buy different armor ('lite_armor')" in {
val terminal = Terminal(GlobalDefinitions.order_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.BuyExosuit(ExoSuitType.Agile)
}
"player can not buy fake equipment ('sabot')" in {
val terminal = Terminal(GlobalDefinitions.order_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "sabot", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
@ -76,7 +75,6 @@ class OrderTerminalTest extends Specification {
//TODO loudout tests
"player can not buy equipment from the wrong page ('9mmbullet_AP', page 1)" in {
val terminal = Terminal(GlobalDefinitions.order_terminal)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "9mmbullet_AP", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()

View file

@ -1,8 +1,10 @@
// Copyright (c) 2017 PSForever
package objects.terminal
import akka.actor.Props
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalControl}
import akka.actor.{ActorSystem, Props}
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalControl, TerminalDefinition}
import net.psforever.objects.zones.Zone
import net.psforever.objects.{GlobalDefinitions, Player}
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
import net.psforever.types._
@ -21,8 +23,7 @@ class TerminalControl1Test extends ActorTest() {
class TerminalControl2Test extends ActorTest() {
"TerminalControl can not process wrong messages" in {
val terminal = Terminal(GlobalDefinitions.cert_terminal)
terminal.Actor = system.actorOf(Props(classOf[TerminalControl], terminal), "test-cert-term")
val (_, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.cert_terminal, PlanetSideEmpire.TR)
terminal.Actor !"hello"
val reply = receiveOne(Duration.create(500, "ms"))
@ -34,9 +35,7 @@ class TerminalControl2Test extends ActorTest() {
//test for Cert_Terminal messages (see CertTerminalTest)
class CertTerminalControl1Test extends ActorTest() {
"TerminalControl can be used to learn a certification ('medium_assault')" in {
val terminal = Terminal(GlobalDefinitions.cert_terminal)
terminal.Actor = system.actorOf(Props(classOf[TerminalControl], terminal), "test-cert-term")
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.cert_terminal, PlanetSideEmpire.TR)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "medium_assault", 0, PlanetSideGUID(0))
terminal.Actor ! Terminal.Request(player, msg)
@ -51,9 +50,7 @@ class CertTerminalControl1Test extends ActorTest() {
class CertTerminalControl2Test extends ActorTest() {
"TerminalControl can be used to warn about not learning a fake certification ('juggling')" in {
val terminal = Terminal(GlobalDefinitions.cert_terminal)
terminal.Actor = system.actorOf(Props(classOf[TerminalControl], terminal), "test-cert-term")
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.cert_terminal, PlanetSideEmpire.TR)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "juggling", 0, PlanetSideGUID(0))
terminal.Actor ! Terminal.Request(player, msg)
@ -68,9 +65,7 @@ class CertTerminalControl2Test extends ActorTest() {
class CertTerminalControl3Test extends ActorTest() {
"TerminalControl can be used to forget a certification ('medium_assault')" in {
val terminal = Terminal(GlobalDefinitions.cert_terminal)
terminal.Actor = system.actorOf(Props(classOf[TerminalControl], terminal), "test-cert-term")
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.cert_terminal, PlanetSideEmpire.TR)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "medium_assault", 0, PlanetSideGUID(0))
terminal.Actor ! Terminal.Request(player, msg)
@ -85,9 +80,7 @@ class CertTerminalControl3Test extends ActorTest() {
class VehicleTerminalControl1Test extends ActorTest() {
"TerminalControl can be used to buy a vehicle ('two_man_assault_buggy')" in {
val terminal = Terminal(GlobalDefinitions.ground_vehicle_terminal)
terminal.Actor = system.actorOf(Props(classOf[TerminalControl], terminal), "test-cert-term")
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.ground_vehicle_terminal, PlanetSideEmpire.TR)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "two_man_assault_buggy", 0, PlanetSideGUID(0))
terminal.Actor ! Terminal.Request(player, msg)
@ -112,9 +105,7 @@ class VehicleTerminalControl1Test extends ActorTest() {
class VehicleTerminalControl2Test extends ActorTest() {
"TerminalControl can be used to warn about not buy a vehicle ('harasser')" in {
val terminal = Terminal(GlobalDefinitions.ground_vehicle_terminal)
terminal.Actor = system.actorOf(Props(classOf[TerminalControl], terminal), "test-cert-term")
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.ground_vehicle_terminal, PlanetSideEmpire.TR)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "harasser", 0, PlanetSideGUID(0))
terminal.Actor ! Terminal.Request(player, msg)
@ -126,3 +117,13 @@ class VehicleTerminalControl2Test extends ActorTest() {
assert(reply2.response == Terminal.NoDeal())
}
}
object TerminalControlTest {
def SetUpAgents(tdef : TerminalDefinition, faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, Terminal) = {
val terminal = Terminal(tdef)
terminal.Actor = system.actorOf(Props(classOf[TerminalControl], terminal), "test-term")
terminal.Owner = new Building(0, Zone.Nowhere)
terminal.Owner.Faction = faction
(Player("test", faction, CharacterGender.Male, 0, 0), terminal)
}
}

View file

@ -2,8 +2,10 @@
package objects.terminal
import akka.actor.ActorRef
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.{GlobalDefinitions, Player}
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
import net.psforever.types.{CharacterGender, PlanetSideEmpire, TransactionType}
import org.specs2.mutable.Specification
@ -11,6 +13,9 @@ import org.specs2.mutable.Specification
class VehicleTerminalCombinedTest extends Specification {
"Ground_Vehicle_Terminal" should {
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val terminal = Terminal(GlobalDefinitions.vehicle_terminal_combined)
terminal.Owner = new Building(0, Zone.Nowhere)
terminal.Owner.Faction = PlanetSideEmpire.TR
"construct" in {
val terminal = Terminal(GlobalDefinitions.vehicle_terminal_combined)
@ -18,8 +23,8 @@ class VehicleTerminalCombinedTest extends Specification {
}
"player can buy a ground vehicle, the harasser ('two_man_assault_buggy')" in {
val terminal = Terminal(GlobalDefinitions.vehicle_terminal_combined)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "two_man_assault_buggy", 0, PlanetSideGUID(0))
val reply = terminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.BuyVehicle]
@ -35,8 +40,8 @@ class VehicleTerminalCombinedTest extends Specification {
}
"player can buy a flying vehicle, the reaver ('lightgunship')" in {
val terminal = Terminal(GlobalDefinitions.vehicle_terminal_combined)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "lightgunship", 0, PlanetSideGUID(0))
val reply = terminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.BuyVehicle]
@ -52,7 +57,6 @@ class VehicleTerminalCombinedTest extends Specification {
}
"player can not buy a fake vehicle ('harasser')" in {
val terminal = Terminal(GlobalDefinitions.vehicle_terminal_combined)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "harasser", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()

View file

@ -7,6 +7,7 @@ import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
import net.psforever.objects.serverobject.locks.IFFLock
import net.psforever.objects.serverobject.mblocker.Locker
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder}
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.types.Vector3
@ -103,30 +104,46 @@ object Maps {
VehicleSpawnPad.Constructor(Vector3(3508.9844f, 2895.961f, 92.296875f), Vector3(0f, 0f, 270.0f))
)) //TODO guid not correct
LocalBases = 30
LocalBuilding(2, FoundationBuilder(Building.Structure))
ObjectToBuilding(186, 2)
ObjectToBuilding(187, 2)
ObjectToBuilding(188, 2)
ObjectToBuilding(522, 2)
ObjectToBuilding(523, 2)
ObjectToBuilding(524, 2)
ObjectToBuilding(525, 2)
ObjectToBuilding(526, 2)
ObjectToBuilding(527, 2)
ObjectToBuilding(528, 2)
ObjectToBuilding(529, 2)
ObjectToBuilding(686, 2)
ObjectToBuilding(687, 2)
ObjectToBuilding(688, 2)
ObjectToBuilding(689, 2)
ObjectToBuilding(690, 2)
ObjectToBuilding(691, 2)
ObjectToBuilding(692, 2)
ObjectToBuilding(693, 2)
ObjectToBuilding(842, 2)
ObjectToBuilding(843, 2)
ObjectToBuilding(844, 2)
ObjectToBuilding(845, 2)
ObjectToBuilding(853, 2) //TODO check building_id
ObjectToBuilding(855, 2) //TODO check building_id
ObjectToBuilding(860, 2) //TODO check building_id
ObjectToBuilding(1063, 2) //TODO unowned courtyard terminal?
ObjectToBuilding(500, 2) //TODO unowned courtyard spawnpad?
ObjectToBuilding(304, 2) //TODO unowned courtyard terminal?
ObjectToBuilding(501, 2) //TODO unowned courtyard spawnpad?
ObjectToBase(330, 29)
ObjectToBase(331, 29)
ObjectToBase(332, 29)
ObjectToBase(333, 29)
//ObjectToBase(520, 29)
ObjectToBase(522, 2)
ObjectToBase(523, 2)
ObjectToBase(524, 2)
ObjectToBase(525, 2)
ObjectToBase(526, 2)
ObjectToBase(527, 2)
ObjectToBase(528, 2)
ObjectToBase(529, 2)
ObjectToBase(556, 29)
ObjectToBase(557, 29)
ObjectToBase(558, 29)
ObjectToBase(559, 29)
ObjectToBase(1081, 2)
ObjectToBase(1063, 2) //TODO unowned courtyard terminal?
ObjectToBase(500, 2) //TODO unowned courtyard spawnpad?
ObjectToBase(304, 2) //TODO unowned courtyard terminal?
ObjectToBase(501, 2) //TODO unowned courtyard spawnpad?
LocalBuilding(29, FoundationBuilder(Building.Structure))
ObjectToBuilding(330, 29)
ObjectToBuilding(332, 29)
ObjectToBuilding(556, 29)
ObjectToBuilding(558, 29)
//ObjectToBuilding(1081, ?)
//ObjectToBuilding(520, ?)
DoorToLock(330, 558)
DoorToLock(331, 559)

View file

@ -14,7 +14,8 @@ import net.psforever.objects._
import net.psforever.objects.equipment._
import net.psforever.objects.guid.{GUIDTask, Task, TaskResolver}
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
import net.psforever.objects.mount.Mountable
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
@ -424,7 +425,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
val player_guid : PlanetSideGUID = tplayer.GUID
val obj_guid : PlanetSideGUID = obj.GUID
log.info(s"MountVehicleMsg: $player_guid mounts $obj @ $seat_num")
tplayer.VehicleSeated = Some(obj_guid)
//tplayer.VehicleSeated = Some(obj_guid)
sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(obj_guid, 0, 1000L))) //health of mech
sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(obj_guid, player_guid, seat_num)))
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.MountVehicle(player_guid, obj_guid, seat_num))
@ -434,7 +435,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
val player_guid : PlanetSideGUID = tplayer.GUID
log.info(s"MountVehicleMsg: $player_guid mounts $obj_guid @ $seat_num")
vehicleService ! VehicleServiceMessage.UnscheduleDeconstruction(obj_guid) //clear all deconstruction timers
tplayer.VehicleSeated = Some(obj_guid)
//tplayer.VehicleSeated = Some(obj_guid)
if(seat_num == 0) { //simplistic vehicle ownership management
obj.Owner match {
case Some(owner_guid) =>
@ -466,8 +467,37 @@ class WorldSessionActor extends Actor with MDCContextAware {
case Mountable.CanMount(obj : Mountable, _) =>
log.warn(s"MountVehicleMsg: $obj is some generic mountable object and nothing will happen")
case Mountable.CanDismount(obj : ImplantTerminalMech, seat_num) =>
val obj_guid : PlanetSideGUID = obj.GUID
val player_guid : PlanetSideGUID = tplayer.GUID
log.info(s"DismountVehicleMsg: $player_guid dismounts $obj @ $seat_num")
sendResponse(PacketCoding.CreateGamePacket(0, DismountVehicleMsg(player_guid, seat_num, false)))
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DismountVehicle(player_guid, seat_num, false))
case Mountable.CanDismount(obj : Vehicle, seat_num) =>
val player_guid : PlanetSideGUID = tplayer.GUID
if(player_guid == player.GUID) {
//disembarking self
log.info(s"DismountVehicleMsg: $player_guid dismounts $obj @ $seat_num")
sendResponse(PacketCoding.CreateGamePacket(0, DismountVehicleMsg(player_guid, seat_num, false)))
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DismountVehicle(player_guid, seat_num, false))
UnAccessContents(obj)
}
else {
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(player_guid, seat_num, true, obj.GUID))
}
if(obj.Seats.values.count(seat => seat.isOccupied) == 0) {
vehicleService ! VehicleServiceMessage.DelayedVehicleDeconstruction(obj, continent, 600L) //start vehicle decay (10m)
}
case Mountable.CanDismount(obj : Mountable, _) =>
log.warn(s"DismountVehicleMsg: $obj is some generic mountable object and nothing will happen")
case Mountable.CanNotMount(obj, seat_num) =>
log.warn(s"MountVehicleMsg: $tplayer attempted to mount $obj's seat $seat_num, but was not allowed")
case Mountable.CanNotDismount(obj, seat_num) =>
log.warn(s"DismountVehicleMsg: $tplayer attempted to dismount $obj's seat $seat_num, but was not allowed")
}
case Terminal.TerminalMessage(tplayer, msg, order) =>
@ -961,11 +991,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
log.info("Load the now-registered player")
//load the now-registered player
tplayer.Spawn
sendResponse(PacketCoding.CreateGamePacket(0,
ObjectCreateDetailedMessage(ObjectClass.avatar, tplayer.GUID, tplayer.Definition.Packet.DetailedConstructorData(tplayer).get)
))
val dcdata = tplayer.Definition.Packet.DetailedConstructorData(tplayer).get
sendResponse(PacketCoding.CreateGamePacket(0, ObjectCreateDetailedMessage(ObjectClass.avatar, tplayer.GUID, dcdata)))
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.LoadPlayer(tplayer.GUID, tplayer.Definition.Packet.ConstructorData(tplayer).get))
log.debug(s"ObjectCreateDetailedMessage: ${tplayer.Definition.Packet.DetailedConstructorData(tplayer).get}")
log.debug(s"ObjectCreateDetailedMessage: $dcdata")
case SetCurrentAvatar(tplayer) =>
val guid = tplayer.GUID
@ -1823,52 +1852,49 @@ class WorldSessionActor extends Actor with MDCContextAware {
// TODO: Not all incoming UseItemMessage's respond with another UseItemMessage (i.e. doors only send out GenericObjectStateMsg)
continent.GUID(object_guid) match {
case Some(door : Door) =>
continent.Map.DoorToLock.get(object_guid.guid) match { //check for IFF Lock
case Some(lock_guid) =>
val lock_hacked = continent.GUID(lock_guid).get.asInstanceOf[IFFLock].HackedBy match {
case Some(_) =>
true
case None =>
Vector3.ScalarProjection(door.Outwards, player.Position - door.Position) < 0f
}
continent.Map.ObjectToBase.get(lock_guid) match { //check for associated base
case Some(base_id) =>
if(continent.Base(base_id).get.Faction == player.Faction || lock_hacked) { //either base allegiance aligns or locks is hacked
door.Actor ! Door.Use(player, msg)
}
case None =>
if(lock_hacked) { //is lock hacked? this may be a weird case
door.Actor ! Door.Use(player, msg)
}
}
case None =>
door.Actor ! Door.Use(player, msg) //let door open freely
if(player.Faction == door.Faction || ((continent.Map.DoorToLock.get(object_guid.guid) match {
case Some(lock_guid) => continent.GUID(lock_guid).get.asInstanceOf[IFFLock].HackedBy.isDefined
case None => !door.isOpen
}) || Vector3.ScalarProjection(door.Outwards, player.Position - door.Position) < 0f)) {
door.Actor ! Door.Use(player, msg)
}
else if(door.isOpen) {
//the door is open globally ... except on our screen
sendResponse(PacketCoding.CreateGamePacket(0, GenericObjectStateMsg(object_guid, 16)))
}
case Some(panel : IFFLock) =>
player.Slot(player.DrawnSlot).Equipment match {
case Some(tool : SimpleItem) =>
if(tool.Definition == GlobalDefinitions.remote_electronics_kit) {
//TODO get player hack level (for now, presume 15s in intervals of 4/s)
progressBarValue = Some(-2.66f)
self ! WorldSessionActor.ItemHacking(player, panel, tool.GUID, 2.66f, FinishHackingDoor(panel, 1114636288L))
log.info("Hacking a door~")
}
case _ => ;
if(panel.Faction != player.Faction && panel.HackedBy.isEmpty) {
player.Slot(player.DrawnSlot).Equipment match {
case Some(tool : SimpleItem) =>
if(tool.Definition == GlobalDefinitions.remote_electronics_kit) {
//TODO get player hack level (for now, presume 15s in intervals of 4/s)
progressBarValue = Some(-2.66f)
self ! WorldSessionActor.ItemHacking(player, panel, tool.GUID, 2.66f, FinishHackingDoor(panel, 1114636288L))
log.info("Hacking a door~")
}
case _ => ;
}
}
case Some(obj : Locker) =>
val container = player.Locker
accessedContainer = Some(container)
sendResponse(PacketCoding.CreateGamePacket(0, UseItemMessage(avatar_guid, unk1, container.GUID, unk2, unk3, unk4, unk5, unk6, unk7, unk8, 456)))
if(player.Faction == obj.Faction) {
log.info(s"UseItem: $player accessing a locker")
val container = player.Locker
accessedContainer = Some(container)
sendResponse(PacketCoding.CreateGamePacket(0, UseItemMessage(avatar_guid, unk1, container.GUID, unk2, unk3, unk4, unk5, unk6, unk7, unk8, 456)))
}
else {
log.info(s"UseItem: not $player's locker")
}
case Some(obj : Vehicle) =>
if(obj.Faction == player.Faction) {
val equipment = player.Slot(player.DrawnSlot).Equipment
val equipment = player.Slot(player.DrawnSlot).Equipment
if(player.Faction == obj.Faction) {
if(equipment match {
case Some(tool : Tool) =>
tool.Definition match {
case GlobalDefinitions.nano_dispenser | GlobalDefinitions.remote_electronics_kit => false
case GlobalDefinitions.nano_dispenser => false
case _ => true
}
case _ => true
@ -1889,13 +1915,19 @@ class WorldSessionActor extends Actor with MDCContextAware {
case GlobalDefinitions.nano_dispenser =>
//TODO repairing behavior
case GlobalDefinitions.remote_electronics_kit =>
//TODO hacking behavior
case _ => ;
}
}
}
//enemy player interactions
else if(equipment.isDefined) {
equipment.get.Definition match {
case GlobalDefinitions.remote_electronics_kit =>
//TODO hacking behavior
case _ => ;
}
}
case Some(obj : PlanetSideGameObject) =>
if(itemType != 121) {
@ -1933,7 +1965,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
log.info("ItemTransaction: " + msg)
continent.GUID(terminal_guid) match {
case Some(term : Terminal) =>
term.Actor ! Terminal.Request(player, msg)
if(player.Faction == term.Faction) {
term.Actor ! Terminal.Request(player, msg)
}
case Some(obj : PlanetSideGameObject) => ;
case None => ;
}
@ -2015,36 +2049,19 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ DismountVehicleMsg(player_guid, unk1, unk2) =>
//TODO optimize this later
log.info(s"DismountVehicleMsg: $msg")
//common warning for this section
def dismountWarning(msg : String) : Unit = {
log.warn(s"$msg; some vehicle might not know that a player is no longer sitting in it")
}
if(player.GUID == player_guid) {
//normally disembarking from a seat
val previouslySeated = player.VehicleSeated
player.VehicleSeated = None
sendResponse(PacketCoding.CreateGamePacket(0, DismountVehicleMsg(player_guid, unk1, unk2)))
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DismountVehicle(player_guid, unk1, unk2))
//common warning for this section
def dismountWarning(msg : String) : Unit = {
log.warn(s"$msg; some vehicle might not know that a player is no longer sitting in it")
}
//find vehicle seat and disembark it
previouslySeated match {
player.VehicleSeated match {
case Some(obj_guid) =>
continent.GUID(obj_guid) match {
case Some(obj : Mountable) =>
val seats = obj.Seats.values
seats.find(seat => seat.Occupant.contains(player)) match {
case Some(seat) =>
if(seat.Bailable || obj.Velocity.isEmpty || Vector3.MagnitudeSquared(obj.Velocity.get).toInt == 0) { //ugh, float comparison
seat.Occupant = None
//special actions
obj match {
case (veh : Vehicle) =>
if(seats.count(seat => seat.isOccupied) == 0) {
vehicleService ! VehicleServiceMessage.DelayedVehicleDeconstruction(veh, continent, 600L) //start vehicle decay (10m)
UnAccessContents(veh)
}
case _ => ;
}
}
obj.PassengerInSeat(player) match {
case Some(seat_num : Int) =>
obj.Actor ! Mountable.TryDismount(player, seat_num)
case None =>
dismountWarning(s"DismountVehicleMsg: can not find where player $player_guid is seated in mountable $obj_guid")
}
@ -2056,35 +2073,23 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
}
else {
//kicking someone else out of a seat; need to own that seat
//kicking someone else out of a seat; need to own that seat/mountable
player.VehicleOwned match {
case Some(vehicle_guid) =>
continent.GUID(player_guid) match {
case Some(tplayer : Player) =>
if(tplayer.VehicleSeated.contains(vehicle_guid)) {
continent.GUID(vehicle_guid) match {
case Some(obj : Vehicle) =>
val seats = obj.Seats.values
seats.find(seat => seat.Occupant.contains(tplayer)) match {
case Some(seat) =>
seat.Occupant = None
tplayer.VehicleSeated = None
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(player_guid, unk1, unk2, vehicle_guid))
if(seats.count(seat => seat.isOccupied) == 0) {
vehicleService ! VehicleServiceMessage.DelayedVehicleDeconstruction(obj, continent, 600L) //start vehicle decay (10m)
}
case None =>
log.warn(s"DismountVehicleMsg: can not find where player $player_guid is seated in vehicle $vehicle_guid")
}
case _ =>
log.warn(s"DismountVehicleMsg: can not find vehicle $vehicle_guid")
}
case Some(obj_guid) =>
(continent.GUID(obj_guid), continent.GUID(player_guid)) match {
case (Some(obj : Mountable), Some(tplayer : Player)) =>
obj.PassengerInSeat(tplayer) match {
case Some(seat_num : Int) =>
obj.Actor ! Mountable.TryDismount(tplayer, seat_num)
case None =>
dismountWarning(s"DismountVehicleMsg: can not find where other player $player_guid is seated in mountable $obj_guid")
}
else {
log.warn(s"DismountVehicleMsg: non-owner player $player trying to kick player $tplayer out of his seat")
}
case _ =>
case (None, _) => ;
log.warn(s"DismountVehicleMsg: $player can not find his vehicle")
case (_, None) => ;
log.warn(s"DismountVehicleMsg: player $player_guid could not be found to kick")
case _ =>
log.warn(s"DismountVehicleMsg: object is either not a Mountable or not a Player")
}
case None =>
log.warn(s"DismountVehicleMsg: $player does not own a vehicle")

View file

@ -32,8 +32,8 @@ object Zones {
super.Init(context)
import net.psforever.types.PlanetSideEmpire
Base(2).get.Faction = PlanetSideEmpire.VS //HART building C
Base(29).get.Faction = PlanetSideEmpire.NC //South Villa Gun Tower
Building(2).get.Faction = PlanetSideEmpire.VS //HART building C
Building(29).get.Faction = PlanetSideEmpire.NC //South Villa Gun Tower
}
}

View file

@ -53,7 +53,7 @@ class DeconstructionActor extends Actor {
case DeconstructionActor.RequestDeleteVehicle(vehicle, zone, time) =>
vehicles = vehicles :+ DeconstructionActor.VehicleEntry(vehicle, zone, time)
vehicle.Actor ! Vehicle.PrepareForDeletion
//kick everyone out
//kick everyone out; this is a no-blocking manual form of MountableBehavior ! Mountable.TryDismount
vehicle.Definition.MountPoints.values.foreach(seat_num => {
val zone_id : String = zone.Id
val seat : Seat = vehicle.Seat(seat_num).get