From c8ab08b2f5c9fe210842e1b9de297e736a527e13 Mon Sep 17 00:00:00 2001 From: Fate-JH Date: Wed, 3 Dec 2025 19:53:22 -0500 Subject: [PATCH] raestored radiator availability; radiator damage restored to value on file (2) rather than makeshift (1); radiator damage (and other cloud-based damage) should not stack; radiator should damage MAX again; vehicle occupant damage may be fixed, but have not tested; most file changes are accounting for two classes moved into their own package --- .../resources/overrides/game_objects0.adb.lst | 2 +- .../scala/net/psforever/objects/Player.scala | 3 +- .../psforever/objects/TurretDeployable.scala | 2 +- .../scala/net/psforever/objects/Vehicle.scala | 2 +- .../avatar/interaction/WithEntrance.scala | 2 +- .../avatar/interaction/WithGantry.scala | 2 +- .../objects/avatar/interaction/WithLava.scala | 2 +- .../avatar/interaction/WithWater.scala | 2 +- .../InteractWithRadiationClouds.scala | 89 ++++------------ .../objects/ce/InteractWithMines.scala | 2 +- .../objects/ce/InteractWithTurrets.scala | 2 +- .../global/GlobalDefinitionsProjectile.scala | 33 ++---- .../interaction/InteractWithEnvironment.scala | 1 + .../interaction/InteractionWith.scala | 2 +- .../RespondsToZoneEnvironment.scala | 2 +- .../interaction/common/Watery.scala | 2 +- .../interaction/common/WithDeath.scala | 2 +- .../common/WithMovementTrigger.scala | 2 +- .../serverobject/interior/InteriorAware.scala | 2 +- ...actWithRadiationCloudsSeatedInEntity.scala | 100 +++++------------- .../RadiationInMountableInteraction.scala | 2 +- .../turret/auto/AutomatedTurretBehavior.scala | 3 +- ...ctWithRadiationCloudsSeatedInVehicle.scala | 22 ++-- .../interaction/WithEntranceInVehicle.scala | 2 +- .../vehicles/interaction/WithLava.scala | 2 +- .../vehicles/interaction/WithWater.scala | 2 +- .../vital/environment/EnvironmentReason.scala | 3 +- .../ProjectileDamageModifierFunctions.scala | 22 ---- .../{ => interaction}/InteractsWithZone.scala | 38 +------ .../RadiationCloudInteraction.scala | 67 ++++++++++++ .../zones/interaction/ZoneInteraction.scala | 40 +++++++ .../local/support/CaptureFlagManager.scala | 3 +- .../InteractsWithZoneEnvironmentTest.scala | 3 +- 33 files changed, 204 insertions(+), 261 deletions(-) rename src/main/scala/net/psforever/objects/zones/{ => interaction}/InteractsWithZone.scala (66%) create mode 100644 src/main/scala/net/psforever/objects/zones/interaction/RadiationCloudInteraction.scala create mode 100644 src/main/scala/net/psforever/objects/zones/interaction/ZoneInteraction.scala diff --git a/server/src/main/resources/overrides/game_objects0.adb.lst b/server/src/main/resources/overrides/game_objects0.adb.lst index 6a7a893ba..8f382ed82 100644 --- a/server/src/main/resources/overrides/game_objects0.adb.lst +++ b/server/src/main/resources/overrides/game_objects0.adb.lst @@ -78,7 +78,7 @@ add_property pulsar equiptime 600 add_property pulsar holstertime 600 add_property punisher equiptime 600 add_property punisher holstertime 600 -add_property radiator allowed false +add_property radiator allowed true add_property r_shotgun equiptime 750 add_property r_shotgun holstertime 750 add_property remote_electronics_kit equiptime 500 diff --git a/src/main/scala/net/psforever/objects/Player.scala b/src/main/scala/net/psforever/objects/Player.scala index e84a88baf..8297e711c 100644 --- a/src/main/scala/net/psforever/objects/Player.scala +++ b/src/main/scala/net/psforever/objects/Player.scala @@ -20,7 +20,8 @@ import net.psforever.objects.vital.damage.DamageProfile import net.psforever.objects.vital.interaction.DamageInteraction import net.psforever.objects.vital.resolution.DamageResistanceModel import net.psforever.objects.zones.blockmap.BlockMapEntity -import net.psforever.objects.zones.{InteractsWithZone, ZoneAware, Zoning} +import net.psforever.objects.zones.interaction.InteractsWithZone +import net.psforever.objects.zones.{ZoneAware, Zoning} import net.psforever.types._ import scala.annotation.tailrec diff --git a/src/main/scala/net/psforever/objects/TurretDeployable.scala b/src/main/scala/net/psforever/objects/TurretDeployable.scala index 8ff12a077..17dd8dc3b 100644 --- a/src/main/scala/net/psforever/objects/TurretDeployable.scala +++ b/src/main/scala/net/psforever/objects/TurretDeployable.scala @@ -18,7 +18,7 @@ import net.psforever.objects.vital.damage.DamageCalculations import net.psforever.objects.vital.interaction.DamageResult import net.psforever.objects.vital.resistance.StandardResistanceProfile import net.psforever.objects.vital.{SimpleResolutions, StandardVehicleResistance} -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone import net.psforever.packet.game.TriggeredSound import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} diff --git a/src/main/scala/net/psforever/objects/Vehicle.scala b/src/main/scala/net/psforever/objects/Vehicle.scala index 386aa98f4..6fb9036eb 100644 --- a/src/main/scala/net/psforever/objects/Vehicle.scala +++ b/src/main/scala/net/psforever/objects/Vehicle.scala @@ -20,8 +20,8 @@ import net.psforever.objects.vehicles.interaction.{TriggerOnVehicleRule, WithLav import net.psforever.objects.vital.resistance.StandardResistanceProfile import net.psforever.objects.vital.Vitality import net.psforever.objects.vital.resolution.DamageResistanceModel -import net.psforever.objects.zones.InteractsWithZone import net.psforever.objects.zones.blockmap.BlockMapEntity +import net.psforever.objects.zones.interaction.InteractsWithZone import net.psforever.packet.PlanetSideGamePacket import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3} diff --git a/src/main/scala/net/psforever/objects/avatar/interaction/WithEntrance.scala b/src/main/scala/net/psforever/objects/avatar/interaction/WithEntrance.scala index 8263b7627..4e15faf4f 100644 --- a/src/main/scala/net/psforever/objects/avatar/interaction/WithEntrance.scala +++ b/src/main/scala/net/psforever/objects/avatar/interaction/WithEntrance.scala @@ -5,7 +5,7 @@ import net.psforever.objects.serverobject.doors.{Door, InteriorDoorPassage} import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, PieceOfEnvironment, interaction} import net.psforever.objects.serverobject.environment.interaction.{InteractionWith, RespondsToZoneEnvironment} import net.psforever.objects.serverobject.interior.{Sidedness, TraditionalInteriorAware} -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone import net.psforever.types.Vector3 import scala.annotation.unused diff --git a/src/main/scala/net/psforever/objects/avatar/interaction/WithGantry.scala b/src/main/scala/net/psforever/objects/avatar/interaction/WithGantry.scala index 35f084055..09d4a330a 100644 --- a/src/main/scala/net/psforever/objects/avatar/interaction/WithGantry.scala +++ b/src/main/scala/net/psforever/objects/avatar/interaction/WithGantry.scala @@ -5,7 +5,7 @@ import net.psforever.objects.serverobject.environment.interaction.{InteractionWi import net.psforever.objects.{Player, Vehicle, Vehicles} import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, GantryDenialField, PieceOfEnvironment, interaction} import net.psforever.objects.serverobject.shuttle.OrbitalShuttlePad -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone import net.psforever.packet.game.{ChatMsg, PlayerStateShiftMessage, ShiftState} import net.psforever.services.Service import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} diff --git a/src/main/scala/net/psforever/objects/avatar/interaction/WithLava.scala b/src/main/scala/net/psforever/objects/avatar/interaction/WithLava.scala index f2f5b6174..8526b878d 100644 --- a/src/main/scala/net/psforever/objects/avatar/interaction/WithLava.scala +++ b/src/main/scala/net/psforever/objects/avatar/interaction/WithLava.scala @@ -8,7 +8,7 @@ import net.psforever.objects.sourcing.SourceEntry import net.psforever.objects.vital.Vitality import net.psforever.objects.vital.environment.EnvironmentReason import net.psforever.objects.vital.interaction.DamageInteraction -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone import scala.concurrent.duration._ diff --git a/src/main/scala/net/psforever/objects/avatar/interaction/WithWater.scala b/src/main/scala/net/psforever/objects/avatar/interaction/WithWater.scala index 674b6dbfb..73af2ad60 100644 --- a/src/main/scala/net/psforever/objects/avatar/interaction/WithWater.scala +++ b/src/main/scala/net/psforever/objects/avatar/interaction/WithWater.scala @@ -6,7 +6,7 @@ import net.psforever.objects.serverobject.environment.interaction.{InteractionWi import net.psforever.objects.serverobject.environment.interaction.common.Watery import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment, interaction} -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.types.OxygenState diff --git a/src/main/scala/net/psforever/objects/ballistics/InteractWithRadiationClouds.scala b/src/main/scala/net/psforever/objects/ballistics/InteractWithRadiationClouds.scala index c0b5b39f0..19e18316d 100644 --- a/src/main/scala/net/psforever/objects/ballistics/InteractWithRadiationClouds.scala +++ b/src/main/scala/net/psforever/objects/ballistics/InteractWithRadiationClouds.scala @@ -7,83 +7,38 @@ import net.psforever.objects.vital.Vitality import net.psforever.objects.vital.base.DamageResolution import net.psforever.objects.vital.etc.RadiationReason import net.psforever.objects.vital.interaction.DamageInteraction -import net.psforever.objects.zones.blockmap.SectorPopulation -import net.psforever.objects.zones.{InteractsWithZone, Zone, ZoneInteraction, ZoneInteractionType} -import net.psforever.types.PlanetSideGUID +import net.psforever.objects.zones.interaction.{InteractsWithZone, RadiationCloudInteraction, ZoneInteractionType} case object RadiationInteraction extends ZoneInteractionType /** - * This game entity may infrequently test whether it may interact with radiation cloud projectiles - * that may be emitted in the game environment for a limited amount of time. - */ + * This game entity may infrequently test whether it may interact with radiation cloud projectiles + * that may be emitted in the game environment for a limited amount of time. + * Since the target entity is a player character, it gets tested for its interaction + */ class InteractWithRadiationClouds( val range: Float, private val user: Option[Player] - ) extends ZoneInteraction { - /** - * radiation clouds that, though detected, are skipped from affecting the target; - * in between interaction tests, a memory of the clouds that were tested last are retained and - * are excluded from being tested this next time; - * clouds that are detected a second time are cleared from the list and are available to be tested next time - */ - private var skipTargets: List[PlanetSideGUID] = List() - + ) extends RadiationCloudInteraction { def Type: ZoneInteractionType = RadiationInteraction - /** - * Wander into a radiation cloud and suffer the consequences. - * @param sector the portion of the block map being tested - * @param target the fixed element in this test - */ - def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit = { - target match { - case t: Vitality => - val position = target.Position - val targetList = List(target) - //collect all projectiles in sector/range - val projectiles = sector - .projectileList - .filter { cloud => - val definition = cloud.Definition - val radius = definition.DamageRadius - definition.radiation_cloud && - Zone.allOnSameSide(cloud, definition, targetList).nonEmpty && - Zone.distanceCheck(target, cloud, radius * radius) - } - .distinct - val notSkipped = projectiles.filterNot { t => skipTargets.contains(t.GUID) } - skipTargets = notSkipped.map { _.GUID } - if (notSkipped.nonEmpty) { - //isolate one of each type of projectile - notSkipped - .foldLeft(Nil: List[Projectile]) { - (acc, next) => if (acc.exists { _.profile == next.profile }) acc else next :: acc - } - .foreach { projectile => - t.Actor ! Vitality.Damage( - DamageInteraction( - SourceEntry(target), - RadiationReason( - ProjectileQuality.modifiers(projectile, DamageResolution.Radiation, t, t.Position, user), - t.DamageModel, - 0f - ), - position - ).calculate() - ) - } + def performInteractionWithTarget(projectiles: List[Projectile], target: InteractsWithZone): Unit = { + if (projectiles.nonEmpty) { + val position = target.Position + projectiles + .foreach { projectile => + target.Actor ! Vitality.Damage( + DamageInteraction( + SourceEntry(target), + RadiationReason( + ProjectileQuality.modifiers(projectile, DamageResolution.Radiation, target, target.Position, user), + target.DamageModel, + RadiationCloudInteraction.RadiationShieldingFrom(target) + ), + position + ).calculate() + ) } - case _ => ; } } - - /** - * Any radiation clouds blocked from being tested should be cleared. - * All that can be done is blanking our retained previous effect targets. - * @param target the fixed element in this test - */ - def resetInteraction(target: InteractsWithZone): Unit = { - skipTargets = List() - } } diff --git a/src/main/scala/net/psforever/objects/ce/InteractWithMines.scala b/src/main/scala/net/psforever/objects/ce/InteractWithMines.scala index 9e7c66f83..2f4898b20 100644 --- a/src/main/scala/net/psforever/objects/ce/InteractWithMines.scala +++ b/src/main/scala/net/psforever/objects/ce/InteractWithMines.scala @@ -3,7 +3,7 @@ package net.psforever.objects.ce import net.psforever.objects.geometry.d3.VolumetricGeometry import net.psforever.objects.zones.blockmap.SectorPopulation -import net.psforever.objects.zones.{InteractsWithZone, ZoneInteraction, ZoneInteractionType} +import net.psforever.objects.zones.interaction.{InteractsWithZone, ZoneInteraction, ZoneInteractionType} import net.psforever.objects.{BoomerDeployable, ExplosiveDeployable} import net.psforever.types.PlanetSideGUID diff --git a/src/main/scala/net/psforever/objects/ce/InteractWithTurrets.scala b/src/main/scala/net/psforever/objects/ce/InteractWithTurrets.scala index acb6e031e..d75f2c536 100644 --- a/src/main/scala/net/psforever/objects/ce/InteractWithTurrets.scala +++ b/src/main/scala/net/psforever/objects/ce/InteractWithTurrets.scala @@ -5,8 +5,8 @@ import net.psforever.objects.GlobalDefinitions import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.turret.auto.{AutomatedTurret, AutomatedTurretBehavior} import net.psforever.objects.zones.blockmap.SectorPopulation -import net.psforever.objects.zones.{InteractsWithZone, ZoneInteraction, ZoneInteractionType} import net.psforever.objects.sourcing.SourceUniqueness +import net.psforever.objects.zones.interaction.{InteractsWithZone, ZoneInteraction, ZoneInteractionType} import net.psforever.types.Vector3 case object TurretInteraction extends ZoneInteractionType diff --git a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsProjectile.scala b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsProjectile.scala index 71687b2d8..a82c67748 100644 --- a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsProjectile.scala +++ b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsProjectile.scala @@ -4,20 +4,14 @@ package net.psforever.objects.global import net.psforever.objects.GlobalDefinitions import net.psforever.objects.ballistics.{AggravatedDamage, AggravatedInfo, AggravatedTiming, ChargeDamage} import net.psforever.objects.definition.ProjectileDefinition -import net.psforever.objects.definition.converter.{ - LittleBuddyProjectileConverter, - ProjectileConverter, - RadiationCloudConverter -} +import net.psforever.objects.definition.converter.{LittleBuddyProjectileConverter, ProjectileConverter, RadiationCloudConverter} import net.psforever.objects.equipment.{ArmorSiphonRepairHost, EffectTarget, TargetValidation} import net.psforever.objects.serverobject.aura.Aura import net.psforever.objects.vital.base.DamageType import net.psforever.objects.vital.damage.{RadialDegrade, SameHit, StandardDamageProfile} import net.psforever.objects.vital.etc.{ ArmorSiphonMaxDistanceCutoff, - ExplosionDamagesOnlyAbove, - InfantryAggravatedRadiation, - InfantryAggravatedRadiationBurn + ExplosionDamagesOnlyAbove } import net.psforever.objects.vital.projectile._ @@ -1529,7 +1523,7 @@ object GlobalDefinitionsProjectile { ProjectileDefinition.CalculateDerivedFields(quasar_projectile) radiator_cloud.Name = "radiator_cloud" - radiator_cloud.Damage0 = 1 //2 + radiator_cloud.Damage0 = 2 radiator_cloud.DamageAtEdge = 1.0f radiator_cloud.DamageRadius = 5f radiator_cloud.DamageToHealthOnly = true @@ -1539,7 +1533,7 @@ object GlobalDefinitionsProjectile { //custom aggravated information radiator_cloud.ProjectileDamageTypeSecondary = DamageType.Aggravated radiator_cloud.Aggravated = AggravatedDamage( - AggravatedInfo(DamageType.Splash, 1f, 80), + AggravatedInfo(DamageType.Splash, 0f, 80), Aura.None, AggravatedTiming(250, 2), 0f, @@ -1552,12 +1546,7 @@ object GlobalDefinitionsProjectile { radiator_cloud.ExistsOnRemoteClients = true radiator_cloud.Packet = radCloudConverter //radiator_cloud.Geometry = GeometryForm.representProjectileBySphere() - radiator_cloud.Modifiers = List( - MaxDistanceCutoff, - InfantryAggravatedRadiation, - InfantryAggravatedRadiationBurn, - ShieldAgainstRadiation - ) + radiator_cloud.Modifiers = MaxDistanceCutoff radiator_grenade_projectile.Name = "radiator_grenade_projectile" // Todo : Radiator damages ? radiator_grenade_projectile.GrenadeProjectile = true //not really, but technically yes @@ -2037,12 +2026,7 @@ object GlobalDefinitionsProjectile { aphelion_plasma_cloud.ExistsOnRemoteClients = true aphelion_plasma_cloud.Packet = radCloudConverter //aphelion_plasma_cloud.Geometry = GeometryForm.representProjectileBySphere() - aphelion_plasma_cloud.Modifiers = List( //TODO placeholder values - MaxDistanceCutoff, - InfantryAggravatedRadiation, - InfantryAggravatedRadiationBurn, - ShieldAgainstRadiation - ) + aphelion_plasma_cloud.Modifiers = MaxDistanceCutoff aphelion_plasma_rocket_projectile.Name = "aphelion_plasma_rocket_projectile" //has property aggravated_damage_max_factor, but it's the aphelion_plasma_cloud that performs aggravated damage @@ -2240,10 +2224,7 @@ object GlobalDefinitionsProjectile { peregrine_particle_cannon_radiation_cloud.ExistsOnRemoteClients = true peregrine_particle_cannon_radiation_cloud.Packet = radCloudConverter //peregrine_particle_cannon_radiation_cloud.Geometry = GeometryForm.representProjectileBySphere() - peregrine_particle_cannon_radiation_cloud.Modifiers = List( - MaxDistanceCutoff, - ShieldAgainstRadiation - ) + peregrine_particle_cannon_radiation_cloud.Modifiers = MaxDistanceCutoff peregrine_rocket_pod_projectile.Name = "peregrine_rocket_pod_projectile" peregrine_rocket_pod_projectile.Damage0 = 30 diff --git a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/InteractWithEnvironment.scala b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/InteractWithEnvironment.scala index e3b6e6871..5c816415d 100644 --- a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/InteractWithEnvironment.scala +++ b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/InteractWithEnvironment.scala @@ -5,6 +5,7 @@ import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment} import net.psforever.objects.zones._ import net.psforever.objects.zones.blockmap.{BlockMapEntity, SectorGroup, SectorPopulation} +import net.psforever.objects.zones.interaction.{InteractsWithZone, ZoneInteraction, ZoneInteractionType} import net.psforever.types.Vector3 import scala.collection.mutable diff --git a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/InteractionWith.scala b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/InteractionWith.scala index c0991fc26..04d5a72ef 100644 --- a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/InteractionWith.scala +++ b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/InteractionWith.scala @@ -1,7 +1,7 @@ package net.psforever.objects.serverobject.environment.interaction import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment} -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone trait InteractionWith { def attribute: EnvironmentTrait diff --git a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/RespondsToZoneEnvironment.scala b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/RespondsToZoneEnvironment.scala index 30ed65b66..0762721e4 100644 --- a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/RespondsToZoneEnvironment.scala +++ b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/RespondsToZoneEnvironment.scala @@ -4,7 +4,7 @@ package net.psforever.objects.serverobject.environment.interaction import akka.actor.{Actor, ActorRef, Cancellable} import net.psforever.objects.Default import net.psforever.objects.serverobject.environment.EnvironmentTrait -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone import scala.collection.mutable import scala.concurrent.duration.FiniteDuration diff --git a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/Watery.scala b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/Watery.scala index e08cd8b27..de99cf44e 100644 --- a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/Watery.scala +++ b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/Watery.scala @@ -6,7 +6,7 @@ import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.environment.interaction.InteractWithEnvironment import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, PieceOfEnvironment} -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone import net.psforever.types.{OxygenState, PlanetSideGUID} trait Watery { diff --git a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/WithDeath.scala b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/WithDeath.scala index 4e63d45ba..aca8c7535 100644 --- a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/WithDeath.scala +++ b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/WithDeath.scala @@ -7,7 +7,7 @@ import net.psforever.objects.sourcing.SourceEntry import net.psforever.objects.vital.etc.SuicideReason import net.psforever.objects.vital.interaction.DamageInteraction import net.psforever.objects.vital.{IncarnationActivity, Vitality} -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone import scala.annotation.unused diff --git a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/WithMovementTrigger.scala b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/WithMovementTrigger.scala index 603c23657..0e1400f89 100644 --- a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/WithMovementTrigger.scala +++ b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/WithMovementTrigger.scala @@ -3,7 +3,7 @@ package net.psforever.objects.serverobject.environment.interaction.common import net.psforever.objects.serverobject.environment._ import net.psforever.objects.serverobject.environment.interaction.InteractionWith -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone import scala.annotation.unused diff --git a/src/main/scala/net/psforever/objects/serverobject/interior/InteriorAware.scala b/src/main/scala/net/psforever/objects/serverobject/interior/InteriorAware.scala index f29e85874..3762a0082 100644 --- a/src/main/scala/net/psforever/objects/serverobject/interior/InteriorAware.scala +++ b/src/main/scala/net/psforever/objects/serverobject/interior/InteriorAware.scala @@ -3,7 +3,7 @@ package net.psforever.objects.serverobject.interior import net.psforever.objects.avatar.interaction.WithEntrance import net.psforever.objects.serverobject.environment.interaction.InteractWithEnvironment -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone import scala.annotation.unused diff --git a/src/main/scala/net/psforever/objects/serverobject/mount/InteractWithRadiationCloudsSeatedInEntity.scala b/src/main/scala/net/psforever/objects/serverobject/mount/InteractWithRadiationCloudsSeatedInEntity.scala index 4c9064cce..6e404519c 100644 --- a/src/main/scala/net/psforever/objects/serverobject/mount/InteractWithRadiationCloudsSeatedInEntity.scala +++ b/src/main/scala/net/psforever/objects/serverobject/mount/InteractWithRadiationCloudsSeatedInEntity.scala @@ -8,91 +8,43 @@ import net.psforever.objects.vital.base.DamageResolution import net.psforever.objects.vital.etc.RadiationReason import net.psforever.objects.vital.interaction.DamageInteraction import net.psforever.objects.vital.resistance.StandardResistanceProfile -import net.psforever.objects.zones.blockmap.SectorPopulation -import net.psforever.objects.zones.{InteractsWithZone, Zone, ZoneInteraction} -import net.psforever.types.PlanetSideGUID +import net.psforever.objects.zones.interaction.{InteractsWithZone, RadiationCloudInteraction, ZoneInteractionType} /** * This game entity may infrequently test whether it may interact with radiation cloud projectiles * that may be emitted in the game environment for a limited amount of time. - * Since the entity in question is a vehicle, the occupants of the vehicle get tested their interaction. + * Since the entity in question is mountable, its occupants get tested for their interaction. */ class InteractWithRadiationCloudsSeatedInEntity( private val obj: Mountable with StandardResistanceProfile, val range: Float - ) extends ZoneInteraction { - /** - * radiation clouds that, though detected, are skipped from affecting the target; - * in between interaction tests, a memory of the clouds that were tested last are retained and - * are excluded from being tested this next time; - * clouds that are detected a second time are cleared from the list and are available to be tested next time - */ - private var skipTargets: List[PlanetSideGUID] = List() + ) extends RadiationCloudInteraction { + def Type: ZoneInteractionType = RadiationInMountableInteraction - def Type: RadiationInMountableInteraction.type = RadiationInMountableInteraction - - /** - * Drive into a radiation cloud and all the vehicle's occupants suffer the consequences. - * @param sector the portion of the block map being tested - * @param target the fixed element in this test - */ - override def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit = { - val position = target.Position - val targetList = List(target) - //collect all projectiles in sector/range - val projectiles = sector - .projectileList - .filter { cloud => - val definition = cloud.Definition - val radius = definition.DamageRadius - definition.radiation_cloud && - Zone.allOnSameSide(cloud, definition, targetList).nonEmpty && - Zone.distanceCheck(target, cloud, radius * radius) - } - .distinct - val notSkipped = projectiles.filterNot { t => skipTargets.contains(t.GUID) } - skipTargets = notSkipped.map { _.GUID } - if (notSkipped.nonEmpty) { - ( - //isolate one of each type of projectile - notSkipped - .foldLeft(Nil: List[Projectile]) { - (acc, next) => if (acc.exists { _.profile == next.profile }) acc else next :: acc - }, - obj.Seats - .values - .collect { case seat => seat.occupant } - .flatten - ) match { - case (uniqueProjectiles, targets) if uniqueProjectiles.nonEmpty && targets.nonEmpty => - val shielding = obj.RadiationShielding - targets.foreach { t => - uniqueProjectiles.foreach { p => - t.Actor ! Vitality.Damage( - DamageInteraction( - SourceEntry(t), - RadiationReason( - ProjectileQuality.modifiers(p, DamageResolution.Radiation, t, t.Position, None), - t.DamageModel, - shielding - ), - position - ).calculate() - ) - } - } - case _ => () + def performInteractionWithTarget(projectiles: List[Projectile], target: InteractsWithZone): Unit = { + val mountedTargets = obj.Seats + .values + .collect { case seat => seat.occupant } + .flatten + if (projectiles.nonEmpty && mountedTargets.nonEmpty) { + val position = target.Position + val shielding = RadiationCloudInteraction.RadiationShieldingFrom(target) + mountedTargets + .flatMap(t => projectiles.map(p => (t, p))) + .foreach { case (t, p) => + t.Actor ! Vitality.Damage( + DamageInteraction( + SourceEntry(t), + RadiationReason( + ProjectileQuality.modifiers(p, DamageResolution.Radiation, t, t.Position, None), + t.DamageModel, + shielding + ), + position + ).calculate() + ) } } } - - /** - * Any radiation clouds blocked from being tested should be cleared. - * All that can be done is blanking our retained previous effect targets. - * @param target the fixed element in this test - */ - def resetInteraction(target: InteractsWithZone): Unit = { - skipTargets = List() - } } diff --git a/src/main/scala/net/psforever/objects/serverobject/mount/RadiationInMountableInteraction.scala b/src/main/scala/net/psforever/objects/serverobject/mount/RadiationInMountableInteraction.scala index 4a6093735..5d6f32ca1 100644 --- a/src/main/scala/net/psforever/objects/serverobject/mount/RadiationInMountableInteraction.scala +++ b/src/main/scala/net/psforever/objects/serverobject/mount/RadiationInMountableInteraction.scala @@ -1,5 +1,5 @@ package net.psforever.objects.serverobject.mount -import net.psforever.objects.zones.ZoneInteractionType +import net.psforever.objects.zones.interaction.ZoneInteractionType case object RadiationInMountableInteraction extends ZoneInteractionType diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/auto/AutomatedTurretBehavior.scala b/src/main/scala/net/psforever/objects/serverobject/turret/auto/AutomatedTurretBehavior.scala index cd116dfd5..b9ef525ac 100644 --- a/src/main/scala/net/psforever/objects/serverobject/turret/auto/AutomatedTurretBehavior.scala +++ b/src/main/scala/net/psforever/objects/serverobject/turret/auto/AutomatedTurretBehavior.scala @@ -13,7 +13,8 @@ import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, SourceUniquene import net.psforever.objects.vital.Vitality import net.psforever.objects.vital.interaction.DamageResult import net.psforever.objects.zones.exp.ToDatabase -import net.psforever.objects.zones.{InteractsWithZone, Zone} +import net.psforever.objects.zones.Zone +import net.psforever.objects.zones.interaction.InteractsWithZone import net.psforever.objects.{Default, PlanetSideGameObject, Player} import net.psforever.packet.game.{ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ObjectDetectedMessage} import net.psforever.services.Service diff --git a/src/main/scala/net/psforever/objects/vehicles/InteractWithRadiationCloudsSeatedInVehicle.scala b/src/main/scala/net/psforever/objects/vehicles/InteractWithRadiationCloudsSeatedInVehicle.scala index fd5fdcd25..2a95e783d 100644 --- a/src/main/scala/net/psforever/objects/vehicles/InteractWithRadiationCloudsSeatedInVehicle.scala +++ b/src/main/scala/net/psforever/objects/vehicles/InteractWithRadiationCloudsSeatedInVehicle.scala @@ -4,24 +4,24 @@ package net.psforever.objects.vehicles import net.psforever.objects.Vehicle import net.psforever.objects.serverobject.mount.{InteractWithRadiationCloudsSeatedInEntity, RadiationInMountableInteraction} import net.psforever.objects.zones.blockmap.SectorPopulation -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone /** - * This game entity may infrequently test whether it may interact with radiation cloud projectiles - * that may be emitted in the game environment for a limited amount of time. - * Since the entity in question is a vehicle, the occupants of the vehicle get tested their interaction. - */ + * This game entity may infrequently test whether it may interact with radiation cloud projectiles + * that may be emitted in the game environment for a limited amount of time. + * Since the entity in question is a vehicle, the occupants of the vehicle's mounted vehicles get tested for their interaction. + */ class InteractWithRadiationCloudsSeatedInVehicle( private val obj: Vehicle, override val range: Float ) extends InteractWithRadiationCloudsSeatedInEntity(obj, range) { /** - * Drive into a radiation cloud and all the vehicle's occupants suffer the consequences. - * @param sector the portion of the block map being tested - * @param target the fixed element in this test - */ + * Drive into a radiation cloud and all the vehicle's occupants suffer the consequences. + * @param sector the portion of the block map being tested + * @param target the fixed element in this test + */ override def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit = { - super.interaction(sector, target) + super.interaction(sector, target) //vehicle is a mountable entity and must call down obj.CargoHolds .values .collect { @@ -30,7 +30,7 @@ class InteractWithRadiationCloudsSeatedInVehicle( target .interaction() .find(_.Type == RadiationInMountableInteraction) - .foreach(func => func.interaction(sector, target)) + .foreach(func => func.interaction(sector, obj)) } } } diff --git a/src/main/scala/net/psforever/objects/vehicles/interaction/WithEntranceInVehicle.scala b/src/main/scala/net/psforever/objects/vehicles/interaction/WithEntranceInVehicle.scala index 75bf9749e..41eed6d99 100644 --- a/src/main/scala/net/psforever/objects/vehicles/interaction/WithEntranceInVehicle.scala +++ b/src/main/scala/net/psforever/objects/vehicles/interaction/WithEntranceInVehicle.scala @@ -5,7 +5,7 @@ import net.psforever.objects.Vehicle import net.psforever.objects.avatar.interaction.WithEntrance import net.psforever.objects.serverobject.doors.InteriorDoorPassage import net.psforever.objects.serverobject.environment.PieceOfEnvironment -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone class WithEntranceInVehicle extends WithEntrance() { diff --git a/src/main/scala/net/psforever/objects/vehicles/interaction/WithLava.scala b/src/main/scala/net/psforever/objects/vehicles/interaction/WithLava.scala index 1670c027f..1664c5b64 100644 --- a/src/main/scala/net/psforever/objects/vehicles/interaction/WithLava.scala +++ b/src/main/scala/net/psforever/objects/vehicles/interaction/WithLava.scala @@ -7,7 +7,7 @@ import net.psforever.objects.sourcing.SourceEntry import net.psforever.objects.vital.Vitality import net.psforever.objects.vital.environment.EnvironmentReason import net.psforever.objects.vital.interaction.DamageInteraction -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone import scala.concurrent.duration._ diff --git a/src/main/scala/net/psforever/objects/vehicles/interaction/WithWater.scala b/src/main/scala/net/psforever/objects/vehicles/interaction/WithWater.scala index 01208856a..1a32f9076 100644 --- a/src/main/scala/net/psforever/objects/vehicles/interaction/WithWater.scala +++ b/src/main/scala/net/psforever/objects/vehicles/interaction/WithWater.scala @@ -8,7 +8,7 @@ import net.psforever.objects.serverobject.environment.interaction.common.Watery import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment, interaction} import net.psforever.objects.vehicles.control.VehicleControl -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone import net.psforever.types.OxygenState import scala.annotation.unused diff --git a/src/main/scala/net/psforever/objects/vital/environment/EnvironmentReason.scala b/src/main/scala/net/psforever/objects/vital/environment/EnvironmentReason.scala index c354ffb10..5abd3b011 100644 --- a/src/main/scala/net/psforever/objects/vital/environment/EnvironmentReason.scala +++ b/src/main/scala/net/psforever/objects/vital/environment/EnvironmentReason.scala @@ -8,11 +8,12 @@ import net.psforever.objects.vital.damage.DamageCalculations import net.psforever.objects.vital.prop.DamageProperties import net.psforever.objects.vital.resolution.{DamageAndResistance, DamageResistanceModel} import net.psforever.objects.vital.{NoResistanceSelection, SimpleResolutions} -import net.psforever.objects.zones.InteractsWithZone +import net.psforever.objects.zones.interaction.InteractsWithZone /** * A wrapper for a "damage source" in damage calculations * that parameterizes information necessary to explain the environment being antagonistic. + * * @see `DamageCalculations` * @param body a representative of an element of the environment * @param against for the purposes of damage, what kind of target is being acted upon diff --git a/src/main/scala/net/psforever/objects/vital/projectile/ProjectileDamageModifierFunctions.scala b/src/main/scala/net/psforever/objects/vital/projectile/ProjectileDamageModifierFunctions.scala index 8d1541408..bfaf28484 100644 --- a/src/main/scala/net/psforever/objects/vital/projectile/ProjectileDamageModifierFunctions.scala +++ b/src/main/scala/net/psforever/objects/vital/projectile/ProjectileDamageModifierFunctions.scala @@ -333,28 +333,6 @@ case object FlailDistanceDamageBoost extends ProjectileDamageModifiers.Mod { } } -/** - * If the damge is caused by a projectile that emits a field that permeates armor, - * determine by how much the traversed armor's shielding reduces the damage. - * Infantry take damage, reduced only if one is equipped with a mechanized assault exo-suit. - */ -case object ShieldAgainstRadiation extends ProjectileDamageModifiers.Mod { - def calculate(damage: Int, data: DamageInteraction, cause: ProjectileReason): Int = { - if (data.resolution == DamageResolution.Radiation) { - data.target match { - case p: PlayerSource if p.ExoSuit == ExoSuitType.MAX => - damage - (damage * p.Modifiers.RadiationShielding).toInt - case _: PlayerSource => - damage - case _ => - 0 - } - } else { - damage - } - } -} - /** The Cerberus turret can not target any entities besides flying vehicles. * An exception to this rule, however, happens when retaliating against something that damaged it first. */ case object CerberusTurretWrongTarget extends ProjectileDamageModifiers.Mod { diff --git a/src/main/scala/net/psforever/objects/zones/InteractsWithZone.scala b/src/main/scala/net/psforever/objects/zones/interaction/InteractsWithZone.scala similarity index 66% rename from src/main/scala/net/psforever/objects/zones/InteractsWithZone.scala rename to src/main/scala/net/psforever/objects/zones/interaction/InteractsWithZone.scala index 4304a6514..b8b1bdd80 100644 --- a/src/main/scala/net/psforever/objects/zones/InteractsWithZone.scala +++ b/src/main/scala/net/psforever/objects/zones/interaction/InteractsWithZone.scala @@ -1,5 +1,5 @@ // Copyright (c) 2021 PSForever -package net.psforever.objects.zones +package net.psforever.objects.zones.interaction import net.psforever.objects.definition.ObjectDefinition import net.psforever.objects.serverobject.PlanetSideServerObject @@ -72,39 +72,3 @@ trait InteractsWithZone override def Definition: ObjectDefinition with VitalityDefinition } - -trait ZoneInteractionType - -/** - * The basic behavior of an entity in a zone. - * @see `InteractsWithZone` - * @see `Zone` - */ -trait ZoneInteraction { - /** - * A categorical descriptor for this interaction. - */ - def Type: ZoneInteractionType - - /** - * The anticipated (radial?) distance across which this interaction affects the zone's blockmap. - */ - def range: Float - - /** - * The method by which zone interactions are tested. - * How a target tests this interaction with elements of the target's zone. - * @param sector the portion of the block map being tested - * @param target the fixed element in this test - */ - def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit - - /** - * Suspend any current interaction procedures. - * How the interactions are undone and stability restored to elements engaged with this target, - * even if only possible by small measure. - * Not all interactions can be reversed. - * @param target the fixed element in this test - */ - def resetInteraction(target: InteractsWithZone): Unit -} diff --git a/src/main/scala/net/psforever/objects/zones/interaction/RadiationCloudInteraction.scala b/src/main/scala/net/psforever/objects/zones/interaction/RadiationCloudInteraction.scala new file mode 100644 index 000000000..8f296c094 --- /dev/null +++ b/src/main/scala/net/psforever/objects/zones/interaction/RadiationCloudInteraction.scala @@ -0,0 +1,67 @@ +// Copyright (c) 2021-2025 PSForever +package net.psforever.objects.zones.interaction + +import net.psforever.objects.ballistics.Projectile +import net.psforever.objects.definition.ProjectileDefinition +import net.psforever.objects.vital.resistance.ResistanceProfile +import net.psforever.objects.zones.Zone +import net.psforever.objects.zones.blockmap.SectorPopulation + +/** + * This game entity may infrequently test whether it may interact with radiation cloud projectiles + * that may be emitted in the game environment for a limited amount of time. + */ +trait RadiationCloudInteraction extends ZoneInteraction { + /** + * radiation clouds that, though detected, are skipped from affecting the target; + * in between interaction tests, a memory of the clouds that were tested last are retained and + * are excluded from being tested this next time; + * clouds that are detected a second time are cleared from the list and are available to be tested next time + */ + private var damageTypesToSkip: List[ProjectileDefinition] = List() + + /** + * Wander into a radiation cloud and suffer the consequences. + * @param sector the portion of the block map being tested + * @param target the fixed element in this test + */ + def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit = { + performInteractionWithTarget(uniqueProjectileDamageToTargetInSector(sector, target), target) + } + + /** + * Any radiation clouds blocked from being tested should be cleared. + * All that can be done is blanking our retained previous effect targets. + * @param target the fixed element in this test + */ + def resetInteraction(target: InteractsWithZone): Unit = { + damageTypesToSkip = List() + } + + private def uniqueProjectileDamageToTargetInSector(sector: SectorPopulation, target: InteractsWithZone): List[Projectile] = { + lazy val targetList = List(target) + val projectiles = sector + .projectileList + .filter { cloud => + val definition = cloud.Definition + val radius = definition.DamageRadius + definition.radiation_cloud && + Zone.allOnSameSide(cloud, definition, targetList).nonEmpty && + Zone.distanceCheck(target, cloud, radius * radius) + } + val projectilesToUse = projectiles.filterNot(p => damageTypesToSkip.contains(p.profile)).distinctBy(_.profile) + damageTypesToSkip = projectilesToUse.map(_.profile) + projectilesToUse + } + + def performInteractionWithTarget(projectiles: List[Projectile], target: InteractsWithZone): Unit +} + +object RadiationCloudInteraction { + def RadiationShieldingFrom(target: InteractsWithZone): Float = { + target match { + case profile: ResistanceProfile => profile.RadiationShielding + case _ => 0f + } + } +} diff --git a/src/main/scala/net/psforever/objects/zones/interaction/ZoneInteraction.scala b/src/main/scala/net/psforever/objects/zones/interaction/ZoneInteraction.scala new file mode 100644 index 000000000..1ec9d876f --- /dev/null +++ b/src/main/scala/net/psforever/objects/zones/interaction/ZoneInteraction.scala @@ -0,0 +1,40 @@ +// Copyright (c) 2021 PSForever +package net.psforever.objects.zones.interaction + +import net.psforever.objects.zones.blockmap.SectorPopulation + +trait ZoneInteractionType + +/** + * The basic behavior of an entity in a zone. + * @see `InteractsWithZone` + * @see `Zone` + */ +trait ZoneInteraction { + /** + * A categorical descriptor for this interaction. + */ + def Type: ZoneInteractionType + + /** + * The anticipated (radial?) distance across which this interaction affects the zone's blockmap. + */ + def range: Float + + /** + * The method by which zone interactions are tested. + * How a target tests this interaction with elements of the target's zone. + * @param sector the portion of the block map being tested + * @param target the fixed element in this test + */ + def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit + + /** + * Suspend any current interaction procedures. + * How the interactions are undone and stability restored to elements engaged with this target, + * even if only possible by small measure. + * Not all interactions can be reversed. + * @param target the fixed element in this test + */ + def resetInteraction(target: InteractsWithZone): Unit +} diff --git a/src/main/scala/net/psforever/services/local/support/CaptureFlagManager.scala b/src/main/scala/net/psforever/services/local/support/CaptureFlagManager.scala index 0760ac269..980a0f756 100644 --- a/src/main/scala/net/psforever/services/local/support/CaptureFlagManager.scala +++ b/src/main/scala/net/psforever/services/local/support/CaptureFlagManager.scala @@ -10,7 +10,8 @@ import net.psforever.objects.serverobject.environment.interaction.InteractWithEn import net.psforever.objects.serverobject.llu.CaptureFlag import net.psforever.objects.serverobject.structures.{Building, WarpGate} import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal -import net.psforever.objects.zones.{InteractsWithZone, Zone} +import net.psforever.objects.zones.Zone +import net.psforever.objects.zones.interaction.InteractsWithZone import net.psforever.packet.game._ import net.psforever.services.{Service, ServiceManager} import net.psforever.services.ServiceManager.{Lookup, LookupResult} diff --git a/src/test/scala/objects/InteractsWithZoneEnvironmentTest.scala b/src/test/scala/objects/InteractsWithZoneEnvironmentTest.scala index 19bd9eeba..6528684c2 100644 --- a/src/test/scala/objects/InteractsWithZoneEnvironmentTest.scala +++ b/src/test/scala/objects/InteractsWithZoneEnvironmentTest.scala @@ -10,7 +10,8 @@ import net.psforever.objects.serverobject.aura.{Aura, AuraEffectBehavior} import net.psforever.objects.serverobject.environment._ import net.psforever.objects.serverobject.environment.interaction.RespondsToZoneEnvironment import net.psforever.objects.vital.Vitality -import net.psforever.objects.zones.{InteractsWithZone, Zone, ZoneMap} +import net.psforever.objects.zones.interaction.InteractsWithZone +import net.psforever.objects.zones.{Zone, ZoneMap} import net.psforever.types.{CharacterSex, CharacterVoice, PlanetSideEmpire, PlanetSideGUID, Vector3} import scala.concurrent.duration._