Restructure repository

* Move /common/src to /src
* Move services to net.psforever package
* Move /pslogin to /server
This commit is contained in:
Jakob Gillich 2020-08-23 03:26:06 +02:00
parent 89a30ae6f6
commit f4fd78fc5d
958 changed files with 527 additions and 725 deletions

View file

@ -0,0 +1,608 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects._
import net.psforever.objects.vital.damage.{DamageCalculations, DamageModifiers, 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.definition.{ProjectileDefinition, VehicleDefinition}
import net.psforever.objects.vital.{DamageType, Vitality}
import net.psforever.packet.game.objectcreate.ObjectClass
import net.psforever.types._
import org.specs2.mutable.Specification
import net.psforever.objects.avatar.Avatar
class DamageCalculationsTests extends Specification {
"DamageCalculations" should {
val wep = GlobalDefinitions.galaxy_gunship_cannon
val wep_fmode = Tool(wep).FireMode
val wep_prof = wep_fmode.Add
val proj = DamageModelTests.projectile
val proj_prof = proj.asInstanceOf[DamageProfile]
val player = Player(Avatar(0, "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(15, 0, 0)
)
"extract no damage numbers" in {
AgainstNothing(proj_prof) mustEqual 0
}
"extract damage against exosuit target" in {
AgainstExoSuit(proj_prof) == proj_prof.Damage0 mustEqual true
}
"extract damage against MAX target" in {
AgainstMaxSuit(proj_prof) == proj_prof.Damage3 mustEqual true
}
"extract damage against vehicle target" in {
AgainstVehicle(proj_prof) == proj_prof.Damage1 mustEqual true
}
"extract damage against aircraft target" in {
AgainstAircraft(proj_prof) == proj_prof.Damage2 mustEqual true
}
"extract damage against battleframe robotics" in {
AgainstBFR(proj_prof) == proj_prof.Damage4 mustEqual true
}
"no degrade damage modifier" in {
DamageModifiers.SameHit.Calculate(100, resprojectile) mustEqual 100
}
"degrade over distance damage modifier (no degrade)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(10, 0, 0)
)
DamageModifiers.DistanceDegrade.Calculate(100, resprojectile2) == 100 mustEqual true
}
"degrade over distance damage modifier (some degrade)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(100, 0, 0)
)
val damage = DamageModifiers.DistanceDegrade.Calculate(100, resprojectile2)
damage < 100 && damage > 0 mustEqual true
}
"degrade over distance damage modifier (zero'd)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(1000, 0, 0)
)
DamageModifiers.DistanceDegrade.Calculate(100, resprojectile2) == 0 mustEqual true
}
"degrade at radial distance damage modifier (no degrade)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(10, 0, 0)
)
DamageModifiers.RadialDegrade.Calculate(100, resprojectile2) == 100 mustEqual true
}
"degrade at radial distance damage modifier (some degrade)" in {
val damage = DamageModifiers.RadialDegrade.Calculate(100, resprojectile)
damage < 100 && damage > 0 mustEqual true
}
"degrade at radial distance damage modifier (zero'd)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(1000, 0, 0)
)
DamageModifiers.RadialDegrade.Calculate(100, resprojectile2) == 0 mustEqual true
}
"lash degrade (no lash; too close)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Lash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(5, 0, 0) //compared to Vector3(2, 2, 0)
)
DamageModifiers.Lash.Calculate(100, resprojectile2) == 0 mustEqual true
}
"lash degrade (lash)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Lash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(20, 0, 0)
)
val damage = DamageModifiers.Lash.Calculate(100, resprojectile2)
damage < 100 && damage > 0 mustEqual true
}
"lash degrade (no lash; too far)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Lash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(1000, 0, 0)
)
DamageModifiers.Lash.Calculate(100, resprojectile2) == 0 mustEqual true
}
"extract a complete damage profile" in {
val result1 = DamageModifiers.RadialDegrade.Calculate(
AgainstVehicle(proj_prof) + AgainstVehicle(wep_prof),
resprojectile
)
val result2 = DamageCalculations.DamageWithModifiers(AgainstVehicle, resprojectile)
result1 mustEqual result2
}
}
}
class ResistanceCalculationsTests extends Specification {
val wep = GlobalDefinitions.galaxy_gunship_cannon
val wep_fmode = Tool(wep).FireMode
val proj = DamageModelTests.projectile
val player = Player(Avatar(0, "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(0, "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.galaxy_gunship_cannon
val wep_fmode = Tool(wep).FireMode
val proj = DamageModelTests.projectile
val player = Player(Avatar(0, "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 bleed through 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(0, "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.galaxy_gunship_cannon
val wep_tool = Tool(wep)
val wep_fmode = wep_tool.FireMode
val proj = DamageModelTests.projectile
val player = Player(Avatar(0, "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(0, "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 => ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
func(tplayer)
tplayer.Health mustEqual 54
tplayer.Armor mustEqual 46
}
"resolve infantry targets in a specific way" in {
val tplayer =
Player(Avatar(0, "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 => ResolvedProjectile =
resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
func(tplayer)
tplayer.Health mustEqual 65
tplayer.Armor mustEqual 35
}
"resolve infantry targets, with damage overflow" in {
val tplayer =
Player(Avatar(0, "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 => ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
tplayer.Armor = 0
func(tplayer)
tplayer.Health mustEqual 50
tplayer.Armor mustEqual 0
}
"resolve vehicle targets" in {
val vehicle = Vehicle(DamageModelTests.vehicle)
vehicle.Health mustEqual 650
val resprojectile = ResolvedProjectile(
ProjectileResolution.Hit,
projectile,
SourceEntry(vehicle),
vehicle.DamageModel,
Vector3.Zero
)
val func: Any => ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
func(vehicle)
vehicle.Health mustEqual 518
}
"resolve vehicle targets (with shields)" in {
val vehicle = Vehicle(DamageModelTests.vehicle)
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 => ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
func(vehicle)
vehicle.Health mustEqual 528
vehicle.Shields mustEqual 0
}
"resolve vehicle targets (losing shields)" in {
val vehicle = Vehicle(DamageModelTests.vehicle)
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 => ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
func(vehicle)
vehicle.Health mustEqual 528
vehicle.Shields mustEqual 0
func(vehicle)
vehicle.Health mustEqual 396
vehicle.Shields mustEqual 0
}
"resolve vehicle targets in a specific way" in {
val vehicle = Vehicle(DamageModelTests.vehicle)
vehicle.Health mustEqual 650
val resprojectile = ResolvedProjectile(
ProjectileResolution.Hit,
projectile,
SourceEntry(vehicle),
vehicle.DamageModel,
Vector3.Zero
)
val func: Any => ResolvedProjectile =
resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
func(vehicle)
vehicle.Health mustEqual 518
}
}
}
object DamageModelTests {
final val projectile = new ProjectileDefinition(Projectiles.heavy_grenade_projectile.id) {
Damage0 = 50
Damage1 = 82
Damage2 = 82
Damage3 = 75
Damage4 = 66
DamageAtEdge = 0.1f
DamageRadius = 5f
DegradeMultiplier = 0.5f
LashRadius = 5f
ProjectileDamageType = DamageType.Splash
InitialVelocity = 75
Lifespan = 5f
ProjectileDefinition.CalculateDerivedFields(pdef = this)
Modifiers = DamageModifiers.RadialDegrade
}
final val vehicle = new VehicleDefinition(ObjectClass.fury) {
MaxHealth = 650
Damageable = true
Repairable = true
RepairIfDestroyed = false
MaxShields = 130 + 1
}
}