force dome messages owner about change in state, triggering the NTU silo to give away repairs for free; activating the force dome kills or destroys all enemies within its radius

This commit is contained in:
Fate-JH 2025-12-16 20:37:29 -05:00
parent 8fedd2e724
commit 6a960ed5ac
8 changed files with 262 additions and 98 deletions

View file

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

View file

@ -187,7 +187,8 @@ object ExplosiveDeployableControl {
zone,
target,
Zone.explosionDamage(Some(cause)),
ExplosiveDeployableControl.detectionForExplosiveSource(target)
ExplosiveDeployableControl.detectionForExplosiveSource(target),
Zone.findAllTargets
)
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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