// Copyright (c) 2020 PSForever package objects import akka.actor.Props import akka.actor.typed.scaladsl.adapter._ import akka.testkit.TestProbe import base.{ActorTest, FreedContextActorTest} import net.psforever.actors.zone.ZoneActor import net.psforever.objects.avatar.{Avatar, PlayerControl} import net.psforever.objects.{GlobalDefinitions, Player, Vehicle} import net.psforever.objects.guid.NumberPoolHub import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.serverobject.environment._ import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.vehicles.{VehicleControl, VehicleLockState} import net.psforever.objects.vital.VehicleShieldCharge import net.psforever.objects.zones.{Zone, ZoneMap} import net.psforever.packet.game.{CargoMountPointStatusMessage, ObjectDetachMessage, PlanetsideAttributeMessage} import net.psforever.services.ServiceManager import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.types._ import scala.concurrent.duration._ class VehicleControlPrepareForDeletionTest extends ActorTest { val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy) vehicle.Faction = PlanetSideEmpire.TR vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test") val vehicleProbe = new TestProbe(system) vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) { VehicleEvents = vehicleProbe.ref } vehicle.GUID = PlanetSideGUID(1) expectNoMessage(200 milliseconds) "VehicleControl" should { "submit for unregistering when marked for deconstruction" in { vehicle.Actor ! Vehicle.Deconstruct() vehicleProbe.expectNoMessage(5 seconds) } } } class VehicleControlPrepareForDeletionPassengerTest extends ActorTest { val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy) vehicle.Faction = PlanetSideEmpire.TR vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test") val vehicleProbe = new TestProbe(system) vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) { VehicleEvents = vehicleProbe.ref } val player1 = Player(VehicleTest.avatar1) vehicle.GUID = PlanetSideGUID(1) player1.GUID = PlanetSideGUID(2) vehicle.Seats(1).Occupant = player1 //passenger seat player1.VehicleSeated = vehicle.GUID expectNoMessage(200 milliseconds) "VehicleControl" should { "kick all players when marked for deconstruction" in { vehicle.Actor ! Vehicle.Deconstruct() val vehicle_msg = vehicleProbe.receiveN(1, 500 milliseconds) assert( vehicle_msg.head match { case VehicleServiceMessage( "test", VehicleAction.KickPassenger(PlanetSideGUID(2), 4, false, PlanetSideGUID(1)) ) => true case _ => false } ) assert(player1.VehicleSeated.isEmpty) assert(vehicle.Seats(1).Occupant.isEmpty) } } } class VehicleControlPrepareForDeletionMountedInTest extends FreedContextActorTest { ServiceManager.boot val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { GUID(guid) override def SetupNumberPools(): Unit = {} } zone.actor = system.spawn(ZoneActor(zone), "test-zone-actor") // crappy workaround but without it the zone doesn't get initialized in time expectNoMessage(400 milliseconds) val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy) vehicle.Faction = PlanetSideEmpire.TR vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test-cargo") vehicle.Zone = zone val lodestar = Vehicle(GlobalDefinitions.lodestar) lodestar.Faction = PlanetSideEmpire.TR val player1 = Player(VehicleTest.avatar1) //name="test1" val player2 = Player(VehicleTest.avatar2) //name="test2" guid.register(vehicle, 1) guid.register(lodestar, 2) player1.GUID = PlanetSideGUID(3) var utilityId = 10 lodestar.Utilities.values.foreach { util => util().GUID = PlanetSideGUID(utilityId) utilityId += 1 } vehicle.Seats(1).Occupant = player1 //passenger seat player1.VehicleSeated = vehicle.GUID lodestar.Seats(0).Occupant = player2 player2.VehicleSeated = lodestar.GUID lodestar.CargoHolds(1).Occupant = vehicle vehicle.MountedIn = lodestar.GUID val vehicleProbe = new TestProbe(system) zone.VehicleEvents = vehicleProbe.ref zone.Transport ! Zone.Vehicle.Spawn(lodestar) //can not fake this expectNoMessage(200 milliseconds) "VehicleControl" should { "if mounted as cargo, self-eject when marked for deconstruction" in { vehicle.Actor ! Vehicle.Deconstruct() val vehicle_msg = vehicleProbe.receiveN(6, 500 milliseconds) //dismounting as cargo messages assert( vehicle_msg.head match { case VehicleServiceMessage( _, VehicleAction.SendResponse(_, PlanetsideAttributeMessage(PlanetSideGUID(1), 0, _)) ) => true case _ => false } ) assert( vehicle_msg(1) match { case VehicleServiceMessage( _, VehicleAction.SendResponse(_, PlanetsideAttributeMessage(PlanetSideGUID(1), 68, _)) ) => true case _ => false } ) assert( vehicle_msg(2) match { case VehicleServiceMessage( "test", VehicleAction.SendResponse( _, CargoMountPointStatusMessage(PlanetSideGUID(2), _, PlanetSideGUID(1), _, 1, CargoStatus.InProgress, 0) ) ) => true case _ => false } ) assert( vehicle_msg(3) match { case VehicleServiceMessage( "test", VehicleAction.SendResponse(_, ObjectDetachMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _, _, _)) ) => true case _ => false } ) assert( vehicle_msg(4) match { case VehicleServiceMessage( "test", VehicleAction.SendResponse( _, CargoMountPointStatusMessage(PlanetSideGUID(2), _, _, PlanetSideGUID(1), 1, CargoStatus.Empty, 0) ) ) => true case _ => false } ) //dismounting as cargo messages //TODO: does not actually kick out the cargo, but instigates the process assert( vehicle_msg(5) match { case VehicleServiceMessage( "test", VehicleAction.KickPassenger(PlanetSideGUID(3), 4, false, PlanetSideGUID(1)) ) => true case _ => false } ) assert(player1.VehicleSeated.isEmpty) assert(vehicle.Seats(1).Occupant.isEmpty) } } } class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActorTest { val guid = new NumberPoolHub(new MaxNumberSource(10)) ServiceManager.boot val zone = new Zone("test", new ZoneMap("test"), 0) { GUID(guid) override def SetupNumberPools(): Unit = {} } zone.actor = system.spawn(ZoneActor(zone), "test-zone-actor") // crappy workaround but without it the zone doesn't get initialized in time expectNoMessage(200 milliseconds) val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy) vehicle.Faction = PlanetSideEmpire.TR vehicle.Zone = zone val cargoProbe = new TestProbe(system) vehicle.Actor = cargoProbe.ref val lodestar = Vehicle(GlobalDefinitions.lodestar) lodestar.Faction = PlanetSideEmpire.TR val player1 = Player(VehicleTest.avatar1) //name="test1" val player2 = Player(VehicleTest.avatar2) //name="test2" guid.register(vehicle, 1) guid.register(lodestar, 2) player1.GUID = PlanetSideGUID(3) player2.GUID = PlanetSideGUID(4) var utilityId = 10 lodestar.Utilities.values.foreach { util => util().GUID = PlanetSideGUID(utilityId) utilityId += 1 } vehicle.Seats(1).Occupant = player1 //passenger seat player1.VehicleSeated = vehicle.GUID lodestar.Seats(0).Occupant = player2 player2.VehicleSeated = lodestar.GUID lodestar.CargoHolds(1).Occupant = vehicle vehicle.MountedIn = lodestar.GUID val vehicleProbe = new TestProbe(system) zone.VehicleEvents = vehicleProbe.ref zone.Transport ! Zone.Vehicle.Spawn(lodestar) //can not fake this expectNoMessage(200 milliseconds) "VehicleControl" should { "if with mounted cargo, eject it when marked for deconstruction" in { lodestar.Actor ! Vehicle.Deconstruct() val vehicle_msg = vehicleProbe.receiveN(6, 500 milliseconds) assert( vehicle_msg.head match { case VehicleServiceMessage( "test", VehicleAction.KickPassenger(PlanetSideGUID(4), 4, false, PlanetSideGUID(2)) ) => true case _ => false } ) assert(player2.VehicleSeated.isEmpty) assert(lodestar.Seats(0).Occupant.isEmpty) //cargo dismounting messages assert( vehicle_msg(1) match { case VehicleServiceMessage( _, VehicleAction.SendResponse(_, PlanetsideAttributeMessage(PlanetSideGUID(1), 0, _)) ) => true case _ => false } ) assert( vehicle_msg(2) match { case VehicleServiceMessage( _, VehicleAction.SendResponse(_, PlanetsideAttributeMessage(PlanetSideGUID(1), 68, _)) ) => true case _ => false } ) assert( vehicle_msg(3) match { case VehicleServiceMessage( "test", VehicleAction.SendResponse( _, CargoMountPointStatusMessage(PlanetSideGUID(2), _, PlanetSideGUID(1), _, 1, CargoStatus.InProgress, 0) ) ) => true case _ => false } ) assert( vehicle_msg(4) match { case VehicleServiceMessage( "test", VehicleAction.SendResponse(_, ObjectDetachMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _, _, _)) ) => true case _ => false } ) assert( vehicle_msg(5) match { case VehicleServiceMessage( "test", VehicleAction.SendResponse( _, CargoMountPointStatusMessage(PlanetSideGUID(2), _, _, PlanetSideGUID(1), 1, CargoStatus.Empty, 0) ) ) => true case _ => false } ) } } } class VehicleControlMountingBlockedExosuitTest extends ActorTest { val probe = new TestProbe(system) def checkCanNotMount(): Unit = { val reply = probe.receiveOne(Duration.create(100, "ms")) reply match { case msg: Mountable.MountMessages => assert(msg.response.isInstanceOf[Mountable.CanNotMount]) case _ => assert(false) } } def checkCanMount(): Unit = { val reply = probe.receiveOne(Duration.create(100, "ms")) reply match { case msg: Mountable.MountMessages => assert(msg.response.isInstanceOf[Mountable.CanMount]) case _ => assert(false) } } val vehicle = Vehicle(GlobalDefinitions.apc_tr) vehicle.Faction = PlanetSideEmpire.TR vehicle.GUID = PlanetSideGUID(10) vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test") val player1 = Player(VehicleTest.avatar1) player1.ExoSuit = ExoSuitType.Reinforced player1.GUID = PlanetSideGUID(1) val player2 = Player(VehicleTest.avatar1) player2.ExoSuit = ExoSuitType.MAX player2.GUID = PlanetSideGUID(2) val player3 = Player(VehicleTest.avatar1) player3.ExoSuit = ExoSuitType.Agile player3.GUID = PlanetSideGUID(3) "Vehicle Control" should { "block players from sitting if their exo-suit is not allowed by the seat" in { //disallow vehicle.Actor.tell(Mountable.TryMount(player1, 0), probe.ref) //Reinforced in non-MAX seat checkCanNotMount() vehicle.Actor.tell(Mountable.TryMount(player2, 0), probe.ref) //MAX in non-Reinforced seat checkCanNotMount() vehicle.Actor.tell(Mountable.TryMount(player2, 1), probe.ref) //MAX in non-MAX seat checkCanNotMount() vehicle.Actor.tell(Mountable.TryMount(player1, 9), probe.ref) //Reinforced in MAX-only seat checkCanNotMount() vehicle.Actor.tell(Mountable.TryMount(player3, 9), probe.ref) //Agile in MAX-only seat checkCanNotMount() //allow vehicle.Actor.tell(Mountable.TryMount(player1, 1), probe.ref) checkCanMount() vehicle.Actor.tell(Mountable.TryMount(player2, 9), probe.ref) checkCanMount() vehicle.Actor.tell(Mountable.TryMount(player3, 0), probe.ref) checkCanMount() } } } class VehicleControlMountingBlockedSeatPermissionTest extends ActorTest { val probe = new TestProbe(system) def checkCanNotMount(): Unit = { val reply = probe.receiveOne(Duration.create(100, "ms")) reply match { case msg: Mountable.MountMessages => assert(msg.response.isInstanceOf[Mountable.CanNotMount]) case _ => assert(false) } } def checkCanMount(): Unit = { val reply = probe.receiveOne(Duration.create(100, "ms")) reply match { case msg: Mountable.MountMessages => assert(msg.response.isInstanceOf[Mountable.CanMount]) case _ => assert(false) } } val vehicle = Vehicle(GlobalDefinitions.apc_tr) vehicle.Faction = PlanetSideEmpire.TR vehicle.GUID = PlanetSideGUID(10) vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test") val player1 = Player(VehicleTest.avatar1) player1.GUID = PlanetSideGUID(1) val player2 = Player(VehicleTest.avatar1) player2.GUID = PlanetSideGUID(2) "Vehicle Control" should { //11 June 2018: Group is not supported yet so do not bother testing it "block players from sitting if the seat does not allow it" in { vehicle.PermissionGroup(2, 3) //passenger group -> empire vehicle.Actor.tell(Mountable.TryMount(player1, 3), probe.ref) //passenger seat checkCanMount() vehicle.PermissionGroup(2, 0) //passenger group -> locked vehicle.Actor.tell(Mountable.TryMount(player2, 4), probe.ref) //passenger seat checkCanNotMount() } } } class VehicleControlMountingDriverSeatTest extends ActorTest { val probe = new TestProbe(system) def checkCanMount(): Unit = { val reply = probe.receiveOne(Duration.create(100, "ms")) reply match { case msg: Mountable.MountMessages => assert(msg.response.isInstanceOf[Mountable.CanMount]) case _ => assert(false) } } val vehicle = Vehicle(GlobalDefinitions.apc_tr) vehicle.Faction = PlanetSideEmpire.TR vehicle.GUID = PlanetSideGUID(10) vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test") val player1 = Player(VehicleTest.avatar1) player1.GUID = PlanetSideGUID(1) "Vehicle Control" should { "allow players to sit in the driver seat, even if it is locked, if the vehicle is unowned" in { assert(vehicle.PermissionGroup(0).contains(VehicleLockState.Locked)) //driver group -> locked assert(vehicle.Seats(0).Occupant.isEmpty) assert(vehicle.Owner.isEmpty) vehicle.Actor.tell(Mountable.TryMount(player1, 0), probe.ref) checkCanMount() assert(vehicle.Seats(0).Occupant.nonEmpty) } } } class VehicleControlMountingOwnedLockedDriverSeatTest extends ActorTest { val probe = new TestProbe(system) def checkCanNotMount(): Unit = { val reply = probe.receiveOne(Duration.create(100, "ms")) reply match { case msg: Mountable.MountMessages => assert(msg.response.isInstanceOf[Mountable.CanNotMount]) case _ => assert(false) } } def checkCanMount(): Unit = { val reply = probe.receiveOne(Duration.create(100, "ms")) reply match { case msg: Mountable.MountMessages => assert(msg.response.isInstanceOf[Mountable.CanMount]) case _ => assert(false) } } val vehicle = Vehicle(GlobalDefinitions.apc_tr) vehicle.Faction = PlanetSideEmpire.TR vehicle.GUID = PlanetSideGUID(10) vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test") val player1 = Player(VehicleTest.avatar1) player1.GUID = PlanetSideGUID(1) val player2 = Player(VehicleTest.avatar1) player2.GUID = PlanetSideGUID(2) "Vehicle Control" should { "block players that are not the current owner from sitting in the driver seat (locked)" in { assert(vehicle.PermissionGroup(0).contains(VehicleLockState.Locked)) //driver group -> locked assert(vehicle.Seats(0).Occupant.isEmpty) vehicle.Owner = player1.GUID vehicle.Actor.tell(Mountable.TryMount(player1, 0), probe.ref) checkCanMount() assert(vehicle.Seats(0).Occupant.nonEmpty) vehicle.Actor.tell(Mountable.TryDismount(player1, 0), probe.ref) probe.receiveOne(Duration.create(100, "ms")) //discard assert(vehicle.Seats(0).Occupant.isEmpty) vehicle.Actor.tell(Mountable.TryMount(player2, 0), probe.ref) checkCanNotMount() assert(vehicle.Seats(0).Occupant.isEmpty) } } } class VehicleControlMountingOwnedUnlockedDriverSeatTest extends ActorTest { val probe = new TestProbe(system) def checkCanMount(): Unit = { val reply = probe.receiveOne(Duration.create(100, "ms")) reply match { case msg: Mountable.MountMessages => assert(msg.response.isInstanceOf[Mountable.CanMount]) case _ => assert(false) } } val vehicle = Vehicle(GlobalDefinitions.apc_tr) vehicle.Faction = PlanetSideEmpire.TR vehicle.GUID = PlanetSideGUID(10) vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test") val player1 = Player(VehicleTest.avatar1) player1.GUID = PlanetSideGUID(1) val player2 = Player(VehicleTest.avatar1) player2.GUID = PlanetSideGUID(2) "Vehicle Control" should { "allow players that are not the current owner to sit in the driver seat (empire)" in { vehicle.PermissionGroup(0, 3) //passenger group -> empire assert(vehicle.PermissionGroup(0).contains(VehicleLockState.Empire)) //driver group -> empire assert(vehicle.Seats(0).Occupant.isEmpty) vehicle.Owner = player1.GUID //owner set vehicle.Actor.tell(Mountable.TryMount(player1, 0), probe.ref) checkCanMount() assert(vehicle.Seats(0).Occupant.nonEmpty) vehicle.Actor.tell(Mountable.TryDismount(player1, 0), probe.ref) probe.receiveOne(Duration.create(100, "ms")) //discard assert(vehicle.Seats(0).Occupant.isEmpty) vehicle.Actor.tell(Mountable.TryMount(player2, 0), probe.ref) checkCanMount() assert(vehicle.Seats(0).Occupant.nonEmpty) } } } class VehicleControlShieldsChargingTest extends ActorTest { val probe = new TestProbe(system) val vehicle = Vehicle(GlobalDefinitions.fury) vehicle.GUID = PlanetSideGUID(10) vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test") vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) { VehicleEvents = probe.ref } "charge vehicle shields" in { assert(vehicle.Shields == 0) assert(!vehicle.History.exists({ p => p.isInstanceOf[VehicleShieldCharge] })) vehicle.Actor ! Vehicle.ChargeShields(15) val msg = probe.receiveOne(500 milliseconds) assert(msg match { case VehicleServiceMessage(_, VehicleAction.PlanetsideAttribute(_, PlanetSideGUID(10), 68, 15)) => true case _ => false }) assert(vehicle.Shields == 15) assert(vehicle.History.exists({ p => p.isInstanceOf[VehicleShieldCharge] })) } } class VehicleControlShieldsNotChargingVehicleDeadTest extends ActorTest { val probe = new TestProbe(system) val vehicle = Vehicle(GlobalDefinitions.fury) vehicle.GUID = PlanetSideGUID(10) vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test") vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) { VehicleEvents = probe.ref } "not charge vehicle shields if the vehicle is destroyed" in { assert(vehicle.Health > 0) vehicle.Health = 0 assert(vehicle.Health == 0) assert(vehicle.Shields == 0) assert(!vehicle.History.exists({ p => p.isInstanceOf[VehicleShieldCharge] })) vehicle.Actor.tell(Vehicle.ChargeShields(15), probe.ref) probe.expectNoMessage(1 seconds) assert(vehicle.Shields == 0) assert(!vehicle.History.exists({ p => p.isInstanceOf[VehicleShieldCharge] })) } } class VehicleControlShieldsNotChargingVehicleShieldsFullTest extends ActorTest { val probe = new TestProbe(system) val vehicle = Vehicle(GlobalDefinitions.fury) vehicle.GUID = PlanetSideGUID(10) vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test") vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) { VehicleEvents = probe.ref } "not charge vehicle shields if the vehicle is destroyed" in { assert(vehicle.Shields == 0) vehicle.Shields = vehicle.MaxShields assert(vehicle.Shields == vehicle.MaxShields) assert(!vehicle.History.exists({ p => p.isInstanceOf[VehicleShieldCharge] })) vehicle.Actor ! Vehicle.ChargeShields(15) probe.expectNoMessage(1 seconds) assert(!vehicle.History.exists({ p => p.isInstanceOf[VehicleShieldCharge] })) } } class VehicleControlShieldsNotChargingTooEarlyTest extends ActorTest { val probe = new TestProbe(system) val vehicle = Vehicle(GlobalDefinitions.fury) vehicle.GUID = PlanetSideGUID(10) vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test") vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) { VehicleEvents = probe.ref } "charge vehicle shields" in { assert(vehicle.Shields == 0) vehicle.Actor ! Vehicle.ChargeShields(15) val msg = probe.receiveOne(200 milliseconds) //assert(msg.isInstanceOf[Vehicle.UpdateShieldsCharge]) assert(msg match { case VehicleServiceMessage(_, VehicleAction.PlanetsideAttribute(_, PlanetSideGUID(10), 68, 15)) => true case _ => false }) assert(vehicle.Shields == 15) vehicle.Actor ! Vehicle.ChargeShields(15) probe.expectNoMessage(200 milliseconds) assert(vehicle.Shields == 15) } } //TODO implement message protocol for zone startup completion //class VehicleControlShieldsNotChargingDamagedTest extends ActorTest { // val probe = new TestProbe(system) // val vehicle = Vehicle(GlobalDefinitions.fury) // vehicle.GUID = PlanetSideGUID(10) // vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test") // vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) { // VehicleEvents = probe.ref // } // // // val beamer_wep = Tool(GlobalDefinitions.beamer) // val p_source = PlayerSource( Player(Avatar(0, "TestTarget", PlanetSideEmpire.NC, CharacterGender.Female, 1, CharacterVoice.Mute)) ) // val projectile = Projectile(beamer_wep.Projectile, GlobalDefinitions.beamer, beamer_wep.FireMode, p_source, GlobalDefinitions.beamer.ObjectId, Vector3.Zero, Vector3.Zero) // val fury_dm = Vehicle(GlobalDefinitions.fury).DamageModel // val obj = DamageInteraction(p_source, ProjectileReason(DamageResolution.Hit, projectile, fury_dm), Vector3(1.2f, 3.4f, 5.6f)) // // "not charge vehicle shields if recently damaged" in { // assert(vehicle.Shields == 0) // vehicle.Actor.tell(Vitality.Damage({case v : Vehicle => v.History(obj); obj }), probe.ref) // // val msg = probe.receiveOne(200 milliseconds) // assert(msg.isInstanceOf[Vitality.DamageResolution]) // assert(vehicle.Shields == 0) // vehicle.Actor.tell(Vehicle.ChargeShields(15), probe.ref) // // probe.expectNoMessage(200 milliseconds) // assert(vehicle.Shields == 0) // } //} class VehicleControlInteractWithWaterPartialTest extends ActorTest { val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2 val player1 = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=1 val playerProbe = TestProbe() val guid = new NumberPoolHub(new MaxNumberSource(15)) val pool = Pool(EnvironmentAttribute.Water, DeepSquare(-1, 10, 10, 0, 0)) val zone = new Zone( id = "test-zone", new ZoneMap(name = "test-map") { environment = List(pool) }, zoneNumber = 0 ) { override def SetupNumberPools() = {} GUID(guid) override def LivePlayers = List(player1) override def Vehicles = List(vehicle) } guid.register(player1, 1) guid.register(vehicle, 2) player1.Zone = zone player1.Spawn() vehicle.Zone = zone vehicle.Faction = PlanetSideEmpire.TR vehicle.Seats(0).Occupant = player1 player1.VehicleSeated = vehicle.GUID player1.Actor = playerProbe.ref vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-control") "VehicleControl" should { "causes disability when the vehicle drives too deep in water (check driver messaging)" in { vehicle.Position = Vector3(5,5,-3) //right in the pool vehicle.zoneInteraction() //trigger val msg_drown = playerProbe.receiveOne(250 milliseconds) assert( msg_drown match { case InteractWithEnvironment( p1, p2, Some(OxygenStateTarget(PlanetSideGUID(2), OxygenState.Suffocation, 100f)) ) => (p1 eq player1) && (p2 eq pool) case _ => false } ) } } } class VehicleControlInteractWithWaterTest extends ActorTest { val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2 val player1 = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=1 val avatarProbe = TestProbe() val vehicleProbe = TestProbe() val guid = new NumberPoolHub(new MaxNumberSource(15)) val pool = Pool(EnvironmentAttribute.Water, DeepSquare(-1, 10, 10, 0, 0)) val zone = new Zone( id = "test-zone", new ZoneMap(name = "test-map") { environment = List(pool) }, zoneNumber = 0 ) { override def SetupNumberPools() = {} GUID(guid) override def LivePlayers = List(player1) override def Vehicles = List(vehicle) override def AvatarEvents = avatarProbe.ref override def VehicleEvents = vehicleProbe.ref } guid.register(player1, 1) guid.register(vehicle, 2) guid.register(player1.avatar.locker, 5) player1.Zone = zone player1.Spawn() vehicle.Zone = zone vehicle.Faction = PlanetSideEmpire.TR vehicle.Seats(0).Occupant = player1 player1.VehicleSeated = vehicle.GUID val (probe, avatarActor) = PlayerControlTest.DummyAvatar(system) player1.Actor = system.actorOf(Props(classOf[PlayerControl], player1, avatarActor), "player1-control") vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-control") "VehicleControl" should { "causes disability when the vehicle drives too deep in water" in { vehicle.Position = Vector3(5,5,-3) //right in the pool vehicle.zoneInteraction() //trigger val msg_drown = avatarProbe.receiveOne(250 milliseconds) assert( msg_drown match { case AvatarServiceMessage( "TestCharacter1", AvatarAction.OxygenState( OxygenStateTarget(PlanetSideGUID(1), OxygenState.Suffocation, 100f), Some(OxygenStateTarget(PlanetSideGUID(2), OxygenState.Suffocation, 100f)) ) ) => true case _ => false } ) //player will die in 60s //vehicle will disable in 5s; driver will be kicked val msg_kick = vehicleProbe.receiveOne(6 seconds) assert( msg_kick match { case VehicleServiceMessage( "test-zone", VehicleAction.KickPassenger(PlanetSideGUID(1), 4, _, PlanetSideGUID(2)) ) => true case _ => false } ) //player will die, but detailing players death messages is not necessary for this test } } } class VehicleControlStopInteractWithWaterTest extends ActorTest { val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2 val player1 = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=1 val playerProbe = TestProbe() val guid = new NumberPoolHub(new MaxNumberSource(15)) val pool = Pool(EnvironmentAttribute.Water, DeepSquare(-1, 10, 10, 0, 0)) val zone = new Zone( id = "test-zone", new ZoneMap(name = "test-map") { environment = List(pool) }, zoneNumber = 0 ) { override def SetupNumberPools() = {} GUID(guid) override def LivePlayers = List(player1) override def Vehicles = List(vehicle) } guid.register(player1, 1) guid.register(vehicle, 2) player1.Zone = zone player1.Spawn() vehicle.Zone = zone vehicle.Faction = PlanetSideEmpire.TR vehicle.Seats(0).Occupant = player1 player1.VehicleSeated = vehicle.GUID player1.Actor = playerProbe.ref vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-control") "VehicleControl" should { "stop becoming disabled if the vehicle drives out of the water" in { vehicle.Position = Vector3(5,5,-3) //right in the pool vehicle.zoneInteraction() //trigger val msg_drown = playerProbe.receiveOne(250 milliseconds) assert( msg_drown match { case InteractWithEnvironment( p1, p2, Some(OxygenStateTarget(PlanetSideGUID(2), OxygenState.Suffocation, 100f)) ) => (p1 eq player1) && (p2 eq pool) case _ => false } ) vehicle.Position = Vector3.Zero //that's enough of that vehicle.zoneInteraction() val msg_recover = playerProbe.receiveOne(250 milliseconds) assert( msg_recover match { case EscapeFromEnvironment( p1, p2, Some(OxygenStateTarget(PlanetSideGUID(2), OxygenState.Recovery, _)) ) => (p1 eq player1) && (p2 eq pool) case _ => false } ) } } } class VehicleControlInteractWithLavaTest extends ActorTest { val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2 val player1 = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=1 val avatarProbe = TestProbe() val vehicleProbe = TestProbe() val guid = new NumberPoolHub(new MaxNumberSource(15)) val pool = Pool(EnvironmentAttribute.Lava, DeepSquare(-1, 10, 10, 0, 0)) val zone = new Zone( id = "test-zone", new ZoneMap(name = "test-map") { environment = List(pool) }, zoneNumber = 0 ) { override def SetupNumberPools() = {} GUID(guid) override def LivePlayers = List(player1) override def Vehicles = List(vehicle) override def AvatarEvents = avatarProbe.ref override def VehicleEvents = vehicleProbe.ref override def Activity = TestProbe().ref } guid.register(player1, 1) guid.register(vehicle, 2) guid.register(player1.avatar.locker, 5) player1.Zone = zone player1.Spawn() vehicle.Zone = zone vehicle.Faction = PlanetSideEmpire.TR vehicle.Seats(0).Occupant = player1 player1.VehicleSeated = vehicle.GUID val (probe, avatarActor) = PlayerControlTest.DummyAvatar(system) player1.Actor = system.actorOf(Props(classOf[PlayerControl], player1, avatarActor), "player1-control") vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-control") "VehicleControl" should { "take continuous damage if vehicle drives into lava" in { assert(vehicle.Health > 0) //alive assert(player1.Health == 100) //alive vehicle.Position = Vector3(5,5,-3) //right in the pool vehicle.zoneInteraction() //trigger val msg_burn = vehicleProbe.receiveN(3,1 seconds) msg_burn.foreach { msg => assert( msg match { case VehicleServiceMessage("test-zone", VehicleAction.PlanetsideAttribute(_, PlanetSideGUID(2), 0, _)) => true case _ => false } ) } //etc.. probe.receiveOne(65 seconds) //wait until player1's implants deinitialize assert(vehicle.Health == 0) //ded assert(player1.Health == 0) //ded } } } class VehicleControlInteractWithDeathTest extends ActorTest { val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2 val player1 = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=1 val guid = new NumberPoolHub(new MaxNumberSource(15)) val pool = Pool(EnvironmentAttribute.Death, DeepSquare(-1, 10, 10, 0, 0)) val zone = new Zone( id = "test-zone", new ZoneMap(name = "test-map") { environment = List(pool) }, zoneNumber = 0 ) { override def SetupNumberPools() = {} GUID(guid) override def LivePlayers = List(player1) override def Vehicles = List(vehicle) override def AvatarEvents = TestProbe().ref override def VehicleEvents = TestProbe().ref } guid.register(player1, 1) guid.register(vehicle, 2) guid.register(player1.avatar.locker, 5) player1.Zone = zone player1.Spawn() vehicle.Zone = zone vehicle.Faction = PlanetSideEmpire.TR vehicle.Seats(0).Occupant = player1 player1.VehicleSeated = vehicle.GUID val (probe, avatarActor) = PlayerControlTest.DummyAvatar(system) player1.Actor = system.actorOf(Props(classOf[PlayerControl], player1, avatarActor), "player1-control") vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-control") "VehicleControl" should { "take continuous damage if vehicle drives into a pool of death" in { assert(vehicle.Health > 0) //alive assert(player1.Health == 100) //alive vehicle.Position = Vector3(5,5,-3) //right in the pool vehicle.zoneInteraction() //trigger probe.receiveOne(2 seconds) //wait until player1's implants deinitialize assert(vehicle.Health == 0) //ded assert(player1.Health == 0) //ded } } } object VehicleControlTest { import net.psforever.objects.avatar.Avatar import net.psforever.types.{CharacterGender, PlanetSideEmpire} val avatar1 = Avatar(0, "test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute) val avatar2 = Avatar(1, "test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute) }