mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-20 02:24:45 +00:00
949 lines
28 KiB
Scala
949 lines
28 KiB
Scala
// Copyright (c) 2017 PSForever
|
|
package objects
|
|
|
|
import net.psforever.objects._
|
|
import net.psforever.objects.vital.damage.{DamageProfile, _}
|
|
import net.psforever.objects.vital.projectile._
|
|
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.Vitality
|
|
import net.psforever.packet.game.objectcreate.ObjectClass
|
|
import net.psforever.types._
|
|
import org.specs2.mutable.Specification
|
|
import net.psforever.objects.avatar.Avatar
|
|
import net.psforever.objects.vital.base._
|
|
import net.psforever.objects.vital.interaction.DamageInteraction
|
|
|
|
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, CharacterSex.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 = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
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 {
|
|
SameHit.calculate(100, resprojectile) mustEqual 100
|
|
}
|
|
|
|
"degrade over distance damage modifier (no degrade)" in {
|
|
DistanceDegrade.calculate(100, resprojectile) == 100 mustEqual true
|
|
}
|
|
|
|
"cut off damage at max distance (no cutoff)" in {
|
|
MaxDistanceCutoff.calculate(100, resprojectile) == 100 mustEqual true
|
|
}
|
|
|
|
"cut off damage at max distance (cutoff)" in {
|
|
val cutoffprojectile = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(1500, 0, 0)
|
|
)
|
|
val damage = MaxDistanceCutoff.calculate(100, cutoffprojectile)
|
|
damage == 0 mustEqual true
|
|
}
|
|
|
|
"cut off damage at custom distance (no cutoff)" in {
|
|
CustomDistanceCutoff(10).calculate(100, resprojectile) == 0 mustEqual true
|
|
}
|
|
|
|
"cut off damage at custom distance (cutoff)" in {
|
|
val coffprojectile = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Splash,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(10, 0, 0)
|
|
)
|
|
CustomDistanceCutoff(2).calculate(100, coffprojectile) == 0 mustEqual true
|
|
}
|
|
|
|
"degrade over distance damage modifier (some degrade)" in {
|
|
val resprojectile2 = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Splash,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(100, 0, 0)
|
|
)
|
|
val damage = DistanceDegrade.calculate(100, resprojectile2)
|
|
damage < 100 && damage > 0 mustEqual true
|
|
}
|
|
|
|
"degrade over distance damage modifier (zero'd)" in {
|
|
val resprojectile2 = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Splash,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(1000, 0, 0)
|
|
)
|
|
DistanceDegrade.calculate(100, resprojectile2) == 0 mustEqual true
|
|
}
|
|
|
|
"degrade at radial distance damage modifier (no degrade)" in {
|
|
val resprojectile2 = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Splash,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(10, 0, 0)
|
|
)
|
|
RadialDegrade.calculate(100, resprojectile2) == 100 mustEqual true
|
|
}
|
|
|
|
"degrade at radial distance damage modifier (some degrade)" in {
|
|
val resprojectile2 = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Splash,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(12, 0, 0)
|
|
)
|
|
val damage = RadialDegrade.calculate(100, resprojectile2)
|
|
damage < 100 && damage > 0 mustEqual true
|
|
}
|
|
|
|
"degrade at radial distance damage modifier (zero'd)" in {
|
|
val resprojectile2 = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Splash,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(100, 0, 0)
|
|
)
|
|
RadialDegrade.calculate(100, resprojectile2) == 0 mustEqual true
|
|
}
|
|
|
|
"lash degrade (no lash; too close)" in {
|
|
val resprojectile2 = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Lash,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(5, 0, 0) //compared to Vector3(2, 2, 0)
|
|
)
|
|
Lash.calculate(100, resprojectile2) == 0 mustEqual true
|
|
}
|
|
|
|
"lash degrade (lash)" in {
|
|
val resprojectile2 = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Lash,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(20, 0, 0)
|
|
)
|
|
val damage = Lash.calculate(100, resprojectile2)
|
|
damage < 100 && damage > 0 mustEqual true
|
|
}
|
|
|
|
"lash degrade (no lash; too far)" in {
|
|
val resprojectile2 = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Lash,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(1000, 0, 0)
|
|
)
|
|
Lash.calculate(100, resprojectile2) == 0 mustEqual true
|
|
}
|
|
|
|
"fireball aggravated damage (aggravated splash burn" in {
|
|
// val burnWeapon = Tool(GlobalDefinitions.flamethrower)
|
|
// val burnProjectile = Projectile(
|
|
// burnWeapon.Projectile,
|
|
// burnWeapon.Definition,
|
|
// burnWeapon.FireMode,
|
|
// player,
|
|
// Vector3(2, 2, 0),
|
|
// Vector3.Zero
|
|
// )
|
|
val burnRes = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.AggravatedSplashBurn,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(15, 0, 0)
|
|
)
|
|
val resistance = target.DamageModel.ResistUsing(burnRes)(burnRes)
|
|
FireballAggravatedBurn.calculate(100, burnRes) == (1 + resistance) mustEqual true
|
|
}
|
|
|
|
"fireball aggravated damage (noral splash, no modification)" in {
|
|
// val burnWeapon = Tool(GlobalDefinitions.flamethrower)
|
|
// val burnProjectile = Projectile(
|
|
// burnWeapon.Projectile,
|
|
// burnWeapon.Definition,
|
|
// burnWeapon.FireMode,
|
|
// player,
|
|
// Vector3(2, 2, 0),
|
|
// Vector3.Zero
|
|
// )
|
|
val burnRes = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Splash,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(15, 0, 0)
|
|
)
|
|
FireballAggravatedBurn.calculate(100, burnRes) == 100 mustEqual true
|
|
}
|
|
|
|
val charge_weapon = Tool(GlobalDefinitions.spiker)
|
|
val charge_projectile = Projectile(
|
|
charge_weapon.Projectile,
|
|
charge_weapon.Definition,
|
|
charge_weapon.FireMode,
|
|
player,
|
|
Vector3(2, 2, 0),
|
|
Vector3.Zero
|
|
)
|
|
val minDamageBase = charge_weapon.Projectile.Charging.get.min.Damage0
|
|
val chargeBaseDamage = charge_weapon.Projectile.Damage0
|
|
|
|
"charge (none)" in {
|
|
val cprojectile = charge_projectile.quality(ProjectileQuality.Modified(0))
|
|
val rescprojectile = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
cprojectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(15, 0, 0)
|
|
)
|
|
val damage = SpikerChargeDamage.calculate(chargeBaseDamage, rescprojectile)
|
|
val calcDam = minDamageBase + math.floor(
|
|
chargeBaseDamage * rescprojectile.cause.asInstanceOf[ProjectileReason].projectile.quality.mod
|
|
)
|
|
damage mustEqual calcDam
|
|
}
|
|
|
|
"charge (half)" in {
|
|
val cprojectile = charge_projectile.quality(ProjectileQuality.Modified(0.5f))
|
|
val rescprojectile = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
cprojectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(15, 0, 0)
|
|
)
|
|
val damage = SpikerChargeDamage.calculate(chargeBaseDamage, rescprojectile)
|
|
val calcDam = minDamageBase + math.floor(
|
|
chargeBaseDamage * rescprojectile.cause.asInstanceOf[ProjectileReason].projectile.quality.mod
|
|
)
|
|
damage mustEqual calcDam
|
|
}
|
|
|
|
"charge (full)" in {
|
|
val cprojectile = charge_projectile.quality(ProjectileQuality.Modified(1))
|
|
val rescprojectile = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
cprojectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(15, 0, 0)
|
|
)
|
|
val damage = SpikerChargeDamage.calculate(chargeBaseDamage, rescprojectile)
|
|
val calcDam = minDamageBase + chargeBaseDamage
|
|
damage mustEqual calcDam
|
|
}
|
|
|
|
val flak_weapon = Tool(GlobalDefinitions.trhev_burster)
|
|
val flak_projectile = Projectile(
|
|
flak_weapon.Projectile,
|
|
flak_weapon.Definition,
|
|
flak_weapon.FireMode,
|
|
player,
|
|
Vector3(2, 2, 0),
|
|
Vector3.Zero
|
|
)
|
|
|
|
"flak hit (resolution is splash, no degrade)" in {
|
|
val resfprojectile = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Splash,
|
|
flak_projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(10, 0, 0)
|
|
)
|
|
val damage = FlakHit.calculate(100, resfprojectile)
|
|
damage == 100 mustEqual true
|
|
}
|
|
|
|
"flak hit (resolution is hit, no degrade)" in {
|
|
val resfprojectile = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
flak_projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(10, 0, 0)
|
|
)
|
|
val damage = FlakHit.calculate(100, resfprojectile)
|
|
damage == 100 mustEqual true
|
|
}
|
|
|
|
"flak burst (resolution is hit)" in {
|
|
val resfprojectile = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
flak_projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(15, 0, 0)
|
|
)
|
|
val damage = FlakBurst.calculate(100, resfprojectile)
|
|
damage == 100 mustEqual true
|
|
}
|
|
|
|
"flak burst (resolution is splash, no degrade)" in {
|
|
val resfprojectile = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Splash,
|
|
flak_projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(10, 0, 0)
|
|
)
|
|
val damage = FlakBurst.calculate(100, resfprojectile)
|
|
damage == 100 mustEqual true
|
|
}
|
|
|
|
"flak burst (resolution is splash, some degrade)" in {
|
|
val resfprojectile = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Splash,
|
|
flak_projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(5, 0, 0)
|
|
)
|
|
val damage = FlakBurst.calculate(100, resfprojectile)
|
|
damage < 100 mustEqual true
|
|
}
|
|
|
|
"galaxy gunship reduction (target is galaxy_gunship, no shields)" in {
|
|
val vehicle = Vehicle(GlobalDefinitions.galaxy_gunship)
|
|
val resfprojectile = DamageInteraction(
|
|
SourceEntry(vehicle),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
vehicle.DamageModel
|
|
),
|
|
Vector3(5, 0, 0)
|
|
)
|
|
val damage = GalaxyGunshipReduction(0.63f).calculate(100, resfprojectile)
|
|
damage == 63 mustEqual true
|
|
}
|
|
|
|
"galaxy gunship reduction (target is galaxy_gunship)" in {
|
|
val vehicle = Vehicle(GlobalDefinitions.galaxy_gunship)
|
|
vehicle.Shields = 1
|
|
val resfprojectile = DamageInteraction(
|
|
SourceEntry(vehicle),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
vehicle.DamageModel
|
|
),
|
|
Vector3(5, 0, 0)
|
|
)
|
|
val damage = GalaxyGunshipReduction(0.63f).calculate(100, resfprojectile)
|
|
damage == 100 mustEqual true
|
|
}
|
|
|
|
"galaxy gunship reduction (target is vehicle, but not a galaxy_gunship)" in {
|
|
val resfprojectile = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3(5, 0, 0)
|
|
)
|
|
val damage = GalaxyGunshipReduction(0.63f).calculate(100, resfprojectile)
|
|
damage == 100 mustEqual true
|
|
}
|
|
|
|
"galaxy gunship reduction (target is not a vehicle)" in {
|
|
val tplayer =
|
|
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute))
|
|
val resfprojectile = DamageInteraction(
|
|
SourceEntry(tplayer),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
tplayer.DamageModel
|
|
),
|
|
Vector3(5, 0, 0)
|
|
)
|
|
val damage = GalaxyGunshipReduction(0.63f).calculate(100, resfprojectile)
|
|
damage == 100 mustEqual true
|
|
}
|
|
|
|
"extract a complete damage profile" in {
|
|
val result1 = RadialDegrade.calculate(
|
|
AgainstVehicle(proj_prof) + AgainstVehicle(wep_prof),
|
|
resprojectile
|
|
)
|
|
val result2 = DamageCalculations.WithModifiers(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, CharacterSex.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 = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
target.DamageModel
|
|
),
|
|
Vector3.Zero
|
|
)
|
|
InvalidTarget(resprojectile).isFailure mustEqual true
|
|
}
|
|
|
|
"discern standard infantry targets" in {
|
|
val target = player
|
|
val resprojectile = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
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, CharacterSex.Male, 0, CharacterVoice.Mute))
|
|
target.ExoSuit = ExoSuitType.MAX
|
|
val resprojectile = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
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 = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
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 = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
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, CharacterSex.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 = DamageInteraction(
|
|
SourceEntry(target),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
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 = DamageInteraction(
|
|
SourceEntry(target1),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
target1.DamageModel
|
|
),
|
|
Vector3.Zero
|
|
)
|
|
InfantryDamage(resprojectile1)(50, 10) mustEqual (0, 0)
|
|
|
|
val target2 = player
|
|
val resprojectile2 = DamageInteraction(
|
|
SourceEntry(target2),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
target2.DamageModel
|
|
),
|
|
Vector3.Zero
|
|
)
|
|
InfantryDamage(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, CharacterSex.Male, 0, CharacterVoice.Mute))
|
|
player2.ExoSuit = ExoSuitType.MAX
|
|
player2.Spawn()
|
|
"calculate no max damage for vehicles" in {
|
|
val target1 = Vehicle(GlobalDefinitions.fury) //!
|
|
val resprojectile1 = DamageInteraction(
|
|
SourceEntry(target1),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
target1.DamageModel
|
|
),
|
|
Vector3.Zero
|
|
)
|
|
MaxDamage(resprojectile1)(50, 10) mustEqual (0, 0)
|
|
|
|
val target2 = player2
|
|
val resprojectile2 = DamageInteraction(
|
|
SourceEntry(target2),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
target2.DamageModel
|
|
),
|
|
Vector3.Zero
|
|
)
|
|
MaxDamage(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 = DamageInteraction(
|
|
SourceEntry(target1),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
target1.DamageModel
|
|
),
|
|
Vector3.Zero
|
|
)
|
|
VehicleDamageAfterResist(resprojectile1)(50, 10) mustEqual 40
|
|
|
|
val target2 = Vehicle(GlobalDefinitions.fury) //!
|
|
val resprojectile2 = DamageInteraction(
|
|
SourceEntry(target2),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
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, CharacterSex.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, CharacterSex.Male, 0, CharacterVoice.Mute))
|
|
tplayer.Spawn()
|
|
tplayer.Health mustEqual 100
|
|
tplayer.Armor mustEqual 50
|
|
|
|
val resprojectile = DamageInteraction(
|
|
SourceEntry(tplayer),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
tplayer.DamageModel
|
|
),
|
|
Vector3.Zero
|
|
)
|
|
val func = resprojectile.calculate()
|
|
func(tplayer)
|
|
tplayer.Health mustEqual 65
|
|
tplayer.Armor mustEqual 35
|
|
}
|
|
|
|
"resolve infantry targets in a specific way" in {
|
|
val tplayer =
|
|
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute))
|
|
tplayer.Spawn()
|
|
tplayer.Health mustEqual 100
|
|
tplayer.Armor mustEqual 50
|
|
|
|
val resprojectile = DamageInteraction(
|
|
SourceEntry(tplayer),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
tplayer.DamageModel
|
|
),
|
|
Vector3.Zero
|
|
)
|
|
val func = resprojectile.calculate(DamageType.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, CharacterSex.Male, 0, CharacterVoice.Mute))
|
|
tplayer.Spawn()
|
|
tplayer.Health mustEqual 100
|
|
tplayer.Armor mustEqual 50
|
|
|
|
val resprojectile = DamageInteraction(
|
|
SourceEntry(tplayer),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
tplayer.DamageModel
|
|
),
|
|
Vector3.Zero
|
|
)
|
|
val func = resprojectile.calculate()
|
|
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 = DamageInteraction(
|
|
SourceEntry(vehicle),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
vehicle.DamageModel
|
|
),
|
|
Vector3.Zero
|
|
)
|
|
val func = resprojectile.calculate()
|
|
|
|
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 = DamageInteraction(
|
|
SourceEntry(vehicle),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
vehicle.DamageModel
|
|
),
|
|
Vector3.Zero
|
|
)
|
|
val func = resprojectile.calculate()
|
|
|
|
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 = DamageInteraction(
|
|
SourceEntry(vehicle),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
vehicle.DamageModel
|
|
),
|
|
Vector3.Zero
|
|
)
|
|
val func = resprojectile.calculate()
|
|
|
|
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 = DamageInteraction(
|
|
SourceEntry(vehicle),
|
|
ProjectileReason(
|
|
DamageResolution.Hit,
|
|
projectile,
|
|
vehicle.DamageModel
|
|
),
|
|
Vector3.Zero
|
|
)
|
|
val func = resprojectile.calculate(DamageType.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 = RadialDegrade
|
|
}
|
|
|
|
final val vehicle = new VehicleDefinition(ObjectClass.fury) {
|
|
MaxHealth = 650
|
|
Damageable = true
|
|
Repairable = true
|
|
RepairIfDestroyed = false
|
|
MaxShields = 130 + 1
|
|
}
|
|
}
|