From e27e8275521b447d2b3abb66e0f7bbc77772eacb Mon Sep 17 00:00:00 2001 From: FateJH Date: Tue, 25 Aug 2020 01:12:53 -0400 Subject: [PATCH] merge rebase; accommodation for suppressing aura where no aura should be displayed; new radial degrade calculations --- .../objects/ballistics/AggravatedDamage.scala | 19 +++ .../aura/AuraEffectBehavior.scala | 2 +- .../damage/AggravatedBehavior.scala | 35 ++---- .../actors/session/SessionActor.scala | 113 ++++-------------- .../psforever/objects/GlobalDefinitions.scala | 6 +- .../definition/ProjectileDefinition.scala | 41 ++++++- .../vital/damage/DamageModifiers.scala | 7 +- 7 files changed, 98 insertions(+), 125 deletions(-) diff --git a/common/src/main/scala/net/psforever/objects/ballistics/AggravatedDamage.scala b/common/src/main/scala/net/psforever/objects/ballistics/AggravatedDamage.scala index 7fad9e15..91c9c3c2 100644 --- a/common/src/main/scala/net/psforever/objects/ballistics/AggravatedDamage.scala +++ b/common/src/main/scala/net/psforever/objects/ballistics/AggravatedDamage.scala @@ -156,4 +156,23 @@ object AggravatedDamage { vanu_aggravated, targets ) + + def burning(resolution: ProjectileResolution.Value): ProjectileResolution.Value = { + resolution match { + case ProjectileResolution.AggravatedDirect => ProjectileResolution.AggravatedDirectBurn + case ProjectileResolution.AggravatedSplash => ProjectileResolution.AggravatedSplashBurn + case _ => resolution + } + } + + 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/common/src/main/scala/net/psforever/objects/serverobject/aura/AuraEffectBehavior.scala b/common/src/main/scala/net/psforever/objects/serverobject/aura/AuraEffectBehavior.scala index 96b6f2c6..1a041b62 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/aura/AuraEffectBehavior.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/aura/AuraEffectBehavior.scala @@ -171,7 +171,7 @@ object AuraEffectBehavior { override def isCancelled : Boolean = timer.isCancelled - override def cancel: Boolean = timer.cancel + override def cancel(): Boolean = timer.cancel() } object Entry { diff --git a/common/src/main/scala/net/psforever/objects/serverobject/damage/AggravatedBehavior.scala b/common/src/main/scala/net/psforever/objects/serverobject/damage/AggravatedBehavior.scala index e2a477e9..ad211cdb 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/damage/AggravatedBehavior.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/damage/AggravatedBehavior.scala @@ -26,7 +26,8 @@ trait AggravatedBehavior { projectile.profile.Aggravated match { case Some(damage) if projectile.profile.ProjectileDamageTypes.contains(DamageType.Aggravated) && - damage.effect_type != Aura.Nothing && + damage.info.exists(_.damage_type == AggravatedDamage.basicDamageType(data.resolution)) && + damage.effect_type != Aura.Nothing && (projectile.quality == ProjectileQuality.AggravatesTarget || damage.targets.exists(validation => validation.test(AggravatedObject))) => TryAggravationEffectActivate(damage, data) @@ -61,7 +62,7 @@ trait AggravatedBehavior { private def SetupAggravationEntry(aggravation: AggravatedDamage, data: ResolvedProjectile): Boolean = { val effect = aggravation.effect_type - aggravation.info.find(_.damage_type == AggravatedBehavior.basicDamageType(data.resolution)) match { + aggravation.info.find(_.damage_type == AggravatedDamage.basicDamageType(data.resolution)) match { case Some(info) => val timing = aggravation.timing val duration = timing.duration @@ -77,7 +78,6 @@ trait AggravatedBehavior { case None => (1000L, (duration / 1000).toInt) } - //val leftoverTime = duration - (tick * iterations) //quality per tick val totalPower = (duration.toFloat / info.infliction_rate).toInt - 1 val averagePowerPerTick = totalPower.toFloat / iterations @@ -108,7 +108,7 @@ trait AggravatedBehavior { powerOffset: List[Float] ): AggravatedBehavior.Entry = { val aggravatedDamageInfo = ResolvedProjectile( - AggravatedBehavior.burning(data.resolution), + AggravatedDamage.burning(data.resolution), data.projectile, target, data.damage_model, @@ -168,7 +168,7 @@ trait AggravatedBehavior { def CleanupAggravationTimer(id: Long): Unit = { //remove and cancel timer aggravationToTimer.remove(id) match { - case Some(timer) => timer.cancel + case Some(timer) => timer.cancel() case _ => ; } } @@ -179,9 +179,9 @@ trait AggravatedBehavior { } def EndAllAggravation(): Unit = { - entryIdToEntry.clear - aggravationToTimer.values.foreach { _.cancel } - aggravationToTimer.clear + entryIdToEntry.clear() + aggravationToTimer.values.foreach { _.cancel() } + aggravationToTimer.clear() } def AggravatedReaction: Boolean = ongoingAggravated @@ -206,23 +206,4 @@ object AggravatedBehavior { private case class Entry(id: Long, effect: Aura, retime: Long, data: ResolvedProjectile, qualityPerTick: List[Float]) private case class Aggravate(id: Long, iterations: Int) - - private def burning(resolution: ProjectileResolution.Value): ProjectileResolution.Value = { - resolution match { - case ProjectileResolution.AggravatedDirect => ProjectileResolution.AggravatedDirectBurn - case ProjectileResolution.AggravatedSplash => ProjectileResolution.AggravatedSplashBurn - case _ => resolution - } - } - - private def basicDamageType(resolution: ProjectileResolution.Value): DamageType.Value = { - resolution match { - case ProjectileResolution.AggravatedDirect | ProjectileResolution.AggravatedDirectBurn => - DamageType.Direct - case ProjectileResolution.AggravatedSplash | ProjectileResolution.AggravatedSplashBurn => - DamageType.Splash - case _ => - DamageType.None - } - } } diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala index 5d4dae49..fdd13f9d 100644 --- a/src/main/scala/net/psforever/actors/session/SessionActor.scala +++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala @@ -1,26 +1,26 @@ package net.psforever.actors.session -import java.util.concurrent.TimeUnit -import akka.actor.MDCContextAware.Implicits._ +//language imports import akka.actor.typed import akka.actor.typed.receptionist.Receptionist +import akka.actor.typed.scaladsl.adapter._ import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware} -import java.util.concurrent.atomic.AtomicInteger +import akka.pattern.ask +import akka.util.Timeout +import java.util.concurrent.TimeUnit +import MDCContextAware.Implicits._ import org.log4s.MDC -import scala.collection.mutable.LongMap +import scala.collection.mutable import scala.concurrent.{Await, Future} import scala.concurrent.duration._ import scala.concurrent.ExecutionContext.Implicits.global -import scala.util.{Failure, Success} +import scala.util.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} +//project imports +import net.psforever.login.{DropCryptoSession, DropSession, HelloFriend, RawPacket} +import net.psforever.login.WorldSession._ import net.psforever.objects._ -import net.psforever.objects.avatar.{Certification, DeployableToolbox, FirstTimeEvents} +import net.psforever.objects.avatar.{Avatar, Certification, Cosmetic, DeployableToolbox} import net.psforever.objects.ballistics._ import net.psforever.objects.ce._ import net.psforever.objects.definition._ @@ -29,6 +29,7 @@ import net.psforever.objects.entity.{SimpleWorldEntity, WorldEntity} import net.psforever.objects.equipment.{EffectTarget, Equipment, FireModeSwitch, JammableUnit} import net.psforever.objects.guid.{GUIDTask, Task, TaskResolver} import net.psforever.objects.inventory.{Container, InventoryItem} +import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject} import net.psforever.objects.serverobject.affinity.FactionAffinity import net.psforever.objects.serverobject.containable.Containable import net.psforever.objects.serverobject.damage.Damageable @@ -48,7 +49,6 @@ import net.psforever.objects.serverobject.terminals._ import net.psforever.objects.serverobject.tube.SpawnTube 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._ import net.psforever.objects.vehicles.Utility.InternalTelepad @@ -56,21 +56,12 @@ import net.psforever.objects.vital._ import net.psforever.objects.zones.{Zone, ZoneHotSpotProjector, Zoning} 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 import net.psforever.services.ServiceManager.LookupResult import net.psforever.services.account.{AccountPersistenceService, PlayerToken, ReceiveAccountData, RetrieveAccountData} import net.psforever.services.avatar.{AvatarAction, AvatarResponse, AvatarServiceMessage, AvatarServiceResponse} +import net.psforever.services.chat.ChatService import net.psforever.services.galaxy.{GalaxyAction, GalaxyResponse, GalaxyServiceMessage, GalaxyServiceResponse} import net.psforever.services.local.support.RouterTelepadActivation import net.psforever.services.local.{LocalAction, LocalResponse, LocalServiceMessage, LocalServiceResponse} @@ -84,20 +75,8 @@ import net.psforever.services.teamwork.{ } import net.psforever.services.vehicle.{VehicleAction, VehicleResponse, VehicleServiceMessage, VehicleServiceResponse} import net.psforever.services.{InterstellarClusterService, RemoverActor, Service, ServiceManager} -import net.psforever.login.{DropCryptoSession, DropSession, HelloFriend, RawPacket} +import net.psforever.types._ import net.psforever.util.{Config, DefinitionUtil} -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} -import scala.util.Success -import akka.actor.typed.scaladsl.adapter._ -import akka.pattern.ask -import akka.util.Timeout -import scala.collection.mutable object SessionActor { @@ -1301,49 +1280,6 @@ class SessionActor extends Actor with MDCContextAware { taskResolver ! RegisterNewAvatar(player) } - case msg @ Zoning.InstantAction.Located(zone, _, spawn_point) => - //in between subsequent reply messages, it does not matter if the destination changes - //so long as there is at least one destination at all (including the fallback) - if (ContemplateZoningResponse(Zoning.InstantAction.Request(player.Faction), cluster)) { - val (pos, ori) = spawn_point.SpecificPoint(player) - SpawnThroughZoningProcess(zone, pos, ori) - } else if (zoningStatus != Zoning.Status.None) { - instantActionFallbackDestination = Some(msg) - } - - case Zoning.InstantAction.NotLocated() => - instantActionFallbackDestination match { - case Some(Zoning.InstantAction.Located(zone, _, spawn_point)) - if spawn_point.Owner.Faction == player.Faction && !spawn_point.Offline => - if (ContemplateZoningResponse(Zoning.InstantAction.Request(player.Faction), cluster)) { - val (pos, ori) = spawn_point.SpecificPoint(player) - SpawnThroughZoningProcess(zone, pos, ori) - } else if (zoningCounter == 0) { - CancelZoningProcessWithReason("@InstantActionNoHotspotsAvailable") - } - case _ => - //no instant action available - CancelZoningProcessWithReason("@InstantActionNoHotspotsAvailable") - } - - case Zoning.Recall.Located(zone, spawn_point) => - if (ContemplateZoningResponse(Zoning.Recall.Request(player.Faction, zone.Id), cluster)) { - val (pos, ori) = spawn_point.SpecificPoint(player) - SpawnThroughZoningProcess(zone, pos, ori) - } - - case Zoning.Recall.Denied(reason) => - CancelZoningProcessWithReason(s"@norecall_sanctuary_$reason", Some(ChatMessageType.CMT_QUIT)) - - case Zoning.Quit() => - if (ContemplateZoningResponse(Zoning.Quit(), self)) { - log.info("Good-bye") - ImmediateDisconnect() - } - - case ZoningReset() => - CancelZoningProcess() - case NewPlayerLoaded(tplayer) => //new zone log.info(s"Player ${tplayer.Name} has been loaded") @@ -3792,7 +3728,7 @@ class SessionActor extends Actor with MDCContextAware { } } continent.VehicleEvents ! VehicleServiceMessage( - continent.Id, + continent.id, VehicleAction.UpdateAmsSpawnPoint(continent) ) upstreamMessageCount = 0 @@ -7753,7 +7689,8 @@ class SessionActor extends Actor with MDCContextAware { val outProjectile = if(projectile.profile.ProjectileDamageTypes.contains(DamageType.Aggravated)) { val quality = projectile.profile.Aggravated match { case Some(aggravation) - if aggravation.targets.exists(validation => validation.test(target)) => + if aggravation.targets.exists(validation => validation.test(target)) && + aggravation.info.exists(_.damage_type == AggravatedDamage.basicDamageType(resolution)) => ProjectileQuality.AggravatesTarget case _ => ProjectileQuality.Normal @@ -8013,12 +7950,12 @@ class SessionActor extends Actor with MDCContextAware { * @return `true`, if the desired certification requirements are met; `false`, otherwise */ def ConstructionItemPermissionComparison( - sample: Set[CertificationType.Value], - test: Set[CertificationType.Value] + sample: Set[Certification], + test: Set[Certification] ): Boolean = { - import CertificationType._ - val engineeringCerts: Set[CertificationType.Value] = Set(AssaultEngineering, FortificationEngineering) - val testDiff: Set[CertificationType.Value] = test diff (engineeringCerts ++ Set(AdvancedEngineering)) + import Certification._ + val engineeringCerts: Set[Certification] = Set(AssaultEngineering, FortificationEngineering) + val testDiff: Set[Certification] = test diff (engineeringCerts ++ Set(AdvancedEngineering)) //substitute `AssaultEngineering` and `FortificationEngineering` for `AdvancedEngineering` val sampleIntersect = if (sample contains AdvancedEngineering) { engineeringCerts @@ -8602,7 +8539,7 @@ class SessionActor extends Actor with MDCContextAware { ) { //do not delete if vehicle has passengers or cargo continent.VehicleEvents ! VehicleServiceMessage( - continent.Id, + continent.id, VehicleAction.UnloadVehicle(pguid, continent, vehicle, topLevel) ) None @@ -9438,7 +9375,7 @@ class SessionActor extends Actor with MDCContextAware { ) taskResolver ! (if (projectile.HasGUID) { continent.AvatarEvents ! AvatarServiceMessage( - continent.Id, + continent.id, AvatarAction.ProjectileExplodes( player.GUID, projectile.GUID, diff --git a/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/src/main/scala/net/psforever/objects/GlobalDefinitions.scala index 8d20e52d..b31e95cb 100644 --- a/src/main/scala/net/psforever/objects/GlobalDefinitions.scala +++ b/src/main/scala/net/psforever/objects/GlobalDefinitions.scala @@ -3918,7 +3918,11 @@ object GlobalDefinitions { 2000, 0f, true, - List(TargetValidation(EffectTarget.Category.Aircraft, EffectTarget.Validation.Aircraft)) + List( + TargetValidation(EffectTarget.Category.Player, EffectTarget.Validation.Player), + TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.Vehicle), + TargetValidation(EffectTarget.Category.Turret, EffectTarget.Validation.Turret) + ) ) starfire_projectile.InitialVelocity = 45 starfire_projectile.Lifespan = 7.8f diff --git a/src/main/scala/net/psforever/objects/definition/ProjectileDefinition.scala b/src/main/scala/net/psforever/objects/definition/ProjectileDefinition.scala index 3f68364c..6c225fb0 100644 --- a/src/main/scala/net/psforever/objects/definition/ProjectileDefinition.scala +++ b/src/main/scala/net/psforever/objects/definition/ProjectileDefinition.scala @@ -16,33 +16,68 @@ class ProjectileDefinition(objectId: Int) with JammingUnit with StandardDamageProfile with DamageModifiers { + /** ascertain that this object is a valid projectile type */ private val projectileType: Projectiles.Value = Projectiles(objectId) //let throw NoSuchElementException + /** how much faster (or slower) the projectile moves (m/s^2^) */ private var acceleration: Int = 0 + /** when the acceleration stops being applied (s) */ private var accelerationUntil: Float = 0f + /** the type of damage that the projectile causes */ private var damageType: DamageType.Value = DamageType.None + /** an auxillary type of damage that the projectile causes */ private var damageTypeSecondary: DamageType.Value = DamageType.None + /** against Infantry targets, this projectile does not do armor damage */ private var damageToHealthOnly: Boolean = false + /** number of seconds before an airborne projectile's damage begins to degrade (s) */ private var degradeDelay: Float = 1f + /** the rate of degrade of projectile damage after the degrade delay */ private var degradeMultiplier: Float = 1f + /** the out-of-the-muzzle speed of a projectile (m/s) */ private var initialVelocity: Int = 1 + /** for how long the projectile exists (s) */ private var lifespan: Float = 1f + /** for radial damage, how much damage has been lost the further away from the impact point (m) */ private var damageAtEdge: Float = 1f + /** for radial damage, the radial distance of the explosion effect (m) */ private var damageRadius: Float = 1f + /** for lashing damage, how far away a target will be affected by the projectile (m) */ private var lashRadius : Float = 0f + /** use a specific modifier as a part of damage calculations */ private var useDamage1Subtract: Boolean = false - private var existsOnRemoteClients: Boolean = false //`true` spawns a server-managed object - private var remoteClientData: (Int, Int) = - (0, 0) //artificial values; for ObjectCreateMessage packet (oicw_little_buddy is undefined) + /** the projectile is represented by a server-side entity + * that is updated by the projectile owner + * and transmitted to all projectile observers; + * `true` spawns a server-managed object */ + private var existsOnRemoteClients: Boolean = false + /** the values used by the `ObjectCreateMessage` packet for construction of the server-managed projectile + * `0, 0` are artificial values; + * the oicw_little_buddy is undefined for these values */ + private var remoteClientData: (Int, Int) = (0, 0) + /** some other entity confers projectile damage; + * a set value should not `None` and not `0` but is preferred to be the damager's uid */ private var damageProxy: Option[Int] = None + /** this projectile follows its target, after a fashion */ private var autoLock: Boolean = false + /** na; + * currently used with jammer properties only */ private var additionalEffect: Boolean = false + /** the projectile tries to confer the jammered status effect to its target(s) */ private var jammerProjectile: Boolean = false + /** projectile takes the form of a type of "grenade"; + * grenades arc with gravity rather than travel in a relatively straight path */ private var grenade_projectile : Boolean = false + /** projectile tries to confers aggravated damage burn to its target */ private var aggravated_damage : Option[AggravatedDamage] = None //derived calculations + /** the calculated distance at which the projectile have traveled far enough to despawn (m); + * typically handled as the projectile no longer performing damage; + * occasionally, this value is purely mathematical as opposed to realistic, e.g., the melee weapons */ private var distanceMax: Float = 0f + /** how far the projectile will travel while accelerating (m) */ private var distanceFromAcceleration: Float = 0f + /** how far the projectile will travel while no degrading (m) */ private var distanceNoDegrade: Float = 0f + /** after acceleration, if any, what is the final speed of the projectile (m/s) */ private var finalVelocity: Float = 0f Name = "projectile" Modifiers = DamageModifiers.DistanceDegrade 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 e0009f1e..fff0a754 100644 --- a/src/main/scala/net/psforever/objects/vital/damage/DamageModifiers.scala +++ b/src/main/scala/net/psforever/objects/vital/damage/DamageModifiers.scala @@ -97,14 +97,11 @@ object DamageModifiers { def Calculate: DamageModifiers.Format = function private def function(damage: Int, data: ResolvedProjectile): Int = { - val projectile = data.projectile - val profile = projectile.profile + val profile = data.projectile.profile val distance = Vector3.Distance(data.hit_pos, data.target.Position) val radius = profile.DamageRadius if (distance <= radius) { - val base: Float = profile.DamageAtEdge - val degrade: Float = (1 - base) * ((radius - distance) / radius) + base - (damage * degrade).toInt + damage * (1f - (profile.DamageAtEdge * distance / radius)).toInt } else { 0 }