diff --git a/common/src/main/scala/net/psforever/objects/avatar/AuraEffectBehavior.scala b/common/src/main/scala/net/psforever/objects/avatar/AuraEffectBehavior.scala
index 0d4cb0ab..90da7f59 100644
--- a/common/src/main/scala/net/psforever/objects/avatar/AuraEffectBehavior.scala
+++ b/common/src/main/scala/net/psforever/objects/avatar/AuraEffectBehavior.scala
@@ -3,19 +3,24 @@ package net.psforever.objects.avatar
import akka.actor.{Actor, Cancellable}
import net.psforever.objects.Player
-import net.psforever.objects.ballistics.{AggravatedDamage, AggravatedInfo, ResolvedProjectile}
-import net.psforever.objects.vital.DamageType
+import net.psforever.objects.ballistics._
+import net.psforever.objects.serverobject.damage.Damageable
+import net.psforever.objects.vital.{DamageType, Vitality}
+import net.psforever.types.Vector3
import scala.collection.mutable
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
trait AuraEffectBehavior {
- _ : Actor =>
- private var activeEffectIndex : Long = 0
- private var effectsToIds : mutable.HashMap[Aura.Value, List[Long]] = mutable.HashMap.empty[Aura.Value, List[Long]]
- private var idsToTimers : mutable.LongMap[Cancellable] = mutable.LongMap.empty[Cancellable]
- private var idsToEntries : mutable.LongMap[AuraEffectBehavior.Entry] = mutable.LongMap.empty[AuraEffectBehavior.Entry]
+ _ : Actor with Damageable =>
+ private var activeEffectIndex: Long = 0
+ private val effectToEntryId: mutable.HashMap[Aura.Value, List[Long]] =
+ mutable.HashMap.empty[Aura.Value, 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 : Player
@@ -25,114 +30,181 @@ trait AuraEffectBehavior {
PerformCleanupEffect(id)
case AuraEffectBehavior.Aggravate(id, 0, leftoverTime) =>
- PerformAggravationAndRetimeEvent(id, iteration = 0, Some(leftoverTime), leftoverTime = 0)
+ RemoveEffectEntry(id)
+ RetimeEvent(id, iteration = 0, Some(leftoverTime), leftoverTime = 0)
case AuraEffectBehavior.Aggravate(id, iteration, leftover) => ;
- PerformAggravationAndRetimeEvent(id, iteration - 1, None, leftover)
+ RetimeEventAndPerformAggravation(id, iteration - 1, None, leftover)
}
- def PerformAggravationAndRetimeEvent(id : Long, iteration : Int, time : Option[Long], leftoverTime : Long) : Unit = {
+ private def RetimeEvent(
+ id: Long,
+ iteration: Int,
+ time: Option[Long],
+ leftoverTime: Long
+ ): Option[AuraEffectBehavior.Entry] = {
CancelEffectTimer(id)
- idsToEntries.get(id) match {
- case Some(entry) =>
- //TODO stuff ...
- idsToTimers += id -> context.system.scheduler.scheduleOnce(
- time.getOrElse(entry.effect.infliction_rate) milliseconds,
+ entryIdToEntry.get(id) match {
+ case Some(oldEntry) =>
+ val target = SourceEntry(AuraTargetObject)
+ val entry = PairIdWithAggravationEntry(
+ id,
+ oldEntry.effect,
+ oldEntry.retime,
+ oldEntry.data,
+ target,
+ target.Position - oldEntry.data.target.Position
+ )
+ entryIdToTimer += id -> context.system.scheduler.scheduleOnce(
+ time.getOrElse(entry.retime) milliseconds,
self,
AuraEffectBehavior.Aggravate(id, iteration, leftoverTime)
)
+ Some(entry)
case _ =>
PerformCleanupEffect(id)
+ None
}
}
- def CancelEffectTimer(id : Long) : Unit = {
- idsToTimers.remove(id) match {
+ private def RetimeEventAndPerformAggravation(id: Long, iteration: Int, time: Option[Long], leftoverTime: Long) : Unit = {
+ RetimeEvent(id, iteration, time, leftoverTime) match {
+ case Some(entry) =>
+ PerformAggravation(entry)
+ case _ => ;
+ }
+ }
+
+ def CancelEffectTimer(id: Long) : Unit = {
+ entryIdToTimer.remove(id) match {
case Some(timer) => timer.cancel
case _ => ;
}
}
- def PerformCleanupEffect(id : Long) : Unit = {
+ def PerformCleanupEffect(id: Long) : Unit = {
CleanupEffect(id) match {
case Aura.None => ;
case _ => UpdateAggravatedEffect(AuraTargetObject)
}
}
- def TryAggravationEffect(data : ResolvedProjectile) : Unit = {
+ def TryAggravationEffect(data: ResolvedProjectile) : Unit = {
data.projectile.profile.Aggravated match {
case Some(damage)
- if data.projectile.profile.ProjectileDamageType == DamageType.Aggravated && damage.effect_type != Aura.None =>
+ if data.projectile.profile.ProjectileDamageTypes.contains(DamageType.Aggravated) &&
+ damage.effect_type != Aura.None =>
TryAggravationEffect(damage, data)
case _ => ;
}
}
- private def TryAggravationEffect(aggravation : AggravatedDamage, data : ResolvedProjectile) : Unit = {
+ private def TryAggravationEffect(aggravation: AggravatedDamage, data: ResolvedProjectile) : Unit = {
val effect = aggravation.effect_type
val obj = AuraTargetObject
- if(obj.Aura.contains(effect)) { //TODO cumulative?
- SetupAggravationEntry(aggravation)
- }
- else if(obj.Aura.diff(obj.AddEffectToAura(effect)).contains(effect)) {
- SetupAggravationEntry(aggravation)
- UpdateAggravatedEffect(obj)
- }
- }
-
- private def SetupAggravationEntry(aggravation : AggravatedDamage) : Unit = {
- val effect = aggravation.effect_type
- aggravation.info.foreach { infos =>
- //get unused id
- val id = activeEffectIndex
- activeEffectIndex += 1
- //pair aura effect with id
- effectsToIds.get(effect) match {
- case None | Some(Nil) => effectsToIds += effect -> List(id)
- case Some(list) => effectsToIds -> (list :+ id)
+ if(CheckForUniqueUnqueuedProjectile(data.projectile)) {
+ val auraEffects = obj.Aura
+ if(auraEffects.contains(effect) && aggravation.cumulative_damage_degrade) { //TODO cumulative?
+ SetupAggravationEntry(aggravation, data)
+ }
+ else if(obj.AddEffectToAura(effect).diff(auraEffects).contains(effect)) {
+ SetupAggravationEntry(aggravation, data)
+ UpdateAggravatedEffect(obj)
}
- //pair id with entry
- idsToEntries += id -> AuraEffectBehavior.Entry(id, infos, aggravation, 0)
- //pair id with timer
- val iterations = (aggravation.duration / infos.infliction_rate).toInt
- val leftoverTime = aggravation.duration % infos.infliction_rate
- idsToTimers += id -> context.system.scheduler.scheduleOnce(infos.infliction_rate milliseconds, self, AuraEffectBehavior.Aggravate(id, iterations, leftoverTime))
}
}
- def CleanupEffect(id : Long) : Aura.Value = {
+ private def CheckForUniqueUnqueuedProjectile(projectile : Projectile) : Boolean = {
+ !entryIdToEntry.values.exists { entry => entry.data.projectile eq projectile }
+ }
+
+ 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)
+ }
+ //pair id with timer
+ val inflictionRate = info.infliction_rate
+ val iterations = (aggravation.duration / inflictionRate).toInt
+ val leftoverTime = aggravation.duration % inflictionRate
+ entryIdToTimer += id -> context.system.scheduler.scheduleOnce(inflictionRate milliseconds, self, AuraEffectBehavior.Aggravate(id, iterations, leftoverTime))
+ //pair id with entry
+ PairIdWithAggravationEntry(id, effect, inflictionRate, data, data.target, Vector3.Zero)
+ case _ => ;
+ }
+ }
+
+ private def PairIdWithAggravationEntry(
+ id: Long,
+ effect: Aura.Value,
+ retime:Long,
+ data: ResolvedProjectile,
+ target: SourceEntry,
+ offset: Vector3
+ ): AuraEffectBehavior.Entry = {
+ val aggravatedDamageInfo = ResolvedProjectile(
+ AuraEffectBehavior.burning(data.resolution),
+ data.projectile,
+ target,
+ data.damage_model,
+ data.hit_pos + offset
+ )
+ val entry = AuraEffectBehavior.Entry(id, effect, retime, aggravatedDamageInfo)
+ entryIdToEntry += id -> entry
+ entry
+ }
+
+ def RemoveEffectEntry(id: Long) : Aura.Value = {
+ 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.Value = {
//remove and cancel timer
- idsToTimers.remove(id) match {
+ entryIdToTimer.remove(id) match {
case Some(timer) => timer.cancel
case _ => ;
}
//remove entry and cache effect
- val out = idsToEntries.remove(id) match {
- case Some(entry) => entry.aggravation.effect_type
- case _ => Aura.None
- }
+ val out = RemoveEffectEntry(id)
//remove id and, if now unsupported, effect
- (effectsToIds.get(out) match {
+ (effectToEntryId.get(out) match {
case Some(list) => (out, list.filterNot(_ == id))
case _ => (Aura.None, Nil)
}) match {
case (Aura.None, _) =>
Aura.None
case (effect, Nil) =>
- effectsToIds.remove(effect)
+ AuraTargetObject.RemoveEffectFromAura(effect)
+ effectToEntryId.remove(effect)
effect
case (effect, list) =>
- effectsToIds += effect -> list
+ effectToEntryId += effect -> list
Aura.None
}
}
def EndAllEffects() : Unit = {
- idsToEntries.clear
- idsToTimers.values.foreach { _.cancel }
- idsToTimers.clear
- effectsToIds.clear
+ entryIdToEntry.clear
+ entryIdToTimer.values.foreach { _.cancel }
+ entryIdToTimer.clear
+ effectToEntryId.clear
+ val obj = AuraTargetObject
+ obj.Aura.foreach { obj.RemoveEffectFromAura }
}
def EndAllEffectsAndUpdate() : Unit = {
@@ -140,16 +212,39 @@ trait AuraEffectBehavior {
UpdateAggravatedEffect(AuraTargetObject)
}
- def UpdateAggravatedEffect(target : Player) : Unit = {
+ def UpdateAggravatedEffect(target: Player) : 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) : Unit = {
+ TakesDamage.apply(Vitality.Damage(entry.data.damage_model.Calculate(entry.data)))
+ }
}
object AuraEffectBehavior {
- private case class Entry(id : Long, effect : AggravatedInfo, aggravation : AggravatedDamage, damage : Any)
+ private case class Entry(id: Long, effect: Aura.Value, retime: Long, data: ResolvedProjectile)
- private case class Aggravate(id : Long, iterations : Int, leftover : Long)
+ 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
+ }
+ }
}
diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala
index 06cf7d55..23e5d283 100644
--- a/src/main/scala/net/psforever/actors/session/SessionActor.scala
+++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala
@@ -1,13 +1,26 @@
package net.psforever.actors.session
import java.util.concurrent.TimeUnit
-
import akka.actor.MDCContextAware.Implicits._
import akka.actor.typed
import akka.actor.typed.receptionist.Receptionist
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
+import java.util.concurrent.atomic.AtomicInteger
+import org.log4s.MDC
+import scala.collection.mutable.LongMap
+import scala.concurrent.{Await, Future}
+import scala.concurrent.duration._
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.util.{Failure, Success}
+import scodec.bits.ByteVector
+import services.properties.PropertyOverrideManager
+import org.joda.time.{LocalDateTime, Period}
+import csr.{CSRWarp, CSRZone, Traveler}
+import MDCContextAware.Implicits._
import net.psforever.objects.{GlobalDefinitions, _}
import net.psforever.objects.avatar.{Avatar, Certification, DeployableToolbox}
+import net.psforever.objects._
+import net.psforever.objects.avatar.{Certification, DeployableToolbox, FirstTimeEvents}
import net.psforever.objects.ballistics._
import net.psforever.objects.ce._
import net.psforever.objects.definition._
@@ -37,15 +50,7 @@ import net.psforever.objects.serverobject.turret.{FacilityTurret, WeaponTurret}
import net.psforever.objects.serverobject.zipline.ZipLinePath
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.teamwork.Squad
-import net.psforever.objects.vehicles.{
- AccessPermissionGroup,
- CargoBehavior,
- MountedWeapons,
- Utility,
- UtilityType,
- VehicleControl,
- VehicleLockState
-}
+import net.psforever.objects.vehicles._
import net.psforever.objects.vehicles.Utility.InternalTelepad
import net.psforever.objects.vital._
import net.psforever.objects.zones.{Zone, ZoneHotSpotProjector, Zoning}
@@ -53,6 +58,13 @@ import net.psforever.packet._
import net.psforever.packet.control._
import net.psforever.packet.game.objectcreate._
import net.psforever.packet.game.{HotSpotInfo => PacketHotSpotInfo, _}
+import net.psforever.objects.zones.{InterstellarCluster, Zone, ZoneHotSpotProjector, Zoning}
+import net.psforever.packet._
+import net.psforever.packet.control._
+import net.psforever.packet.game._
+import net.psforever.packet.game.objectcreate._
+import net.psforever.packet.game.{HotSpotInfo => PacketHotSpotInfo}
+import net.psforever.persistence
import net.psforever.types._
import org.log4s.MDC
import scodec.bits.ByteVector
@@ -78,7 +90,6 @@ import net.psforever.login.WorldSession._
import net.psforever.zones.Zones
import net.psforever.services.chat.ChatService
import net.psforever.objects.avatar.Cosmetic
-
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.concurrent.{Await, Future}
@@ -86,7 +97,6 @@ import scala.util.Success
import akka.actor.typed.scaladsl.adapter._
import akka.pattern.ask
import akka.util.Timeout
-
import scala.collection.mutable
object SessionActor {
@@ -5328,7 +5338,15 @@ class SessionActor extends Actor with MDCContextAware {
case _ => ;
}
- case msg @ HitMessage(seq_time, projectile_guid, unk1, hit_info, unk2, unk3, unk4) =>
+ case msg @ HitMessage(
+ seq_time,
+ projectile_guid,
+ unk1,
+ hit_info,
+ unk2,
+ unk3,
+ unk4
+ ) =>
log.info(s"Hit: $msg")
//find defined projectile
FindProjectileEntry(projectile_guid) match {
@@ -5395,31 +5413,33 @@ class SessionActor extends Actor with MDCContextAware {
}
case msg @ SplashHitMessage(
- seq_time,
- projectile_guid,
- explosion_pos,
- direct_victim_uid,
- unk3,
- projectile_vel,
- unk4,
- targets
+ seq_time,
+ projectile_guid,
+ explosion_pos,
+ direct_victim_uid,
+ unk3,
+ projectile_vel,
+ unk4,
+ targets
) =>
log.info(s"Splash: $msg")
FindProjectileEntry(projectile_guid) match {
case Some(projectile) =>
+ val profile = projectile.profile
projectile.Position = explosion_pos
projectile.Velocity = projectile_vel
+ val (resolution1, resolution2) = profile.Aggravated match {
+ case Some(_)
+ if profile.ProjectileDamageTypes.contains(DamageType.Aggravated) =>
+ (ProjectileResolution.AggravatedDirect, ProjectileResolution.AggravatedSplash)
+ case _ =>
+ (ProjectileResolution.Splash, ProjectileResolution.Splash)
+ }
//direct_victim_uid
ValidObject(direct_victim_uid) match {
- case Some(
- target: PlanetSideGameObject with FactionAffinity with Vitality
- ) =>
- CheckForHitPositionDiscrepancy(
- projectile_guid,
- explosion_pos,
- target
- )
- ResolveProjectileEntry(projectile, ProjectileResolution.Splash, target, explosion_pos) match {
+ case Some(target: PlanetSideGameObject with FactionAffinity with Vitality) =>
+ CheckForHitPositionDiscrepancy(projectile_guid, target.Position, target)
+ ResolveProjectileEntry(projectile, resolution1, target, target.Position) match {
case Some(projectile) =>
HandleDealingDamage(target, projectile)
case None => ;
@@ -5431,7 +5451,7 @@ class SessionActor extends Actor with MDCContextAware {
ValidObject(elem.uid) match {
case Some(target: PlanetSideGameObject with FactionAffinity with Vitality) =>
CheckForHitPositionDiscrepancy(projectile_guid, explosion_pos, target)
- ResolveProjectileEntry(projectile, ProjectileResolution.Splash, target, explosion_pos) match {
+ ResolveProjectileEntry(projectile, resolution2, target, explosion_pos) match {
case Some(projectile) =>
HandleDealingDamage(target, projectile)
case None => ;
@@ -5439,7 +5459,7 @@ class SessionActor extends Actor with MDCContextAware {
case _ => ;
}
})
- if (projectile.profile.ExistsOnRemoteClients && projectile.HasGUID) {
+ if (profile.ExistsOnRemoteClients && projectile.HasGUID) {
//cleanup
val localIndex = projectile_guid.guid - Projectile.baseUID
if (projectile.HasGUID) {
@@ -5642,16 +5662,16 @@ class SessionActor extends Actor with MDCContextAware {
log.debug("Ouch! " + msg)
case msg @ BugReportMessage(
- version_major,
- version_minor,
- version_date,
- bug_type,
- repeatable,
- location,
- zone,
- pos,
- summary,
- desc
+ version_major,
+ version_minor,
+ version_date,
+ bug_type,
+ repeatable,
+ location,
+ zone,
+ pos,
+ summary,
+ desc
) =>
log.info("BugReportMessage: " + msg)
diff --git a/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
index dbdf1411..e33c4dc3 100644
--- a/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
+++ b/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
@@ -2040,6 +2040,7 @@ object GlobalDefinitions {
no_projectile.Name = "none"
ProjectileDefinition.CalculateDerivedFields(no_projectile)
+ no_projectile.Modifiers = Nil
bullet_105mm_projectile.Name = "105mmbullet_projectile"
bullet_105mm_projectile.Damage0 = 150
@@ -2363,6 +2364,7 @@ object GlobalDefinitions {
chainblade_projectile.InitialVelocity = 100
chainblade_projectile.Lifespan = .02f
ProjectileDefinition.CalculateDerivedFields(chainblade_projectile)
+ chainblade_projectile.Modifiers = DamageModifiers.MaxDistanceCutoff
colossus_100mm_projectile.Name = "colossus_100mm_projectile"
colossus_100mm_projectile.Damage0 = 58
@@ -2597,6 +2599,7 @@ object GlobalDefinitions {
flamethrower_fireball.Damage2 = 0
flamethrower_fireball.Damage3 = 20
flamethrower_fireball.Damage4 = 0
+ flamethrower_fireball.DamageToHealthOnly = true
flamethrower_fireball.DamageAtEdge = 0.15f
flamethrower_fireball.DamageRadius = 5f
flamethrower_fireball.ProjectileDamageType = DamageType.Aggravated
@@ -2611,6 +2614,13 @@ object GlobalDefinitions {
flamethrower_fireball.InitialVelocity = 15
flamethrower_fireball.Lifespan = 1.2f
ProjectileDefinition.CalculateDerivedFields(flamethrower_fireball)
+ flamethrower_fireball.Modifiers = List(
+ DamageModifiers.AggravatedDirect,
+ DamageModifiers.AggravatedDirectBurn,
+ DamageModifiers.AggravatedSplash,
+ DamageModifiers.AggravatedSplashBurn,
+ DamageModifiers.RadialDegrade
+ )
flamethrower_projectile.Name = "flamethrower_projectile"
flamethrower_projectile.Damage0 = 10
@@ -2618,6 +2628,7 @@ object GlobalDefinitions {
flamethrower_projectile.Damage2 = 0
flamethrower_projectile.Damage3 = 4
flamethrower_projectile.Damage4 = 0
+ flamethrower_projectile.DamageToHealthOnly = true
flamethrower_projectile.Acceleration = -5
flamethrower_projectile.AccelerationUntil = 2f
flamethrower_projectile.ProjectileDamageType = DamageType.Aggravated
@@ -2634,6 +2645,11 @@ object GlobalDefinitions {
flamethrower_projectile.InitialVelocity = 10
flamethrower_projectile.Lifespan = 2.0f
ProjectileDefinition.CalculateDerivedFields(flamethrower_projectile)
+ flamethrower_projectile.Modifiers = List(
+ DamageModifiers.AggravatedDirect,
+ DamageModifiers.AggravatedDirectBurn,
+ DamageModifiers.MaxDistanceCutoff
+ )
flux_cannon_apc_projectile.Name = "flux_cannon_apc_projectile"
// TODO for later, maybe : set_resource_parent flux_cannon_apc_projectile game_objects flux_cannon_thresher_projectile
@@ -2685,6 +2701,7 @@ object GlobalDefinitions {
forceblade_projectile.InitialVelocity = 100
forceblade_projectile.Lifespan = .02f
ProjectileDefinition.CalculateDerivedFields(forceblade_projectile)
+ forceblade_projectile.Modifiers = DamageModifiers.MaxDistanceCutoff
frag_cartridge_projectile.Name = "frag_cartridge_projectile"
// TODO for later, maybe : set_resource_parent frag_cartridge_projectile game_objects frag_grenade_projectile
@@ -2898,7 +2915,7 @@ object GlobalDefinitions {
EffectTarget.Validation.VehicleNotAMS
) -> 10000
ProjectileDefinition.CalculateDerivedFields(jammer_cartridge_projectile)
- jammer_cartridge_projectile.Modifiers = Nil
+ jammer_cartridge_projectile.Modifiers = DamageModifiers.MaxDistanceCutoff
jammer_cartridge_projectile_b.Name = "jammer_cartridge_projectile_b"
// TODO for later, maybe : set_resource_parent jammer_cartridge_projectile_b game_objects jammer_grenade_projectile_enh
@@ -2937,7 +2954,7 @@ object GlobalDefinitions {
EffectTarget.Validation.VehicleNotAMS
) -> 10000
ProjectileDefinition.CalculateDerivedFields(jammer_cartridge_projectile_b)
- jammer_cartridge_projectile_b.Modifiers = Nil
+ jammer_cartridge_projectile_b.Modifiers = DamageModifiers.MaxDistanceCutoff
jammer_grenade_projectile.Name = "jammer_grenade_projectile"
jammer_grenade_projectile.Damage0 = 0
@@ -2975,7 +2992,7 @@ object GlobalDefinitions {
EffectTarget.Validation.VehicleNotAMS
) -> 10000
ProjectileDefinition.CalculateDerivedFields(jammer_grenade_projectile)
- jammer_grenade_projectile.Modifiers = Nil
+ jammer_grenade_projectile.Modifiers = DamageModifiers.MaxDistanceCutoff
jammer_grenade_projectile_enh.Name = "jammer_grenade_projectile_enh"
// TODO for later, maybe : set_resource_parent jammer_grenade_projectile_enh game_objects jammer_grenade_projectile
@@ -3014,7 +3031,7 @@ object GlobalDefinitions {
EffectTarget.Validation.VehicleNotAMS
) -> 10000
ProjectileDefinition.CalculateDerivedFields(jammer_grenade_projectile_enh)
- jammer_grenade_projectile_enh.Modifiers = Nil
+ jammer_grenade_projectile_enh.Modifiers = DamageModifiers.MaxDistanceCutoff
katana_projectile.Name = "katana_projectile"
katana_projectile.Damage0 = 25
@@ -3057,7 +3074,10 @@ object GlobalDefinitions {
lasher_projectile.LashRadius = 2.5f
lasher_projectile.Lifespan = 0.75f
ProjectileDefinition.CalculateDerivedFields(lasher_projectile)
- lasher_projectile.Modifiers = List(DamageModifiers.DistanceDegrade, DamageModifiers.Lash)
+ lasher_projectile.Modifiers = List(
+ DamageModifiers.DistanceDegrade,
+ DamageModifiers.Lash
+ )
lasher_projectile_ap.Name = "lasher_projectile_ap"
lasher_projectile_ap.Damage0 = 12
@@ -3072,7 +3092,10 @@ object GlobalDefinitions {
lasher_projectile_ap.LashRadius = 2.5f
lasher_projectile_ap.Lifespan = 0.75f
ProjectileDefinition.CalculateDerivedFields(lasher_projectile_ap)
- lasher_projectile_ap.Modifiers = List(DamageModifiers.DistanceDegrade, DamageModifiers.Lash)
+ lasher_projectile_ap.Modifiers = List(
+ DamageModifiers.DistanceDegrade,
+ DamageModifiers.Lash
+ )
liberator_bomb_cluster_bomblet_projectile.Name = "liberator_bomb_cluster_bomblet_projectile"
liberator_bomb_cluster_bomblet_projectile.Damage0 = 75
@@ -3145,6 +3168,7 @@ object GlobalDefinitions {
maelstrom_stream_projectile.InitialVelocity = 200
maelstrom_stream_projectile.Lifespan = 0.2f
ProjectileDefinition.CalculateDerivedFields(maelstrom_stream_projectile)
+ maelstrom_stream_projectile.Modifiers = DamageModifiers.MaxDistanceCutoff
magcutter_projectile.Name = "magcutter_projectile"
// TODO for later, maybe : set_resource_parent magcutter_projectile game_objects melee_ammo_projectile
@@ -3154,6 +3178,7 @@ object GlobalDefinitions {
magcutter_projectile.InitialVelocity = 100
magcutter_projectile.Lifespan = .02f
ProjectileDefinition.CalculateDerivedFields(magcutter_projectile)
+ magcutter_projectile.Modifiers = DamageModifiers.MaxDistanceCutoff
melee_ammo_projectile.Name = "melee_ammo_projectile"
melee_ammo_projectile.Damage0 = 25
@@ -3162,6 +3187,7 @@ object GlobalDefinitions {
melee_ammo_projectile.InitialVelocity = 100
melee_ammo_projectile.Lifespan = .02f
ProjectileDefinition.CalculateDerivedFields(melee_ammo_projectile)
+ melee_ammo_projectile.Modifiers = DamageModifiers.MaxDistanceCutoff
meteor_common.Name = "meteor_common"
meteor_common.DamageAtEdge = .1f
@@ -3482,6 +3508,13 @@ object GlobalDefinitions {
plasma_cartridge_projectile.InitialVelocity = 30
plasma_cartridge_projectile.Lifespan = 15f
ProjectileDefinition.CalculateDerivedFields(plasma_cartridge_projectile)
+ plasma_cartridge_projectile.Modifiers = List(
+ DamageModifiers.AggravatedDirect,
+ DamageModifiers.AggravatedDirectBurn,
+ DamageModifiers.AggravatedSplash,
+ DamageModifiers.AggravatedSplashBurn,
+ DamageModifiers.RadialDegrade
+ )
plasma_cartridge_projectile_b.Name = "plasma_cartridge_projectile_b"
// TODO for later, maybe : set_resource_parent plasma_cartridge_projectile_b game_objects plasma_grenade_projectile_B
@@ -3502,6 +3535,13 @@ object GlobalDefinitions {
plasma_cartridge_projectile_b.InitialVelocity = 30
plasma_cartridge_projectile_b.Lifespan = 2f
ProjectileDefinition.CalculateDerivedFields(plasma_cartridge_projectile_b)
+ plasma_cartridge_projectile_b.Modifiers = List(
+ DamageModifiers.AggravatedDirect,
+ DamageModifiers.AggravatedDirectBurn,
+ DamageModifiers.AggravatedSplash,
+ DamageModifiers.AggravatedSplashBurn,
+ DamageModifiers.RadialDegrade
+ )
plasma_grenade_projectile.Name = "plasma_grenade_projectile"
plasma_grenade_projectile.Damage0 = 40
@@ -3521,6 +3561,13 @@ object GlobalDefinitions {
plasma_grenade_projectile.InitialVelocity = 30
plasma_grenade_projectile.Lifespan = 15f
ProjectileDefinition.CalculateDerivedFields(plasma_grenade_projectile)
+ plasma_grenade_projectile.Modifiers = List(
+ DamageModifiers.AggravatedDirect,
+ DamageModifiers.AggravatedDirectBurn,
+ DamageModifiers.AggravatedSplash,
+ DamageModifiers.AggravatedSplashBurn,
+ DamageModifiers.RadialDegrade
+ )
plasma_grenade_projectile_B.Name = "plasma_grenade_projectile_B"
// TODO for later, maybe : set_resource_parent plasma_grenade_projectile_B game_objects plasma_grenade_projectile
@@ -3541,6 +3588,13 @@ object GlobalDefinitions {
plasma_grenade_projectile_B.InitialVelocity = 30
plasma_grenade_projectile_B.Lifespan = 3f
ProjectileDefinition.CalculateDerivedFields(plasma_grenade_projectile_B)
+ plasma_grenade_projectile_B.Modifiers = List(
+ DamageModifiers.AggravatedDirect,
+ DamageModifiers.AggravatedDirectBurn,
+ DamageModifiers.AggravatedSplash,
+ DamageModifiers.AggravatedSplashBurn,
+ DamageModifiers.RadialDegrade
+ )
pounder_projectile.Name = "pounder_projectile"
pounder_projectile.Damage0 = 31
@@ -3689,7 +3743,7 @@ object GlobalDefinitions {
rocklet_jammer_projectile.InitialVelocity = 50
rocklet_jammer_projectile.Lifespan = 8f
ProjectileDefinition.CalculateDerivedFields(rocklet_jammer_projectile)
- rocklet_jammer_projectile.Modifiers = Nil
+ //TODO rocklet_jammer_projectile.Modifiers = DamageModifiers.RadialDegrade?
scattercannon_projectile.Name = "scattercannon_projectile"
scattercannon_projectile.Damage0 = 11
@@ -3809,7 +3863,6 @@ object GlobalDefinitions {
spiker_projectile.InitialVelocity = 40
spiker_projectile.Lifespan = 5f
ProjectileDefinition.CalculateDerivedFields(spiker_projectile)
- spiker_projectile.Modifiers = DamageModifiers.RadialDegrade
spitfire_aa_ammo_projectile.Name = "spitfire_aa_ammo_projectile"
spitfire_aa_ammo_projectile.Damage0 = 5
@@ -3907,6 +3960,7 @@ object GlobalDefinitions {
trek_projectile.InitialVelocity = 40
trek_projectile.Lifespan = 7f
ProjectileDefinition.CalculateDerivedFields(trek_projectile)
+ trek_projectile.Modifiers = DamageModifiers.MaxDistanceCutoff
vanu_sentry_turret_projectile.Name = "vanu_sentry_turret_projectile"
vanu_sentry_turret_projectile.Damage0 = 25
@@ -4585,7 +4639,7 @@ object GlobalDefinitions {
flamethrower.FireModes(1).AmmoSlotIndex = 0
flamethrower.FireModes(1).Magazine = 100
flamethrower.FireModes(1).RoundsPerShot = 50
- flamethrower.Tile = InventoryTile.Tile63
+ flamethrower.Tile = InventoryTile.Tile93
winchester.Name = "winchester"
winchester.Size = EquipmentSize.Rifle
diff --git a/src/main/scala/net/psforever/objects/Player.scala b/src/main/scala/net/psforever/objects/Player.scala
index 111fa739..aec00096 100644
--- a/src/main/scala/net/psforever/objects/Player.scala
+++ b/src/main/scala/net/psforever/objects/Player.scala
@@ -359,7 +359,9 @@ class Player(var avatar: Avatar)
def Aura : Set[AuraEffect.Value] = aura
def AddEffectToAura(effect : AuraEffect.Value) : Set[AuraEffect.Value] = {
- aura = aura + effect
+ if(effect != AuraEffect.None) {
+ aura = aura + effect
+ }
Aura
}
diff --git a/src/main/scala/net/psforever/objects/ballistics/ProjectileResolution.scala b/src/main/scala/net/psforever/objects/ballistics/ProjectileResolution.scala
index 87b56805..09b2e3b3 100644
--- a/src/main/scala/net/psforever/objects/ballistics/ProjectileResolution.scala
+++ b/src/main/scala/net/psforever/objects/ballistics/ProjectileResolution.scala
@@ -2,16 +2,32 @@
package net.psforever.objects.ballistics
/**
- * An `Enumeration` of outcomes regarding what actually happened to the projectile.
+ * An `Enumeration` of outcomes regarding what actually happened to the projectile,
+ * complementing normal damage type distinction in directing damage calculations.
+ *
+ * Although the latter states reflect what sort of damage the projectile might perform - `Hit`, `Splash`, etc. -
+ * the state is more a communication about how that damage is interpreted by the server.
+ * For example, some projectiles:
+ * perform `Direct` damage, are reported by `HitMessage` packets, and resolve as `Hit`;
+ * or, perform `Direct` damage, are reported by `LashDamage` packets, and resolve as `Lash`.
+ * Furthermore, some projectiles:
+ * perform `Splash` damage, are reported by `SplashHitMessage` packets, and resolve as `Splash`;
+ * or, perform `Aggravated` damage, are reported by `SplashHitMessage` packets
+ * and resolve either as `AggravatedDirect` or as `AggravatedSplash`.
*/
object ProjectileResolution extends Enumeration {
type Type = Value
- val Unresolved, //original basic non-resolution
- MissedShot, //projectile did not encounter any collision object and was despawned
- Resolved, //a general "projectile encountered something" status with a more specific resolution
- Hit, //direct hit, one target
- Splash, //area of effect damage, potentially multiple targets
- Lash //lashing damage, potentially multiple targets
+ val
+ Unresolved, //original basic non-resolution
+ MissedShot, //projectile did not encounter any collision object and was despawned
+ Resolved, //a general "projectile encountered something" status with a more specific resolution
+ Hit, //direct hit, one target
+ Splash, //area of effect damage, potentially multiple targets
+ Lash, //lashing damage, potentially multiple targets
+ AggravatedDirect, //direct hit aggravated damage
+ AggravatedDirectBurn, //continuous direct hit aggravated damage
+ AggravatedSplash, //splashed aggravated damage
+ AggravatedSplashBurn //continuous splashed aggravated damage
= Value
}
diff --git a/src/main/scala/net/psforever/objects/definition/ProjectileDefinition.scala b/src/main/scala/net/psforever/objects/definition/ProjectileDefinition.scala
index 0bfab8f2..3f68364c 100644
--- a/src/main/scala/net/psforever/objects/definition/ProjectileDefinition.scala
+++ b/src/main/scala/net/psforever/objects/definition/ProjectileDefinition.scala
@@ -21,6 +21,7 @@ class ProjectileDefinition(objectId: Int)
private var accelerationUntil: Float = 0f
private var damageType: DamageType.Value = DamageType.None
private var damageTypeSecondary: DamageType.Value = DamageType.None
+ private var damageToHealthOnly: Boolean = false
private var degradeDelay: Float = 1f
private var degradeMultiplier: Float = 1f
private var initialVelocity: Int = 1
@@ -83,6 +84,17 @@ class ProjectileDefinition(objectId: Int)
ProjectileDamageTypeSecondary
}
+ def ProjectileDamageTypes : Set[DamageType.Value] = {
+ Set(damageType, damageTypeSecondary).filterNot(_ == DamageType.None)
+ }
+
+ def DamageToHealthOnly : Boolean = damageToHealthOnly
+
+ def DamageToHealthOnly_=(healthOnly: Boolean) : Boolean = {
+ damageToHealthOnly = healthOnly
+ DamageToHealthOnly
+ }
+
def DegradeDelay: Float = degradeDelay
def DegradeDelay_=(degradeDelay: Float): Float = {
diff --git a/src/main/scala/net/psforever/objects/vital/StandardResolutions.scala b/src/main/scala/net/psforever/objects/vital/StandardResolutions.scala
index fb5eb164..673c7aea 100644
--- a/src/main/scala/net/psforever/objects/vital/StandardResolutions.scala
+++ b/src/main/scala/net/psforever/objects/vital/StandardResolutions.scala
@@ -11,13 +11,13 @@ object NoResolutions
object InfantryResolutions
extends DamageResistCalculations(
- ResolutionCalculations.InfantryDamageAfterResist,
+ ResolutionCalculations.InfantryDamage,
ResolutionCalculations.InfantryApplication
)
object MaxResolutions
extends DamageResistCalculations(
- ResolutionCalculations.MaxDamageAfterResist,
+ ResolutionCalculations.MaxDamage,
ResolutionCalculations.InfantryApplication
)
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 478f5bfb..bb7aedc9 100644
--- a/src/main/scala/net/psforever/objects/vital/damage/DamageModifiers.scala
+++ b/src/main/scala/net/psforever/objects/vital/damage/DamageModifiers.scala
@@ -1,8 +1,9 @@
// Copyright (c) 2020 PSForever
package net.psforever.objects.vital.damage
-import net.psforever.objects.ballistics.{ProjectileResolution, ResolvedProjectile}
-import net.psforever.types.Vector3
+import net.psforever.objects.ballistics.{PlayerSource, ProjectileResolution, ResolvedProjectile}
+import net.psforever.objects.vital.DamageType
+import net.psforever.types.{ExoSuitType, Vector3}
/**
* Adjustments performed on the subsequent manipulations of the "base damage" value of an attack vector
@@ -45,6 +46,21 @@ object DamageModifiers {
private def function(damage: Int, data: ResolvedProjectile): Int = damage
}
+ case object MaxDistanceCutoff extends Mod {
+ def Calculate: DamageModifiers.Format = function
+
+ private def function(damage: Int, data: ResolvedProjectile): Int = {
+ val projectile = data.projectile
+ val profile = projectile.profile
+ val distance = Vector3.Distance(data.hit_pos, projectile.shot_origin)
+ if (distance <= profile.DistanceMax) {
+ damage
+ } else {
+ 0
+ }
+ }
+ }
+
/**
* The input value degrades (lessens)
* the further the distance between the point of origin (`shot_origin`)
@@ -117,4 +133,91 @@ object DamageModifiers {
}
}
}
+
+ case object AggravatedDirect extends Mod {
+ def Calculate: DamageModifiers.Format =
+ BaseAggravatedFormula(ProjectileResolution.AggravatedDirect, DamageType.Direct)
+ }
+
+ case object AggravatedSplash extends Mod {
+ def Calculate: DamageModifiers.Format =
+ BaseAggravatedFormula(ProjectileResolution.AggravatedSplash, DamageType.Splash)
+ }
+
+ case object AggravatedDirectBurn extends Mod {
+ def Calculate: DamageModifiers.Format =
+ BaseAggravatedBurnFormula(ProjectileResolution.AggravatedDirectBurn, DamageType.Direct)
+ }
+
+ case object AggravatedSplashBurn extends Mod {
+ def Calculate: DamageModifiers.Format =
+ BaseAggravatedBurnFormula(ProjectileResolution.AggravatedSplashBurn, DamageType.Splash)
+ }
+
+ private def BaseAggravatedFormula(
+ resolution: ProjectileResolution.Value,
+ damageType : DamageType.Value
+ )
+ (
+ damage: Int,
+ data: ResolvedProjectile
+ ): Int = {
+ if (data.resolution == resolution) {
+ (data.projectile.profile.Aggravated, data.target) match {
+ case (Some(aggravation), p: PlayerSource) if p.ExoSuit == ExoSuitType.MAX =>
+ val aggravatedDirectDamage = (aggravation.info.find(_.damage_type == damageType) match {
+ case Some(infos) =>
+ damage * infos.degradation_percentage
+ case _ =>
+ damage toFloat
+ }) * aggravation.max_factor
+ damage + aggravatedDirectDamage toInt
+ case _ =>
+ damage
+ }
+ } else {
+ damage
+ }
+ }
+
+ private def BaseAggravatedBurnFormula(
+ resolution: ProjectileResolution.Value,
+ damageType : DamageType.Value
+ )
+ (
+ damage: Int,
+ data: ResolvedProjectile
+ ): Int = {
+ if (data.resolution == resolution) {
+ (data.projectile.profile.Aggravated, data.target) match {
+ case (Some(aggravation), p: PlayerSource) =>
+ val degradation = aggravation.info.find(_.damage_type == damageType) match {
+ case Some(info) =>
+ info.degradation_percentage
+ case _ =>
+ 1f
+ }
+ if (p.exosuit == ExoSuitType.MAX) {
+ (damage * degradation * aggravation.max_factor) toInt
+ } else {
+ val resist = data.damage_model.ResistUsing(data)(data)
+ if (damage > resist) {
+ ((damage - resist) * degradation).toInt + resist
+ } else {
+ val degradedDamage = damage * degradation
+ if (degradedDamage > resist) {
+ degradedDamage toInt
+ }
+ else {
+ damage
+ }
+ }
+ }
+ case _ =>
+ damage
+ }
+ } else {
+ damage
+ }
+ }
}
diff --git a/src/main/scala/net/psforever/objects/vital/resolution/ResolutionCalculations.scala b/src/main/scala/net/psforever/objects/vital/resolution/ResolutionCalculations.scala
index 5067a74e..9166f7d0 100644
--- a/src/main/scala/net/psforever/objects/vital/resolution/ResolutionCalculations.scala
+++ b/src/main/scala/net/psforever/objects/vital/resolution/ResolutionCalculations.scala
@@ -38,15 +38,31 @@ object ResolutionCalculations {
def NoDamage(data: ResolvedProjectile)(a: Int, b: Int): Int = 0
- def InfantryDamageAfterResist(data: ResolvedProjectile): (Int, Int) => (Int, Int) = {
+ def InfantryDamage(data: ResolvedProjectile): (Int, Int) => (Int, Int) = {
data.target match {
case target: PlayerSource =>
- InfantryDamageAfterResist(target.health, target.armor)
+ if(data.projectile.profile.DamageToHealthOnly) {
+ DamageToHealthOnly(target.health)
+ } else {
+ InfantryDamageAfterResist(target.health, target.armor)
+ }
case _ =>
InfantryDamageAfterResist(0, 0)
}
}
+ def DamageToHealthOnly(currentHP: Int)(damages: Int, resistance: Int): (Int, Int) = {
+ if (damages > 0 && currentHP > 0) {
+ if(damages > resistance) {
+ (damages - resistance, 0)
+ } else {
+ (damages, 0)
+ }
+ } else {
+ (0, 0)
+ }
+ }
+
def InfantryDamageAfterResist(currentHP: Int, currentArmor: Int)(damages: Int, resistance: Int): (Int, Int) = {
if (damages > 0 && currentHP > 0) {
if (currentArmor <= 0) {
@@ -67,10 +83,14 @@ object ResolutionCalculations {
}
}
- def MaxDamageAfterResist(data: ResolvedProjectile): (Int, Int) => (Int, Int) = {
+ def MaxDamage(data: ResolvedProjectile): (Int, Int) => (Int, Int) = {
data.target match {
case target: PlayerSource =>
- MaxDamageAfterResist(target.health, target.armor)
+ if(data.projectile.profile.DamageToHealthOnly) {
+ DamageToHealthOnly(target.health)
+ } else {
+ MaxDamageAfterResist(target.health, target.armor)
+ }
case _ =>
MaxDamageAfterResist(0, 0)
}
diff --git a/src/test/scala/objects/DamageModelTests.scala b/src/test/scala/objects/DamageModelTests.scala
index c9de3554..7e6935cd 100644
--- a/src/test/scala/objects/DamageModelTests.scala
+++ b/src/test/scala/objects/DamageModelTests.scala
@@ -302,7 +302,7 @@ class ResolutionCalculationsTests extends Specification {
target1.DamageModel,
Vector3.Zero
)
- InfantryDamageAfterResist(resprojectile1)(50, 10) mustEqual (0, 0)
+ InfantryDamage(resprojectile1)(50, 10) mustEqual (0, 0)
val target2 = player
val resprojectile2 = ResolvedProjectile(
@@ -312,7 +312,7 @@ class ResolutionCalculationsTests extends Specification {
target2.DamageModel,
Vector3.Zero
)
- InfantryDamageAfterResist(resprojectile2)(50, 10) mustEqual (40, 10)
+ InfantryDamage(resprojectile2)(50, 10) mustEqual (40, 10)
}
"calculate health and armor damage for infantry target" in {
@@ -346,7 +346,7 @@ class ResolutionCalculationsTests extends Specification {
target1.DamageModel,
Vector3.Zero
)
- MaxDamageAfterResist(resprojectile1)(50, 10) mustEqual (0, 0)
+ MaxDamage(resprojectile1)(50, 10) mustEqual (0, 0)
val target2 = player2
val resprojectile2 = ResolvedProjectile(
@@ -356,7 +356,7 @@ class ResolutionCalculationsTests extends Specification {
target2.DamageModel,
Vector3.Zero
)
- MaxDamageAfterResist(resprojectile2)(50, 10) mustEqual (0, 40)
+ MaxDamage(resprojectile2)(50, 10) mustEqual (0, 40)
}
"calculate health and armor damage for max target" in {
diff --git a/src/test/scala/objects/DamageableTest.scala b/src/test/scala/objects/DamageableTest.scala
index 554e6887..63c59290 100644
--- a/src/test/scala/objects/DamageableTest.scala
+++ b/src/test/scala/objects/DamageableTest.scala
@@ -40,6 +40,7 @@ class DamageableTest extends Specification {
"permit damage" in {
val target = new SensorDeployable(GlobalDefinitions.motionalarmsensor)
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectileA, weaponA.Definition, weaponA.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
SourceEntry(target),
target.DamageModel,
@@ -52,6 +53,7 @@ class DamageableTest extends Specification {
"ignore attempts at non-zero damage" in {
val target = new SensorDeployable(GlobalDefinitions.motionalarmsensor)
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectileA,
weaponA.Definition,
@@ -76,6 +78,7 @@ class DamageableTest extends Specification {
Faction = player1.Faction
}
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectileA, weaponA.Definition, weaponA.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
SourceEntry(target),
target.DamageModel,
@@ -98,6 +101,7 @@ class DamageableTest extends Specification {
Faction = PlanetSideEmpire.NC
}
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectileA, weaponA.Definition, weaponA.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
SourceEntry(target),
target.DamageModel,
@@ -124,6 +128,7 @@ class DamageableTest extends Specification {
Faction = player1.Faction
}
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectileA, weaponA.Definition, weaponA.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
SourceEntry(target),
target.DamageModel,
@@ -147,6 +152,7 @@ class DamageableTest extends Specification {
"permit jamming" in {
val target = new SensorDeployable(GlobalDefinitions.motionalarmsensor)
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectileB, weaponB.Definition, weaponB.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
SourceEntry(target),
target.DamageModel,
@@ -160,6 +166,7 @@ class DamageableTest extends Specification {
"ignore attempts at jamming if the projectile is does not cause the effect" in {
val target = new SensorDeployable(GlobalDefinitions.motionalarmsensor)
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectileA, weaponA.Definition, weaponA.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
SourceEntry(target),
target.DamageModel,
@@ -174,6 +181,7 @@ class DamageableTest extends Specification {
val target = new SensorDeployable(GlobalDefinitions.motionalarmsensor)
target.Faction = player1.Faction
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectileB, weaponB.Definition, weaponB.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
SourceEntry(target),
target.DamageModel,
@@ -188,6 +196,7 @@ class DamageableTest extends Specification {
"ignore attempts at jamming targets that are not jammable" in {
val target = new TrapDeployable(GlobalDefinitions.tank_traps)
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectileB, weaponB.Definition, weaponB.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
SourceEntry(target),
target.DamageModel,
@@ -207,6 +216,7 @@ class DamageableTest extends Specification {
val target = new SensorDeployable(GlobalDefinitions.motionalarmsensor)
target.Faction = player1.Faction
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectileB, weaponB.Definition, weaponB.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
SourceEntry(target),
target.DamageModel,
@@ -261,6 +271,7 @@ class DamageableEntityDamageTest extends ActorTest {
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -331,6 +342,7 @@ class DamageableEntityDestroyedTest extends ActorTest {
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -404,6 +416,7 @@ class DamageableEntityNotDestroyTwice extends ActorTest {
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -474,6 +487,7 @@ class DamageableAmenityTest extends ActorTest {
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -566,6 +580,7 @@ class DamageableMountableDamageTest extends ActorTest {
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -660,6 +675,7 @@ class DamageableMountableDestroyTest extends ActorTest {
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -748,6 +764,7 @@ class DamageableWeaponTurretDamageTest extends ActorTest {
val projectile = weapon.Projectile
val turretSource = SourceEntry(turret)
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -845,6 +862,7 @@ class DamageableWeaponTurretJammerTest extends ActorTest {
val projectile = weapon.Projectile
val turretSource = SourceEntry(turret)
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -946,6 +964,7 @@ class DamageableWeaponTurretDestructionTest extends ActorTest {
val weaponA = Tool(GlobalDefinitions.jammer_grenade)
val projectileA = weaponA.Projectile
val resolvedA = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectileA,
weaponA.Definition,
@@ -964,6 +983,7 @@ class DamageableWeaponTurretDestructionTest extends ActorTest {
val weaponB = Tool(GlobalDefinitions.phoenix) //decimator
val projectileB = weaponB.Projectile
val resolvedB = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectileB,
weaponB.Definition,
@@ -1085,6 +1105,7 @@ class DamageableVehicleDamageTest extends ActorTest {
val projectile = weapon.Projectile
val vehicleSource = SourceEntry(atv)
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -1216,6 +1237,7 @@ class DamageableVehicleDamageMountedTest extends ActorTest {
val projectile = weapon.Projectile
val vehicleSource = SourceEntry(lodestar)
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -1363,6 +1385,7 @@ class DamageableVehicleJammeringMountedTest extends ActorTest {
val weapon = Tool(GlobalDefinitions.jammer_grenade)
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -1452,6 +1475,7 @@ class DamageableVehicleDestroyTest extends ActorTest {
val projectile = weapon.Projectile
val vehicleSource = SourceEntry(atv)
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -1577,6 +1601,7 @@ class DamageableVehicleDestroyMountedTest extends ActorTest {
val weaponA = Tool(GlobalDefinitions.jammer_grenade)
val projectileA = weaponA.Projectile
val resolvedA = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectileA,
weaponA.Definition,
@@ -1595,6 +1620,7 @@ class DamageableVehicleDestroyMountedTest extends ActorTest {
val weaponB = Tool(GlobalDefinitions.phoenix) //decimator
val projectileB = weaponB.Projectile
val resolvedB = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectileB,
weaponB.Definition,
diff --git a/src/test/scala/objects/DeployableTest.scala b/src/test/scala/objects/DeployableTest.scala
index 63e99a62..39ab6107 100644
--- a/src/test/scala/objects/DeployableTest.scala
+++ b/src/test/scala/objects/DeployableTest.scala
@@ -334,6 +334,7 @@ class ExplosiveDeployableJammerTest extends ActorTest {
val pSource = PlayerSource(player1)
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectile, weapon.Definition, weapon.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
jMineSource,
j_mine.DamageModel,
@@ -373,7 +374,7 @@ class ExplosiveDeployableJammerTest extends ActorTest {
assert(
msg_local(2) match {
case LocalServiceMessage.Deployables(SupportActor.ClearSpecific(List(target), _zone)) =>
- (target eq j_mine) && (_zone eq zone)
+ (j_mine eq target) && (_zone eq zone)
case _ => false
}
)
@@ -431,6 +432,7 @@ class ExplosiveDeployableJammerExplodeTest extends ActorTest {
val pSource = PlayerSource(player1)
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectile, weapon.Definition, weapon.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
hMineSource,
h_mine.DamageModel,
@@ -476,7 +478,7 @@ class ExplosiveDeployableJammerExplodeTest extends ActorTest {
assert(
msg_local(3) match {
case LocalServiceMessage.Deployables(SupportActor.ClearSpecific(List(target), _zone)) =>
- (target eq h_mine) && (_zone eq zone)
+ (h_mine eq target) && (_zone eq zone)
case _ => false
}
)
@@ -540,6 +542,7 @@ class ExplosiveDeployableDestructionTest extends ActorTest {
val pSource = PlayerSource(player1)
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectile, weapon.Definition, weapon.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
hMineSource,
h_mine.DamageModel,
@@ -581,7 +584,7 @@ class ExplosiveDeployableDestructionTest extends ActorTest {
assert(
msg_local(2) match {
case LocalServiceMessage.Deployables(SupportActor.ClearSpecific(List(target), _zone)) =>
- (target eq h_mine) && (_zone eq zone)
+ (h_mine eq target) && (_zone eq zone)
case _ => false
}
)
diff --git a/src/test/scala/objects/GeneratorTest.scala b/src/test/scala/objects/GeneratorTest.scala
index 48c98756..4d53ae41 100644
--- a/src/test/scala/objects/GeneratorTest.scala
+++ b/src/test/scala/objects/GeneratorTest.scala
@@ -80,6 +80,7 @@ class GeneratorControlDamageTest extends ActorTest {
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -161,6 +162,7 @@ class GeneratorControlCriticalTest extends ActorTest {
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -251,6 +253,7 @@ class GeneratorControlDestroyedTest extends ActorTest {
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -381,6 +384,7 @@ class GeneratorControlKillsTest extends ActorTest {
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -503,6 +507,7 @@ class GeneratorControlNotDestroyTwice extends ActorTest {
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -592,6 +597,7 @@ class GeneratorControlNotDamageIfExplodingTest extends ActorTest {
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
@@ -685,6 +691,7 @@ class GeneratorControlNotRepairIfExplodingTest extends ActorTest {
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
weapon.Definition,
diff --git a/src/test/scala/objects/PlayerControlTest.scala b/src/test/scala/objects/PlayerControlTest.scala
index 06a528f2..56b34460 100644
--- a/src/test/scala/objects/PlayerControlTest.scala
+++ b/src/test/scala/objects/PlayerControlTest.scala
@@ -378,6 +378,7 @@ class PlayerControlDamageTest extends ActorTest {
val projectile = tool.Projectile
val playerSource = SourceEntry(player2)
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(
projectile,
tool.Definition,
@@ -477,6 +478,7 @@ class PlayerControlDeathStandingTest extends ActorTest {
val projectile = tool.Projectile
val player1Source = SourceEntry(player1)
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectile, tool.Definition, tool.FireMode, player1Source, 0, Vector3(2, 0, 0), Vector3(-1, 0, 0)),
SourceEntry(player2),
player2.DamageModel,
@@ -605,6 +607,7 @@ class PlayerControlDeathSeatedTest extends ActorTest {
val projectile = tool.Projectile
val player1Source = SourceEntry(player1)
val resolved = ResolvedProjectile(
+ ProjectileResolution.Hit,
Projectile(projectile, tool.Definition, tool.FireMode, player1Source, 0, Vector3(2, 0, 0), Vector3(-1, 0, 0)),
SourceEntry(player2),
player2.DamageModel,
diff --git a/src/test/scala/objects/ProjectileTest.scala b/src/test/scala/objects/ProjectileTest.scala
index 44638010..4d96ccd1 100644
--- a/src/test/scala/objects/ProjectileTest.scala
+++ b/src/test/scala/objects/ProjectileTest.scala
@@ -352,6 +352,7 @@ class ProjectileTest extends Specification {
"construct" in {
val obj = ResolvedProjectile(
+ ProjectileResolution.Hit,
projectile,
PlayerSource(player2),
fury_dm,
diff --git a/src/test/scala/objects/VitalityTest.scala b/src/test/scala/objects/VitalityTest.scala
index 750ca986..ee459f06 100644
--- a/src/test/scala/objects/VitalityTest.scala
+++ b/src/test/scala/objects/VitalityTest.scala
@@ -21,6 +21,7 @@ class VitalityTest extends Specification {
val pSource = PlayerSource(player)
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
val resprojectile = ResolvedProjectile(
+ ProjectileResolution.Hit,
projectile,
SourceEntry(player),
player.DamageModel,
@@ -68,6 +69,7 @@ class VitalityTest extends Specification {
val pSource = PlayerSource(player)
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
val resprojectile = ResolvedProjectile(
+ ProjectileResolution.Hit,
projectile,
SourceEntry(player),
player.DamageModel,