Merge pull request #186 from Fate-JH/facilities

Buildings and Stuff
This commit is contained in:
Fate-JH 2018-02-10 15:15:03 -05:00 committed by GitHub
commit fb1c365bc2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 1362 additions and 425 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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