PSF-LoginServer/common/src/test/scala/objects/GeneratorTest.scala

766 lines
28 KiB
Scala

// Copyright (c) 2020 PSForever
package objects
import akka.actor.{ActorRef, Props}
import akka.testkit.TestProbe
import base.ActorTest
import net.psforever.objects.ballistics._
import net.psforever.objects.{Avatar, GlobalDefinitions, Player, Tool}
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl}
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.vital.Vitality
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.packet.game.{InventoryStateMessage, RepairMessage, TriggerEffectMessage}
import net.psforever.types._
import org.specs2.mutable.Specification
import services.avatar.{AvatarAction, AvatarServiceMessage}
import scala.concurrent.duration._
class GeneratorTest extends Specification {
"Generator" should {
"construct" in {
Generator(GlobalDefinitions.generator)
ok
}
"start in 'Normal' condition" in {
val obj = Generator(GlobalDefinitions.generator)
obj.Condition mustEqual PlanetSideGeneratorState.Normal
}
}
}
class GeneratorControlConstructTest extends ActorTest {
"GeneratorControl" should {
"construct" in {
val gen = Generator(GlobalDefinitions.generator)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "gen-control")
assert(gen.Actor != ActorRef.noSender)
}
}
}
class GeneratorControlDamageTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = { }
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 = Player(Avatar("TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(projectile, weapon.Definition, weapon.FireMode, PlayerSource(player1), 0, Vector3(2, 0, 0), Vector3(-1, 0, 0)),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"handle damage" in {
assert(gen.Health == gen.Definition.MaxHealth)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
gen.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar = avatarProbe.receiveN(2, 500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
assert(
msg_avatar.head match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar(1) match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 15)) => true
case _ => false
}
)
assert(gen.Health < gen.Definition.MaxHealth)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
}
}
}
class GeneratorControlCriticalTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = { }
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 = Player(Avatar("TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(projectile, weapon.Definition, weapon.FireMode, PlayerSource(player1), 0, Vector3(2, 0, 0), Vector3(-1, 0, 0)),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
val halfHealth = gen.Definition.MaxHealth / 2
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"handle damage through the generator's critical state" in {
gen.Health = halfHealth + 1 //no matter what, the next shot pushes it to critical status
assert(gen.Health > halfHealth)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
gen.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar = avatarProbe.receiveN(2, 500 milliseconds)
val msg_building = buildingProbe.receiveOne(500 milliseconds)
assert(
msg_avatar.head match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar(1) match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 15)) => true
case _ => false
}
)
assert(
msg_building match {
case Building.AmenityStateChange(o) => o eq gen
case _ => false
}
)
assert(gen.Health < halfHealth)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Critical)
}
}
}
class GeneratorControlDestroyedTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = { }
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 = Player(Avatar("TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn
player1.Actor = TestProbe().ref
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(projectile, weapon.Definition, weapon.FireMode, PlayerSource(player1), 0, Vector3(2, 0, 0), Vector3(-1, 0, 0)),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"handle damage until destroyed" in {
gen.Health = 1 //no matter what, the next shot destroys the generator
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal) //skipped critical state because didn't transition ~50%
gen.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar1 = avatarProbe.receiveOne(500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
assert(
msg_avatar1 match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 16)) => true
case _ => false
}
)
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
avatarProbe.expectNoMessage(9 seconds)
buildingProbe.expectNoMessage(50 milliseconds) //no prior messages
val msg_avatar2 = avatarProbe.receiveN(3, 1000 milliseconds) //see DamageableEntity test file
val msg_building = buildingProbe.receiveOne(200 milliseconds)
assert(
msg_building match {
case Building.AmenityStateChange(o) => o eq gen
case _ => false
}
)
assert(
msg_avatar2.head match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar2(1) match {
case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => true
case _ => false
}
)
assert(
msg_avatar2(2) match {
case AvatarServiceMessage("test",
AvatarAction.SendResponse(_, TriggerEffectMessage(PlanetSideGUID(2), "explosion_generator", None, None))
) => true
case _ => false
}
)
assert(gen.Health == 0)
assert(gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Destroyed)
}
}
}
class GeneratorControlKillsTest extends ActorTest {
/*
to perform this test, players need to be added to the SOI organization of the test base in proximity of the generator
under normal player scenario, this is an automatic process
extending from the act of players being in a zone
and players being within the SOI radius from the center of a facility on a periodic check
the test base being used has no established SOI region or automatic SOI check refresh,
but its SOI information can be loaded with the players manually
the players need something to catch the die message
*/
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = { }
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 = Player(Avatar("TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn
val player1Probe = TestProbe()
player1.Actor = player1Probe.ref
val player2 = Player(Avatar("TestCharacter2", PlanetSideEmpire.TR, CharacterGender.Female, 1, CharacterVoice.Mute)) //guid=4
player2.Position = Vector3(15, 0, 0) //>14m from generator; lives
player2.Spawn
val player2Probe = TestProbe()
player2.Actor = player2Probe.ref
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1, player2)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
guid.register(player2, 4)
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(projectile, weapon.Definition, weapon.FireMode, PlayerSource(player1), 0, Vector3(2, 0, 0), Vector3(-1, 0, 0)),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"kill players when the generator is destroyed" in {
gen.Health = 1 //no matter what, the next shot destroys the generator
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal) //skipped critical state because didn't transition ~50%
gen.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar1 = avatarProbe.receiveN(2, 500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
player2Probe.expectNoMessage(200 milliseconds)
assert(
msg_avatar1.head match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 16)) => true
case _ => false
}
)
assert(
msg_avatar1(1) match {
case AvatarServiceMessage("TestCharacter2", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 16)) => true
case _ => false
}
)
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
val msg_building = buildingProbe.receiveOne(10500 milliseconds)
val msg_avatar2 = avatarProbe.receiveN(3, 200 milliseconds)
val msg_player1 = player1Probe.receiveOne(100 milliseconds)
player2Probe.expectNoMessage(200 milliseconds)
assert(
msg_building match {
case Building.AmenityStateChange(o) => o eq gen
case _ => false
}
)
assert(
msg_avatar2.head match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar2(1) match {
case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => true
case _ => false
}
)
assert(
msg_avatar2(2) match {
case AvatarServiceMessage("test",
AvatarAction.SendResponse(_, TriggerEffectMessage(PlanetSideGUID(2), "explosion_generator", None, None))
) => true
case _ => false
}
)
assert(
msg_player1 match {
case _ @ Player.Die() => true
case _ => false
}
)
assert(gen.Health == 0)
assert(gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Destroyed)
}
}
}
class GeneratorControlNotDestroyTwice extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
val gen = Generator(GlobalDefinitions.generator) //guid=2
val player1 = Player(Avatar("TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Spawn
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val activityProbe = TestProbe()
val avatarProbe = TestProbe()
val buildingProbe = TestProbe()
zone.Activity = activityProbe.ref
zone.AvatarEvents = avatarProbe.ref
building.Actor = buildingProbe.ref
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(projectile, weapon.Definition, weapon.FireMode, PlayerSource(player1), 0, Vector3(2, 0, 0), Vector3(-1, 0, 0)),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"not send a status update if destroyed and partially repaired, but destroyed again" in {
//damaged, not yet restored, but will not be destroyed again within one shot
val originalHealth = gen.Health = gen.Definition.DamageDestroysAt + 1
gen.Condition = PlanetSideGeneratorState.Destroyed //initial state manip
gen.Destroyed = true
assert(gen.Destroyed)
assert(originalHealth < gen.Definition.DefaultHealth)
assert(originalHealth < gen.Definition.RepairRestoresAt)
assert(originalHealth > gen.Definition.DamageDestroysAt)
gen.Actor ! Vitality.Damage(applyDamageTo)
avatarProbe.expectNoMessage(500 milliseconds)
activityProbe.receiveOne(500 milliseconds)
buildingProbe.expectNoMessage(1000 milliseconds)
assert(gen.Health < originalHealth)
assert(gen.Destroyed)
assert(originalHealth < gen.Definition.DefaultHealth)
assert(originalHealth < gen.Definition.RepairRestoresAt)
assert(gen.Health <= gen.Definition.DamageDestroysAt)
//damaged, not yet restored, and would have been destroyed with next shot
gen.Health = 1
assert(gen.Health == 1)
assert(gen.Destroyed)
gen.Actor ! Vitality.Damage(applyDamageTo)
avatarProbe.expectNoMessage(500 milliseconds)
activityProbe.receiveOne(500 milliseconds) //activity alert occurs because this was not a kill shot
buildingProbe.expectNoMessage(1000 milliseconds)
assert(gen.Health == 0)
assert(gen.Destroyed)
}
}
}
class GeneratorControlNotDamageIfExplodingTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = { }
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 = Player(Avatar("TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn
val player1Probe = TestProbe()
player1.Actor = player1Probe.ref
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(projectile, weapon.Definition, weapon.FireMode, PlayerSource(player1), 0, Vector3(2, 0, 0), Vector3(-1, 0, 0)),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"not damage if the generator is going to explode" in {
gen.Health = 1 //no matter what, the next shot destroys the generator
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal) //skipped critical state because didn't transition ~50%
gen.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar = avatarProbe.receiveOne(500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
assert(
msg_avatar match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 16)) => true
case _ => false
}
)
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
//going to explode state
//once
gen.Actor ! Vitality.Damage(applyDamageTo)
avatarProbe.expectNoMessage(500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
assert(gen.Health == 1)
//twice
gen.Actor ! Vitality.Damage(applyDamageTo)
avatarProbe.expectNoMessage(500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
assert(gen.Health == 1)
}
}
}
class GeneratorControlNotRepairIfExplodingTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = { }
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 = Player(Avatar("TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn
val player1Probe = TestProbe()
player1.Actor = player1Probe.ref
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(projectile, weapon.Definition, weapon.FireMode, PlayerSource(player1), 0, Vector3(2, 0, 0), Vector3(-1, 0, 0)),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
val tool = Tool(GlobalDefinitions.nano_dispenser) //4 & 5
guid.register(tool, 4)
guid.register(tool.AmmoSlot.Box, 5)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"not repair if the generator is going to explode" in {
gen.Health = 1 //no matter what, the next shot destroys the generator
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal) //skipped critical state because didn't transition ~50%
gen.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar1 = avatarProbe.receiveOne(500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
assert(
msg_avatar1 match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 16)) => true
case _ => false
}
)
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
//going to explode state
//once
gen.Actor ! CommonMessages.Use(player1, Some(tool)) //repair?
avatarProbe.expectNoMessage(1000 milliseconds) //no messages
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
assert(gen.Health == 1)
//twice
gen.Actor ! CommonMessages.Use(player1, Some(tool)) //repair?
avatarProbe.expectNoMessage(1000 milliseconds) //no messages
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
assert(gen.Health == 1)
}
}
}
class GeneratorControlRepairPastRestorePoint extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = { }
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 = Player(Avatar("TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn
val player1Probe = TestProbe()
player1.Actor = player1Probe.ref
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
val tool = Tool(GlobalDefinitions.nano_dispenser) //4 & 5
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
guid.register(tool, 4)
guid.register(tool.AmmoSlot.Box, 5)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"send a status update if destroyed and repairing past the restoration point" in {
val originalHealth = gen.Health = gen.Definition.RepairRestoresAt - 1 //damage
gen.Condition = PlanetSideGeneratorState.Destroyed //initial state manip
gen.Destroyed = true
assert(originalHealth < gen.Definition.DefaultHealth)
assert(originalHealth < gen.Definition.RepairRestoresAt)
assert(gen.Destroyed)
gen.Actor ! CommonMessages.Use(player1, Some(tool)) //repair
val msg_avatar = avatarProbe.receiveN(4, 500 milliseconds) //expected
val msg_building = buildingProbe.receiveOne(200 milliseconds)
assert(
msg_avatar.head match {
case AvatarServiceMessage("TestCharacter1",
AvatarAction.SendResponse(_, InventoryStateMessage(ValidPlanetSideGUID(5), _, ValidPlanetSideGUID(4), _))
) => true
case _ => false
}
)
assert(
msg_avatar(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar(2) match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 17)) => true
case _ => false
}
)
assert(
msg_avatar(3) match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.SendResponse(_, RepairMessage(ValidPlanetSideGUID(2), _))) => true
case _ => false
}
)
assert(
msg_building match {
case Building.AmenityStateChange(o) => o eq gen
case _ => false
}
)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
assert(gen.Health > gen.Definition.RepairRestoresAt)
assert(!gen.Destroyed)
}
}
}