mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-04-28 07:15:21 +00:00
separated aggravation behavior and uara management behavior; moved files into packages and deleted old files
This commit is contained in:
parent
a79fc6bd2f
commit
89d7aea633
16 changed files with 451 additions and 514 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2020 PSForever
|
// Copyright (c) 2020 PSForever
|
||||||
package net.psforever.objects.ballistics
|
package net.psforever.objects.ballistics
|
||||||
import net.psforever.objects.equipment.TargetValidation
|
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
|
import net.psforever.objects.vital.DamageType
|
||||||
|
|
||||||
final case class AggravatedTiming(duration: Long, ticks: Option[Int])
|
final case class AggravatedTiming(duration: Long, ticks: Option[Int])
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
// Copyright (c) 2020 PSForever
|
package net.psforever.objects.serverobject.aura
|
||||||
package net.psforever.objects.serverobject.aggravated
|
|
||||||
|
|
||||||
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 {
|
trait AuraContainer {
|
||||||
private var aura : Set[AuraEffect] = Set.empty[AuraEffect]
|
private var aura : Set[AuraEffect] = Set.empty[AuraEffect]
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
|
||||||
//}
|
|
||||||
|
|
@ -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
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
@ -8,7 +8,7 @@ import net.psforever.objects.definition._
|
||||||
import net.psforever.objects.definition.converter._
|
import net.psforever.objects.definition.converter._
|
||||||
import net.psforever.objects.equipment._
|
import net.psforever.objects.equipment._
|
||||||
import net.psforever.objects.inventory.InventoryTile
|
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.doors.DoorDefinition
|
||||||
import net.psforever.objects.serverobject.generator.GeneratorDefinition
|
import net.psforever.objects.serverobject.generator.GeneratorDefinition
|
||||||
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMechDefinition
|
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMechDefinition
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot,
|
||||||
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
|
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
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.resistance.ResistanceProfile
|
||||||
import net.psforever.objects.vital.{DamageResistanceModel, Vitality}
|
import net.psforever.objects.vital.{DamageResistanceModel, Vitality}
|
||||||
import net.psforever.objects.zones.ZoneAware
|
import net.psforever.objects.zones.ZoneAware
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem,
|
||||||
import net.psforever.objects.serverobject.mount.Mountable
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
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.deploy.Deployment
|
||||||
import net.psforever.objects.serverobject.hackable.Hackable
|
import net.psforever.objects.serverobject.hackable.Hackable
|
||||||
import net.psforever.objects.serverobject.structures.AmenityOwner
|
import net.psforever.objects.serverobject.structures.AmenityOwner
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ import net.psforever.objects.ballistics.{PlayerSource, ResolvedProjectile}
|
||||||
import net.psforever.objects.equipment._
|
import net.psforever.objects.equipment._
|
||||||
import net.psforever.objects.inventory.{GridInventory, InventoryItem}
|
import net.psforever.objects.inventory.{GridInventory, InventoryItem}
|
||||||
import net.psforever.objects.loadouts.Loadout
|
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.serverobject.containable.{Containable, ContainableBehavior}
|
||||||
import net.psforever.objects.vital.{PlayerSuicide, Vitality}
|
import net.psforever.objects.vital.{PlayerSuicide, Vitality}
|
||||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||||
|
|
@ -32,6 +33,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
with JammableBehavior
|
with JammableBehavior
|
||||||
with Damageable
|
with Damageable
|
||||||
with ContainableBehavior
|
with ContainableBehavior
|
||||||
|
with AggravatedBehavior
|
||||||
with AuraEffectBehavior {
|
with AuraEffectBehavior {
|
||||||
def JammableObject = player
|
def JammableObject = player
|
||||||
|
|
||||||
|
|
@ -39,6 +41,8 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
|
|
||||||
def ContainerObject = player
|
def ContainerObject = player
|
||||||
|
|
||||||
|
def AggravatedObject = player
|
||||||
|
|
||||||
def AuraTargetObject = player
|
def AuraTargetObject = player
|
||||||
|
|
||||||
private[this] val log = org.log4s.getLogger(player.Name)
|
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
|
lockerControlAgent ! akka.actor.PoisonPill
|
||||||
player.avatar.locker.Actor = Default.Actor
|
player.avatar.locker.Actor = Default.Actor
|
||||||
EndAllEffects()
|
EndAllEffects()
|
||||||
|
EndAllAggravation()
|
||||||
}
|
}
|
||||||
|
|
||||||
def receive: Receive =
|
def receive: Receive =
|
||||||
jammableBehavior
|
jammableBehavior
|
||||||
.orElse(takesDamage)
|
.orElse(takesDamage)
|
||||||
|
.orElse(aggravatedBehavior)
|
||||||
.orElse(auraBehavior)
|
.orElse(auraBehavior)
|
||||||
.orElse(containerBehavior)
|
.orElse(containerBehavior)
|
||||||
.orElse {
|
.orElse {
|
||||||
|
|
@ -554,7 +560,11 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
if (Damageable.CanJammer(target, cause)) {
|
if (Damageable.CanJammer(target, cause)) {
|
||||||
TryJammerEffectActivate(target, cause)
|
TryJammerEffectActivate(target, cause)
|
||||||
}
|
}
|
||||||
TryAggravationEffect(cause)
|
TryAggravationEffect(cause) match {
|
||||||
|
case Some(aggravation) =>
|
||||||
|
StartAuraEffect(aggravation.effect_type, aggravation.timing.duration)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
DestructionAwareness(target, Some(cause))
|
DestructionAwareness(target, Some(cause))
|
||||||
}
|
}
|
||||||
|
|
@ -609,6 +619,8 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
target.Die
|
target.Die
|
||||||
//aura effects cancel
|
//aura effects cancel
|
||||||
EndAllEffects()
|
EndAllEffects()
|
||||||
|
//aggravation cancel
|
||||||
|
EndAllAggravation()
|
||||||
//unjam
|
//unjam
|
||||||
CancelJammeredSound(target)
|
CancelJammeredSound(target)
|
||||||
CancelJammeredStatus(target)
|
CancelJammeredStatus(target)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ import net.psforever.objects.inventory.{GridInventory, InventoryItem}
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
import net.psforever.objects.serverobject.CommonMessages
|
||||||
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
||||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
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.containable.{Containable, ContainableBehavior}
|
||||||
import net.psforever.objects.serverobject.damage.Damageable.Target
|
import net.psforever.objects.serverobject.damage.Damageable.Target
|
||||||
import net.psforever.objects.serverobject.damage.DamageableVehicle
|
import net.psforever.objects.serverobject.damage.DamageableVehicle
|
||||||
|
|
@ -54,11 +55,12 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
with JammableMountedWeapons
|
with JammableMountedWeapons
|
||||||
with ContainableBehavior
|
with ContainableBehavior
|
||||||
with AntTransferBehavior
|
with AntTransferBehavior
|
||||||
|
with AggravatedBehavior
|
||||||
with AuraEffectBehavior {
|
with AuraEffectBehavior {
|
||||||
|
|
||||||
//make control actors belonging to utilities when making control actor belonging to vehicle
|
//make control actors belonging to utilities when making control actor belonging to vehicle
|
||||||
vehicle.Utilities.foreach({ case (_, util) => util.Setup })
|
vehicle.Utilities.foreach({ case (_, util) => util.Setup })
|
||||||
|
|
||||||
def MountableObject = vehicle
|
def MountableObject = vehicle
|
||||||
|
|
||||||
def CargoObject = vehicle
|
def CargoObject = vehicle
|
||||||
|
|
@ -79,6 +81,8 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
|
|
||||||
def AuraTargetObject = vehicle
|
def AuraTargetObject = vehicle
|
||||||
|
|
||||||
|
def AggravatedObject = vehicle
|
||||||
|
|
||||||
if(vehicle.Definition == GlobalDefinitions.ant) {
|
if(vehicle.Definition == GlobalDefinitions.ant) {
|
||||||
findChargeTargetFunc = Vehicles.FindANTChargingSource
|
findChargeTargetFunc = Vehicles.FindANTChargingSource
|
||||||
findDischargeTargetFunc = Vehicles.FindANTDischargingTarget
|
findDischargeTargetFunc = Vehicles.FindANTDischargingTarget
|
||||||
|
|
@ -101,6 +105,7 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
util().Actor = Default.Actor
|
util().Actor = Default.Actor
|
||||||
}
|
}
|
||||||
EndAllEffects()
|
EndAllEffects()
|
||||||
|
EndAllAggravation()
|
||||||
}
|
}
|
||||||
|
|
||||||
def Enabled: Receive =
|
def Enabled: Receive =
|
||||||
|
|
@ -109,6 +114,7 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
.orElse(cargoBehavior)
|
.orElse(cargoBehavior)
|
||||||
.orElse(jammableBehavior)
|
.orElse(jammableBehavior)
|
||||||
.orElse(takesDamage)
|
.orElse(takesDamage)
|
||||||
|
.orElse(aggravatedBehavior)
|
||||||
.orElse(auraBehavior)
|
.orElse(auraBehavior)
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
.orElse(containerBehavior)
|
.orElse(containerBehavior)
|
||||||
|
|
@ -592,7 +598,11 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
cause: ResolvedProjectile,
|
cause: ResolvedProjectile,
|
||||||
amount: Int
|
amount: Int
|
||||||
): Unit = {
|
): Unit = {
|
||||||
TryAggravationEffect(cause)
|
TryAggravationEffect(cause) match {
|
||||||
|
case Some(aggravation) =>
|
||||||
|
StartAuraEffect(aggravation.effect_type, aggravation.timing.duration)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
super.DamageAwareness(target, cause, amount)
|
super.DamageAwareness(target, cause, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -602,6 +612,8 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
): Unit = {
|
): Unit = {
|
||||||
//aura effects cancel
|
//aura effects cancel
|
||||||
EndAllEffects()
|
EndAllEffects()
|
||||||
|
//aggravation cancel
|
||||||
|
EndAllAggravation()
|
||||||
super.DestructionAwareness(target, cause)
|
super.DestructionAwareness(target, cause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,7 @@ object GamePacketOpcode extends Enumeration {
|
||||||
// 0x68
|
// 0x68
|
||||||
case 0x68 => game.DroppodFreefallingMessage.decode
|
case 0x68 => game.DroppodFreefallingMessage.decode
|
||||||
case 0x69 => game.AvatarFirstTimeEventMessage.decode
|
case 0x69 => game.AvatarFirstTimeEventMessage.decode
|
||||||
case 0x6a => noDecoder(AggravatedDamageMessage)
|
case 0x6a => game.AggravatedDamageMessage.decode
|
||||||
case 0x6b => game.TriggerSoundMessage.decode
|
case 0x6b => game.TriggerSoundMessage.decode
|
||||||
case 0x6c => game.LootItemMessage.decode
|
case 0x6c => game.LootItemMessage.decode
|
||||||
case 0x6d => game.VehicleSubStateMessage.decode
|
case 0x6d => game.VehicleSubStateMessage.decode
|
||||||
|
|
|
||||||
|
|
@ -451,8 +451,8 @@ class DamageModelTests extends Specification {
|
||||||
)
|
)
|
||||||
val func: Any => ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
|
val func: Any => ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
|
||||||
func(tplayer)
|
func(tplayer)
|
||||||
tplayer.Health mustEqual 54
|
tplayer.Health mustEqual 65
|
||||||
tplayer.Armor mustEqual 46
|
tplayer.Armor mustEqual 35
|
||||||
}
|
}
|
||||||
|
|
||||||
"resolve infantry targets in a specific way" in {
|
"resolve infantry targets in a specific way" in {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue