timing and damage tuning around: standard, reinforced, max; plasma grenades, dragon

This commit is contained in:
FateJH 2020-08-04 23:08:57 -04:00
parent d149e07e89
commit 97e64d5edc
16 changed files with 500 additions and 136 deletions

View file

@ -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
}
}
}

View file

@ -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)

View file

@ -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

View file

@ -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
}

View file

@ -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.<br>
* <br>
* 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
}

View file

@ -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 = {

View file

@ -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
)

View file

@ -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
}
}
}

View file

@ -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)
}

View file

@ -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 {

View file

@ -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,

View file

@ -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
}
)

View file

@ -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,

View file

@ -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,

View file

@ -352,6 +352,7 @@ class ProjectileTest extends Specification {
"construct" in {
val obj = ResolvedProjectile(
ProjectileResolution.Hit,
projectile,
PlayerSource(player2),
fury_dm,

View file

@ -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,