mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-12 15:04:39 +00:00
modifiers for flak burst (#579)
This commit is contained in:
parent
d67119b255
commit
d70d23deb8
3 changed files with 450 additions and 150 deletions
|
|
@ -2356,7 +2356,11 @@ object GlobalDefinitions {
|
||||||
burster_projectile.InitialVelocity = 125
|
burster_projectile.InitialVelocity = 125
|
||||||
burster_projectile.Lifespan = 4f
|
burster_projectile.Lifespan = 4f
|
||||||
ProjectileDefinition.CalculateDerivedFields(burster_projectile)
|
ProjectileDefinition.CalculateDerivedFields(burster_projectile)
|
||||||
//TODO burster_projectile.Modifiers = DamageModifiers.RadialDegrade?
|
burster_projectile.Modifiers = List(
|
||||||
|
//DamageModifiers.FlakHit,
|
||||||
|
DamageModifiers.FlakBurst,
|
||||||
|
DamageModifiers.MaxDistanceCutoff
|
||||||
|
)
|
||||||
|
|
||||||
chainblade_projectile.Name = "chainblade_projectile"
|
chainblade_projectile.Name = "chainblade_projectile"
|
||||||
// TODO for later, maybe : set_resource_parent chainblade_projectile game_objects melee_ammo_projectile
|
// TODO for later, maybe : set_resource_parent chainblade_projectile game_objects melee_ammo_projectile
|
||||||
|
|
@ -2396,7 +2400,11 @@ object GlobalDefinitions {
|
||||||
colossus_burster_projectile.InitialVelocity = 175
|
colossus_burster_projectile.InitialVelocity = 175
|
||||||
colossus_burster_projectile.Lifespan = 2.5f
|
colossus_burster_projectile.Lifespan = 2.5f
|
||||||
ProjectileDefinition.CalculateDerivedFields(colossus_burster_projectile)
|
ProjectileDefinition.CalculateDerivedFields(colossus_burster_projectile)
|
||||||
//TODO colossus_burster_projectile.Modifiers = DamageModifiers.RadialDegrade?
|
colossus_burster_projectile.Modifiers = List(
|
||||||
|
//DamageModifiers.FlakHit,
|
||||||
|
DamageModifiers.FlakBurst,
|
||||||
|
DamageModifiers.MaxDistanceCutoff
|
||||||
|
)
|
||||||
|
|
||||||
colossus_chaingun_projectile.Name = "colossus_chaingun_projectile"
|
colossus_chaingun_projectile.Name = "colossus_chaingun_projectile"
|
||||||
// TODO for later, maybe : set_resource_parent colossus_chaingun_projectile game_objects 35mmbullet_projectile
|
// TODO for later, maybe : set_resource_parent colossus_chaingun_projectile game_objects 35mmbullet_projectile
|
||||||
|
|
@ -3448,7 +3456,11 @@ object GlobalDefinitions {
|
||||||
phalanx_flak_projectile.InitialVelocity = 100
|
phalanx_flak_projectile.InitialVelocity = 100
|
||||||
phalanx_flak_projectile.Lifespan = 5f
|
phalanx_flak_projectile.Lifespan = 5f
|
||||||
ProjectileDefinition.CalculateDerivedFields(phalanx_flak_projectile)
|
ProjectileDefinition.CalculateDerivedFields(phalanx_flak_projectile)
|
||||||
//TODO phalanx_flak_projectile.Modifiers = DamageModifiers.RadialDegrade?
|
phalanx_flak_projectile.Modifiers = List(
|
||||||
|
//DamageModifiers.FlakHit,
|
||||||
|
DamageModifiers.FlakBurst,
|
||||||
|
DamageModifiers.MaxDistanceCutoff
|
||||||
|
)
|
||||||
|
|
||||||
phalanx_projectile.Name = "phalanx_projectile"
|
phalanx_projectile.Name = "phalanx_projectile"
|
||||||
phalanx_projectile.Damage0 = 20
|
phalanx_projectile.Damage0 = 20
|
||||||
|
|
@ -3747,7 +3759,11 @@ object GlobalDefinitions {
|
||||||
rocklet_flak_projectile.InitialVelocity = 60
|
rocklet_flak_projectile.InitialVelocity = 60
|
||||||
rocklet_flak_projectile.Lifespan = 3.2f
|
rocklet_flak_projectile.Lifespan = 3.2f
|
||||||
ProjectileDefinition.CalculateDerivedFields(rocklet_flak_projectile)
|
ProjectileDefinition.CalculateDerivedFields(rocklet_flak_projectile)
|
||||||
//TODO rocklet_flak_projectile.Modifiers = DamageModifiers.RadialDegrade?
|
rocklet_flak_projectile.Modifiers = List(
|
||||||
|
//DamageModifiers.FlakHit,
|
||||||
|
DamageModifiers.FlakBurst,
|
||||||
|
DamageModifiers.MaxDistanceCutoff
|
||||||
|
)
|
||||||
|
|
||||||
rocklet_jammer_projectile.Name = "rocklet_jammer_projectile"
|
rocklet_jammer_projectile.Name = "rocklet_jammer_projectile"
|
||||||
rocklet_jammer_projectile.Damage0 = 0
|
rocklet_jammer_projectile.Damage0 = 0
|
||||||
|
|
@ -3826,7 +3842,11 @@ object GlobalDefinitions {
|
||||||
skyguard_flak_cannon_projectile.InitialVelocity = 100
|
skyguard_flak_cannon_projectile.InitialVelocity = 100
|
||||||
skyguard_flak_cannon_projectile.Lifespan = 5f
|
skyguard_flak_cannon_projectile.Lifespan = 5f
|
||||||
ProjectileDefinition.CalculateDerivedFields(skyguard_flak_cannon_projectile)
|
ProjectileDefinition.CalculateDerivedFields(skyguard_flak_cannon_projectile)
|
||||||
//TODO skyguard_flak_cannon_projectile.Modifiers = DamageModifiers.RadialDegrade?
|
skyguard_flak_cannon_projectile.Modifiers = List(
|
||||||
|
//DamageModifiers.FlakHit,
|
||||||
|
DamageModifiers.FlakBurst,
|
||||||
|
DamageModifiers.MaxDistanceCutoff
|
||||||
|
)
|
||||||
|
|
||||||
sparrow_projectile.Name = "sparrow_projectile"
|
sparrow_projectile.Name = "sparrow_projectile"
|
||||||
sparrow_projectile.Damage0 = 35
|
sparrow_projectile.Damage0 = 35
|
||||||
|
|
@ -3894,7 +3914,11 @@ object GlobalDefinitions {
|
||||||
spitfire_aa_ammo_projectile.InitialVelocity = 100
|
spitfire_aa_ammo_projectile.InitialVelocity = 100
|
||||||
spitfire_aa_ammo_projectile.Lifespan = 5f
|
spitfire_aa_ammo_projectile.Lifespan = 5f
|
||||||
ProjectileDefinition.CalculateDerivedFields(spitfire_aa_ammo_projectile)
|
ProjectileDefinition.CalculateDerivedFields(spitfire_aa_ammo_projectile)
|
||||||
//TODO spitfire_aa_ammo_projectile.Modifiers = DamageModifiers.RadialDegrade?
|
spitfire_aa_ammo_projectile.Modifiers = List(
|
||||||
|
//DamageModifiers.FlakHit,
|
||||||
|
DamageModifiers.FlakBurst,
|
||||||
|
DamageModifiers.MaxDistanceCutoff
|
||||||
|
)
|
||||||
|
|
||||||
spitfire_ammo_projectile.Name = "spitfire_ammo_projectile"
|
spitfire_ammo_projectile.Name = "spitfire_ammo_projectile"
|
||||||
spitfire_ammo_projectile.Damage0 = 15
|
spitfire_ammo_projectile.Damage0 = 15
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ object DamageModifiers {
|
||||||
private def function(damage: Int, data: ResolvedProjectile): Int = damage
|
private def function(damage: Int, data: ResolvedProjectile): Int = damage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** If the calculated distance is greater than the maximum distance of the projectile, damage is zero'd. */
|
||||||
case object MaxDistanceCutoff extends Mod {
|
case object MaxDistanceCutoff extends Mod {
|
||||||
def Calculate: DamageModifiers.Format = function
|
def Calculate: DamageModifiers.Format = function
|
||||||
|
|
||||||
|
|
@ -62,6 +63,21 @@ object DamageModifiers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** If the calculated distance is greater than a custom distance, damage is zero'd. */
|
||||||
|
case class CustomDistanceCutoff(cutoff: Float) extends Mod {
|
||||||
|
def Calculate: DamageModifiers.Format = function
|
||||||
|
|
||||||
|
private def function(damage: Int, data: ResolvedProjectile): Int = {
|
||||||
|
val projectile = data.projectile
|
||||||
|
val distance = Vector3.Distance(data.hit_pos, projectile.shot_origin)
|
||||||
|
if (distance <= cutoff) {
|
||||||
|
damage
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The input value degrades (lessens)
|
* The input value degrades (lessens)
|
||||||
* the further the distance between the point of origin (`shot_origin`)
|
* the further the distance between the point of origin (`shot_origin`)
|
||||||
|
|
@ -70,22 +86,7 @@ object DamageModifiers {
|
||||||
* If the value is encountered beyond its maximum distance, the value is zero'd.
|
* If the value is encountered beyond its maximum distance, the value is zero'd.
|
||||||
*/
|
*/
|
||||||
case object DistanceDegrade extends Mod {
|
case object DistanceDegrade extends Mod {
|
||||||
def Calculate: DamageModifiers.Format = function
|
def Calculate: DamageModifiers.Format = distanceDegradeFunction
|
||||||
|
|
||||||
private def function(damage: Int, data: ResolvedProjectile): Int = {
|
|
||||||
val projectile = data.projectile
|
|
||||||
val profile = projectile.profile
|
|
||||||
val distance = Vector3.Distance(data.hit_pos, projectile.shot_origin)
|
|
||||||
if (distance <= profile.DistanceMax) {
|
|
||||||
if (profile.DistanceNoDegrade == profile.DistanceMax || distance <= profile.DistanceNoDegrade) {
|
|
||||||
damage
|
|
||||||
} else {
|
|
||||||
damage - ((damage - profile.DegradeMultiplier * damage) * ((distance - profile.DistanceNoDegrade) / (profile.DistanceMax - profile.DistanceNoDegrade))).toInt
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -95,24 +96,7 @@ object DamageModifiers {
|
||||||
* If the value is encountered beyond its maximum radial distance, the value is zero'd.
|
* If the value is encountered beyond its maximum radial distance, the value is zero'd.
|
||||||
*/
|
*/
|
||||||
case object RadialDegrade extends Mod {
|
case object RadialDegrade extends Mod {
|
||||||
def Calculate: DamageModifiers.Format = function
|
def Calculate: DamageModifiers.Format = radialDegradeFunction
|
||||||
|
|
||||||
private def function(damage: Int, data: ResolvedProjectile): Int = {
|
|
||||||
val profile = data.projectile.profile
|
|
||||||
val distance = Vector3.Distance(data.hit_pos, data.target.Position)
|
|
||||||
val radius = profile.DamageRadius
|
|
||||||
val radiusMin = profile.DamageRadiusMin
|
|
||||||
if (distance <= radiusMin) {
|
|
||||||
damage
|
|
||||||
} else if (distance <= radius) {
|
|
||||||
//damage - (damage * profile.DamageAtEdge * (distance - radiusMin) / (radius - radiusMin)).toInt
|
|
||||||
val base = profile.DamageAtEdge
|
|
||||||
val radi = radius - radiusMin
|
|
||||||
(damage * ((1 - base) * ((radi - (distance - radiusMin)) / radi) + base)).toInt
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,7 +123,7 @@ object DamageModifiers {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Below this point are the calculations for sources of aggravated damage.
|
Aggravated damage.
|
||||||
For the most part, these calculations are individualistic and arbitrary.
|
For the most part, these calculations are individualistic and arbitrary.
|
||||||
They exist in their current form to satisfy observed shots to kill (STK) of specific weapon systems
|
They exist in their current form to satisfy observed shots to kill (STK) of specific weapon systems
|
||||||
according to 2012 standards of the Youtube video series by TheLegendaryNarwhal.
|
according to 2012 standards of the Youtube video series by TheLegendaryNarwhal.
|
||||||
|
|
@ -150,7 +134,7 @@ object DamageModifiers {
|
||||||
*/
|
*/
|
||||||
case object InfantryAggravatedDirect extends Mod {
|
case object InfantryAggravatedDirect extends Mod {
|
||||||
def Calculate: DamageModifiers.Format =
|
def Calculate: DamageModifiers.Format =
|
||||||
BaseAggravatedFormula(ProjectileResolution.AggravatedDirect, DamageType.Direct)
|
baseAggravatedFormula(ProjectileResolution.AggravatedDirect, DamageType.Direct)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -159,7 +143,7 @@ object DamageModifiers {
|
||||||
*/
|
*/
|
||||||
case object InfantryAggravatedSplash extends Mod {
|
case object InfantryAggravatedSplash extends Mod {
|
||||||
def Calculate: DamageModifiers.Format =
|
def Calculate: DamageModifiers.Format =
|
||||||
BaseAggravatedFormula(ProjectileResolution.AggravatedSplash, DamageType.Splash)
|
baseAggravatedFormula(ProjectileResolution.AggravatedSplash, DamageType.Splash)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -169,7 +153,7 @@ object DamageModifiers {
|
||||||
*/
|
*/
|
||||||
case object InfantryAggravatedDirectBurn extends Mod {
|
case object InfantryAggravatedDirectBurn extends Mod {
|
||||||
def Calculate: DamageModifiers.Format =
|
def Calculate: DamageModifiers.Format =
|
||||||
BaseAggravatedBurnFormula(ProjectileResolution.AggravatedDirectBurn, DamageType.Direct)
|
baseAggravatedBurnFormula(ProjectileResolution.AggravatedDirectBurn, DamageType.Direct)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -179,110 +163,7 @@ object DamageModifiers {
|
||||||
*/
|
*/
|
||||||
case object InfantryAggravatedSplashBurn extends Mod {
|
case object InfantryAggravatedSplashBurn extends Mod {
|
||||||
def Calculate: DamageModifiers.Format =
|
def Calculate: DamageModifiers.Format =
|
||||||
BaseAggravatedBurnFormula(ProjectileResolution.AggravatedSplashBurn, DamageType.Splash)
|
baseAggravatedBurnFormula(ProjectileResolution.AggravatedSplashBurn, DamageType.Splash)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For damage application that involves aggravation of a particular damage type,
|
|
||||||
* calculate that initial damage application for infantry targets
|
|
||||||
* and produce the modified damage value.
|
|
||||||
* Infantry wearing mechanized assault exo-suits (MAX) incorporate an additional modifier.
|
|
||||||
* @see `AggravatedDamage`
|
|
||||||
* @see `ExoSuitType`
|
|
||||||
* @see `InfantryAggravatedDirect`
|
|
||||||
* @see `InfantryAggravatedSplash`
|
|
||||||
* @see `PlayerSource`
|
|
||||||
* @see `ProjectileTarget.AggravatesTarget`
|
|
||||||
* @see `ResolvedProjectile`
|
|
||||||
* @param resolution the projectile resolution to match against
|
|
||||||
* @param damageType the damage type to find in as a component of aggravated information
|
|
||||||
* @param damage the base damage value
|
|
||||||
* @param data historical information related to the damage interaction
|
|
||||||
* @return the modified damage
|
|
||||||
*/
|
|
||||||
private def BaseAggravatedFormula(
|
|
||||||
resolution: ProjectileResolution.Value,
|
|
||||||
damageType : DamageType.Value
|
|
||||||
)
|
|
||||||
(
|
|
||||||
damage: Int,
|
|
||||||
data: ResolvedProjectile
|
|
||||||
): Int = {
|
|
||||||
if (data.resolution == resolution &&
|
|
||||||
data.projectile.quality == ProjectileQuality.AggravatesTarget) {
|
|
||||||
(data.projectile.profile.Aggravated, data.target) match {
|
|
||||||
case (Some(aggravation), p: PlayerSource) =>
|
|
||||||
val aggravatedDamage = aggravation.info.find(_.damage_type == damageType) match {
|
|
||||||
case Some(infos) =>
|
|
||||||
damage * infos.degradation_percentage + damage
|
|
||||||
case _ =>
|
|
||||||
damage toFloat
|
|
||||||
}
|
|
||||||
if(p.ExoSuit == ExoSuitType.MAX) {
|
|
||||||
(aggravatedDamage * aggravation.max_factor) toInt
|
|
||||||
} else {
|
|
||||||
aggravatedDamage toInt
|
|
||||||
}
|
|
||||||
case _ =>
|
|
||||||
damage
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
damage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For damage application that involves aggravation of a particular damage type,
|
|
||||||
* calculate that damage application burn for each tick for infantry targets
|
|
||||||
* and produce the modified damage value.
|
|
||||||
* Infantry wearing mechanized assault exo-suits (MAX) incorporate an additional modifier.
|
|
||||||
* Vanilla infantry incorporate their resistance value into a slightly different calculation than usual.
|
|
||||||
* @see `AggravatedDamage`
|
|
||||||
* @see `ExoSuitType`
|
|
||||||
* @see `InfantryAggravatedDirectBurn`
|
|
||||||
* @see `InfantryAggravatedSplashBurn`
|
|
||||||
* @see `PlayerSource`
|
|
||||||
* @see `ResolvedProjectile`
|
|
||||||
* @param resolution the projectile resolution to match against
|
|
||||||
* @param damageType the damage type to find in as a component of aggravated information
|
|
||||||
* @param damage the base damage value
|
|
||||||
* @param data historical information related to the damage interaction
|
|
||||||
* @return the modified damage
|
|
||||||
*/
|
|
||||||
private def BaseAggravatedBurnFormula(
|
|
||||||
resolution: ProjectileResolution.Value,
|
|
||||||
damageType : DamageType.Value
|
|
||||||
)
|
|
||||||
(
|
|
||||||
damage: Int,
|
|
||||||
data: ResolvedProjectile
|
|
||||||
): Int = {
|
|
||||||
if (data.resolution == resolution) {
|
|
||||||
(data.projectile.profile.Aggravated, data.target) match {
|
|
||||||
case (Some(aggravation), p: PlayerSource) =>
|
|
||||||
val degradation = aggravation.info.find(_.damage_type == damageType) match {
|
|
||||||
case Some(info) =>
|
|
||||||
info.degradation_percentage
|
|
||||||
case _ =>
|
|
||||||
1f
|
|
||||||
}
|
|
||||||
if (p.exosuit == ExoSuitType.MAX) {
|
|
||||||
(damage * degradation * aggravation.max_factor) toInt
|
|
||||||
} else {
|
|
||||||
val resist = data.damage_model.ResistUsing(data)(data)
|
|
||||||
//add resist to offset resist subtraction later
|
|
||||||
if (damage > resist) {
|
|
||||||
((damage - resist) * degradation).toInt + resist
|
|
||||||
} else {
|
|
||||||
(damage * degradation).toInt + resist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case _ =>
|
|
||||||
0
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
damage
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -295,8 +176,8 @@ object DamageModifiers {
|
||||||
|
|
||||||
private def formula(damage: Int, data: ResolvedProjectile): Int = {
|
private def formula(damage: Int, data: ResolvedProjectile): Int = {
|
||||||
if (damage > 0 &&
|
if (damage > 0 &&
|
||||||
data.resolution == ProjectileResolution.AggravatedDirectBurn ||
|
(data.resolution == ProjectileResolution.AggravatedDirectBurn ||
|
||||||
data.resolution == ProjectileResolution.AggravatedSplashBurn) {
|
data.resolution == ProjectileResolution.AggravatedSplashBurn)) {
|
||||||
//add resist to offset resist subtraction later
|
//add resist to offset resist subtraction later
|
||||||
1 + data.damage_model.ResistUsing(data)(data)
|
1 + data.damage_model.ResistUsing(data)(data)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -425,6 +306,17 @@ object DamageModifiers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the projectile has charging properties,
|
||||||
|
* and the weapon that produced the projectile has charging mechanics,
|
||||||
|
* calculate the current value of the damage as a sum
|
||||||
|
* of some minimum damage and scaled normal damage.
|
||||||
|
* The projectile quality has information about the "factor" of damage scaling.
|
||||||
|
* @see `ChargeDamage`
|
||||||
|
* @see `ChargeFireModeDefinition`
|
||||||
|
* @see `ProjectileQuality`
|
||||||
|
* @see `ResolvedProjectile`
|
||||||
|
*/
|
||||||
case object SpikerChargeDamage extends Mod {
|
case object SpikerChargeDamage extends Mod {
|
||||||
def Calculate: DamageModifiers.Format = formula
|
def Calculate: DamageModifiers.Format = formula
|
||||||
|
|
||||||
|
|
@ -439,4 +331,193 @@ object DamageModifiers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the damage is resolved through a `HitDamage` packet,
|
||||||
|
* calculate the damage as a function of its degrading value over distance traveled by its carrier projectile.
|
||||||
|
* @see `distanceDegradeFunction`
|
||||||
|
* @see `ProjectileQuality`
|
||||||
|
* @see `ResolvedProjectile`
|
||||||
|
*/
|
||||||
|
case object FlakHit extends Mod {
|
||||||
|
def Calculate: DamageModifiers.Format = formula
|
||||||
|
|
||||||
|
private def formula(damage: Int, data: ResolvedProjectile): Int = {
|
||||||
|
if(data.resolution == ProjectileResolution.Hit) {
|
||||||
|
distanceDegradeFunction(damage, data)
|
||||||
|
} else {
|
||||||
|
damage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the damage is resolved through a `SplashHitDamage` packet,
|
||||||
|
* calculate the damage as a function of its degrading value over distance
|
||||||
|
* between the hit position of the projectile and the position of the target.
|
||||||
|
* @see `radialDegradeFunction`
|
||||||
|
* @see `ProjectileQuality`
|
||||||
|
* @see `ResolvedProjectile`
|
||||||
|
*/
|
||||||
|
case object FlakBurst extends Mod {
|
||||||
|
def Calculate: DamageModifiers.Format = formula
|
||||||
|
|
||||||
|
private def formula(damage: Int, data: ResolvedProjectile): Int = {
|
||||||
|
if(data.resolution == ProjectileResolution.Splash) {
|
||||||
|
radialDegradeFunction(damage, data)
|
||||||
|
} else {
|
||||||
|
damage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Functions */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The input value degrades (lessens)
|
||||||
|
* the further the distance between the point of origin (`shot_origin`)
|
||||||
|
* and the point of encounter (`hit_pos`) of its vector (projectile).
|
||||||
|
* If the value is not set to degrade over any distance within its maximum distance, the value goes unmodified.
|
||||||
|
* If the value is encountered beyond its maximum distance, the value is zero'd.
|
||||||
|
*/
|
||||||
|
private def distanceDegradeFunction(damage: Int, data: ResolvedProjectile): Int = {
|
||||||
|
val projectile = data.projectile
|
||||||
|
val profile = projectile.profile
|
||||||
|
val distance = Vector3.Distance(data.hit_pos, projectile.shot_origin)
|
||||||
|
if (distance <= profile.DistanceMax) {
|
||||||
|
if (profile.DistanceNoDegrade == profile.DistanceMax || distance <= profile.DistanceNoDegrade) {
|
||||||
|
damage
|
||||||
|
} else {
|
||||||
|
damage - ((damage - profile.DegradeMultiplier * damage) * ((distance - profile.DistanceNoDegrade) / (profile.DistanceMax - profile.DistanceNoDegrade))).toInt
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The input value degrades (lessens)
|
||||||
|
* the further the distance between the point of origin (target position)
|
||||||
|
* and the point of encounter (`hit_pos`) of its vector (projectile).
|
||||||
|
* If the value is encountered beyond its maximum radial distance, the value is zero'd.
|
||||||
|
*/
|
||||||
|
private def radialDegradeFunction(damage: Int, data: ResolvedProjectile): Int = {
|
||||||
|
val profile = data.projectile.profile
|
||||||
|
val distance = Vector3.Distance(data.hit_pos, data.target.Position)
|
||||||
|
val radius = profile.DamageRadius
|
||||||
|
val radiusMin = profile.DamageRadiusMin
|
||||||
|
if (distance <= radiusMin) {
|
||||||
|
damage
|
||||||
|
} else if (distance <= radius) {
|
||||||
|
//damage - (damage * profile.DamageAtEdge * (distance - radiusMin) / (radius - radiusMin)).toInt
|
||||||
|
val base = profile.DamageAtEdge
|
||||||
|
val radi = radius - radiusMin
|
||||||
|
(damage * ((1 - base) * ((radi - (distance - radiusMin)) / radi) + base)).toInt
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For damage application that involves aggravation of a particular damage type,
|
||||||
|
* calculate that initial damage application for infantry targets
|
||||||
|
* and produce the modified damage value.
|
||||||
|
* Infantry wearing mechanized assault exo-suits (MAX) incorporate an additional modifier.
|
||||||
|
* @see `AggravatedDamage`
|
||||||
|
* @see `ExoSuitType`
|
||||||
|
* @see `InfantryAggravatedDirect`
|
||||||
|
* @see `InfantryAggravatedSplash`
|
||||||
|
* @see `PlayerSource`
|
||||||
|
* @see `ProjectileTarget.AggravatesTarget`
|
||||||
|
* @see `ResolvedProjectile`
|
||||||
|
* @param resolution the projectile resolution to match against
|
||||||
|
* @param damageType the damage type to find in as a component of aggravated information
|
||||||
|
* @param damage the base damage value
|
||||||
|
* @param data historical information related to the damage interaction
|
||||||
|
* @return the modified damage
|
||||||
|
*/
|
||||||
|
private def baseAggravatedFormula(
|
||||||
|
resolution: ProjectileResolution.Value,
|
||||||
|
damageType : DamageType.Value
|
||||||
|
)
|
||||||
|
(
|
||||||
|
damage: Int,
|
||||||
|
data: ResolvedProjectile
|
||||||
|
): Int = {
|
||||||
|
if (data.resolution == resolution &&
|
||||||
|
data.projectile.quality == ProjectileQuality.AggravatesTarget) {
|
||||||
|
(data.projectile.profile.Aggravated, data.target) match {
|
||||||
|
case (Some(aggravation), p: PlayerSource) =>
|
||||||
|
val aggravatedDamage = aggravation.info.find(_.damage_type == damageType) match {
|
||||||
|
case Some(infos) =>
|
||||||
|
damage * infos.degradation_percentage + damage
|
||||||
|
case _ =>
|
||||||
|
damage toFloat
|
||||||
|
}
|
||||||
|
if(p.ExoSuit == ExoSuitType.MAX) {
|
||||||
|
(aggravatedDamage * aggravation.max_factor) toInt
|
||||||
|
} else {
|
||||||
|
aggravatedDamage toInt
|
||||||
|
}
|
||||||
|
case _ =>
|
||||||
|
damage
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
damage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For damage application that involves aggravation of a particular damage type,
|
||||||
|
* calculate that damage application burn for each tick for infantry targets
|
||||||
|
* and produce the modified damage value.
|
||||||
|
* Infantry wearing mechanized assault exo-suits (MAX) incorporate an additional modifier.
|
||||||
|
* Vanilla infantry incorporate their resistance value into a slightly different calculation than usual.
|
||||||
|
* @see `AggravatedDamage`
|
||||||
|
* @see `ExoSuitType`
|
||||||
|
* @see `InfantryAggravatedDirectBurn`
|
||||||
|
* @see `InfantryAggravatedSplashBurn`
|
||||||
|
* @see `PlayerSource`
|
||||||
|
* @see `ResolvedProjectile`
|
||||||
|
* @param resolution the projectile resolution to match against
|
||||||
|
* @param damageType the damage type to find in as a component of aggravated information
|
||||||
|
* @param damage the base damage value
|
||||||
|
* @param data historical information related to the damage interaction
|
||||||
|
* @return the modified damage
|
||||||
|
*/
|
||||||
|
private def baseAggravatedBurnFormula(
|
||||||
|
resolution: ProjectileResolution.Value,
|
||||||
|
damageType : DamageType.Value
|
||||||
|
)
|
||||||
|
(
|
||||||
|
damage: Int,
|
||||||
|
data: ResolvedProjectile
|
||||||
|
): Int = {
|
||||||
|
if (data.resolution == resolution) {
|
||||||
|
(data.projectile.profile.Aggravated, data.target) match {
|
||||||
|
case (Some(aggravation), p: PlayerSource) =>
|
||||||
|
val degradation = aggravation.info.find(_.damage_type == damageType) match {
|
||||||
|
case Some(info) =>
|
||||||
|
info.degradation_percentage
|
||||||
|
case _ =>
|
||||||
|
1f
|
||||||
|
}
|
||||||
|
if (p.exosuit == ExoSuitType.MAX) {
|
||||||
|
(damage * degradation * aggravation.max_factor) toInt
|
||||||
|
} else {
|
||||||
|
val resist = data.damage_model.ResistUsing(data)(data)
|
||||||
|
//add resist to offset resist subtraction later
|
||||||
|
if (damage > resist) {
|
||||||
|
((damage - resist) * degradation).toInt + resist
|
||||||
|
} else {
|
||||||
|
(damage * degradation).toInt + resist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case _ =>
|
||||||
|
0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
damage
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,36 @@ class DamageCalculationsTests extends Specification {
|
||||||
DamageModifiers.DistanceDegrade.Calculate(100, resprojectile) == 100 mustEqual true
|
DamageModifiers.DistanceDegrade.Calculate(100, resprojectile) == 100 mustEqual true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"cut off damage at max distance (no cutoff)" in {
|
||||||
|
DamageModifiers.MaxDistanceCutoff.Calculate(100, resprojectile) == 100 mustEqual true
|
||||||
|
}
|
||||||
|
|
||||||
|
"cut off damage at max distance (cutoff)" in {
|
||||||
|
val cutoffprojectile = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
projectile,
|
||||||
|
SourceEntry(target),
|
||||||
|
target.DamageModel,
|
||||||
|
Vector3(1500, 0, 0)
|
||||||
|
)
|
||||||
|
DamageModifiers.MaxDistanceCutoff.Calculate(100, cutoffprojectile) == 0 mustEqual true
|
||||||
|
}
|
||||||
|
|
||||||
|
"cut off damage at custom distance (no cutoff)" in {
|
||||||
|
DamageModifiers.CustomDistanceCutoff(10).Calculate(100, resprojectile) == 0 mustEqual true
|
||||||
|
}
|
||||||
|
|
||||||
|
"cut off damage at custom distance (cutoff)" in {
|
||||||
|
val coffprojectile = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Splash,
|
||||||
|
projectile,
|
||||||
|
SourceEntry(target),
|
||||||
|
target.DamageModel,
|
||||||
|
Vector3(10, 0, 0)
|
||||||
|
)
|
||||||
|
DamageModifiers.CustomDistanceCutoff(2).Calculate(100, coffprojectile) == 0 mustEqual true
|
||||||
|
}
|
||||||
|
|
||||||
"degrade over distance damage modifier (some degrade)" in {
|
"degrade over distance damage modifier (some degrade)" in {
|
||||||
val resprojectile2 = ResolvedProjectile(
|
val resprojectile2 = ResolvedProjectile(
|
||||||
ProjectileResolution.Splash,
|
ProjectileResolution.Splash,
|
||||||
|
|
@ -158,6 +188,171 @@ class DamageCalculationsTests extends Specification {
|
||||||
DamageModifiers.Lash.Calculate(100, resprojectile2) == 0 mustEqual true
|
DamageModifiers.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 = ResolvedProjectile(
|
||||||
|
ProjectileResolution.AggravatedSplashBurn,
|
||||||
|
projectile,
|
||||||
|
SourceEntry(target),
|
||||||
|
target.DamageModel,
|
||||||
|
Vector3(15, 0, 0)
|
||||||
|
)
|
||||||
|
val resistance = burnRes.damage_model.ResistUsing(burnRes)(burnRes)
|
||||||
|
DamageModifiers.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 = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Splash,
|
||||||
|
projectile,
|
||||||
|
SourceEntry(target),
|
||||||
|
target.DamageModel,
|
||||||
|
Vector3(15, 0, 0)
|
||||||
|
)
|
||||||
|
DamageModifiers.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 = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
cprojectile,
|
||||||
|
SourceEntry(target),
|
||||||
|
target.DamageModel,
|
||||||
|
Vector3(15, 0, 0)
|
||||||
|
)
|
||||||
|
val damage = DamageModifiers.SpikerChargeDamage.Calculate(chargeBaseDamage, rescprojectile)
|
||||||
|
val calcDam = minDamageBase + math.floor(chargeBaseDamage * rescprojectile.projectile.quality.mod)
|
||||||
|
damage mustEqual calcDam
|
||||||
|
}
|
||||||
|
|
||||||
|
"charge (half)" in {
|
||||||
|
val cprojectile = charge_projectile.quality(ProjectileQuality.Modified(0.5f))
|
||||||
|
val rescprojectile = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
cprojectile,
|
||||||
|
SourceEntry(target),
|
||||||
|
target.DamageModel,
|
||||||
|
Vector3(15, 0, 0)
|
||||||
|
)
|
||||||
|
val damage = DamageModifiers.SpikerChargeDamage.Calculate(chargeBaseDamage, rescprojectile)
|
||||||
|
val calcDam = minDamageBase + math.floor(chargeBaseDamage * rescprojectile.projectile.quality.mod)
|
||||||
|
damage mustEqual calcDam
|
||||||
|
}
|
||||||
|
|
||||||
|
"charge (full)" in {
|
||||||
|
val cprojectile = charge_projectile.quality(ProjectileQuality.Modified(1))
|
||||||
|
val rescprojectile = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
cprojectile,
|
||||||
|
SourceEntry(target),
|
||||||
|
target.DamageModel,
|
||||||
|
Vector3(15, 0, 0)
|
||||||
|
)
|
||||||
|
val damage = DamageModifiers.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 = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Splash,
|
||||||
|
flak_projectile,
|
||||||
|
SourceEntry(target),
|
||||||
|
target.DamageModel,
|
||||||
|
Vector3(10, 0, 0)
|
||||||
|
)
|
||||||
|
val damage = DamageModifiers.FlakHit.Calculate(100, resfprojectile)
|
||||||
|
damage == 100 mustEqual true
|
||||||
|
}
|
||||||
|
|
||||||
|
"flak hit (resolution is hit, no degrade)" in {
|
||||||
|
val resfprojectile = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
flak_projectile,
|
||||||
|
SourceEntry(target),
|
||||||
|
target.DamageModel,
|
||||||
|
Vector3(10, 0, 0)
|
||||||
|
)
|
||||||
|
val damage = DamageModifiers.FlakHit.Calculate(100, resfprojectile)
|
||||||
|
damage == 100 mustEqual true
|
||||||
|
}
|
||||||
|
|
||||||
|
"flak burst (resolution is hit)" in {
|
||||||
|
val resfprojectile = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
flak_projectile,
|
||||||
|
SourceEntry(target),
|
||||||
|
target.DamageModel,
|
||||||
|
Vector3(15, 0, 0)
|
||||||
|
)
|
||||||
|
val damage = DamageModifiers.FlakBurst.Calculate(100, resfprojectile)
|
||||||
|
damage == 100 mustEqual true
|
||||||
|
}
|
||||||
|
|
||||||
|
"flak burst (resolution is splash, no degrade)" in {
|
||||||
|
val resfprojectile = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Splash,
|
||||||
|
flak_projectile,
|
||||||
|
SourceEntry(target),
|
||||||
|
target.DamageModel,
|
||||||
|
Vector3(10, 0, 0)
|
||||||
|
)
|
||||||
|
val damage = DamageModifiers.FlakBurst.Calculate(100, resfprojectile)
|
||||||
|
damage == 100 mustEqual true
|
||||||
|
}
|
||||||
|
|
||||||
|
"flak burst (resolution is splash, some degrade)" in {
|
||||||
|
val resfprojectile = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Splash,
|
||||||
|
flak_projectile,
|
||||||
|
SourceEntry(target),
|
||||||
|
target.DamageModel,
|
||||||
|
Vector3(5, 0, 0)
|
||||||
|
)
|
||||||
|
val damage = DamageModifiers.FlakBurst.Calculate(100, resfprojectile)
|
||||||
|
damage < 100 mustEqual true
|
||||||
|
}
|
||||||
|
|
||||||
"extract a complete damage profile" in {
|
"extract a complete damage profile" in {
|
||||||
val result1 = DamageModifiers.RadialDegrade.Calculate(
|
val result1 = DamageModifiers.RadialDegrade.Calculate(
|
||||||
AgainstVehicle(proj_prof) + AgainstVehicle(wep_prof),
|
AgainstVehicle(proj_prof) + AgainstVehicle(wep_prof),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue