diff --git a/common/src/main/scala/net/psforever/objects/ballistics/AggravatedDamage.scala b/common/src/main/scala/net/psforever/objects/ballistics/AggravatedDamage.scala index e28a2544e..81c4fedb0 100644 --- a/common/src/main/scala/net/psforever/objects/ballistics/AggravatedDamage.scala +++ b/common/src/main/scala/net/psforever/objects/ballistics/AggravatedDamage.scala @@ -4,6 +4,14 @@ import net.psforever.objects.equipment.TargetValidation import net.psforever.objects.serverobject.aggravated.Aura import net.psforever.objects.vital.DamageType +final case class AggravatedTiming(duration: Long, ticks: Option[Int]) + +object AggravatedTiming { + def apply(duration: Long): AggravatedTiming = AggravatedTiming(duration, None) + + def apply(duration: Long, ticks: Int): AggravatedTiming = AggravatedTiming(duration, Some(ticks)) +} + final case class AggravatedInfo(damage_type: DamageType.Value, degradation_percentage: Float, infliction_rate: Long) { @@ -12,13 +20,44 @@ final case class AggravatedInfo(damage_type: DamageType.Value, final case class AggravatedDamage(info: List[AggravatedInfo], effect_type: Aura, - duration: Long, + timing: AggravatedTiming, max_factor: Float, cumulative_damage_degrade: Boolean, vanu_aggravated: Boolean, targets: List[TargetValidation]) object AggravatedDamage { + def apply(info: AggravatedInfo, + effect_type: Aura, + timing: AggravatedTiming, + max_factor: Float, + targets: List[TargetValidation]): AggravatedDamage = + AggravatedDamage( + List(info), + effect_type, + timing, + max_factor, + cumulative_damage_degrade = true, + vanu_aggravated = false, + targets + ) + + def apply(info: AggravatedInfo, + effect_type: Aura, + timing: AggravatedTiming, + max_factor: Float, + vanu_aggravated: Boolean, + targets: List[TargetValidation]): AggravatedDamage = + AggravatedDamage( + List(info), + effect_type, + timing, + max_factor, + cumulative_damage_degrade = true, + vanu_aggravated, + targets + ) + def apply(info: AggravatedInfo, effect_type: Aura, duration: Long, @@ -27,7 +66,7 @@ object AggravatedDamage { AggravatedDamage( List(info), effect_type, - duration, + AggravatedTiming(duration), max_factor, cumulative_damage_degrade = true, vanu_aggravated = false, @@ -43,7 +82,7 @@ object AggravatedDamage { AggravatedDamage( List(info), effect_type, - duration, + AggravatedTiming(duration), max_factor, cumulative_damage_degrade = true, vanu_aggravated, diff --git a/common/src/main/scala/net/psforever/objects/serverobject/aggravated/AuraEffectBehavior.scala b/common/src/main/scala/net/psforever/objects/serverobject/aggravated/AuraEffectBehavior.scala index 1a2cc3dad..9f7745259 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/aggravated/AuraEffectBehavior.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/aggravated/AuraEffectBehavior.scala @@ -122,19 +122,27 @@ trait AuraEffectBehavior { case Some(list) => effectToEntryId -> (list :+ id) } //setup timer data - val tick = 1000 //each second - val duration = aggravation.duration - val iterations = (duration / tick).toInt - val leftoverTime = duration - (iterations * tick) + val timing = aggravation.timing + val duration = timing.duration + val (tick: Long, iterations: Int) = timing.ticks match { + case Some(n) if n < 1 => + val rate = info.infliction_rate + (rate, (duration / rate).toInt) + case Some(ticks) => + (duration / ticks, ticks) + case None => + (1000, (duration / 1000).toInt) + } + val leftoverTime = duration - (tick * iterations) //quality per tick val totalPower = (duration.toFloat / info.infliction_rate).toInt - 1 - val averagePowerPerTick = math.max(1, totalPower.toFloat / iterations).toInt + val averagePowerPerTick = totalPower.toFloat / iterations val lastTickRemainder = totalPower - averagePowerPerTick * iterations - val qualityPerTick: List[Int] = if (lastTickRemainder > 0) { - 0 +: List.fill[Int](iterations - 1)(averagePowerPerTick) :+ (lastTickRemainder + averagePowerPerTick) + val qualityPerTick: List[Float] = if (lastTickRemainder > 0) { + 0f +: List.fill[Float](iterations - 1)(averagePowerPerTick) :+ (lastTickRemainder + averagePowerPerTick) } else { - 0 +: List.fill[Int](iterations)(averagePowerPerTick) + 0f +: List.fill[Float](iterations)(averagePowerPerTick) } //pair id with entry PairIdWithAggravationEntry(id, effect, tick, data, data.target, qualityPerTick) @@ -150,7 +158,7 @@ trait AuraEffectBehavior { retime: Long, data: ResolvedProjectile, target: SourceEntry, - powerOffset: List[Int] + powerOffset: List[Float] ): AuraEffectBehavior.Entry = { val aggravatedDamageInfo = ResolvedProjectile( AuraEffectBehavior.burning(data.resolution), @@ -224,21 +232,22 @@ trait AuraEffectBehavior { private def PerformAggravation(entry: AuraEffectBehavior.Entry, tick: Int = 0) : Unit = { val data = entry.data - val info = ResolvedProjectile( + val model = data.damage_model + val aggravatedProjectileData = ResolvedProjectile( data.resolution, - data.projectile.quality(entry.qualityPerTick(tick).toFloat), + data.projectile.quality(entry.qualityPerTick(tick)), data.target, - data.damage_model, + model, data.hit_pos ) - TakesDamage.apply(Vitality.Damage(info.damage_model.Calculate(info))) + TakesDamage.apply(Vitality.Damage(model.Calculate(aggravatedProjectileData))) } } object AuraEffectBehavior { type Target = PlanetSideServerObject with Vitality with AuraContainer - private case class Entry(id: Long, effect: Aura, retime: Long, data: ResolvedProjectile, qualityPerTick: List[Int]) + private case class Entry(id: Long, effect: Aura, retime: Long, data: ResolvedProjectile, qualityPerTick: List[Float]) private case class Aggravate(id: Long, iterations: Int, leftover: Long) diff --git a/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/src/main/scala/net/psforever/objects/GlobalDefinitions.scala index f8171f012..e9295cb13 100644 --- a/src/main/scala/net/psforever/objects/GlobalDefinitions.scala +++ b/src/main/scala/net/psforever/objects/GlobalDefinitions.scala @@ -2,7 +2,7 @@ package net.psforever.objects import net.psforever.objects.avatar.Certification -import net.psforever.objects.ballistics.{AggravatedDamage, AggravatedInfo, Projectiles} +import net.psforever.objects.ballistics.{AggravatedDamage, AggravatedInfo, AggravatedTiming, Projectiles} import net.psforever.objects.ce.{DeployableCategory, DeployedItem} import net.psforever.objects.definition._ import net.psforever.objects.definition.converter._ @@ -2454,7 +2454,7 @@ object GlobalDefinitions { comet_projectile.Aggravated = AggravatedDamage( AggravatedInfo(DamageType.Direct, 0.2f, 500), Aura.Comet, - 2000, + AggravatedTiming(2000, 4), 10f, List( TargetValidation(EffectTarget.Category.Player, EffectTarget.Validation.Player), @@ -2464,6 +2464,10 @@ object GlobalDefinitions { comet_projectile.InitialVelocity = 80 comet_projectile.Lifespan = 3.1f ProjectileDefinition.CalculateDerivedFields(comet_projectile) + comet_projectile.Modifiers = List( + DamageModifiers.CometAggravated, + DamageModifiers.CometAggravatedBurn + ) dualcycler_projectile.Name = "dualcycler_projectile" dualcycler_projectile.Damage0 = 18 @@ -2611,7 +2615,7 @@ object GlobalDefinitions { flamethrower_fireball.Aggravated = AggravatedDamage( List(AggravatedInfo(DamageType.Direct, 0.9f, 500), AggravatedInfo(DamageType.Splash, 0.9f, 500)), Aura.Fire, - 5000, + AggravatedTiming(5000), 0.1f, false, false, @@ -2641,7 +2645,7 @@ object GlobalDefinitions { flamethrower_projectile.Aggravated = AggravatedDamage( List(AggravatedInfo(DamageType.Direct, 0.5f, 500)), Aura.Fire, - 5000, + AggravatedTiming(5000), 0.5f, false, false, @@ -3507,7 +3511,7 @@ object GlobalDefinitions { plasma_cartridge_projectile.Aggravated = AggravatedDamage( List(AggravatedInfo(DamageType.Direct, 0.25f, 750), AggravatedInfo(DamageType.Splash, 0.25f, 1000)), Aura.Plasma, - 3000, + AggravatedTiming(3000), 1.5f, true, false, @@ -3535,7 +3539,7 @@ object GlobalDefinitions { plasma_cartridge_projectile_b.Aggravated = AggravatedDamage( List(AggravatedInfo(DamageType.Direct, 0.25f, 750), AggravatedInfo(DamageType.Splash, 0.25f, 1000)), Aura.Plasma, - 3000, + AggravatedTiming(3000), 1.5f, true, false, @@ -3562,7 +3566,7 @@ object GlobalDefinitions { plasma_grenade_projectile.Aggravated = AggravatedDamage( List(AggravatedInfo(DamageType.Direct, 0.25f, 750), AggravatedInfo(DamageType.Splash, 0.25f, 1000)), Aura.Plasma, - 3000, + AggravatedTiming(3000), 1.5f, true, false, @@ -3590,7 +3594,7 @@ object GlobalDefinitions { plasma_grenade_projectile_B.Aggravated = AggravatedDamage( List(AggravatedInfo(DamageType.Direct, 0.25f, 750), AggravatedInfo(DamageType.Splash, 0.25f, 1000)), Aura.Plasma, - 3000, + AggravatedTiming(3000), 1.5f, true, false, diff --git a/src/main/scala/net/psforever/objects/serverobject/damage/Damageable.scala b/src/main/scala/net/psforever/objects/serverobject/damage/Damageable.scala index 5dc877562..8fcde16c6 100644 --- a/src/main/scala/net/psforever/objects/serverobject/damage/Damageable.scala +++ b/src/main/scala/net/psforever/objects/serverobject/damage/Damageable.scala @@ -59,7 +59,7 @@ object Damageable { */ def CanDamage(obj: Vitality with FactionAffinity, damage: Int, data: ResolvedProjectile): Boolean = { val definition = obj.Definition - damage > 0 && + (damage > 0 || data.projectile.profile.Aggravated.nonEmpty) && definition.Damageable && (definition.DamageableByFriendlyFire || (data.projectile.owner.Faction != obj.Faction || diff --git a/src/main/scala/net/psforever/objects/vital/damage/DamageModifiers.scala b/src/main/scala/net/psforever/objects/vital/damage/DamageModifiers.scala index 1ae9dbc99..d544e5260 100644 --- a/src/main/scala/net/psforever/objects/vital/damage/DamageModifiers.scala +++ b/src/main/scala/net/psforever/objects/vital/damage/DamageModifiers.scala @@ -269,4 +269,33 @@ object DamageModifiers { } } } + + case object CometAggravated extends Mod { + def Calculate: DamageModifiers.Format = formula + + private def formula(damage: Int, data: ResolvedProjectile): Int = { + if (data.resolution == ProjectileResolution.AggravatedDirect) { + 0 + } else { + damage + } + } + } + + case object CometAggravatedBurn extends Mod { + def Calculate: DamageModifiers.Format = formula + + private def formula(damage: Int, data: ResolvedProjectile): Int = { + if (data.resolution == ProjectileResolution.AggravatedDirectBurn) { + data.projectile.profile.Aggravated match { + case Some(_) => + (damage * data.projectile.quality) toInt + case _ => + 0 + } + } else { + damage + } + } + } }