diff --git a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
index 4c9b542b6..d22bea556 100644
--- a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
+++ b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
@@ -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
diff --git a/common/src/main/scala/net/psforever/objects/LockerContainer.scala b/common/src/main/scala/net/psforever/objects/LockerContainer.scala
index 91f13590a..0282b8a39 100644
--- a/common/src/main/scala/net/psforever/objects/LockerContainer.scala
+++ b/common/src/main/scala/net/psforever/objects/LockerContainer.scala
@@ -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)
diff --git a/common/src/main/scala/net/psforever/objects/Player.scala b/common/src/main/scala/net/psforever/objects/Player.scala
index 710a38458..6da1a64c6 100644
--- a/common/src/main/scala/net/psforever/objects/Player.scala
+++ b/common/src/main/scala/net/psforever/objects/Player.scala
@@ -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
diff --git a/common/src/main/scala/net/psforever/objects/Vehicle.scala b/common/src/main/scala/net/psforever/objects/Vehicle.scala
index 98e0f4851..eb2bd6362 100644
--- a/common/src/main/scala/net/psforever/objects/Vehicle.scala
+++ b/common/src/main/scala/net/psforever/objects/Vehicle.scala
@@ -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
diff --git a/common/src/main/scala/net/psforever/objects/mount/MountableBehavior.scala b/common/src/main/scala/net/psforever/objects/mount/MountableBehavior.scala
deleted file mode 100644
index 6ccd0dfbd..000000000
--- a/common/src/main/scala/net/psforever/objects/mount/MountableBehavior.scala
+++ /dev/null
@@ -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))
- }
- }
-}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/PlanetSideServerObject.scala b/common/src/main/scala/net/psforever/objects/serverobject/PlanetSideServerObject.scala
index b81d8e0f6..3f8436b62 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/PlanetSideServerObject.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/PlanetSideServerObject.scala
@@ -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
/**
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/affinity/FactionAffinity.scala b/common/src/main/scala/net/psforever/objects/serverobject/affinity/FactionAffinity.scala
new file mode 100644
index 000000000..8fecc4de0
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/affinity/FactionAffinity.scala
@@ -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)
+}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/affinity/FactionAffinityBehavior.scala b/common/src/main/scala/net/psforever/objects/serverobject/affinity/FactionAffinityBehavior.scala
new file mode 100644
index 000000000..21ab5b733
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/affinity/FactionAffinityBehavior.scala
@@ -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)
+ }
+ }
+}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/doors/Base.scala b/common/src/main/scala/net/psforever/objects/serverobject/doors/Base.scala
deleted file mode 100644
index 90e6c490a..000000000
--- a/common/src/main/scala/net/psforever/objects/serverobject/doors/Base.scala
+++ /dev/null
@@ -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
- }
-}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/doors/Door.scala b/common/src/main/scala/net/psforever/objects/serverobject/doors/Door.scala
index 5f9b26de0..562ce8d04 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/doors/Door.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/doors/Door.scala
@@ -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" */
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/doors/DoorControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/doors/DoorControl.scala
index 8f1163316..0b1123457 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/doors/DoorControl.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/doors/DoorControl.scala
@@ -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))
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMech.scala b/common/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMech.scala
index 114a20f30..d9d9af334 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMech.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMech.scala
@@ -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
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechControl.scala
index e47a675bb..67f5d14cd 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechControl.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechControl.scala
@@ -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 _ => ;
+ }
}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/locks/IFFLock.scala b/common/src/main/scala/net/psforever/objects/serverobject/locks/IFFLock.scala
index a1c3380db..8142fd9af 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/locks/IFFLock.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/locks/IFFLock.scala
@@ -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.
*/
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/locks/IFFLockControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/locks/IFFLockControl.scala
index bf9d1b81a..0af058115 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/locks/IFFLockControl.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/locks/IFFLockControl.scala
@@ -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
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/mblocker/Locker.scala b/common/src/main/scala/net/psforever/objects/serverobject/mblocker/Locker.scala
index 60ee7979b..d614b53a8 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/mblocker/Locker.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/mblocker/Locker.scala
@@ -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
}
}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/mblocker/LockerControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/mblocker/LockerControl.scala
new file mode 100644
index 000000000..2e037e644
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/mblocker/LockerControl.scala
@@ -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 _ => ;
+ }
+}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/mblocker/LockerDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/mblocker/LockerDefinition.scala
new file mode 100644
index 000000000..b73a9e533
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/mblocker/LockerDefinition.scala
@@ -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"
+}
diff --git a/common/src/main/scala/net/psforever/objects/mount/Mountable.scala b/common/src/main/scala/net/psforever/objects/serverobject/mount/Mountable.scala
similarity index 80%
rename from common/src/main/scala/net/psforever/objects/mount/Mountable.scala
rename to common/src/main/scala/net/psforever/objects/serverobject/mount/Mountable.scala
index 06b63faff..b65a251f7 100644
--- a/common/src/main/scala/net/psforever/objects/mount/Mountable.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/mount/Mountable.scala
@@ -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
}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/mount/MountableBehavior.scala b/common/src/main/scala/net/psforever/objects/serverobject/mount/MountableBehavior.scala
new file mode 100644
index 000000000..33f8aa3fd
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/mount/MountableBehavior.scala
@@ -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))
+ }
+ }
+ }
+}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala
index 412774bf1..8f1e75a4b 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala
@@ -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)
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPad.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPad.scala
index 16c1357c3..19df456df 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPad.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPad.scala
@@ -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)
}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPadDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPadDefinition.scala
new file mode 100644
index 000000000..aa7972079
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPadDefinition.scala
@@ -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"
+}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/structures/Amenity.scala b/common/src/main/scala/net/psforever/objects/serverobject/structures/Amenity.scala
new file mode 100644
index 000000000..6458757d9
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/structures/Amenity.scala
@@ -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.
+ *
+ * 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`.
+ *
+ * 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] { }
+ }
+}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala b/common/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala
new file mode 100644
index 000000000..84a14c2c0
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala
@@ -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
+ }
+}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/structures/BuildingControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/structures/BuildingControl.scala
new file mode 100644
index 000000000..2f7b7b7ce
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/structures/BuildingControl.scala
@@ -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 _ => ;
+ }
+}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/structures/FoundationBuilder.scala b/common/src/main/scala/net/psforever/objects/serverobject/structures/FoundationBuilder.scala
new file mode 100644
index 000000000..fdf247e7f
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/structures/FoundationBuilder.scala
@@ -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)
+ }
+}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala
index c7c9b5bd7..3f6f6389d 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala
@@ -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()
}
}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala
index c74ada798..ad63babf4 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala
@@ -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))
diff --git a/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala b/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala
index 016ce6319..70639d455 100644
--- a/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala
+++ b/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala
@@ -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`.
@@ -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 _ => ;
+ }
}
diff --git a/common/src/main/scala/net/psforever/objects/zones/Zone.scala b/common/src/main/scala/net/psforever/objects/zones/Zone.scala
index dbd2501df..13e055048 100644
--- a/common/src/main/scala/net/psforever/objects/zones/Zone.scala
+++ b/common/src/main/scala/net/psforever/objects/zones/Zone.scala
@@ -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.
@@ -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`.
@@ -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)`
diff --git a/common/src/main/scala/net/psforever/objects/zones/ZoneActor.scala b/common/src/main/scala/net/psforever/objects/zones/ZoneActor.scala
index d72d7db4b..af5c06eab 100644
--- a/common/src/main/scala/net/psforever/objects/zones/ZoneActor.scala
+++ b/common/src/main/scala/net/psforever/objects/zones/ZoneActor.scala
@@ -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]
+ }
+}
diff --git a/common/src/main/scala/net/psforever/objects/zones/ZoneMap.scala b/common/src/main/scala/net/psforever/objects/zones/ZoneMap.scala
index 36a5bbe5c..d80192743 100644
--- a/common/src/main/scala/net/psforever/objects/zones/ZoneMap.scala
+++ b/common/src/main/scala/net/psforever/objects/zones/ZoneMap.scala
@@ -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
diff --git a/common/src/test/scala/objects/BuildingTest.scala b/common/src/test/scala/objects/BuildingTest.scala
new file mode 100644
index 000000000..122f3d993
--- /dev/null
+++ b/common/src/test/scala/objects/BuildingTest.scala
@@ -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)
+ }
+ }
+}
diff --git a/common/src/test/scala/objects/DoorTest.scala b/common/src/test/scala/objects/DoorTest.scala
index d95b77cad..228d44ab5 100644
--- a/common/src/test/scala/objects/DoorTest.scala
+++ b/common/src/test/scala/objects/DoorTest.scala
@@ -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)
+ }
+}
diff --git a/common/src/test/scala/objects/FactionAffinityTest.scala b/common/src/test/scala/objects/FactionAffinityTest.scala
new file mode 100644
index 000000000..c4598896a
--- /dev/null
+++ b/common/src/test/scala/objects/FactionAffinityTest.scala
@@ -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
+ }
+ }
+}
\ No newline at end of file
diff --git a/common/src/test/scala/objects/IFFLockTest.scala b/common/src/test/scala/objects/IFFLockTest.scala
index 54be04d16..05eb1e2fb 100644
--- a/common/src/test/scala/objects/IFFLockTest.scala
+++ b/common/src/test/scala/objects/IFFLockTest.scala
@@ -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)
+ }
+}
diff --git a/common/src/test/scala/objects/LockerTest.scala b/common/src/test/scala/objects/LockerTest.scala
new file mode 100644
index 000000000..ae5ffb3a1
--- /dev/null
+++ b/common/src/test/scala/objects/LockerTest.scala
@@ -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))
+ }
+ }
+}
diff --git a/common/src/test/scala/objects/MountableTest.scala b/common/src/test/scala/objects/MountableTest.scala
index 3b33ecd3b..83ba5babd 100644
--- a/common/src/test/scala/objects/MountableTest.scala
+++ b/common/src/test/scala/objects/MountableTest.scala
@@ -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)
}
}
diff --git a/common/src/test/scala/objects/ServerObjectBuilderTest.scala b/common/src/test/scala/objects/ServerObjectBuilderTest.scala
index 863278f45..73f802031 100644
--- a/common/src/test/scala/objects/ServerObjectBuilderTest.scala
+++ b/common/src/test/scala/objects/ServerObjectBuilderTest.scala
@@ -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)
+ }
+ }
}
diff --git a/common/src/test/scala/objects/VehicleSpawnPadTest.scala b/common/src/test/scala/objects/VehicleSpawnPadTest.scala
index 61f1deeb9..f595da65f 100644
--- a/common/src/test/scala/objects/VehicleSpawnPadTest.scala
+++ b/common/src/test/scala/objects/VehicleSpawnPadTest.scala
@@ -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)
+ }
+}
diff --git a/common/src/test/scala/objects/VehicleTest.scala b/common/src/test/scala/objects/VehicleTest.scala
index eba1463a3..1bd7abfaf 100644
--- a/common/src/test/scala/objects/VehicleTest.scala
+++ b/common/src/test/scala/objects/VehicleTest.scala
@@ -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])
+ }
+ }
+}
diff --git a/common/src/test/scala/objects/ZoneTest.scala b/common/src/test/scala/objects/ZoneTest.scala
index a16eeb109..024c8aef6 100644
--- a/common/src/test/scala/objects/ZoneTest.scala
+++ b/common/src/test/scala/objects/ZoneTest.scala
@@ -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
diff --git a/common/src/test/scala/objects/terminal/AirVehicleTerminalTest.scala b/common/src/test/scala/objects/terminal/AirVehicleTerminalTest.scala
index ffab2595f..65436e495 100644
--- a/common/src/test/scala/objects/terminal/AirVehicleTerminalTest.scala
+++ b/common/src/test/scala/objects/terminal/AirVehicleTerminalTest.scala
@@ -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()
diff --git a/common/src/test/scala/objects/terminal/CertTerminalTest.scala b/common/src/test/scala/objects/terminal/CertTerminalTest.scala
index 96b836682..c3d000d0e 100644
--- a/common/src/test/scala/objects/terminal/CertTerminalTest.scala
+++ b/common/src/test/scala/objects/terminal/CertTerminalTest.scala
@@ -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()
diff --git a/common/src/test/scala/objects/terminal/DropshipVehicleTerminalTest.scala b/common/src/test/scala/objects/terminal/DropshipVehicleTerminalTest.scala
index d7850c4e2..d498e3e0b 100644
--- a/common/src/test/scala/objects/terminal/DropshipVehicleTerminalTest.scala
+++ b/common/src/test/scala/objects/terminal/DropshipVehicleTerminalTest.scala
@@ -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()
diff --git a/common/src/test/scala/objects/terminal/GroundVehicleTerminalTest.scala b/common/src/test/scala/objects/terminal/GroundVehicleTerminalTest.scala
index c2207562f..831bb0b17 100644
--- a/common/src/test/scala/objects/terminal/GroundVehicleTerminalTest.scala
+++ b/common/src/test/scala/objects/terminal/GroundVehicleTerminalTest.scala
@@ -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()
diff --git a/common/src/test/scala/objects/terminal/ImplantTerminalInterfaceTest.scala b/common/src/test/scala/objects/terminal/ImplantTerminalInterfaceTest.scala
index c5893ea04..d846ab944 100644
--- a/common/src/test/scala/objects/terminal/ImplantTerminalInterfaceTest.scala
+++ b/common/src/test/scala/objects/terminal/ImplantTerminalInterfaceTest.scala
@@ -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]
diff --git a/common/src/test/scala/objects/terminal/ImplantTerminalMechTest.scala b/common/src/test/scala/objects/terminal/ImplantTerminalMechTest.scala
index 9677a09a3..a58f0cf0c 100644
--- a/common/src/test/scala/objects/terminal/ImplantTerminalMechTest.scala
+++ b/common/src/test/scala/objects/terminal/ImplantTerminalMechTest.scala
@@ -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)
+ }
+}
diff --git a/common/src/test/scala/objects/terminal/OrderTerminalTest.scala b/common/src/test/scala/objects/terminal/OrderTerminalTest.scala
index c5e41100c..1998d7d75 100644
--- a/common/src/test/scala/objects/terminal/OrderTerminalTest.scala
+++ b/common/src/test/scala/objects/terminal/OrderTerminalTest.scala
@@ -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()
diff --git a/common/src/test/scala/objects/terminal/TerminalControlTest.scala b/common/src/test/scala/objects/terminal/TerminalControlTest.scala
index b51062594..f3a461f90 100644
--- a/common/src/test/scala/objects/terminal/TerminalControlTest.scala
+++ b/common/src/test/scala/objects/terminal/TerminalControlTest.scala
@@ -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)
+ }
+}
diff --git a/common/src/test/scala/objects/terminal/VehicleTerminalCombinedTest.scala b/common/src/test/scala/objects/terminal/VehicleTerminalCombinedTest.scala
index 0bcb24d1b..6a390432b 100644
--- a/common/src/test/scala/objects/terminal/VehicleTerminalCombinedTest.scala
+++ b/common/src/test/scala/objects/terminal/VehicleTerminalCombinedTest.scala
@@ -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()
diff --git a/pslogin/src/main/scala/Maps.scala b/pslogin/src/main/scala/Maps.scala
index 03e55a6c7..71c810840 100644
--- a/pslogin/src/main/scala/Maps.scala
+++ b/pslogin/src/main/scala/Maps.scala
@@ -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)
diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala
index cbe972f4d..46b6ef0ee 100644
--- a/pslogin/src/main/scala/WorldSessionActor.scala
+++ b/pslogin/src/main/scala/WorldSessionActor.scala
@@ -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")
diff --git a/pslogin/src/main/scala/Zones.scala b/pslogin/src/main/scala/Zones.scala
index 786d33842..f856f4875 100644
--- a/pslogin/src/main/scala/Zones.scala
+++ b/pslogin/src/main/scala/Zones.scala
@@ -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
}
}
diff --git a/pslogin/src/main/scala/services/vehicle/support/DeconstructionActor.scala b/pslogin/src/main/scala/services/vehicle/support/DeconstructionActor.scala
index 760cbf204..adc9668a2 100644
--- a/pslogin/src/main/scala/services/vehicle/support/DeconstructionActor.scala
+++ b/pslogin/src/main/scala/services/vehicle/support/DeconstructionActor.scala
@@ -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