separated aggravation behavior and uara management behavior; moved files into packages and deleted old files

This commit is contained in:
FateJH 2020-08-12 20:59:13 -04:00
parent a79fc6bd2f
commit 89d7aea633
16 changed files with 451 additions and 514 deletions

View file

@ -1,7 +1,7 @@
// Copyright (c) 2020 PSForever
package net.psforever.objects.ballistics
import net.psforever.objects.equipment.TargetValidation
import net.psforever.objects.serverobject.aggravated.Aura
import net.psforever.objects.serverobject.aura.Aura
import net.psforever.objects.vital.DamageType
final case class AggravatedTiming(duration: Long, ticks: Option[Int])

View file

@ -0,0 +1,223 @@
// Copyright (c) 2020 PSForever
package net.psforever.objects.serverobject.aggravated
import akka.actor.{Actor, Cancellable}
import net.psforever.objects.ballistics._
import net.psforever.objects.serverobject.aura.{Aura, AuraEffectBehavior}
import net.psforever.objects.serverobject.damage.Damageable
import net.psforever.objects.vital.{DamageType, Vitality}
import scala.collection.mutable
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
trait AggravatedBehavior {
_ : Actor with Damageable =>
private val entryIdToEntry: mutable.LongMap[AggravatedBehavior.Entry] =
mutable.LongMap.empty[AggravatedBehavior.Entry]
private val aggravationToTimer: mutable.LongMap[Cancellable] =
mutable.LongMap.empty[Cancellable]
def AggravatedObject: AggravatedBehavior.Target
def TryAggravationEffect(data: ResolvedProjectile): Option[AggravatedDamage] = {
data.projectile.profile.Aggravated match {
case Some(damage)
if data.projectile.profile.ProjectileDamageTypes.contains(DamageType.Aggravated) &&
damage.effect_type != Aura.Nothing &&
damage.targets.exists(validation => validation.test(AggravatedObject)) =>
TryAggravationEffect(damage, data)
case _ =>
None
}
}
private def TryAggravationEffect(aggravation: AggravatedDamage, data: ResolvedProjectile): Option[AggravatedDamage] = {
val effect = aggravation.effect_type
val obj = AggravatedObject
if(CheckForUniqueUnqueuedProjectile(data.projectile)) {
val auraEffects = obj.Aura
if(auraEffects.contains(effect) && aggravation.cumulative_damage_degrade) {
SetupAggravationEntry(aggravation, data)
Some(aggravation)
}
else if(obj.AddEffectToAura(effect).diff(auraEffects).contains(effect)) {
SetupAggravationEntry(aggravation, data)
Some(aggravation)
}
else {
None
}
}
else {
None
}
}
private def CheckForUniqueUnqueuedProjectile(projectile : Projectile): Boolean = {
!entryIdToEntry.values.exists { entry => entry.data.projectile.id == projectile.id }
}
private def SetupAggravationEntry(aggravation: AggravatedDamage, data: ResolvedProjectile): Boolean = {
val effect = aggravation.effect_type
aggravation.info.find(_.damage_type == AggravatedBehavior.basicDamageType(data.resolution)) match {
case Some(info) =>
val timing = aggravation.timing
val duration = timing.duration
//setup effect
val id = data.projectile.id
//setup timer data
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 =>
(1000L, (duration / 1000).toInt)
}
//val leftoverTime = duration - (tick * iterations)
//quality per tick
val totalPower = (duration.toFloat / info.infliction_rate).toInt - 1
val averagePowerPerTick = totalPower.toFloat / iterations
val lastTickRemainder = totalPower - averagePowerPerTick * iterations
val qualityPerTick: List[Float] = if (lastTickRemainder > 0) {
0f +: List.fill[Float](iterations - 1)(averagePowerPerTick) :+ (lastTickRemainder + averagePowerPerTick)
}
else {
0f +: List.fill[Float](iterations)(averagePowerPerTick)
}
//pair id with entry
PairIdWithAggravationEntry(id, effect, tick, data, data.target, qualityPerTick)
//pair id with timer
aggravationToTimer += id -> context.system.scheduler.scheduleOnce(tick milliseconds, self, AggravatedBehavior.Aggravate(id, iterations))
true
case _ =>
false
}
}
private def PairIdWithAggravationEntry(
id: Long,
effect: Aura,
retime: Long,
data: ResolvedProjectile,
target: SourceEntry,
powerOffset: List[Float]
): AggravatedBehavior.Entry = {
val aggravatedDamageInfo = ResolvedProjectile(
AggravatedBehavior.burning(data.resolution),
data.projectile,
target,
data.damage_model,
data.hit_pos
)
val entry = AggravatedBehavior.Entry(id, effect, retime, aggravatedDamageInfo, powerOffset)
entryIdToEntry += id -> entry
entry
}
val aggravatedBehavior: Receive = {
case AggravatedBehavior.Aggravate(id, 0) =>
AggravationCleanup(id)
case AggravatedBehavior.Aggravate(id, iteration) =>
RetimeEventAndPerformAggravation(id, iteration, None)
}
private def RetimeEventAndPerformAggravation(id: Long, iteration: Int, time: Option[Long]) : Unit = {
RetimeAggravation(id, iteration - 1, time) match {
case Some(entry) =>
PerformAggravation(entry, iteration)
case _ => ;
}
}
private def RetimeAggravation(
id: Long,
iteration: Int,
time: Option[Long]
): Option[AggravatedBehavior.Entry] = {
CleanupAggravationTimer(id)
entryIdToEntry.get(id) match {
case out @ Some(oldEntry) =>
aggravationToTimer += id -> context.system.scheduler.scheduleOnce(
time.getOrElse(oldEntry.retime) milliseconds,
self,
AggravatedBehavior.Aggravate(id, iteration)
)
out
case _ =>
AggravationCleanup(id)
None
}
}
def RemoveAggravatedEntry(id: Long): Aura = {
entryIdToEntry.remove(id) match {
case Some(entry) =>
entry.data.projectile.profile.Aggravated.get.effect_type
case _ =>
Aura.Nothing
}
}
def CleanupAggravationTimer(id: Long): Unit = {
//remove and cancel timer
aggravationToTimer.remove(id) match {
case Some(timer) => timer.cancel
case _ => ;
}
}
def AggravationCleanup(id: Long): Unit = {
RemoveAggravatedEntry(id)
CleanupAggravationTimer(id)
}
def EndAllAggravation(): Unit = {
entryIdToEntry.clear
aggravationToTimer.values.foreach { _.cancel }
aggravationToTimer.clear
}
private def PerformAggravation(entry: AggravatedBehavior.Entry, tick: Int = 0): Unit = {
val data = entry.data
val model = data.damage_model
val aggravatedProjectileData = ResolvedProjectile(
data.resolution,
data.projectile.quality(entry.qualityPerTick(tick)),
data.target,
model,
data.hit_pos
)
TakesDamage.apply(Vitality.Damage(model.Calculate(aggravatedProjectileData)))
}
}
object AggravatedBehavior {
type Target = AuraEffectBehavior.Target with Vitality
private case class Entry(id: Long, effect: Aura, retime: Long, data: ResolvedProjectile, qualityPerTick: List[Float])
private case class Aggravate(id: Long, iterations: Int)
private def burning(resolution: ProjectileResolution.Value): ProjectileResolution.Value = {
resolution match {
case ProjectileResolution.AggravatedDirect => ProjectileResolution.AggravatedDirectBurn
case ProjectileResolution.AggravatedSplash => ProjectileResolution.AggravatedSplashBurn
case _ => resolution
}
}
private def basicDamageType(resolution: ProjectileResolution.Value): DamageType.Value = {
resolution match {
case ProjectileResolution.AggravatedDirect | ProjectileResolution.AggravatedDirectBurn =>
DamageType.Direct
case ProjectileResolution.AggravatedSplash | ProjectileResolution.AggravatedSplashBurn =>
DamageType.Splash
case _ =>
DamageType.None
}
}
}

View file

@ -1,16 +0,0 @@
// Copyright (c) 2020 PSForever
package net.psforever.objects.serverobject.aggravated
sealed class Aura(val id: Int)
object Aura {
final case object None extends Aura(id = 0)
final case object Plasma extends Aura(id = 1)
final case object Comet extends Aura(id = 2)
final case object Napalm extends Aura(id = 4)
final case object Fire extends Aura(id = 8)
}

View file

@ -1,272 +0,0 @@
// Copyright (c) 2020 PSForever
package net.psforever.objects.serverobject.aggravated
import akka.actor.{Actor, Cancellable}
import net.psforever.objects.ballistics._
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.damage.Damageable
import net.psforever.objects.vital.{DamageType, Vitality}
import scala.collection.mutable
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
trait AuraEffectBehavior {
_ : Actor with Damageable =>
private var activeEffectIndex: Long = 0
private val effectToEntryId: mutable.HashMap[Aura, List[Long]] =
mutable.HashMap.empty[Aura, List[Long]]
private val entryIdToTimer: mutable.LongMap[Cancellable] =
mutable.LongMap.empty[Cancellable]
private val entryIdToEntry: mutable.LongMap[AuraEffectBehavior.Entry] =
mutable.LongMap.empty[AuraEffectBehavior.Entry]
def AuraTargetObject: AuraEffectBehavior.Target
val auraBehavior: Receive = {
case AuraEffectBehavior.Aggravate(id, 0, 0) =>
CancelEffectTimer(id)
PerformCleanupEffect(id)
case AuraEffectBehavior.Aggravate(id, 0, leftoverTime) =>
RemoveEffectEntry(id)
RetimeEvent(id, iteration = 0, Some(leftoverTime), leftoverTime = 0)
case AuraEffectBehavior.Aggravate(id, iteration, leftover) =>
RetimeEventAndPerformAggravation(id, iteration, None, leftover)
}
private def RetimeEvent(
id: Long,
iteration: Int,
time: Option[Long],
leftoverTime: Long
): Option[AuraEffectBehavior.Entry] = {
CancelEffectTimer(id)
entryIdToEntry.get(id) match {
case out @ Some(oldEntry) =>
entryIdToTimer += id -> context.system.scheduler.scheduleOnce(
time.getOrElse(oldEntry.retime) milliseconds,
self,
AuraEffectBehavior.Aggravate(id, iteration, leftoverTime)
)
out
case _ =>
PerformCleanupEffect(id)
None
}
}
private def RetimeEventAndPerformAggravation(id: Long, iteration: Int, time: Option[Long], leftoverTime: Long) : Unit = {
RetimeEvent(id, iteration - 1, time, leftoverTime) match {
case Some(entry) =>
PerformAggravation(entry, iteration)
case _ => ;
}
}
def CancelEffectTimer(id: Long) : Unit = {
entryIdToTimer.remove(id) match {
case Some(timer) => timer.cancel
case _ => ;
}
}
def PerformCleanupEffect(id: Long) : Unit = {
CleanupEffect(id) match {
case Aura.None => ;
case _ => UpdateAggravatedEffect(AuraTargetObject)
}
}
def TryAggravationEffect(data: ResolvedProjectile) : Unit = {
data.projectile.profile.Aggravated match {
case Some(damage)
if data.projectile.profile.ProjectileDamageTypes.contains(DamageType.Aggravated) &&
damage.effect_type != Aura.None && //TODO aphelion starfire
damage.targets.exists(validation => validation.test(AuraTargetObject)) =>
TryAggravationEffect(damage, data)
case _ => ;
}
}
private def TryAggravationEffect(aggravation: AggravatedDamage, data: ResolvedProjectile) : Unit = {
val effect = aggravation.effect_type
val obj = AuraTargetObject
if(CheckForUniqueUnqueuedProjectile(data.projectile)) {
val auraEffects = obj.Aura
if(auraEffects.contains(effect) && aggravation.cumulative_damage_degrade) {
SetupAggravationEntry(aggravation, data)
}
else if(obj.AddEffectToAura(effect).diff(auraEffects).contains(effect)) {
SetupAggravationEntry(aggravation, data)
UpdateAggravatedEffect(obj)
}
}
}
private def CheckForUniqueUnqueuedProjectile(projectile : Projectile) : Boolean = {
!entryIdToEntry.values.exists { entry => entry.data.projectile.id == projectile.id }
}
private def SetupAggravationEntry(aggravation: AggravatedDamage, data: ResolvedProjectile) : Unit = {
val effect = aggravation.effect_type
aggravation.info.find(_.damage_type == AuraEffectBehavior.basicDamageType(data.resolution)) match {
case Some(info) =>
//get unused id
val id = activeEffectIndex
activeEffectIndex += 1
//pair aura effect with id
effectToEntryId.get(effect) match {
case None | Some(Nil) => effectToEntryId += effect -> List(id)
case Some(list) => effectToEntryId -> (list :+ id)
}
//setup timer data
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 = totalPower.toFloat / iterations
val lastTickRemainder = totalPower - averagePowerPerTick * iterations
val qualityPerTick: List[Float] = if (lastTickRemainder > 0) {
0f +: List.fill[Float](iterations - 1)(averagePowerPerTick) :+ (lastTickRemainder + averagePowerPerTick)
}
else {
0f +: List.fill[Float](iterations)(averagePowerPerTick)
}
//pair id with entry
PairIdWithAggravationEntry(id, effect, tick, data, data.target, qualityPerTick)
//pair id with timer
entryIdToTimer += id -> context.system.scheduler.scheduleOnce(tick milliseconds, self, AuraEffectBehavior.Aggravate(id, iterations, leftoverTime))
case _ => ;
}
}
private def PairIdWithAggravationEntry(
id: Long,
effect: Aura,
retime: Long,
data: ResolvedProjectile,
target: SourceEntry,
powerOffset: List[Float]
): AuraEffectBehavior.Entry = {
val aggravatedDamageInfo = ResolvedProjectile(
AuraEffectBehavior.burning(data.resolution),
data.projectile,
target,
data.damage_model,
data.hit_pos
)
val entry = AuraEffectBehavior.Entry(id, effect, retime, aggravatedDamageInfo, powerOffset)
entryIdToEntry += id -> entry
entry
}
def RemoveEffectEntry(id: Long) : Aura = {
entryIdToEntry.remove(id) match {
case Some(entry) =>
entry.data.projectile.profile.Aggravated.get.effect_type
case None =>
effectToEntryId.find { case (_, values) => values.contains(id) } match {
case Some((effect, _)) => effect
case _ => Aura.None
}
}
}
def CleanupEffect(id: Long) : Aura = {
//remove and cancel timer
entryIdToTimer.remove(id) match {
case Some(timer) => timer.cancel
case _ => ;
}
//remove entry and cache effect
val out = RemoveEffectEntry(id)
//remove id and, if now unsupported, effect
(effectToEntryId.get(out) match {
case Some(list) => (out, list.filterNot(_ == id))
case _ => (Aura.None, Nil)
}) match {
case (Aura.None, _) =>
Aura.None
case (effect, Nil) =>
AuraTargetObject.RemoveEffectFromAura(effect)
effectToEntryId.remove(effect)
effect
case (effect, list) =>
effectToEntryId += effect -> list
Aura.None
}
}
def EndAllEffects() : Unit = {
entryIdToEntry.clear
entryIdToTimer.values.foreach { _.cancel }
entryIdToTimer.clear
effectToEntryId.clear
val obj = AuraTargetObject
obj.Aura.foreach { obj.RemoveEffectFromAura }
}
def EndAllEffectsAndUpdate() : Unit = {
EndAllEffects()
UpdateAggravatedEffect(AuraTargetObject)
}
def UpdateAggravatedEffect(target: AuraEffectBehavior.Target) : Unit = {
import services.avatar.{AvatarAction, AvatarServiceMessage}
val zone = target.Zone
val value = target.Aura.foldLeft(0)(_ + _.id)
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttributeToAll(target.GUID, 54, value))
}
private def PerformAggravation(entry: AuraEffectBehavior.Entry, tick: Int = 0) : Unit = {
val data = entry.data
val model = data.damage_model
val aggravatedProjectileData = ResolvedProjectile(
data.resolution,
data.projectile.quality(entry.qualityPerTick(tick)),
data.target,
model,
data.hit_pos
)
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[Float])
private case class Aggravate(id: Long, iterations: Int, leftover: Long)
private def burning(resolution: ProjectileResolution.Value): ProjectileResolution.Value = {
resolution match {
case ProjectileResolution.AggravatedDirect => ProjectileResolution.AggravatedDirectBurn
case ProjectileResolution.AggravatedSplash => ProjectileResolution.AggravatedSplashBurn
case _ => resolution
}
}
private def basicDamageType(resolution: ProjectileResolution.Value): DamageType.Value = {
resolution match {
case ProjectileResolution.AggravatedDirect | ProjectileResolution.AggravatedDirectBurn =>
DamageType.Direct
case ProjectileResolution.AggravatedSplash | ProjectileResolution.AggravatedSplashBurn =>
DamageType.Splash
case _ =>
DamageType.None
}
}
}

View file

@ -0,0 +1,33 @@
// Copyright (c) 2020 PSForever
package net.psforever.objects.serverobject.aura
/**
* An effect that can be emitted by a target game object entity.
*/
sealed class Aura()
/**
* Visual effects emitted by a target, usually a `Player` entity.
* Most often paired with aggravated damage.
* Unrelated to the effects emitted by obtaining and transporting
* the lattice logic unit, or a facility module, or the rabbit ball.
*/
object Aura {
/** Since `None` is an actual effect, the "no effect" default is repurposed as "Nothing". */
final case object Nothing extends Aura
/** Conferred by the `aphelion_starfire_projectile`. */
final case object None extends Aura
/** A green emission. */
final case object Plasma extends Aura
/** A purple emission. */
final case object Comet extends Aura
/** A white and yellow starburst emission. */
final case object Napalm extends Aura
/** A red and orange emission. */
final case object Fire extends Aura
}

View file

@ -1,8 +1,11 @@
// Copyright (c) 2020 PSForever
package net.psforever.objects.serverobject.aggravated
package net.psforever.objects.serverobject.aura
import net.psforever.objects.serverobject.aggravated.{Aura => AuraEffect}
import net.psforever.objects.serverobject.aura.{Aura => AuraEffect}
/**
* An entity that can display specific special effects that decorate its model.
* These animations confer information about the nature of some status that is affecting the target entity.
*/
trait AuraContainer {
private var aura : Set[AuraEffect] = Set.empty[AuraEffect]

View file

@ -0,0 +1,153 @@
// Copyright (c) 2020 PSForever
package net.psforever.objects.serverobject.aura
import akka.actor.{Actor, Cancellable}
import net.psforever.objects.serverobject.PlanetSideServerObject
import scala.collection.mutable
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
trait AuraEffectBehavior {
_ : Actor =>
private var activeEffectIndex: Long = 0
private val effectToEntryId: mutable.HashMap[Aura, List[Long]] =
mutable.HashMap.empty[Aura, List[Long]]
private val effectIdToTimer: mutable.LongMap[Cancellable] =
mutable.LongMap.empty[Cancellable]
def AuraTargetObject: AuraEffectBehavior.Target
val auraBehavior: Receive = {
case AuraEffectBehavior.StartEffect(effect, duration) =>
StartAuraEffect(effect, duration)
case AuraEffectBehavior.EndEffect(Some(id), None) =>
EndAuraEffect(id)
case AuraEffectBehavior.EndEffect(None, Some(effect)) =>
EndAuraEffect(effect)
case AuraEffectBehavior.EndAllEffects() =>
EndAllEffectsAndUpdate()
}
final def GetUnusedEffectId: Long = {
val id = activeEffectIndex
activeEffectIndex += 1
id
}
def StartAuraEffect(effect: Aura, duration: Long): Long = {
StartAuraEffect(GetUnusedEffectId, effect, duration)
}
def StartAuraEffect(id: Long, effect: Aura, duration: Long): Long = {
//pair aura effect with id
effectToEntryId.get(effect) match {
case None | Some(Nil) => effectToEntryId += effect -> List(id)
case Some(list) => effectToEntryId -> (list :+ id)
}
//pair id with timer
effectIdToTimer += id -> context.system.scheduler.scheduleOnce(duration milliseconds, self, AuraEffectBehavior.EndEffect(id))
//update visuals
UpdateAuraEffect(AuraTargetObject)
id
}
def EndAuraEffect(id: Long): Unit = {
EndActiveEffect(id) match {
case Aura.Nothing => ;
case effect =>
CancelEffectTimer(id)
val obj = AuraTargetObject
obj.RemoveEffectFromAura(effect)
UpdateAuraEffect(obj)
}
}
def EndActiveEffect(id: Long): Aura = {
effectToEntryId.find { case (_, ids) => ids.contains(id) } match {
case Some((effect, ids)) if ids.size == 1 =>
effectToEntryId.remove(effect)
effect
case Some((effect, ids)) =>
effectToEntryId += effect -> ids.filterNot(_ == id)
Aura.Nothing
case None =>
Aura.Nothing
}
}
def CancelEffectTimer(id: Long) : Unit = {
effectIdToTimer.remove(id) match {
case Some(timer) => timer.cancel
case _ => ;
}
}
def EndAuraEffect(effect: Aura): Unit = {
effectToEntryId.remove(effect) match {
case Some(idList) =>
idList.foreach { id =>
val obj = AuraTargetObject
CancelEffectTimer(id)
obj.RemoveEffectFromAura(effect)
UpdateAuraEffect(obj)
}
case _ => ;
}
}
def EndAllEffects() : Unit = {
effectIdToTimer.values.foreach { _.cancel }
effectIdToTimer.clear
effectToEntryId.clear
val obj = AuraTargetObject
obj.Aura.foreach { obj.RemoveEffectFromAura }
}
def EndAllEffectsAndUpdate() : Unit = {
EndAllEffects()
UpdateAuraEffect(AuraTargetObject)
}
def UpdateAuraEffect(target: AuraEffectBehavior.Target) : Unit = {
import services.avatar.{AvatarAction, AvatarServiceMessage}
val zone = target.Zone
val value = target.Aura.foldLeft(0)(_ + AuraEffectBehavior.effectToAttributeValue(_))
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttributeToAll(target.GUID, 54, value))
}
def TestForEffect(id: Long): Aura = {
effectToEntryId.find { case (_, ids) => ids.contains(id) } match {
case Some((effect, _)) => effect
case _ => Aura.Nothing
}
}
}
object AuraEffectBehavior {
type Target = PlanetSideServerObject with AuraContainer
final case class StartEffect(effect: Aura, duration: Long)
final case class EndEffect(id: Option[Long], aura: Option[Aura])
object EndEffect {
def apply(id: Long): EndEffect = EndEffect(Some(id), None)
def apply(aura: Aura): EndEffect = EndEffect(None, Some(aura))
}
final case class EndAllEffects()
private def effectToAttributeValue(effect: Aura): Int = effect match {
case Aura.None => 0
case Aura.Plasma => 1
case Aura.Comet => 2
case Aura.Napalm => 4
case Aura.Fire => 8
case _ => Int.MinValue
}
}

View file

@ -1,176 +0,0 @@
// Copyright (c) 2017 PSForever
//package net.psforever.objects.vital
//
//import net.psforever.objects.vital.StandardAmenityDamage.None
//import net.psforever.objects.vital.StandardDeployableDamage.None
//import net.psforever.objects.vital.damage._
//import net.psforever.objects.vital.damage.DamageCalculations._
//import net.psforever.objects.vital.projectile.ProjectileCalculations
//
///**
// * A protected super class for calculating "no damage."
// * Used for `NoDamage` but also for the base of `*LashDamage` calculation objects
// * to maintain the polymorphic identity of `DamageCalculations`.
// */
//protected class NoDamageBase
// extends DamageCalculations(
// DamageCalculations.NoDamage,
// DamageWithModifiers(NoDamageAgainst),
// TooFar
// )
//
//object NoDamage extends NoDamageBase
//
//object InfantryHitDamage
// extends DamageCalculations(
// DirectHitDamageWithDegrade,
// DamageWithModifiers(DamageAgainstExoSuit),
// DistanceBetweenTargetandSource
// )
//
//object MaxHitDamage
// extends DamageCalculations(
// DirectHitDamageWithDegrade,
// DamageWithModifiers(DamageAgainstMaxSuit),
// DistanceBetweenTargetandSource
// )
//
//object VehicleHitDamage
// extends DamageCalculations(
// DirectHitDamageWithDegrade,
// DamageWithModifiers(DamageAgainstVehicle),
// DistanceBetweenTargetandSource
// )
//
//object AircraftHitDamage
// extends DamageCalculations(
// DirectHitDamageWithDegrade,
// DamageWithModifiers(DamageAgainstAircraft),
// DistanceBetweenTargetandSource
// )
//
//object InfantrySplashDamage
// extends DamageCalculations(
// SplashDamageWithRadialDegrade,
// DamageWithModifiers(DamageAgainstExoSuit),
// DistanceFromExplosionToTarget
// )
//
//object MaxSplashDamage
// extends DamageCalculations(
// SplashDamageWithRadialDegrade,
// DamageWithModifiers(DamageAgainstMaxSuit),
// DistanceFromExplosionToTarget
// )
//
//object VehicleSplashDamage
// extends DamageCalculations(
// SplashDamageWithRadialDegrade,
// DamageWithModifiers(DamageAgainstVehicle),
// DistanceFromExplosionToTarget
// )
//
//object AircraftSplashDamage
// extends DamageCalculations(
// SplashDamageWithRadialDegrade,
// DamageWithModifiers(DamageAgainstAircraft),
// DistanceFromExplosionToTarget
// )
//
//object InfantrySplashDamageDirect
// extends DamageCalculations(
// SplashDamageWithRadialDegrade,
// DamageWithModifiers(DamageAgainstAircraft),
// NoDistance
// )
//
//object InfantryLashDamage
// extends DamageCalculations(
// LashDamage,
// DamageWithModifiers(DamageAgainstExoSuit),
// DistanceBetweenTargetandSource
// )
//
//object MaxLashDamage
// extends DamageCalculations(
// LashDamage,
// DamageWithModifiers(DamageAgainstMaxSuit),
// DistanceBetweenTargetandSource
// )
//
//object VehicleLashDamage
// extends DamageCalculations(
// LashDamage,
// DamageWithModifiers(DamageAgainstVehicle),
// DistanceBetweenTargetandSource
// )
//
//object AircraftLashDamage
// extends DamageCalculations(
// LashDamage,
// DamageWithModifiers(DamageAgainstAircraft),
// DistanceBetweenTargetandSource
// )
//
//object AmenityHitDamage
// extends DamageCalculations(
// DirectHitDamageWithDegrade,
// DamageWithModifiers(DamageAgainstVehicle),
// DistanceBetweenTargetandSource
// )
//
//object AmenitySplashDamage
// extends DamageCalculations(
// SplashDamageWithRadialDegrade,
// DamageWithModifiers(DamageAgainstVehicle),
// DistanceFromExplosionToTarget
// )
//
//object NoDamageSelection extends DamageSelection {
// def Direct = None
// def Splash = None
// def Lash = None
// def Aggravated : ProjectileCalculations.Form = None
//}
//
//object StandardInfantryDamage extends DamageSelection {
// def Direct : ProjectileCalculations.Form = InfantryHitDamage.Calculate
// def Splash : ProjectileCalculations.Form = InfantrySplashDamage.Calculate
// def Lash : ProjectileCalculations.Form = InfantryLashDamage.Calculate
// def Aggravated : ProjectileCalculations.Form = InfantrySplashDamage.Calculate
//}
//
//object StandardMaxDamage extends DamageSelection {
// def Direct : ProjectileCalculations.Form = MaxHitDamage.Calculate
// def Splash : ProjectileCalculations.Form = MaxSplashDamage.Calculate
// def Lash : ProjectileCalculations.Form = MaxLashDamage.Calculate
// def Aggravated : ProjectileCalculations.Form = None
//}
//
//object StandardVehicleDamage extends DamageSelection {
// def Direct : ProjectileCalculations.Form = VehicleHitDamage.Calculate
// def Splash : ProjectileCalculations.Form = VehicleSplashDamage.Calculate
// def Lash : ProjectileCalculations.Form = VehicleLashDamage.Calculate
// def Aggravated : ProjectileCalculations.Form = None
//}
//
//object StandardAircraftDamage extends DamageSelection {
// def Direct : ProjectileCalculations.Form = AircraftHitDamage.Calculate
// def Splash : ProjectileCalculations.Form = AircraftSplashDamage.Calculate
// def Lash : ProjectileCalculations.Form = AircraftLashDamage.Calculate
// def Aggravated : ProjectileCalculations.Form = None
//}
//
//object StandardDeployableDamage extends DamageSelection {
// def Direct : ProjectileCalculations.Form = VehicleHitDamage.Calculate
// def Splash : ProjectileCalculations.Form = VehicleSplashDamage.Calculate
// def Lash : ProjectileCalculations.Form = NoDamage.Calculate
// def Aggravated : ProjectileCalculations.Form = None
//}
//
//object StandardAmenityDamage extends DamageSelection {
// def Direct : ProjectileCalculations.Form = AmenityHitDamage.Calculate
// def Splash : ProjectileCalculations.Form = AmenitySplashDamage.Calculate
// def Lash : ProjectileCalculations.Form = NoDamage.Calculate
// def Aggravated : ProjectileCalculations.Form = None
//}

View file

@ -1,35 +0,0 @@
// Copyright (c) 2017 PSForever
//package net.psforever.objects.vital.damage
//
//import net.psforever.objects.ballistics.ResolvedProjectile
//import net.psforever.objects.vital.{DamageType, NoDamage}
//import net.psforever.objects.vital.projectile.ProjectileCalculations
//
///**
// * Maintain information about three primary forms of damage calculation
// * and a means to test which calculation is valid in a given situation.
// */
//trait DamageSelection {
// final def None: ProjectileCalculations.Form = NoDamage
//
// def Direct : ProjectileCalculations.Form
// def Splash : ProjectileCalculations.Form
// def Lash : ProjectileCalculations.Form
// def Aggravated : ProjectileCalculations.Form
//
// def apply(data : ResolvedProjectile) : ProjectileCalculations.Form = data.projectile.profile.ProjectileDamageType match {
// case DamageType.Direct => Direct
// case DamageType.Splash => Splash
// case DamageType.Lash => Lash
// case DamageType.Aggravated => Aggravated
// case _ => None
// }
//
// def apply(res : DamageType.Value) : ProjectileCalculations.Form = res match {
// case DamageType.Direct => Direct
// case DamageType.Splash => Splash
// case DamageType.Lash => Lash
// case DamageType.Aggravated => Aggravated
// case _ => None
// }
//}

View file

@ -8,7 +8,7 @@ import net.psforever.objects.definition._
import net.psforever.objects.definition.converter._
import net.psforever.objects.equipment._
import net.psforever.objects.inventory.InventoryTile
import net.psforever.objects.serverobject.aggravated.Aura
import net.psforever.objects.serverobject.aura.Aura
import net.psforever.objects.serverobject.doors.DoorDefinition
import net.psforever.objects.serverobject.generator.GeneratorDefinition
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMechDefinition

View file

@ -14,7 +14,7 @@ import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot,
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.aggravated.AuraContainer
import net.psforever.objects.serverobject.aura.AuraContainer
import net.psforever.objects.vital.resistance.ResistanceProfile
import net.psforever.objects.vital.{DamageResistanceModel, Vitality}
import net.psforever.objects.zones.ZoneAware

View file

@ -7,7 +7,7 @@ import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem,
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.aggravated.AuraContainer
import net.psforever.objects.serverobject.aura.AuraContainer
import net.psforever.objects.serverobject.deploy.Deployment
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.structures.AmenityOwner

View file

@ -8,7 +8,8 @@ import net.psforever.objects.ballistics.{PlayerSource, ResolvedProjectile}
import net.psforever.objects.equipment._
import net.psforever.objects.inventory.{GridInventory, InventoryItem}
import net.psforever.objects.loadouts.Loadout
import net.psforever.objects.serverobject.aggravated.AuraEffectBehavior
import net.psforever.objects.serverobject.aggravated.AggravatedBehavior
import net.psforever.objects.serverobject.aura.AuraEffectBehavior
import net.psforever.objects.serverobject.containable.{Containable, ContainableBehavior}
import net.psforever.objects.vital.{PlayerSuicide, Vitality}
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
@ -32,6 +33,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
with JammableBehavior
with Damageable
with ContainableBehavior
with AggravatedBehavior
with AuraEffectBehavior {
def JammableObject = player
@ -39,6 +41,8 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
def ContainerObject = player
def AggravatedObject = player
def AuraTargetObject = player
private[this] val log = org.log4s.getLogger(player.Name)
@ -58,11 +62,13 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
lockerControlAgent ! akka.actor.PoisonPill
player.avatar.locker.Actor = Default.Actor
EndAllEffects()
EndAllAggravation()
}
def receive: Receive =
jammableBehavior
.orElse(takesDamage)
.orElse(aggravatedBehavior)
.orElse(auraBehavior)
.orElse(containerBehavior)
.orElse {
@ -554,7 +560,11 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
if (Damageable.CanJammer(target, cause)) {
TryJammerEffectActivate(target, cause)
}
TryAggravationEffect(cause)
TryAggravationEffect(cause) match {
case Some(aggravation) =>
StartAuraEffect(aggravation.effect_type, aggravation.timing.duration)
case _ => ;
}
} else {
DestructionAwareness(target, Some(cause))
}
@ -609,6 +619,8 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
target.Die
//aura effects cancel
EndAllEffects()
//aggravation cancel
EndAllAggravation()
//unjam
CancelJammeredSound(target)
CancelJammeredStatus(target)

View file

@ -10,7 +10,8 @@ import net.psforever.objects.inventory.{GridInventory, InventoryItem}
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.aggravated.AuraEffectBehavior
import net.psforever.objects.serverobject.aggravated.AggravatedBehavior
import net.psforever.objects.serverobject.aura.AuraEffectBehavior
import net.psforever.objects.serverobject.containable.{Containable, ContainableBehavior}
import net.psforever.objects.serverobject.damage.Damageable.Target
import net.psforever.objects.serverobject.damage.DamageableVehicle
@ -54,11 +55,12 @@ class VehicleControl(vehicle: Vehicle)
with JammableMountedWeapons
with ContainableBehavior
with AntTransferBehavior
with AggravatedBehavior
with AuraEffectBehavior {
//make control actors belonging to utilities when making control actor belonging to vehicle
vehicle.Utilities.foreach({ case (_, util) => util.Setup })
def MountableObject = vehicle
def CargoObject = vehicle
@ -79,6 +81,8 @@ class VehicleControl(vehicle: Vehicle)
def AuraTargetObject = vehicle
def AggravatedObject = vehicle
if(vehicle.Definition == GlobalDefinitions.ant) {
findChargeTargetFunc = Vehicles.FindANTChargingSource
findDischargeTargetFunc = Vehicles.FindANTDischargingTarget
@ -101,6 +105,7 @@ class VehicleControl(vehicle: Vehicle)
util().Actor = Default.Actor
}
EndAllEffects()
EndAllAggravation()
}
def Enabled: Receive =
@ -109,6 +114,7 @@ class VehicleControl(vehicle: Vehicle)
.orElse(cargoBehavior)
.orElse(jammableBehavior)
.orElse(takesDamage)
.orElse(aggravatedBehavior)
.orElse(auraBehavior)
.orElse(canBeRepairedByNanoDispenser)
.orElse(containerBehavior)
@ -592,7 +598,11 @@ class VehicleControl(vehicle: Vehicle)
cause: ResolvedProjectile,
amount: Int
): Unit = {
TryAggravationEffect(cause)
TryAggravationEffect(cause) match {
case Some(aggravation) =>
StartAuraEffect(aggravation.effect_type, aggravation.timing.duration)
case _ => ;
}
super.DamageAwareness(target, cause, amount)
}
@ -602,6 +612,8 @@ class VehicleControl(vehicle: Vehicle)
): Unit = {
//aura effects cancel
EndAllEffects()
//aggravation cancel
EndAllAggravation()
super.DestructionAwareness(target, cause)
}
}

View file

@ -255,7 +255,7 @@ object GamePacketOpcode extends Enumeration {
// 0x68
case 0x68 => game.DroppodFreefallingMessage.decode
case 0x69 => game.AvatarFirstTimeEventMessage.decode
case 0x6a => noDecoder(AggravatedDamageMessage)
case 0x6a => game.AggravatedDamageMessage.decode
case 0x6b => game.TriggerSoundMessage.decode
case 0x6c => game.LootItemMessage.decode
case 0x6d => game.VehicleSubStateMessage.decode

View file

@ -451,8 +451,8 @@ class DamageModelTests extends Specification {
)
val func: Any => ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
func(tplayer)
tplayer.Health mustEqual 54
tplayer.Armor mustEqual 46
tplayer.Health mustEqual 65
tplayer.Armor mustEqual 35
}
"resolve infantry targets in a specific way" in {