diff --git a/src/main/scala/net/psforever/actors/zone/building/MajorFacilityLogic.scala b/src/main/scala/net/psforever/actors/zone/building/MajorFacilityLogic.scala index 2ee6b7797..00325776c 100644 --- a/src/main/scala/net/psforever/actors/zone/building/MajorFacilityLogic.scala +++ b/src/main/scala/net/psforever/actors/zone/building/MajorFacilityLogic.scala @@ -6,7 +6,9 @@ import akka.actor.typed.{ActorRef, Behavior} import akka.actor.typed.scaladsl.{ActorContext, Behaviors} import net.psforever.actors.commands.NtuCommand import net.psforever.actors.zone.{BuildingActor, BuildingControlDetails, ZoneActor} +import net.psforever.objects.serverobject.dome.ForceDomePhysics import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl} +import net.psforever.objects.serverobject.resourcesilo.ResourceSiloControl import net.psforever.objects.serverobject.structures.{Amenity, Building} import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAware, CaptureTerminalAwareBehavior} import net.psforever.objects.sourcing.PlayerSource @@ -104,6 +106,10 @@ case object MajorFacilityLogic ) } // No map update needed - will be sent by `HackCaptureActor` when required + case dome: ForceDomePhysics => + // The force dome being expanded modifies the NTU drain rate + val multiplier: Float = calculateNtuDrainMultiplierFrom(details.building, domeOpt = Some(dome)) + details.building.NtuSource.foreach(_.Actor ! ResourceSiloControl.DrainMultiplier(multiplier)) case _ => details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage())) } @@ -345,4 +351,32 @@ case object MajorFacilityLogic } Behaviors.same } + + private def calculateNtuDrainMultiplierFrom( + building: Building, + domeOpt: Option[ForceDomePhysics] = None, + mainTerminalOpt: Option[Any] = None + ): Float = { + val domeParam = domeOpt.orElse { + building.Amenities.find(_.isInstanceOf[ForceDomePhysics]) match { + case Some(d: ForceDomePhysics) => Some(d) + case _ => None + } + } + val mainTerminalParam = mainTerminalOpt.orElse(None) //todo main terminal and viruses + getNtuDrainMultiplierFromAmenities(domeParam, mainTerminalParam) + } + + private def getNtuDrainMultiplierFromAmenities( + dome: Option[ForceDomePhysics], + mainTerminal: Option[Any] + ): Float = { + // The force dome being expanded means all repairs are essentially for free + dome + .map { case d if d.Energized => 0f } + .orElse { + mainTerminal.flatMap { _ => Some(2f) } //todo main terminal and viruses + } + .getOrElse(1f) + } } diff --git a/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala b/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala index b32bf2e4d..ceea45622 100644 --- a/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala +++ b/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala @@ -187,7 +187,8 @@ object ExplosiveDeployableControl { zone, target, Zone.explosionDamage(Some(cause)), - ExplosiveDeployableControl.detectionForExplosiveSource(target) + ExplosiveDeployableControl.detectionForExplosiveSource(target), + Zone.findAllTargets ) } diff --git a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala index ff136ba94..9714631bd 100644 --- a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala +++ b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala @@ -956,5 +956,20 @@ object GlobalDefinitionsMiscellaneous { zipline.Name = "zipline" zipline.interference = InterferenceRange(deployables = 5.5f) + + force_dome_amp_physics.Name = "force_dome_amp_physics" + force_dome_amp_physics.UseRadius = 142.26f + + force_dome_comm_physics.Name = "force_dome_comm_physics" + force_dome_comm_physics.UseRadius = 121.8149f + + force_dome_cryo_physics.Name = "force_dome_cryo_physics" + force_dome_cryo_physics.UseRadius = 127.9241f //127.7963f + + force_dome_dsp_physics.Name = "force_dome_dsp_physics" + force_dome_dsp_physics.UseRadius = 175.8838f //175.7081f + + force_dome_tech_physics.Name = "force_dome_tech_physics" + force_dome_tech_physics.UseRadius = 150.1284f } } diff --git a/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala b/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala index dc101b229..12c438043 100644 --- a/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala @@ -2,10 +2,18 @@ package net.psforever.objects.serverobject.dome import net.psforever.actors.zone.BuildingActor +import net.psforever.objects.serverobject.PlanetSideServerObject +import net.psforever.objects.PlanetSideGameObject import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} import net.psforever.objects.serverobject.structures.{Amenity, Building, PoweredAmenityControl} import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAware, CaptureTerminalAwareBehavior} import net.psforever.objects.serverobject.turret.FacilityTurret +import net.psforever.objects.sourcing.SourceEntry +import net.psforever.objects.vital.Vitality +import net.psforever.objects.vital.etc.ForceDomeExposure +import net.psforever.objects.vital.interaction.DamageInteraction +import net.psforever.objects.vital.prop.DamageWithPosition +import net.psforever.objects.zones.Zone import net.psforever.packet.game.ChatMsg import net.psforever.services.Service import net.psforever.services.local.{LocalAction, LocalServiceMessage} @@ -29,6 +37,7 @@ object ForceDomeControl { dome.Energized = activationState val owner = dome.Owner val zone = owner.Zone + owner.Actor ! BuildingActor.AmenityStateChange(dome) zone.LocalEvents ! LocalServiceMessage( zone.id, LocalAction.UpdateForceDomeStatus(Service.defaultPlayerGUID, owner.GUID, activationState) @@ -48,12 +57,12 @@ object ForceDomeControl { def CheckForceDomeStatus(building: Building, dome: ForceDomePhysics): Option[Boolean] = { if (building.IsCapitol) { Some( - if (ForceDomeControl.InvalidBuildingCapitolForceDomeConditions(building)) { + if (InvalidBuildingCapitolForceDomeConditions(building)) { false } else { building .Neighbours(building.Faction) - .map(_.count(b => !ForceDomeControl.InvalidBuildingCapitolForceDomeConditions(b))) + .map(_.count(b => !InvalidBuildingCapitolForceDomeConditions(b))) .exists(_ > 1) } ) @@ -105,24 +114,25 @@ object ForceDomeControl { .distinct } - def TechPlantFacilityPerimeter(dome: ForceDomePhysics): List[(Vector3, Vector3)] = { - val generatorTowerCenter = dome.Position.xy - val turretPoints = dome.Owner.Amenities.filter(_.isInstanceOf[FacilityTurret]).map(_.Position.xy) - val organizedByClosestToGarage = dome - .Owner - .Amenities - .find(_.Definition.Name.equals("gr_door_garage_ext")) - .map { garage => - val doorPosition = garage.Position.xy - turretPoints.sortBy(point => Vector3.DistanceSquared(doorPosition, point)) - } - .getOrElse(List[Vector3]()) - - //val turretPoints = dome.Owner.Amenities.filter(_.isInstanceOf[FacilityTurret]).map(_.Position.xy) - val pointsOfForceDomePerimeter = turretPoints.map { p => - val segmentFromTowerToTurret = p - generatorTowerCenter - Vector3.Unit(segmentFromTowerToTurret) * (Vector3.Magnitude(segmentFromTowerToTurret) + 20) //todo get correct distance offset - } + import scala.annotation.unused + def TechPlantFacilityPerimeter(@unused dome: ForceDomePhysics): List[(Vector3, Vector3)] = { +// val generatorTowerCenter = dome.Position.xy +// val turretPoints = dome.Owner.Amenities.filter(_.isInstanceOf[FacilityTurret]).map(_.Position.xy) +// val organizedByClosestToGarage = dome +// .Owner +// .Amenities +// .find(_.Definition.Name.equals("gr_door_garage_ext")) +// .map { garage => +// val doorPosition = garage.Position.xy +// turretPoints.sortBy(point => Vector3.DistanceSquared(doorPosition, point)) +// } +// .getOrElse(List[Vector3]()) +// +// //val turretPoints = dome.Owner.Amenities.filter(_.isInstanceOf[FacilityTurret]).map(_.Position.xy) +// val pointsOfForceDomePerimeter = turretPoints.map { p => +// val segmentFromTowerToTurret = p - generatorTowerCenter +// Vector3.Unit(segmentFromTowerToTurret) * (Vector3.Magnitude(segmentFromTowerToTurret) + 20) //todo get correct distance offset +// } Nil } @@ -147,7 +157,7 @@ object ForceDomeControl { /** * na - * @param building target building + * @param building facility */ def NormalDomeStateMessage(building: Building): Unit = { val events = building.Zone.LocalEvents @@ -159,6 +169,116 @@ object ForceDomeControl { events ! LocalServiceMessage(player.Name, message) } } + + /** + * Evaluate the conditions of the building + * and determine if its capitol force dome state should be updated + * to reflect the actual conditions of the base or its surrounding bases. + * If this building is considered a subcapitol facility to the zone's actual capitol facility, + * and has the capitol force dome has a dependency upon it, + * pass a message onto that facility that it should check its own state alignment. + * @param building facility with `dome` + */ + def AlignForceDomeStatusAndUpdate(building: Building, dome: ForceDomePhysics): Unit = { + CheckForceDomeStatus(building, dome).foreach { + case true => + if (!dome.Energized) { + ChangeDomeEnergizedState(dome, activationState = true) + ForceDomeKills(dome) + dome.Owner.Actor ! BuildingActor.MapUpdate() + } + case false => + if (dome.Energized) { + ChangeDomeEnergizedState(dome, activationState = false) + dome.Owner.Actor ! BuildingActor.MapUpdate() + } + } + } + + /** + * Evaluate the conditions of the building + * and determine if its capitol force dome state should be updated + * to reflect the actual conditions of the base or its surrounding bases. + * If this building is considered a subcapitol facility to the zone's actual capitol facility, + * and has the capitol force dome has a dependency upon it, + * pass a message onto that facility that it should check its own state alignment. + * @param building facility with `dome` + */ + private def AlignForceDomeStatus(building: Building, dome: ForceDomePhysics): Unit = { + CheckForceDomeStatus(building, dome).foreach { + case true => + if (!dome.Energized) { + ChangeDomeEnergizedState(dome, activationState = true) + ForceDomeKills(dome) + } + case false => + if (dome.Energized) { + ChangeDomeEnergizedState(dome, activationState = false) + } + } + } + + /** + * Being too close to the force dome can destroy targets if they do not match the faction alignment of the dome. + * This is the usual fate of opponents upon it being expanded (energeized). + * @see `Zone.serverSideDamage` + * @param dome force dome + * @return a list of affected entities + */ + def ForceDomeKills(dome: ForceDomePhysics): List[PlanetSideServerObject] = { + Zone.serverSideDamage( + dome.Zone, + dome, + contactWithForceDome, + Zone.distanceCheck, + forceDomeTargets(dome.Definition.UseRadius, dome.Faction) + ) + } + + /** + * na + * @param source a game object that represents the source of the explosion + * @param target a game object that is affected by the explosion + * @return a `DamageInteraction` object + */ + private def contactWithForceDome( + source: PlanetSideGameObject with FactionAffinity with Vitality, + target: PlanetSideGameObject with FactionAffinity with Vitality + ): DamageInteraction = { + DamageInteraction( + SourceEntry(target), + ForceDomeExposure(SourceEntry(source)), + target.Position + ) + } + + /** + * na + * @see `DamageWithPosition` + * @see `Zone.blockMap.sector` + * @param zone the zone in which the explosion should occur + * @param source a game entity that is treated as the origin and is excluded from results + * @param damagePropertiesBySource information about the effect/damage + * @return a list of affected entities + */ + private def forceDomeTargets( + radius: Float, + targetFaction: PlanetSideEmpire.Value + ) + ( + zone: Zone, + source: PlanetSideGameObject with Vitality, + damagePropertiesBySource: DamageWithPosition + ): List[PlanetSideServerObject with Vitality] = { + val sector = zone.blockMap.sector(source.Position.xy, radius) + val playerTargets = sector.livePlayerList.filterNot { _.VehicleSeated.nonEmpty } + //vehicles + val vehicleTargets = sector.vehicleList.filterNot { v => v.Destroyed || v.MountedIn.nonEmpty } + //deployables + val deployableTargets = sector.deployableList.filterNot { _.Destroyed } + //altogether ... + (playerTargets ++ vehicleTargets ++ deployableTargets).filterNot(_.Faction == targetFaction) + } } /** @@ -172,17 +292,12 @@ class ForceDomeControl(dome: ForceDomePhysics) def CaptureTerminalAwareObject: Amenity with CaptureTerminalAware = dome def FactionObject: FactionAffinity = dome - private var perimeterSegments: List[(Vector3, Vector3)] = Nil - private lazy val domeOwnerAsABuilding = dome.Owner.asInstanceOf[Building] private var customState: Option[Boolean] = None def commonBehavior: Receive = checkBehavior .orElse { - case Service.Startup() => - setupPerimeter() - case ForceDomeControl.CustomExpand if !dome.Energized && (customState.isEmpty || customState.contains(false)) => customState = Some(true) @@ -209,7 +324,7 @@ class ForceDomeControl(dome: ForceDomePhysics) if customState.nonEmpty => customState = None ForceDomeControl.NormalDomeStateMessage(domeOwnerAsABuilding) - alignForceDomeStatusAndUpdate(domeOwnerAsABuilding) + ForceDomeControl.AlignForceDomeStatusAndUpdate(domeOwnerAsABuilding, dome) } def poweredStateLogic: Receive = { @@ -217,7 +332,7 @@ class ForceDomeControl(dome: ForceDomePhysics) .orElse(captureTerminalAwareBehaviour) .orElse { case BuildingActor.AlertToFactionChange(_) => - blockedByCustomStateOr(alignForceDomeStatusAndUpdate, domeOwnerAsABuilding) + blockedByCustomStateOr(ForceDomeControl.AlignForceDomeStatusAndUpdate) case _ => () } @@ -231,83 +346,53 @@ class ForceDomeControl(dome: ForceDomePhysics) } def powerTurnOffCallback() : Unit = { - if (dome.Energized && customState.isEmpty) { - ForceDomeControl.ChangeDomeEnergizedState(dome,activationState = false) - } + deenergizeUnlessSuppressedDueToCustomState() } def powerTurnOnCallback() : Unit = { - blockedByCustomStateOr(alignForceDomeStatus, domeOwnerAsABuilding) + blockedByCustomStateOr(ForceDomeControl.AlignForceDomeStatus) } override protected def captureTerminalIsResecured(terminal: CaptureTerminal): Unit = { super.captureTerminalIsResecured(terminal) - blockedByCustomStateOr(alignForceDomeStatus, domeOwnerAsABuilding) + blockedByCustomStateOr(ForceDomeControl.AlignForceDomeStatus) } override protected def captureTerminalIsHacked(terminal: CaptureTerminal): Unit = { super.captureTerminalIsHacked(terminal) - if (dome.Energized && customState.isEmpty) { - ForceDomeControl.ChangeDomeEnergizedState(dome, activationState = false) - } + deenergizeUnlessSuppressedDueToCustomState() } - private def setupPerimeter(): Unit = { - //todo tech plants have an indent - if (perimeterSegments.isEmpty) { - perimeterSegments = ForceDomeControl.GeneralFacilityPerimeter(dome) + private def deenergizeUnlessSuppressedDueToCustomState(): Unit = { + if (dome.Energized) { + if (customState.isEmpty) { + ForceDomeControl.ChangeDomeEnergizedState(dome, activationState = false) + } else { + ForceDomeControl.CustomDomeStateEnforcedMessage(domeOwnerAsABuilding, state = true) + } } } + /** + * na + * @param func function to run if not blocked + * @return next behavior for an actor state + */ + private def blockedByCustomStateOr(func: (Building, ForceDomePhysics) => Unit): Unit = { + blockedByCustomStateOr(func, domeOwnerAsABuilding, dome) + } /** * na * @param func function to run if not blocked * @param building facility to operate upon (parameter to `func`) * @return next behavior for an actor state */ - private def blockedByCustomStateOr(func: Building => Unit, building: Building): Unit = { + private def blockedByCustomStateOr(func: (Building, ForceDomePhysics) => Unit, building: Building, dome: ForceDomePhysics): Unit = { customState match { case None => - func(building) + func(building, dome) case Some(state) => ForceDomeControl.CustomDomeStateEnforcedMessage(building, state) } } - - /** - * Evaluate the conditions of the building - * and determine if its capitol force dome state should be updated - * to reflect the actual conditions of the base or its surrounding bases. - * If this building is considered a subcapitol facility to the zone's actual capitol facility, - * and has the capitol force dome has a dependency upon it, - * pass a message onto that facility that it should check its own state alignment. - * @param building the building being evaluated - */ - private def alignForceDomeStatusAndUpdate(building: Building): Unit = { - ForceDomeControl.CheckForceDomeStatus(building, dome).foreach { - updatedStatus => - if (updatedStatus != dome.Energized) { - ForceDomeControl.ChangeDomeEnergizedState(dome, updatedStatus) - dome.Owner.Actor ! BuildingActor.MapUpdate() - } - } - } - - /** - * Evaluate the conditions of the building - * and determine if its capitol force dome state should be updated - * to reflect the actual conditions of the base or its surrounding bases. - * If this building is considered a subcapitol facility to the zone's actual capitol facility, - * and has the capitol force dome has a dependency upon it, - * pass a message onto that facility that it should check its own state alignment. - * @param building the building being evaluated - */ - private def alignForceDomeStatus(building: Building): Unit = { - ForceDomeControl.CheckForceDomeStatus(building, dome).foreach { - updatedStatus => - if (updatedStatus != dome.Energized) { - ForceDomeControl.ChangeDomeEnergizedState(dome, updatedStatus) - } - } - } } diff --git a/src/main/scala/net/psforever/objects/serverobject/generator/GeneratorControl.scala b/src/main/scala/net/psforever/objects/serverobject/generator/GeneratorControl.scala index 07e2b9d9f..a7b0c78d5 100644 --- a/src/main/scala/net/psforever/objects/serverobject/generator/GeneratorControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/generator/GeneratorControl.scala @@ -122,7 +122,7 @@ class GeneratorControl(gen: Generator) queuedExplosion = Default.Cancellable imminentExplosion = false //hate on everything nearby - Zone.serverSideDamage(gen.Zone, gen, Zone.explosionDamage(gen.LastDamage), explosionFunc) + Zone.serverSideDamage(gen.Zone, gen, Zone.explosionDamage(gen.LastDamage), explosionFunc, Zone.findAllTargets) case GeneratorControl.Restored() => gen.ClearHistory() diff --git a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlRailJack.scala b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlRailJack.scala index 0f87181bc..c7740c7da 100644 --- a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlRailJack.scala +++ b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlRailJack.scala @@ -37,7 +37,8 @@ class VehicleSpawnControlRailJack(pad: VehicleSpawnPad) extends VehicleSpawnCont pad.Zone, pad, VehicleSpawnControlRailJack.prepareSpawnExplosion(pad, SourceEntry(driver), SourceEntry(vehicle)), - pad.Definition.killBox(pad, vehicle.Definition.CanFly) + pad.Definition.killBox(pad, vehicle.Definition.CanFly), + Zone.findAllTargets ) pad.Zone.VehicleEvents ! VehicleSpawnPad.AttachToRails(vehicle, pad) context.system.scheduler.scheduleOnce(10 milliseconds, seatDriver, order) diff --git a/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala b/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala index ab4d3499c..996b4d876 100644 --- a/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala @@ -18,6 +18,10 @@ import net.psforever.util.Config import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ +object ResourceSiloControl { + final case class DrainMultiplier(multiplier: Float) +} + /** * An `Actor` that handles messages being dispatched to a specific `ResourceSilo` entity. * @@ -30,7 +34,9 @@ class ResourceSiloControl(resourceSilo: ResourceSilo) def FactionObject: FactionAffinity = resourceSilo private[this] val log = org.log4s.getLogger - var panelAnimationFunc: (ActorRef, Float) => Unit = PanelAnimation + private var panelAnimationFunc: (ActorRef, Float) => Unit = PanelAnimation + /** the higher the multiplier, the greater the drain */ + private var drainMultiplier: Float = 1.0f def receive: Receive = { case Service.Startup() => @@ -53,6 +59,9 @@ class ResourceSiloControl(resourceSilo: ResourceSilo) checkBehavior .orElse(storageBehavior) .orElse { + case ResourceSiloControl.DrainMultiplier(multiplier) => + drainMultiplier = multiplier + case CommonMessages.Use(_, Some(vehicle: Vehicle)) if GlobalDefinitions.isBattleFrameVehicle(vehicle.Definition) => val siloFaction = resourceSilo.Faction @@ -171,7 +180,7 @@ class ResourceSiloControl(resourceSilo: ResourceSilo) */ def HandleNtuRequest(sender: ActorRef, min: Float, max: Float): Unit = { val originalAmount = resourceSilo.NtuCapacitor - UpdateChargeLevel(-min) + UpdateChargeLevel(-min * drainMultiplier) sender ! Ntu.Grant(resourceSilo, originalAmount - resourceSilo.NtuCapacitor) } diff --git a/src/main/scala/net/psforever/objects/zones/Zone.scala b/src/main/scala/net/psforever/objects/zones/Zone.scala index e48338c59..b47182a6f 100644 --- a/src/main/scala/net/psforever/objects/zones/Zone.scala +++ b/src/main/scala/net/psforever/objects/zones/Zone.scala @@ -40,7 +40,6 @@ import net.psforever.objects.geometry.d3.VolumetricGeometry import net.psforever.objects.guid.pool.NumberPool import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.affinity.FactionAffinity -import net.psforever.objects.serverobject.dome.{ForceDomeDefinition, ForceDomePhysics} import net.psforever.objects.serverobject.doors.Door import net.psforever.objects.serverobject.environment.EnvironmentAttribute import net.psforever.objects.serverobject.interior.{InteriorAware, Sidedness} @@ -1639,13 +1638,6 @@ object Zone { case painbox: Painbox => painbox.Actor ! Service.Startup() } - //capitol facilities have force domes - buildings.values - .flatMap(_.Amenities.filter(_.Definition.isInstanceOf[ForceDomeDefinition])) - .collect { - case obj: ForceDomePhysics => - obj.Actor ! Service.Startup() - } //the orbital_buildings in sanctuary zones have to establish their shuttle routes map.shuttleBays .map { @@ -1817,6 +1809,29 @@ object Zone { /* explosions */ + /** + * Allocates `Damageable` targets within the vicinity of server-prepared damage dealing + * and informs those entities that they have affected by the aforementioned damage. + * Usually, this is considered an "explosion;" but, the application can be utilized for a variety of unbound damage. + * @param zone the zone in which the damage should occur + * @param source the entity that embodies the damage (information) + * @param createInteraction how the interaction for this damage is to prepared + * @return a list of affected entities; + * only mostly complete due to the exclusion of objects whose damage resolution is different than usual + */ + def serverSideDamage( + zone: Zone, + source: PlanetSideGameObject with FactionAffinity with Vitality, + createInteraction: (PlanetSideGameObject with FactionAffinity with Vitality, PlanetSideGameObject with FactionAffinity with Vitality) => DamageInteraction + ): List[PlanetSideServerObject] = { + source.Definition.innateDamage match { + case Some(damage) => + serverSideDamage(zone, source, damage, createInteraction, distanceCheck, findAllTargets) + case None => + Nil + } + } + /** * Allocates `Damageable` targets within the vicinity of server-prepared damage dealing * and informs those entities that they have affected by the aforementioned damage. @@ -1824,8 +1839,10 @@ object Zone { * @param zone the zone in which the damage should occur * @param source the entity that embodies the damage (information) * @param createInteraction how the interaction for this damage is to prepared - * @param testTargetsFromZone a custom test for determining whether the allocated targets are affected by the damage - * @param acquireTargetsFromZone the main target-collecting algorithm + * @param testTargetsFromZone a custom test for determining whether the allocated targets are affected by the damage; + * filters targets from the existing selection + * @param acquireTargetsFromZone the main target-collecting algorithm; + * collects targets from sector information * @return a list of affected entities; * only mostly complete due to the exclusion of objects whose damage resolution is different than usual */ @@ -1833,8 +1850,8 @@ object Zone { zone: Zone, source: PlanetSideGameObject with FactionAffinity with Vitality, createInteraction: (PlanetSideGameObject with FactionAffinity with Vitality, PlanetSideGameObject with FactionAffinity with Vitality) => DamageInteraction, - testTargetsFromZone: (PlanetSideGameObject, PlanetSideGameObject, Float) => Boolean = distanceCheck, - acquireTargetsFromZone: (Zone, PlanetSideGameObject with FactionAffinity with Vitality, DamageWithPosition) => List[PlanetSideServerObject with Vitality] = findAllTargets + testTargetsFromZone: (PlanetSideGameObject, PlanetSideGameObject, Float) => Boolean, + acquireTargetsFromZone: (Zone, PlanetSideGameObject with FactionAffinity with Vitality, DamageWithPosition) => List[PlanetSideServerObject with Vitality] ): List[PlanetSideServerObject] = { source.Definition.innateDamage match { case Some(damage) => @@ -1859,8 +1876,10 @@ object Zone { * @param zone the zone in which the damage should occur * @param source the entity that embodies the damage (information) * @param createInteraction how the interaction for this damage is to prepared - * @param testTargetsFromZone a custom test for determining whether the allocated targets are affected by the damage - * @param acquireTargetsFromZone the main target-collecting algorithm + * @param testTargetsFromZone a custom test for determining whether the allocated targets are affected by the damage; + * filters targets from the existing selection + * @param acquireTargetsFromZone the main target-collecting algorithm; + * collects targets from sector information * @return a list of affected entities; * only mostly complete due to the exclusion of objects whose damage resolution is different than usual */