mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-03-19 03:50:39 +00:00
Damages (#225)
* refactored WSA code handling HitMessage, handling SplashMessage, and handling LashMessage; modified projectiles for future functionality
* players can die from being shot now; the damage model is simplistic since main goal was to write around the potential for negative damage ('healed from getting shot'); HitHint works correctly; dedicated AvatarService channel for each avatar helps reduce message spam
* vehicle destruction, and replacement with lightweight wreckage objects upon continent join; made flushing vehicle terminal more accessible
* simple work on vehicle shield charging (amp station benefit) (that's my commit story and I'm sticking with it)
* a flexible calculation workflow that can be applied, grabbing damage information, resistance information, and then combining it with a resolution function; players and vehicles have resistance values; removed redundant damage calculations from WSA
* broke up DamageCalculations, ResistanceCalculations, and ResolutionCalculations into packages under vital; fixed an error with exo-suit calculation resistances; events for dealing with synchronized player and vehicle damage calculations and building the papertrail of those damages; updating codecov.yml file for ignore classes
* added tests for various components (damage model, destroyed vehicle converter, vitality, etc..) and some functionality improvements
* added a field to keep track of how projectiles will be attributed at the time of target death
This commit is contained in:
parent
fc78d53ecb
commit
7901f66324
52 changed files with 3045 additions and 267 deletions
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import net.psforever.objects.definition.converter.{ACEConverter, CharacterSelectConverter, REKConverter}
|
||||
import net.psforever.objects.definition.converter.{ACEConverter, CharacterSelectConverter, DestroyedVehicleConverter, REKConverter}
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.definition._
|
||||
import net.psforever.objects.equipment.CItem.{DeployedItem, Unit}
|
||||
|
|
@ -9,6 +9,7 @@ import net.psforever.objects.equipment._
|
|||
import net.psforever.objects.inventory.InventoryTile
|
||||
import net.psforever.objects.serverobject.terminals.Terminal
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.vehicles.DestroyedVehicle
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.packet.game.objectcreate._
|
||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, Vector3}
|
||||
|
|
@ -368,7 +369,40 @@ class ConverterTest extends Specification {
|
|||
ams.Utilities(4)().GUID = PlanetSideGUID(417)
|
||||
|
||||
ams.Definition.Packet.ConstructorData(ams).isSuccess mustEqual true
|
||||
ok //TODO write more of this test
|
||||
}
|
||||
|
||||
"convert to packet (3)" in {
|
||||
val
|
||||
ams = Vehicle(GlobalDefinitions.ams)
|
||||
ams.GUID = PlanetSideGUID(413)
|
||||
ams.Health = 0 //destroyed vehicle
|
||||
|
||||
ams.Definition.Packet.ConstructorData(ams).isSuccess mustEqual true
|
||||
//did not initialize the utilities, but the converter did not fail
|
||||
}
|
||||
}
|
||||
|
||||
"DestroyedVehicle" should {
|
||||
"not convert a working vehicle" in {
|
||||
val ams = Vehicle(GlobalDefinitions.ams)
|
||||
ams.GUID = PlanetSideGUID(413)
|
||||
ams.Health mustEqual 3000 //not destroyed vehicle
|
||||
DestroyedVehicleConverter.converter.ConstructorData(ams).isFailure mustEqual true
|
||||
}
|
||||
|
||||
"convert to packet" in {
|
||||
val ams = Vehicle(GlobalDefinitions.ams)
|
||||
ams.GUID = PlanetSideGUID(413)
|
||||
ams.Health = 0
|
||||
DestroyedVehicleConverter.converter.ConstructorData(ams).isSuccess mustEqual true
|
||||
//did not initialize the utilities, but the converter did not fail
|
||||
}
|
||||
|
||||
"not convert into a detailed packet" in {
|
||||
val ams = Vehicle(GlobalDefinitions.ams)
|
||||
ams.GUID = PlanetSideGUID(413)
|
||||
ams.Health = 0
|
||||
DestroyedVehicleConverter.converter.DetailedConstructorData(ams).isFailure mustEqual true
|
||||
}
|
||||
}
|
||||
}
|
||||
416
common/src/test/scala/objects/DamageModelTests.scala
Normal file
416
common/src/test/scala/objects/DamageModelTests.scala
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.vital.damage.{DamageCalculations, DamageProfile}
|
||||
import DamageCalculations._
|
||||
import net.psforever.objects.vital.resistance.ResistanceCalculations
|
||||
import ResistanceCalculations._
|
||||
import net.psforever.objects.vital.resolution.ResolutionCalculations
|
||||
import ResolutionCalculations._
|
||||
import net.psforever.objects.ballistics._
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.types._
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
class DamageCalculationsTests extends Specification {
|
||||
"DamageCalculations" should {
|
||||
val wep = GlobalDefinitions.galaxy_gunship_cannon
|
||||
val wep_fmode = Tool(wep).FireMode
|
||||
val wep_prof = wep_fmode.Modifiers.asInstanceOf[DamageProfile]
|
||||
val proj = wep.ProjectileTypes.head
|
||||
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||
val player = Player(Avatar("TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
|
||||
val target = Vehicle(GlobalDefinitions.fury)
|
||||
target.Position = Vector3(10, 0, 0)
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(target), target.DamageModel, Vector3(50, 50, 0))
|
||||
"extract no damage numbers" in {
|
||||
NoDamageAgainst(proj_prof) mustEqual 0
|
||||
}
|
||||
|
||||
"extract damage against exosuit target" in {
|
||||
DamageAgainstExoSuit(proj_prof) mustEqual 50
|
||||
}
|
||||
|
||||
"extract damage against MAX target" in {
|
||||
DamageAgainstMaxSuit(proj_prof) mustEqual 75
|
||||
}
|
||||
|
||||
"extract damage against vehicle target" in {
|
||||
DamageAgainstVehicle(proj_prof) mustEqual 82
|
||||
}
|
||||
|
||||
"extract damage against aircraft target" in {
|
||||
DamageAgainstAircraft(proj_prof) mustEqual 82
|
||||
}
|
||||
|
||||
"extract damage against something" in {
|
||||
DamageAgainstUnknown(proj_prof) mustEqual 66
|
||||
}
|
||||
|
||||
"extract a complete damage profile (1)" in {
|
||||
val result = DamageAgainstVehicle(proj_prof) + DamageAgainstVehicle(wep_prof)
|
||||
val func : (DamageProfile, List[DamageProfile]) => Int = DamageWithModifiers(DamageAgainstVehicle)
|
||||
func(proj_prof, List(wep_prof)) mustEqual result
|
||||
}
|
||||
|
||||
"extract a complete damage profile (2)" in {
|
||||
val result = 2 * DamageAgainstVehicle(proj_prof) + DamageAgainstVehicle(wep_prof)
|
||||
val func : (DamageProfile, List[DamageProfile]) => Int = DamageWithModifiers(DamageAgainstVehicle)
|
||||
func(proj_prof, List(proj_prof, wep_prof)) mustEqual result
|
||||
}
|
||||
|
||||
"calculate no distance" in {
|
||||
NoDistance(resprojectile) mustEqual 0
|
||||
}
|
||||
|
||||
"calculate too far distance" in {
|
||||
TooFar(resprojectile) mustEqual Float.MaxValue
|
||||
}
|
||||
|
||||
"calculate distance between target and source" in {
|
||||
DistanceBetweenTargetandSource(resprojectile) mustEqual 10
|
||||
}
|
||||
|
||||
"calculate distance between target and explosion (splash)" in {
|
||||
DistanceFromExplosionToTarget(resprojectile) mustEqual 64.03124f
|
||||
}
|
||||
|
||||
"calculate no damage from components" in {
|
||||
val result = DamageWithModifiers(DamageAgainstVehicle)(proj_prof, List(wep_prof))
|
||||
val distance = DistanceFromExplosionToTarget(resprojectile)
|
||||
DamageCalculations.NoDamage(projectile, result, distance) mustEqual 0
|
||||
}
|
||||
|
||||
"calculate degraded damage from components (near)" in {
|
||||
val projectile_alt = Projectile(GlobalDefinitions.galaxy_gunship_gun_projectile, //need projectile with degrade
|
||||
wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
|
||||
val result = DamageWithModifiers(DamageAgainstVehicle)(proj_prof, List(wep_prof))
|
||||
DirectHitDamageWithDegrade(projectile_alt, result, 0) mustEqual 132
|
||||
}
|
||||
|
||||
"calculate degraded damage from components (medium)" in {
|
||||
val projectile_alt = Projectile(GlobalDefinitions.galaxy_gunship_gun_projectile, //need projectile with degrade
|
||||
wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
|
||||
val result = DamageWithModifiers(DamageAgainstVehicle)(proj_prof, List(wep_prof))
|
||||
DirectHitDamageWithDegrade(projectile_alt, result, 250) mustEqual 103
|
||||
}
|
||||
|
||||
"calculate degraded damage from components (far)" in {
|
||||
val projectile_alt = Projectile(GlobalDefinitions.galaxy_gunship_gun_projectile, //need projectile with degrade
|
||||
wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
|
||||
val result = DamageWithModifiers(DamageAgainstVehicle)(proj_prof, List(wep_prof))
|
||||
DirectHitDamageWithDegrade(projectile_alt, result, 1000) mustEqual 0
|
||||
}
|
||||
|
||||
"calculate splash damage from components (near)" in {
|
||||
val result = DamageWithModifiers(DamageAgainstVehicle)(proj_prof, List(wep_prof))
|
||||
SplashDamageWithRadialDegrade(projectile, result, 0) mustEqual 264
|
||||
}
|
||||
|
||||
"calculate splash damage from components (medium)" in {
|
||||
val result = DamageWithModifiers(DamageAgainstVehicle)(proj_prof, List(wep_prof))
|
||||
SplashDamageWithRadialDegrade(projectile, result, 5) mustEqual 145
|
||||
}
|
||||
|
||||
"calculate splash damage from components (far)" in {
|
||||
val result = DamageWithModifiers(DamageAgainstVehicle)(proj_prof, List(wep_prof))
|
||||
SplashDamageWithRadialDegrade(projectile, result, 6) mustEqual 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResistanceCalculationsTests extends Specification {
|
||||
val wep = GlobalDefinitions.galaxy_gunship_cannon
|
||||
val wep_fmode = Tool(wep).FireMode
|
||||
val proj = wep.ProjectileTypes.head //GlobalDefinitions.heavy_grenade_projectile
|
||||
val player = Player(Avatar("TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2,2,0), Vector3.Zero)
|
||||
|
||||
"ResistanceCalculations" should {
|
||||
"ignore all targets" in {
|
||||
val target = Vehicle(GlobalDefinitions.fury)
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(target), target.DamageModel, Vector3.Zero)
|
||||
InvalidTarget(resprojectile).isFailure mustEqual true
|
||||
}
|
||||
|
||||
"discern standard infantry targets" in {
|
||||
val target = player
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(target), target.DamageModel, Vector3.Zero)
|
||||
ValidInfantryTarget(resprojectile).isSuccess mustEqual true
|
||||
ValidMaxTarget(resprojectile).isSuccess mustEqual false
|
||||
ValidVehicleTarget(resprojectile).isSuccess mustEqual false
|
||||
ValidAircraftTarget(resprojectile).isSuccess mustEqual false
|
||||
}
|
||||
|
||||
"discern mechanized infantry targets" in {
|
||||
val target = Player(Avatar("TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
target.ExoSuit = ExoSuitType.MAX
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(target), target.DamageModel, Vector3.Zero)
|
||||
ValidInfantryTarget(resprojectile).isSuccess mustEqual false
|
||||
ValidMaxTarget(resprojectile).isSuccess mustEqual true
|
||||
ValidVehicleTarget(resprojectile).isSuccess mustEqual false
|
||||
ValidAircraftTarget(resprojectile).isSuccess mustEqual false
|
||||
}
|
||||
|
||||
"discern ground vehicle targets" in {
|
||||
val target = Vehicle(GlobalDefinitions.fury)
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(target), target.DamageModel, Vector3.Zero)
|
||||
ValidInfantryTarget(resprojectile).isSuccess mustEqual false
|
||||
ValidMaxTarget(resprojectile).isSuccess mustEqual false
|
||||
ValidVehicleTarget(resprojectile).isSuccess mustEqual true
|
||||
ValidAircraftTarget(resprojectile).isSuccess mustEqual false
|
||||
}
|
||||
|
||||
"discern flying vehicle targets" in {
|
||||
val target = Vehicle(GlobalDefinitions.mosquito)
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(target), target.DamageModel, Vector3.Zero)
|
||||
ValidInfantryTarget(resprojectile).isSuccess mustEqual false
|
||||
ValidMaxTarget(resprojectile).isSuccess mustEqual false
|
||||
ValidVehicleTarget(resprojectile).isSuccess mustEqual false
|
||||
ValidAircraftTarget(resprojectile).isSuccess mustEqual true
|
||||
}
|
||||
|
||||
"extract no resistance values" in {
|
||||
NoResistExtractor(SourceEntry(player)) mustEqual 0
|
||||
}
|
||||
|
||||
"extract resistance values from exo-suit" in {
|
||||
val pSource = PlayerSource(player)
|
||||
ExoSuitDirectExtractor(pSource) mustEqual 4
|
||||
ExoSuitSplashExtractor(pSource) mustEqual 15
|
||||
ExoSuitAggravatedExtractor(pSource) mustEqual 8
|
||||
ExoSuitRadiationExtractor(pSource) mustEqual 0
|
||||
}
|
||||
|
||||
"extract resistance values from vehicle" in {
|
||||
val vSource = VehicleSource(Vehicle(GlobalDefinitions.fury))
|
||||
VehicleDirectExtractor(vSource) mustEqual 0
|
||||
VehicleSplashExtractor(vSource) mustEqual 0
|
||||
VehicleAggravatedExtractor(vSource) mustEqual 0
|
||||
VehicleRadiationExtractor(vSource) mustEqual 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResolutionCalculationsTests extends Specification {
|
||||
val wep = GlobalDefinitions.suppressor
|
||||
val wep_fmode = Tool(wep).FireMode
|
||||
val proj = wep.ProjectileTypes.head
|
||||
val player = Player(Avatar("TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
player.Spawn
|
||||
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2,2,0), Vector3.Zero)
|
||||
|
||||
"ResolutionCalculations" should {
|
||||
"calculate no damage" in {
|
||||
val target = player
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(target), target.DamageModel, Vector3.Zero)
|
||||
ResolutionCalculations.NoDamage(resprojectile)(50,50) mustEqual 0
|
||||
}
|
||||
|
||||
"calculate no infantry damage for vehicles" in {
|
||||
val target1 = Vehicle(GlobalDefinitions.fury) //!
|
||||
val resprojectile1 = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(target1), target1.DamageModel, Vector3.Zero)
|
||||
InfantryDamageAfterResist(resprojectile1)(50, 10) mustEqual (0,0)
|
||||
|
||||
val target2 = player
|
||||
val resprojectile2 = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(target2), target2.DamageModel, Vector3.Zero)
|
||||
InfantryDamageAfterResist(resprojectile2)(50, 10) mustEqual (40,10)
|
||||
}
|
||||
|
||||
"calculate health and armor damage for infantry target" in {
|
||||
InfantryDamageAfterResist(100,100)(50, 10) mustEqual (40,10)
|
||||
}
|
||||
|
||||
"calculate health and armor damage, with bonus damage, for infantry target" in {
|
||||
//health = 100, armor = 5 -> resist 10 but only have 5, so rollover extra -> damages (40+5, 5)
|
||||
InfantryDamageAfterResist(100,5)(50, 10) mustEqual (45,5)
|
||||
}
|
||||
|
||||
"calculate health damage for infantry target" in {
|
||||
//health = 100, armor = 0
|
||||
InfantryDamageAfterResist(100,0)(50, 10) mustEqual (50,0)
|
||||
}
|
||||
|
||||
"calculate armor damage for infantry target" in {
|
||||
//resistance > damage
|
||||
InfantryDamageAfterResist(100,100)(50, 60) mustEqual (0,50)
|
||||
}
|
||||
|
||||
val player2 = Player(Avatar("TestCharacter2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
player2.ExoSuit = ExoSuitType.MAX
|
||||
player2.Spawn
|
||||
"calculate no max damage for vehicles" in {
|
||||
val target1 = Vehicle(GlobalDefinitions.fury) //!
|
||||
val resprojectile1 = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(target1), target1.DamageModel, Vector3.Zero)
|
||||
MaxDamageAfterResist(resprojectile1)(50, 10) mustEqual (0,0)
|
||||
|
||||
val target2 = player2
|
||||
val resprojectile2 = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(target2), target2.DamageModel, Vector3.Zero)
|
||||
MaxDamageAfterResist(resprojectile2)(50, 10) mustEqual (0,40)
|
||||
}
|
||||
|
||||
"calculate health and armor damage for max target" in {
|
||||
MaxDamageAfterResist(100,5)(50, 10) mustEqual (35,5)
|
||||
}
|
||||
|
||||
"calculate health damage for max target" in {
|
||||
//health = 100, armor = 0
|
||||
MaxDamageAfterResist(100,0)(50, 10) mustEqual (40,0)
|
||||
}
|
||||
|
||||
"calculate armor damage for max target" in {
|
||||
//resistance > damage
|
||||
MaxDamageAfterResist(100,100)(50, 10) mustEqual (0,40)
|
||||
}
|
||||
|
||||
"do not care if target is infantry for vehicle calculations" in {
|
||||
val target1 = player
|
||||
val resprojectile1 = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(target1), target1.DamageModel, Vector3.Zero)
|
||||
VehicleDamageAfterResist(resprojectile1)(50, 10) mustEqual 40
|
||||
|
||||
val target2 = Vehicle(GlobalDefinitions.fury) //!
|
||||
val resprojectile2 = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(target2), target2.DamageModel, Vector3.Zero)
|
||||
VehicleDamageAfterResist(resprojectile2)(50, 10) mustEqual 40
|
||||
}
|
||||
}
|
||||
|
||||
"calculate resisted damage for vehicle target" in {
|
||||
VehicleDamageAfterResist(50, 10) mustEqual 40
|
||||
}
|
||||
|
||||
"calculate un-resisted damage for vehicle target" in {
|
||||
VehicleDamageAfterResist(50, 0) mustEqual 50
|
||||
}
|
||||
}
|
||||
|
||||
class DamageModelTests extends Specification {
|
||||
val wep = GlobalDefinitions.suppressor
|
||||
val wep_tool = Tool(wep)
|
||||
val wep_fmode = wep_tool.FireMode
|
||||
val proj = wep.ProjectileTypes.head
|
||||
val player = Player(Avatar("TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
player.Spawn
|
||||
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2,2,0), Vector3.Zero)
|
||||
|
||||
"DamageModel" should {
|
||||
"be a part of vitality" in {
|
||||
player.isInstanceOf[Vitality] mustEqual true
|
||||
try {
|
||||
player.getClass.getDeclaredMethod("DamageModel").hashCode()
|
||||
}
|
||||
catch {
|
||||
case _ : Exception =>
|
||||
ko //the method doesn't exist
|
||||
}
|
||||
|
||||
wep_tool.isInstanceOf[Vitality] mustEqual false
|
||||
try {
|
||||
wep_tool.getClass.getDeclaredMethod("DamageModel").hashCode()
|
||||
ko
|
||||
}
|
||||
catch {
|
||||
case _ : Exception =>
|
||||
ok //the method doesn't exist
|
||||
}
|
||||
ok
|
||||
}
|
||||
|
||||
"resolve infantry targets" in {
|
||||
val tplayer = Player(Avatar("TestCharacter2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
tplayer.Spawn
|
||||
tplayer.Health mustEqual 100
|
||||
tplayer.Armor mustEqual 50
|
||||
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(tplayer), tplayer.DamageModel, Vector3.Zero)
|
||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile)
|
||||
|
||||
func(tplayer)
|
||||
tplayer.Health mustEqual 87
|
||||
tplayer.Armor mustEqual 46
|
||||
}
|
||||
|
||||
"resolve infantry targets in a specific way" in {
|
||||
val tplayer = Player(Avatar("TestCharacter2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
tplayer.Spawn
|
||||
tplayer.Health mustEqual 100
|
||||
tplayer.Armor mustEqual 50
|
||||
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(tplayer), tplayer.DamageModel, Vector3.Zero)
|
||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
|
||||
|
||||
func(tplayer)
|
||||
tplayer.Health mustEqual 81
|
||||
tplayer.Armor mustEqual 35
|
||||
}
|
||||
|
||||
"resolve infantry targets, with damage overflow" in {
|
||||
val tplayer = Player(Avatar("TestCharacter2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
tplayer.Spawn
|
||||
tplayer.Health mustEqual 100
|
||||
tplayer.Armor mustEqual 50
|
||||
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(tplayer), tplayer.DamageModel, Vector3.Zero)
|
||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile)
|
||||
tplayer.Armor = 0
|
||||
|
||||
func(tplayer)
|
||||
tplayer.Health mustEqual 83
|
||||
tplayer.Armor mustEqual 0
|
||||
}
|
||||
|
||||
"resolve vehicle targets" in {
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
vehicle.Health mustEqual 650
|
||||
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(vehicle), vehicle.DamageModel, Vector3.Zero)
|
||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile)
|
||||
|
||||
func(vehicle)
|
||||
vehicle.Health mustEqual 641
|
||||
}
|
||||
|
||||
"resolve vehicle targets (with shields)" in {
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
vehicle.Shields = 10
|
||||
vehicle.Health mustEqual 650
|
||||
vehicle.Shields mustEqual 10
|
||||
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(vehicle), vehicle.DamageModel, Vector3.Zero)
|
||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile)
|
||||
|
||||
func(vehicle)
|
||||
vehicle.Health mustEqual 650
|
||||
vehicle.Shields mustEqual 1
|
||||
}
|
||||
|
||||
"resolve vehicle targets (losing shields)" in {
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
vehicle.Shields = 10
|
||||
vehicle.Health mustEqual 650
|
||||
vehicle.Shields mustEqual 10
|
||||
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(vehicle), vehicle.DamageModel, Vector3.Zero)
|
||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile)
|
||||
|
||||
func(vehicle)
|
||||
vehicle.Health mustEqual 650
|
||||
vehicle.Shields mustEqual 1
|
||||
func(vehicle)
|
||||
vehicle.Health mustEqual 642
|
||||
vehicle.Shields mustEqual 0
|
||||
}
|
||||
|
||||
"resolve vehicle targets in a specific way" in {
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
vehicle.Health mustEqual 650
|
||||
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(vehicle), vehicle.DamageModel, Vector3.Zero)
|
||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
|
||||
|
||||
func(vehicle)
|
||||
vehicle.Health mustEqual 632
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,29 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import net.psforever.objects.{GlobalDefinitions, LocalProjectile, Tool}
|
||||
import net.psforever.objects.ballistics.{DamageType, Projectile, ProjectileResolution, Projectiles}
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.ballistics._
|
||||
import net.psforever.objects.definition.ProjectileDefinition
|
||||
import net.psforever.types.Vector3
|
||||
import net.psforever.objects.serverobject.mblocker.Locker
|
||||
import net.psforever.objects.vital.DamageType
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types._
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
class ProjectileTest extends Specification {
|
||||
val player = Player(Avatar("TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
val fury = Vehicle(GlobalDefinitions.fury)
|
||||
|
||||
"LocalProjectile" should {
|
||||
"construct" in {
|
||||
val obj = new LocalProjectile() //since they're just placeholders, they only need to construct
|
||||
obj.Definition.ObjectId mustEqual 0
|
||||
obj.Definition.Name mustEqual "projectile"
|
||||
}
|
||||
|
||||
"local projectile range" in {
|
||||
Projectile.BaseUID < Projectile.RangeUID mustEqual true
|
||||
}
|
||||
}
|
||||
|
||||
"ProjectileDefinition" should {
|
||||
|
|
@ -151,48 +161,156 @@ class ProjectileTest extends Specification {
|
|||
}
|
||||
}
|
||||
|
||||
"Projectile" should {
|
||||
"construct" in {
|
||||
val beamer_wep = Tool(GlobalDefinitions.beamer)
|
||||
val projectile = beamer_wep.Projectile
|
||||
val obj = Projectile(projectile, beamer_wep.Definition, Vector3(1.2f, 3.4f, 5.6f), Vector3(0.2f, 0.4f, 0.6f))
|
||||
"SourceEntry" should {
|
||||
"construct for players" in {
|
||||
SourceEntry(player) match {
|
||||
case o : PlayerSource =>
|
||||
o.Name mustEqual "TestCharacter"
|
||||
o.Faction mustEqual PlanetSideEmpire.TR
|
||||
o.Seated mustEqual false
|
||||
o.ExoSuit mustEqual ExoSuitType.Standard
|
||||
o.Health mustEqual 0
|
||||
o.Armor mustEqual 0
|
||||
o.Definition mustEqual GlobalDefinitions.avatar
|
||||
o.Position mustEqual Vector3.Zero
|
||||
o.Orientation mustEqual Vector3.Zero
|
||||
o.Velocity mustEqual None
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
obj.profile mustEqual beamer_wep.Projectile
|
||||
obj.tool_def mustEqual GlobalDefinitions.beamer
|
||||
"construct for vehicles" in {
|
||||
SourceEntry(fury) match {
|
||||
case o : VehicleSource =>
|
||||
o.Name mustEqual "Fury"
|
||||
o.Faction mustEqual PlanetSideEmpire.TR
|
||||
o.Definition mustEqual GlobalDefinitions.fury
|
||||
o.Health mustEqual 650
|
||||
o.Shields mustEqual 0
|
||||
o.Position mustEqual Vector3.Zero
|
||||
o.Orientation mustEqual Vector3.Zero
|
||||
o.Velocity mustEqual None
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"construct for generic object" in {
|
||||
val obj = Locker()
|
||||
SourceEntry(obj) match {
|
||||
case o : ObjectSource =>
|
||||
o.obj mustEqual obj
|
||||
o.Name mustEqual "Mb Locker"
|
||||
o.Faction mustEqual PlanetSideEmpire.NEUTRAL
|
||||
o.Definition mustEqual GlobalDefinitions.mb_locker
|
||||
o.Position mustEqual Vector3.Zero
|
||||
o.Orientation mustEqual Vector3.Zero
|
||||
o.Velocity mustEqual None
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"contain timely information" in {
|
||||
val obj = Player(Avatar("TestCharacter-alt", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
obj.VehicleSeated = Some(PlanetSideGUID(1))
|
||||
obj.Position = Vector3(1.2f, 3.4f, 5.6f)
|
||||
obj.Orientation = Vector3(2.1f, 4.3f, 6.5f)
|
||||
obj.Velocity = Some(Vector3(1.1f, 2.2f, 3.3f))
|
||||
val sobj = SourceEntry(obj)
|
||||
obj.VehicleSeated = None
|
||||
obj.Position = Vector3.Zero
|
||||
obj.Orientation = Vector3.Zero
|
||||
obj.Velocity = None
|
||||
obj.ExoSuit = ExoSuitType.Agile
|
||||
|
||||
sobj match {
|
||||
case o : PlayerSource =>
|
||||
o.Name mustEqual "TestCharacter-alt"
|
||||
o.Faction mustEqual PlanetSideEmpire.TR
|
||||
o.Seated mustEqual true
|
||||
o.ExoSuit mustEqual ExoSuitType.Standard
|
||||
o.Definition mustEqual GlobalDefinitions.avatar
|
||||
o.Position mustEqual Vector3(1.2f, 3.4f, 5.6f)
|
||||
o.Orientation mustEqual Vector3(2.1f, 4.3f, 6.5f)
|
||||
o.Velocity mustEqual Some(Vector3(1.1f, 2.2f, 3.3f))
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Projectile" should {
|
||||
val beamer_def = GlobalDefinitions.beamer
|
||||
val beamer_wep = Tool(beamer_def)
|
||||
val firemode = beamer_wep.FireMode
|
||||
val projectile = beamer_wep.Projectile
|
||||
|
||||
"construct" in {
|
||||
val obj = Projectile(beamer_wep.Projectile, beamer_wep.Definition, beamer_wep.FireMode, PlayerSource(player), beamer_def.ObjectId, Vector3(1.2f, 3.4f, 5.6f), Vector3(0.2f, 0.4f, 0.6f))
|
||||
obj.profile mustEqual projectile
|
||||
obj.tool_def mustEqual beamer_def
|
||||
obj.fire_mode mustEqual firemode
|
||||
obj.owner match {
|
||||
case _ : PlayerSource =>
|
||||
ok
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
obj.attribute_to mustEqual obj.tool_def.ObjectId
|
||||
obj.shot_origin mustEqual Vector3(1.2f, 3.4f, 5.6f)
|
||||
obj.shot_angle mustEqual Vector3(0.2f, 0.4f, 0.6f)
|
||||
obj.resolution mustEqual ProjectileResolution.Unresolved
|
||||
obj.fire_time <= System.nanoTime mustEqual true
|
||||
obj.hit_time mustEqual 0
|
||||
obj.isResolved mustEqual false
|
||||
}
|
||||
|
||||
"construct (different attribute)" in {
|
||||
val obj1 = Projectile(beamer_wep.Projectile, beamer_wep.Definition, beamer_wep.FireMode, player, Vector3(1.2f, 3.4f, 5.6f), Vector3(0.2f, 0.4f, 0.6f))
|
||||
obj1.attribute_to mustEqual obj1.tool_def.ObjectId
|
||||
|
||||
val obj2 = Projectile(beamer_wep.Projectile, beamer_wep.Definition, beamer_wep.FireMode, PlayerSource(player), 65, Vector3(1.2f, 3.4f, 5.6f), Vector3(0.2f, 0.4f, 0.6f))
|
||||
obj2.attribute_to == obj2.tool_def.ObjectId mustEqual false
|
||||
obj2.attribute_to mustEqual 65
|
||||
}
|
||||
|
||||
"resolve" in {
|
||||
val beamer_wep = Tool(GlobalDefinitions.beamer)
|
||||
val projectile = beamer_wep.Projectile
|
||||
val obj = Projectile(projectile, beamer_wep.Definition, Vector3(1.2f, 3.4f, 5.6f), Vector3(0.2f, 0.4f, 0.6f))
|
||||
val obj2 = obj.Resolve(ProjectileResolution.MissedShot)
|
||||
val obj = Projectile(projectile, beamer_def, firemode, PlayerSource(player), beamer_def.ObjectId, Vector3.Zero, Vector3.Zero)
|
||||
obj.isResolved mustEqual false
|
||||
obj.isMiss mustEqual false
|
||||
|
||||
obj.resolution mustEqual ProjectileResolution.Unresolved
|
||||
obj.fire_time <= System.nanoTime mustEqual true
|
||||
obj.hit_time mustEqual 0
|
||||
obj2.resolution mustEqual ProjectileResolution.MissedShot
|
||||
obj2.fire_time == obj.fire_time mustEqual true
|
||||
obj2.hit_time <= System.nanoTime mustEqual true
|
||||
obj2.fire_time <= obj2.hit_time mustEqual true
|
||||
obj.Resolve()
|
||||
obj.isResolved mustEqual true
|
||||
obj.isMiss mustEqual false
|
||||
}
|
||||
|
||||
"resolve, with coordinates" in {
|
||||
val beamer_wep = Tool(GlobalDefinitions.beamer)
|
||||
val projectile = beamer_wep.Projectile
|
||||
val obj = Projectile(projectile, beamer_wep.Definition, Vector3(1.2f, 3.4f, 5.6f), Vector3(0.2f, 0.4f, 0.6f))
|
||||
val obj2 = obj.Resolve(Vector3(7.2f, 8.4f, 9.6f), Vector3(1.2f, 1.4f, 1.6f), ProjectileResolution.Resolved)
|
||||
"missed" in {
|
||||
val obj = Projectile(projectile, beamer_def, firemode, PlayerSource(player), beamer_def.ObjectId, Vector3.Zero, Vector3.Zero)
|
||||
obj.isResolved mustEqual false
|
||||
obj.isMiss mustEqual false
|
||||
|
||||
obj.resolution mustEqual ProjectileResolution.Unresolved
|
||||
obj.current.Position mustEqual Vector3.Zero
|
||||
obj.current.Orientation mustEqual Vector3.Zero
|
||||
obj2.resolution mustEqual ProjectileResolution.Resolved
|
||||
obj2.current.Position mustEqual Vector3(7.2f, 8.4f, 9.6f)
|
||||
obj2.current.Orientation mustEqual Vector3(1.2f, 1.4f, 1.6f)
|
||||
obj.Miss()
|
||||
obj.isResolved mustEqual true
|
||||
obj.isMiss mustEqual true
|
||||
}
|
||||
}
|
||||
|
||||
"ResolvedProjectile" should {
|
||||
val beamer_wep = Tool(GlobalDefinitions.beamer)
|
||||
val p_source = PlayerSource(player)
|
||||
val player2 = Player(Avatar("TestTarget", PlanetSideEmpire.NC, CharacterGender.Female, 1, CharacterVoice.Mute))
|
||||
val p2_source = PlayerSource(player2)
|
||||
val projectile = Projectile(beamer_wep.Projectile, GlobalDefinitions.beamer, beamer_wep.FireMode, p_source, GlobalDefinitions.beamer.ObjectId, Vector3.Zero, Vector3.Zero)
|
||||
val fury_dm = fury.DamageModel
|
||||
|
||||
"construct" in {
|
||||
val obj = ResolvedProjectile(ProjectileResolution.Hit, projectile, PlayerSource(player2), fury_dm, Vector3(1.2f, 3.4f, 5.6f), 123456L)
|
||||
obj.resolution mustEqual ProjectileResolution.Hit
|
||||
obj.projectile mustEqual projectile
|
||||
obj.target mustEqual p2_source
|
||||
obj.damage_model mustEqual fury.DamageModel
|
||||
obj.hit_pos mustEqual Vector3(1.2f, 3.4f, 5.6f)
|
||||
obj.hit_time mustEqual 123456L
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,16 @@ package objects
|
|||
import akka.actor.Props
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.ballistics.{PlayerSource, Projectile, ProjectileResolution, ResolvedProjectile}
|
||||
import net.psforever.objects.definition.{SeatDefinition, VehicleDefinition}
|
||||
import net.psforever.objects.serverobject.mount.Mountable
|
||||
import net.psforever.objects.vehicles._
|
||||
import net.psforever.objects.vital.{VehicleShieldCharge, Vitality}
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types.{CharacterVoice, ExoSuitType}
|
||||
import net.psforever.types._
|
||||
import org.specs2.mutable._
|
||||
|
||||
import scala.concurrent.duration.Duration
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class VehicleTest extends Specification {
|
||||
import VehicleTest._
|
||||
|
|
@ -611,6 +613,103 @@ class VehicleControlMountingOwnedUnlockedDriverSeatTest extends ActorTest {
|
|||
}
|
||||
}
|
||||
|
||||
class VehicleControlShieldsChargingTest extends ActorTest {
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
vehicle.GUID = PlanetSideGUID(10)
|
||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||
|
||||
"charge vehicle shields" in {
|
||||
assert(vehicle.Shields == 0)
|
||||
assert(!vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
||||
vehicle.Actor ! Vehicle.ChargeShields(15)
|
||||
|
||||
val msg = receiveOne(500 milliseconds)
|
||||
assert(msg.isInstanceOf[Vehicle.UpdateShieldsCharge])
|
||||
assert(vehicle.Shields == 15)
|
||||
assert(vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
||||
}
|
||||
}
|
||||
|
||||
class VehicleControlShieldsNotChargingVehicleDeadTest extends ActorTest {
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
vehicle.GUID = PlanetSideGUID(10)
|
||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||
|
||||
"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 ! Vehicle.ChargeShields(15)
|
||||
|
||||
expectNoMsg(1 seconds)
|
||||
assert(vehicle.Shields == 0)
|
||||
assert(!vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
||||
}
|
||||
}
|
||||
|
||||
class VehicleControlShieldsNotChargingVehicleShieldsFullTest extends ActorTest {
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
vehicle.GUID = PlanetSideGUID(10)
|
||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||
|
||||
"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)
|
||||
|
||||
expectNoMsg(1 seconds)
|
||||
assert(!vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
||||
}
|
||||
}
|
||||
|
||||
class VehicleControlShieldsNotChargingTooEarlyTest extends ActorTest {
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
vehicle.GUID = PlanetSideGUID(10)
|
||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||
|
||||
"charge vehicle shields" in {
|
||||
assert(vehicle.Shields == 0)
|
||||
vehicle.Actor ! Vehicle.ChargeShields(15)
|
||||
|
||||
val msg = receiveOne(200 milliseconds)
|
||||
assert(msg.isInstanceOf[Vehicle.UpdateShieldsCharge])
|
||||
assert(vehicle.Shields == 15)
|
||||
vehicle.Actor ! Vehicle.ChargeShields(15)
|
||||
|
||||
expectNoMsg(200 milliseconds)
|
||||
assert(vehicle.Shields == 15)
|
||||
}
|
||||
}
|
||||
|
||||
class VehicleControlShieldsNotChargingDamagedTest extends ActorTest {
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
vehicle.GUID = PlanetSideGUID(10)
|
||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||
//
|
||||
val beamer_wep = Tool(GlobalDefinitions.beamer)
|
||||
val p_source = PlayerSource( Player(Avatar("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 = ResolvedProjectile(ProjectileResolution.Hit, projectile, p_source, fury_dm, Vector3(1.2f, 3.4f, 5.6f), System.nanoTime)
|
||||
|
||||
"charge vehicle shields" in {
|
||||
assert(vehicle.Shields == 0)
|
||||
vehicle.Actor ! Vitality.Damage({case v : Vehicle => v.History(obj)})
|
||||
|
||||
val msg = receiveOne(200 milliseconds)
|
||||
assert(msg.isInstanceOf[Vitality.DamageResolution])
|
||||
assert(vehicle.Shields == 0)
|
||||
vehicle.Actor ! Vehicle.ChargeShields(15)
|
||||
|
||||
expectNoMsg(200 milliseconds)
|
||||
assert(vehicle.Shields == 0)
|
||||
}
|
||||
}
|
||||
|
||||
object VehicleTest {
|
||||
import net.psforever.objects.Avatar
|
||||
import net.psforever.types.{CharacterGender, PlanetSideEmpire}
|
||||
|
|
|
|||
83
common/src/test/scala/objects/VitalityTest.scala
Normal file
83
common/src/test/scala/objects/VitalityTest.scala
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import net.psforever.objects.ballistics._
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.vital._
|
||||
import net.psforever.types._
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
class VitalityTest extends Specification {
|
||||
"Vitality" should {
|
||||
val wep = GlobalDefinitions.galaxy_gunship_cannon
|
||||
val wep_fmode = Tool(wep).FireMode
|
||||
val proj = wep.ProjectileTypes.head
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
val vSource = VehicleSource(vehicle)
|
||||
|
||||
"accept a variety of events" in {
|
||||
val player = Player(Avatar("TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
val pSource = PlayerSource(player)
|
||||
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(player), player.DamageModel, Vector3(50, 50, 0))
|
||||
|
||||
player.History(resprojectile) //ResolvedProjectile, straight-up
|
||||
player.History(DamageFromProjectile(resprojectile))
|
||||
player.History(HealFromKit(pSource, 10, GlobalDefinitions.medkit))
|
||||
player.History(HealFromTerm(pSource, 10, 0, GlobalDefinitions.order_terminal))
|
||||
player.History(HealFromImplant(pSource, 10, ImplantType.AdvancedRegen))
|
||||
player.History(HealFromExoSuitChange(pSource, ExoSuitType.Standard))
|
||||
player.History(RepairFromTerm(vSource, 10, GlobalDefinitions.order_terminal))
|
||||
player.History(VehicleShieldCharge(vSource, 10))
|
||||
player.History(PlayerSuicide(pSource))
|
||||
ok
|
||||
}
|
||||
|
||||
"return and clear the former list of vital activities" in {
|
||||
val player = Player(Avatar("TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
val pSource = PlayerSource(player)
|
||||
|
||||
player.History(HealFromKit(pSource, 10, GlobalDefinitions.medkit))
|
||||
player.History(HealFromTerm(pSource, 10, 0, GlobalDefinitions.order_terminal))
|
||||
player.History(HealFromImplant(pSource, 10, ImplantType.AdvancedRegen))
|
||||
player.History(HealFromExoSuitChange(pSource, ExoSuitType.Standard))
|
||||
player.History(RepairFromTerm(vSource, 10, GlobalDefinitions.order_terminal))
|
||||
player.History(VehicleShieldCharge(vSource, 10))
|
||||
player.History(PlayerSuicide(pSource))
|
||||
player.History.size mustEqual 7
|
||||
|
||||
val list = player.ClearHistory()
|
||||
player.History.size mustEqual 0
|
||||
list.head.isInstanceOf[PlayerSuicide] mustEqual true
|
||||
list(1).isInstanceOf[VehicleShieldCharge] mustEqual true
|
||||
list(2).isInstanceOf[RepairFromTerm] mustEqual true
|
||||
list(3).isInstanceOf[HealFromExoSuitChange] mustEqual true
|
||||
list(4).isInstanceOf[HealFromImplant] mustEqual true
|
||||
list(5).isInstanceOf[HealFromTerm] mustEqual true
|
||||
list(6).isInstanceOf[HealFromKit] mustEqual true
|
||||
}
|
||||
|
||||
"get exactly one entry that was caused by projectile damage" in {
|
||||
val player = Player(Avatar("TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
val pSource = PlayerSource(player)
|
||||
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
|
||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Splash, projectile, SourceEntry(player), player.DamageModel, Vector3(50, 50, 0))
|
||||
|
||||
player.History(DamageFromProjectile(resprojectile))
|
||||
player.History(HealFromKit(pSource, 10, GlobalDefinitions.medkit))
|
||||
player.History(HealFromTerm(pSource, 10, 0, GlobalDefinitions.order_terminal))
|
||||
player.History(HealFromImplant(pSource, 10, ImplantType.AdvancedRegen))
|
||||
player.History(HealFromExoSuitChange(pSource, ExoSuitType.Standard))
|
||||
player.History(RepairFromTerm(vSource, 10, GlobalDefinitions.order_terminal))
|
||||
player.History(VehicleShieldCharge(vSource, 10))
|
||||
player.History(PlayerSuicide(pSource))
|
||||
|
||||
player.LastShot match {
|
||||
case Some(resolved_projectile) =>
|
||||
resolved_projectile.projectile mustEqual projectile
|
||||
case None =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue