mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-07-14 07:55:33 +00:00
commit
8f1badb862
45 changed files with 386 additions and 328 deletions
|
|
@ -74,7 +74,7 @@ add_property pulsar equiptime 600
|
||||||
add_property pulsar holstertime 600
|
add_property pulsar holstertime 600
|
||||||
add_property punisher equiptime 600
|
add_property punisher equiptime 600
|
||||||
add_property punisher holstertime 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 equiptime 750
|
||||||
add_property r_shotgun holstertime 750
|
add_property r_shotgun holstertime 750
|
||||||
add_property remote_electronics_kit equiptime 500
|
add_property remote_electronics_kit equiptime 500
|
||||||
|
|
|
||||||
|
|
@ -127,14 +127,14 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit
|
||||||
val list = ops.composeDirectDamageInformation(pkt)
|
val list = ops.composeDirectDamageInformation(pkt)
|
||||||
if (!player.spectator) {
|
if (!player.spectator) {
|
||||||
list.foreach {
|
list.foreach {
|
||||||
case (target, projectile, _, _) =>
|
case (target, projectile, _, targetPos) =>
|
||||||
ops.resolveProjectileInteraction(target, projectile, DamageResolution.Hit, target.Position)
|
ops.resolveProjectileInteractionAndProxy(target, projectile, DamageResolution.Hit, targetPos)
|
||||||
}
|
}
|
||||||
//...
|
//...
|
||||||
if (list.isEmpty) {
|
if (list.isEmpty) {
|
||||||
ops.handleProxyDamage(pkt.projectile_guid, pkt.hit_info.map(_.hit_pos).getOrElse(Vector3.Zero)).foreach {
|
ops.handleProxyDamage(pkt.projectile_guid, pkt.hit_info.map(_.hit_pos).getOrElse(Vector3.Zero)).foreach {
|
||||||
case (target, proxy, hitPos, _) =>
|
case (target, proxy, _, targetPos) =>
|
||||||
ops.resolveProjectileInteraction(target, proxy, DamageResolution.Hit, hitPos)
|
ops.resolveProjectileInteraction(target, proxy, DamageResolution.Hit, targetPos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -157,12 +157,12 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit
|
||||||
//...
|
//...
|
||||||
val (direct, others) = list.partition { case (_, _, hitPos, targetPos) => hitPos == targetPos }
|
val (direct, others) = list.partition { case (_, _, hitPos, targetPos) => hitPos == targetPos }
|
||||||
direct.foreach {
|
direct.foreach {
|
||||||
case (target, _, _, _) =>
|
case (target, _, _, targetPos) =>
|
||||||
ops.resolveProjectileInteraction(target, projectile, resolution1, target.Position)
|
ops.resolveProjectileInteractionAndProxy(target, projectile, resolution1, targetPos)
|
||||||
}
|
}
|
||||||
others.foreach {
|
others.foreach {
|
||||||
case (target, _, _, _) =>
|
case (target, _, _, targetPos) =>
|
||||||
ops.resolveProjectileInteraction(target, projectile, resolution2, target.Position)
|
ops.resolveProjectileInteraction(target, projectile, resolution2, targetPos)
|
||||||
}
|
}
|
||||||
//...
|
//...
|
||||||
if (
|
if (
|
||||||
|
|
@ -183,11 +183,11 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit
|
||||||
if (profile.ExistsOnRemoteClients && projectile.HasGUID) {
|
if (profile.ExistsOnRemoteClients && projectile.HasGUID) {
|
||||||
continent.Projectile ! ZoneProjectile.Remove(projectileGuid)
|
continent.Projectile ! ZoneProjectile.Remove(projectileGuid)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
//...
|
ops.handleProxyDamage(pkt.projectile_uid, pkt.projectile_pos).foreach {
|
||||||
ops.handleProxyDamage(pkt.projectile_uid, pkt.projectile_pos).foreach {
|
case (target, proxy, _, targetPos) =>
|
||||||
case (target, proxy, hitPos, _) =>
|
ops.resolveProjectileInteraction(target, proxy, DamageResolution.Splash, targetPos)
|
||||||
ops.resolveProjectileInteraction(target, proxy, DamageResolution.Splash, hitPos)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -144,9 +144,9 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit
|
||||||
val projectileGuid = pkt.projectile_guid
|
val projectileGuid = pkt.projectile_guid
|
||||||
val list = ops.composeDirectDamageInformation(pkt)
|
val list = ops.composeDirectDamageInformation(pkt)
|
||||||
.collect {
|
.collect {
|
||||||
case (target, projectile, hitPos, _) =>
|
case (target, projectile, hitPos, targetPos) =>
|
||||||
ops.checkForHitPositionDiscrepancy(projectileGuid, hitPos, target)
|
ops.checkForHitPositionDiscrepancy(projectileGuid, hitPos, targetPos)
|
||||||
ops.resolveProjectileInteraction(target, projectile, DamageResolution.Hit, hitPos)
|
ops.resolveProjectileInteractionAndProxy(target, projectile, DamageResolution.Hit, hitPos)
|
||||||
projectile
|
projectile
|
||||||
}
|
}
|
||||||
//...
|
//...
|
||||||
|
|
@ -174,9 +174,9 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit
|
||||||
//...
|
//...
|
||||||
val (direct, others) = list.partition { case (_, _, hitPos, targetPos) => hitPos == targetPos }
|
val (direct, others) = list.partition { case (_, _, hitPos, targetPos) => hitPos == targetPos }
|
||||||
direct.foreach {
|
direct.foreach {
|
||||||
case (target, _, hitPos, _) =>
|
case (target, _, hitPos, targetPos) =>
|
||||||
ops.checkForHitPositionDiscrepancy(projectileGuid, hitPos, target)
|
ops.checkForHitPositionDiscrepancy(projectileGuid, hitPos, targetPos)
|
||||||
ops.resolveProjectileInteraction(target, projectile, resolution1, hitPos)
|
ops.resolveProjectileInteractionAndProxy(target, projectile, resolution1, hitPos)
|
||||||
}
|
}
|
||||||
others.foreach {
|
others.foreach {
|
||||||
case (target, _, hitPos, _) =>
|
case (target, _, hitPos, _) =>
|
||||||
|
|
@ -202,19 +202,19 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit
|
||||||
//cleanup
|
//cleanup
|
||||||
continent.Projectile ! ZoneProjectile.Remove(projectile.GUID)
|
continent.Projectile ! ZoneProjectile.Remove(projectile.GUID)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
//...
|
ops.handleProxyDamage(pkt.projectile_uid, pkt.projectile_pos).foreach {
|
||||||
ops.handleProxyDamage(pkt.projectile_uid, pkt.projectile_pos).foreach {
|
case (target, proxy, hitPos, _) =>
|
||||||
case (target, proxy, hitPos, _) =>
|
ops.resolveProjectileInteraction(target, proxy, DamageResolution.Splash, hitPos)
|
||||||
ops.resolveProjectileInteraction(target, proxy, DamageResolution.Splash, hitPos)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def handleLashHit(pkt: LashMessage): Unit = {
|
def handleLashHit(pkt: LashMessage): Unit = {
|
||||||
val list = ops.composeLashDamageInformation(pkt)
|
val list = ops.composeLashDamageInformation(pkt)
|
||||||
list.foreach {
|
list.foreach {
|
||||||
case (target, projectile, hitPos, _) =>
|
case (target, projectile, hitPos, targetPos) =>
|
||||||
ops.checkForHitPositionDiscrepancy(projectile.GUID, hitPos, target)
|
ops.checkForHitPositionDiscrepancy(projectile.GUID, hitPos, targetPos)
|
||||||
ops.resolveProjectileInteraction(target, projectile, DamageResolution.Lash, hitPos)
|
ops.resolveProjectileInteraction(target, projectile, DamageResolution.Lash, hitPos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -223,8 +223,8 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit
|
||||||
val list = ops.composeAIDamageInformation(pkt)
|
val list = ops.composeAIDamageInformation(pkt)
|
||||||
if (ops.confirmAIDamageTarget(pkt, list.map(_._1))) {
|
if (ops.confirmAIDamageTarget(pkt, list.map(_._1))) {
|
||||||
list.foreach {
|
list.foreach {
|
||||||
case (target, projectile, hitPos, _) =>
|
case (target, projectile, hitPos, targetPos) =>
|
||||||
ops.checkForHitPositionDiscrepancy(pkt.attacker_guid, hitPos, target)
|
ops.checkForHitPositionDiscrepancy(pkt.attacker_guid, hitPos, targetPos)
|
||||||
ops.resolveProjectileInteraction(target, projectile, DamageResolution.Hit, hitPos)
|
ops.resolveProjectileInteraction(target, projectile, DamageResolution.Hit, hitPos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -513,6 +513,7 @@ class WeaponAndProjectileOperations(
|
||||||
hit_info match {
|
hit_info match {
|
||||||
case Some(hitInfo) =>
|
case Some(hitInfo) =>
|
||||||
val hitPos = hitInfo.hit_pos
|
val hitPos = hitInfo.hit_pos
|
||||||
|
projectile.Position = hitPos
|
||||||
sessionLogic.validObject(hitInfo.hitobject_guid, decorator = "Hit/hitInfo") match {
|
sessionLogic.validObject(hitInfo.hitobject_guid, decorator = "Hit/hitInfo") match {
|
||||||
case _ if projectile.profile == GlobalDefinitions.flail_projectile =>
|
case _ if projectile.profile == GlobalDefinitions.flail_projectile =>
|
||||||
val radius = projectile.profile.DamageRadius * projectile.profile.DamageRadius
|
val radius = projectile.profile.DamageRadius * projectile.profile.DamageRadius
|
||||||
|
|
@ -522,7 +523,7 @@ class WeaponAndProjectileOperations(
|
||||||
.map(target => (target, projectile, hitPos, target.Position))
|
.map(target => (target, projectile, hitPos, target.Position))
|
||||||
|
|
||||||
case Some(target: PlanetSideGameObject with FactionAffinity with Vitality) =>
|
case Some(target: PlanetSideGameObject with FactionAffinity with Vitality) =>
|
||||||
List((target, projectile, hitInfo.shot_origin, hitPos))
|
List((target, projectile, hitPos, target.Position))
|
||||||
|
|
||||||
case None =>
|
case None =>
|
||||||
Nil
|
Nil
|
||||||
|
|
@ -585,7 +586,9 @@ class WeaponAndProjectileOperations(
|
||||||
FindProjectileEntry(projectile_guid)
|
FindProjectileEntry(projectile_guid)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
projectile =>
|
projectile =>
|
||||||
sessionLogic
|
//projectile may still be moving, and may lash other targets in the future when in a different position
|
||||||
|
projectile.Position = hit_pos
|
||||||
|
sessionLogic
|
||||||
.validObject(victim_guid, decorator = "LashHit/victim_guid")
|
.validObject(victim_guid, decorator = "LashHit/victim_guid")
|
||||||
.collect {
|
.collect {
|
||||||
case target: PlanetSideGameObject with FactionAffinity with Vitality =>
|
case target: PlanetSideGameObject with FactionAffinity with Vitality =>
|
||||||
|
|
@ -668,6 +671,18 @@ class WeaponAndProjectileOperations(
|
||||||
.getOrElse(Nil)
|
.getOrElse(Nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def handleProxyDamage(
|
||||||
|
projectile: Projectile,
|
||||||
|
explosionPosition: Vector3
|
||||||
|
): List[(PlanetSideGameObject with FactionAffinity with Vitality, Projectile, Vector3, Vector3)] = {
|
||||||
|
val proxyList = resolveDamageProxy(projectile, projectile.GUID, explosionPosition)
|
||||||
|
proxyList.collectFirst {
|
||||||
|
case (_, proxy, _, _) if proxy.profile == GlobalDefinitions.oicw_little_buddy =>
|
||||||
|
queueLittleBuddyExplosion(proxy)
|
||||||
|
}
|
||||||
|
proxyList
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take a projectile that was introduced into the game world and
|
* Take a projectile that was introduced into the game world and
|
||||||
* determine if it generates a secondary damage projectile or
|
* determine if it generates a secondary damage projectile or
|
||||||
|
|
@ -698,12 +713,14 @@ class WeaponAndProjectileOperations(
|
||||||
queueLittleBuddyExplosion(proxy)
|
queueLittleBuddyExplosion(proxy)
|
||||||
Nil
|
Nil
|
||||||
} else if (proxy.profile.ExistsOnRemoteClients) {
|
} else if (proxy.profile.ExistsOnRemoteClients) {
|
||||||
|
proxy.Position = hitPos
|
||||||
proxy.WhichSide = projectile.WhichSide
|
proxy.WhichSide = projectile.WhichSide
|
||||||
continent.Projectile ! ZoneProjectile.Add(player.GUID, proxy)
|
continent.Projectile ! ZoneProjectile.Add(player.GUID, proxy)
|
||||||
Nil
|
Nil
|
||||||
} else if (proxy.tool_def == GlobalDefinitions.maelstrom) {
|
} else if (proxy.tool_def == GlobalDefinitions.maelstrom) {
|
||||||
//server-side maelstrom grenade target selection
|
//server-side maelstrom grenade target selection
|
||||||
//for convenience purposes, all resulting chain lashing is handled here and resolves in one pass
|
//for convenience purposes, all resulting chain lashing is handled here and resolves in one pass
|
||||||
|
proxy.Position = hitPos
|
||||||
proxy.WhichSide = Sidedness.StrictlyBetweenSides
|
proxy.WhichSide = Sidedness.StrictlyBetweenSides
|
||||||
val radiusSquared = proxy.profile.LashRadius * proxy.profile.LashRadius
|
val radiusSquared = proxy.profile.LashRadius * proxy.profile.LashRadius
|
||||||
var availableTargets = sessionLogic.localSector.livePlayerList
|
var availableTargets = sessionLogic.localSector.livePlayerList
|
||||||
|
|
@ -812,6 +829,26 @@ class WeaponAndProjectileOperations(
|
||||||
context.system.scheduler.scheduleOnce(500.milliseconds) { explosionFunc() }
|
context.system.scheduler.scheduleOnce(500.milliseconds) { explosionFunc() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a projectile with the given globally unique identifier and mark it as a resolved shot.
|
||||||
|
* A `Resolved` shot has either encountered an obstacle or is being cleaned up for not finding an obstacle.
|
||||||
|
* Check if we are required to deal with damage proxy management as well.
|
||||||
|
* @param projectile projectile
|
||||||
|
* @param resolution resolution status to promote the projectile
|
||||||
|
* @return package that contains information about the damage
|
||||||
|
*/
|
||||||
|
def resolveProjectileInteractionAndProxy(
|
||||||
|
target: PlanetSideGameObject with FactionAffinity with Vitality,
|
||||||
|
projectile: Projectile,
|
||||||
|
resolution: DamageResolution.Value,
|
||||||
|
hitPosition: Vector3
|
||||||
|
): Option[DamageInteraction] = {
|
||||||
|
if (projectile.profile.DamageProxyOnDirectHit.exists(_.test(target))) {
|
||||||
|
handleProxyDamage(projectile, hitPosition)
|
||||||
|
}
|
||||||
|
resolveProjectileInteraction(target, projectile, resolution, hitPosition)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a projectile with the given globally unique identifier and mark it as a resolved shot.
|
* Find a projectile with the given globally unique identifier and mark it as a resolved shot.
|
||||||
* A `Resolved` shot has either encountered an obstacle or is being cleaned up for not finding an obstacle.
|
* A `Resolved` shot has either encountered an obstacle or is being cleaned up for not finding an obstacle.
|
||||||
|
|
@ -1445,15 +1482,23 @@ class WeaponAndProjectileOperations(
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkForHitPositionDiscrepancy(
|
def checkForHitPositionDiscrepancy(
|
||||||
projectile_guid: PlanetSideGUID,
|
projectileGuid: PlanetSideGUID,
|
||||||
hitPos: Vector3,
|
hitPosition: Vector3,
|
||||||
target: PlanetSideGameObject with Vitality
|
target: PlanetSideGameObject with Vitality
|
||||||
): Unit = {
|
): Unit = {
|
||||||
val hitPositionDiscrepancy = Vector3.DistanceSquared(hitPos, target.Position)
|
checkForHitPositionDiscrepancy(projectileGuid, hitPosition, target.Position)
|
||||||
|
}
|
||||||
|
|
||||||
|
def checkForHitPositionDiscrepancy(
|
||||||
|
projectileGuid: PlanetSideGUID,
|
||||||
|
hitPosition: Vector3,
|
||||||
|
targetPosition: Vector3
|
||||||
|
): Unit = {
|
||||||
|
val hitPositionDiscrepancy = Vector3.DistanceSquared(hitPosition, targetPosition)
|
||||||
if (hitPositionDiscrepancy > Config.app.antiCheat.hitPositionDiscrepancyThreshold) {
|
if (hitPositionDiscrepancy > Config.app.antiCheat.hitPositionDiscrepancyThreshold) {
|
||||||
// If the target position on the server does not match the position where the projectile landed within reason there may be foul play
|
// If the target position on the server does not match the position where the projectile landed within reason there may be foul play
|
||||||
log.warn(
|
log.warn(
|
||||||
s"${player.Name}'s shot #${projectile_guid.guid} has hit discrepancy with target. Target: ${target.Position}, Reported: $hitPos, Distance: $hitPositionDiscrepancy / ${math.sqrt(hitPositionDiscrepancy).toFloat}; suspect"
|
s"${player.Name}'s shot #${projectileGuid.guid} has hit discrepancy with target. Target: $targetPosition, Reported: $hitPosition, Distance: $hitPositionDiscrepancy / ${math.sqrt(hitPositionDiscrepancy).toFloat}; suspect"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ import net.psforever.objects.vital.damage.DamageProfile
|
||||||
import net.psforever.objects.vital.interaction.DamageInteraction
|
import net.psforever.objects.vital.interaction.DamageInteraction
|
||||||
import net.psforever.objects.vital.resolution.DamageResistanceModel
|
import net.psforever.objects.vital.resolution.DamageResistanceModel
|
||||||
import net.psforever.objects.zones.blockmap.BlockMapEntity
|
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 net.psforever.types._
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import net.psforever.objects.vital.damage.DamageCalculations
|
||||||
import net.psforever.objects.vital.interaction.DamageResult
|
import net.psforever.objects.vital.interaction.DamageResult
|
||||||
import net.psforever.objects.vital.resistance.StandardResistanceProfile
|
import net.psforever.objects.vital.resistance.StandardResistanceProfile
|
||||||
import net.psforever.objects.vital.{SimpleResolutions, StandardVehicleResistance}
|
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.packet.game.TriggeredSound
|
||||||
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ import net.psforever.objects.vehicles.interaction.{TriggerOnVehicleRule, WithLav
|
||||||
import net.psforever.objects.vital.resistance.StandardResistanceProfile
|
import net.psforever.objects.vital.resistance.StandardResistanceProfile
|
||||||
import net.psforever.objects.vital.Vitality
|
import net.psforever.objects.vital.Vitality
|
||||||
import net.psforever.objects.vital.resolution.DamageResistanceModel
|
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.blockmap.BlockMapEntity
|
||||||
|
import net.psforever.objects.zones.interaction.InteractsWithZone
|
||||||
import net.psforever.packet.PlanetSideGamePacket
|
import net.psforever.packet.PlanetSideGamePacket
|
||||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
|
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -898,7 +898,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
//initial damage for aggravation, but never treat as "aggravated"
|
//initial damage for aggravation, but never treat as "aggravated"
|
||||||
false
|
false
|
||||||
case _ =>
|
case _ =>
|
||||||
cause.interaction.cause.source.Aggravated.nonEmpty
|
target.VehicleSeated.isEmpty && cause.interaction.cause.source.Aggravated.nonEmpty
|
||||||
}
|
}
|
||||||
//log historical event (always)
|
//log historical event (always)
|
||||||
target.LogActivity(cause)
|
target.LogActivity(cause)
|
||||||
|
|
|
||||||
|
|
@ -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.{EnvironmentAttribute, EnvironmentTrait, PieceOfEnvironment, interaction}
|
||||||
import net.psforever.objects.serverobject.environment.interaction.{InteractionWith, RespondsToZoneEnvironment}
|
import net.psforever.objects.serverobject.environment.interaction.{InteractionWith, RespondsToZoneEnvironment}
|
||||||
import net.psforever.objects.serverobject.interior.{Sidedness, TraditionalInteriorAware}
|
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 net.psforever.types.Vector3
|
||||||
|
|
||||||
import scala.annotation.unused
|
import scala.annotation.unused
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import net.psforever.objects.serverobject.environment.interaction.{InteractionWi
|
||||||
import net.psforever.objects.{Player, Vehicle, Vehicles}
|
import net.psforever.objects.{Player, Vehicle, Vehicles}
|
||||||
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, GantryDenialField, PieceOfEnvironment, interaction}
|
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, GantryDenialField, PieceOfEnvironment, interaction}
|
||||||
import net.psforever.objects.serverobject.shuttle.OrbitalShuttlePad
|
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.packet.game.{ChatMsg, PlayerStateShiftMessage, ShiftState}
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import net.psforever.objects.sourcing.SourceEntry
|
||||||
import net.psforever.objects.vital.Vitality
|
import net.psforever.objects.vital.Vitality
|
||||||
import net.psforever.objects.vital.environment.EnvironmentReason
|
import net.psforever.objects.vital.environment.EnvironmentReason
|
||||||
import net.psforever.objects.vital.interaction.DamageInteraction
|
import net.psforever.objects.vital.interaction.DamageInteraction
|
||||||
import net.psforever.objects.zones.InteractsWithZone
|
import net.psforever.objects.zones.interaction.InteractsWithZone
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
||||||
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment, interaction}
|
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.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
import net.psforever.types.OxygenState
|
import net.psforever.types.OxygenState
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,83 +7,38 @@ import net.psforever.objects.vital.Vitality
|
||||||
import net.psforever.objects.vital.base.DamageResolution
|
import net.psforever.objects.vital.base.DamageResolution
|
||||||
import net.psforever.objects.vital.etc.RadiationReason
|
import net.psforever.objects.vital.etc.RadiationReason
|
||||||
import net.psforever.objects.vital.interaction.DamageInteraction
|
import net.psforever.objects.vital.interaction.DamageInteraction
|
||||||
import net.psforever.objects.zones.blockmap.SectorPopulation
|
import net.psforever.objects.zones.interaction.{InteractsWithZone, RadiationCloudInteraction, ZoneInteractionType}
|
||||||
import net.psforever.objects.zones.{InteractsWithZone, Zone, ZoneInteraction, ZoneInteractionType}
|
|
||||||
import net.psforever.types.PlanetSideGUID
|
|
||||||
|
|
||||||
case object RadiationInteraction extends ZoneInteractionType
|
case object RadiationInteraction extends ZoneInteractionType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This game entity may infrequently test whether it may interact with radiation cloud projectiles
|
* 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.
|
* 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(
|
class InteractWithRadiationClouds(
|
||||||
val range: Float,
|
val range: Float,
|
||||||
private val user: Option[Player]
|
private val user: Option[Player]
|
||||||
) extends ZoneInteraction {
|
) extends RadiationCloudInteraction {
|
||||||
/**
|
|
||||||
* 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()
|
|
||||||
|
|
||||||
def Type: ZoneInteractionType = RadiationInteraction
|
def Type: ZoneInteractionType = RadiationInteraction
|
||||||
|
|
||||||
/**
|
def performInteractionWithTarget(projectiles: List[Projectile], target: InteractsWithZone): Unit = {
|
||||||
* Wander into a radiation cloud and suffer the consequences.
|
if (projectiles.nonEmpty) {
|
||||||
* @param sector the portion of the block map being tested
|
val position = target.Position
|
||||||
* @param target the fixed element in this test
|
projectiles
|
||||||
*/
|
.foreach { projectile =>
|
||||||
def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit = {
|
target.Actor ! Vitality.Damage(
|
||||||
target match {
|
DamageInteraction(
|
||||||
case t: Vitality =>
|
SourceEntry(target),
|
||||||
val position = target.Position
|
RadiationReason(
|
||||||
val targetList = List(target)
|
ProjectileQuality.modifiers(projectile, DamageResolution.Radiation, target, target.Position, user),
|
||||||
//collect all projectiles in sector/range
|
target.DamageModel,
|
||||||
val projectiles = sector
|
RadiationCloudInteraction.RadiationShieldingFrom(target)
|
||||||
.projectileList
|
),
|
||||||
.filter { cloud =>
|
position
|
||||||
val definition = cloud.Definition
|
).calculate()
|
||||||
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()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects.ce
|
||||||
|
|
||||||
import net.psforever.objects.geometry.d3.VolumetricGeometry
|
import net.psforever.objects.geometry.d3.VolumetricGeometry
|
||||||
import net.psforever.objects.zones.blockmap.SectorPopulation
|
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.objects.{BoomerDeployable, ExplosiveDeployable}
|
||||||
import net.psforever.types.PlanetSideGUID
|
import net.psforever.types.PlanetSideGUID
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ import net.psforever.objects.GlobalDefinitions
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.turret.auto.{AutomatedTurret, AutomatedTurretBehavior}
|
import net.psforever.objects.serverobject.turret.auto.{AutomatedTurret, AutomatedTurretBehavior}
|
||||||
import net.psforever.objects.zones.blockmap.SectorPopulation
|
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.sourcing.SourceUniqueness
|
||||||
|
import net.psforever.objects.zones.interaction.{InteractsWithZone, ZoneInteraction, ZoneInteractionType}
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
|
|
||||||
case object TurretInteraction extends ZoneInteractionType
|
case object TurretInteraction extends ZoneInteractionType
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,8 @@ class SpecialExoSuitDefinition(private val suitType: ExoSuitType.Value) extends
|
||||||
|
|
||||||
override def Use: ExoSuitDefinition = {
|
override def Use: ExoSuitDefinition = {
|
||||||
val obj = new SpecialExoSuitDefinition(SuitType)
|
val obj = new SpecialExoSuitDefinition(SuitType)
|
||||||
|
obj.Name = Name
|
||||||
|
obj.Descriptor = Descriptor
|
||||||
obj.Permissions = Permissions
|
obj.Permissions = Permissions
|
||||||
obj.MaxArmor = MaxArmor
|
obj.MaxArmor = MaxArmor
|
||||||
obj.MaxCapacitor = MaxCapacitor
|
obj.MaxCapacitor = MaxCapacitor
|
||||||
|
|
@ -150,6 +152,7 @@ class SpecialExoSuitDefinition(private val suitType: ExoSuitType.Value) extends
|
||||||
obj.ResistanceDirectHit = ResistanceDirectHit
|
obj.ResistanceDirectHit = ResistanceDirectHit
|
||||||
obj.ResistanceSplash = ResistanceSplash
|
obj.ResistanceSplash = ResistanceSplash
|
||||||
obj.ResistanceAggravated = ResistanceAggravated
|
obj.ResistanceAggravated = ResistanceAggravated
|
||||||
|
obj.RadiationShielding = RadiationShielding
|
||||||
obj.DamageUsing = DamageUsing
|
obj.DamageUsing = DamageUsing
|
||||||
obj.ResistUsing = ResistUsing
|
obj.ResistUsing = ResistUsing
|
||||||
obj.Model = Model
|
obj.Model = Model
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ object EffectTarget {
|
||||||
* Arbitrary, but useful.
|
* Arbitrary, but useful.
|
||||||
*/
|
*/
|
||||||
object Category extends Enumeration {
|
object Category extends Enumeration {
|
||||||
val Aircraft, Deployable, Equipment, Player, Turret, Vehicle = Value
|
val Aircraft, Deployable, Equipment, Player, Turret, Vehicle, All = Value
|
||||||
}
|
}
|
||||||
|
|
||||||
object Validation {
|
object Validation {
|
||||||
|
|
@ -26,6 +26,9 @@ object EffectTarget {
|
||||||
//noinspection ScalaUnusedSymbol
|
//noinspection ScalaUnusedSymbol
|
||||||
def Invalid(target: PlanetSideGameObject): Boolean = false
|
def Invalid(target: PlanetSideGameObject): Boolean = false
|
||||||
|
|
||||||
|
//noinspection ScalaUnusedSymbol
|
||||||
|
def Valid(target: PlanetSideGameObject): Boolean = true
|
||||||
|
|
||||||
def Medical(target: PlanetSideGameObject): Boolean = {
|
def Medical(target: PlanetSideGameObject): Boolean = {
|
||||||
target match {
|
target match {
|
||||||
case p: Player =>
|
case p: Player =>
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,14 @@ package net.psforever.objects.global
|
||||||
import net.psforever.objects.GlobalDefinitions
|
import net.psforever.objects.GlobalDefinitions
|
||||||
import net.psforever.objects.ballistics.{AggravatedDamage, AggravatedInfo, AggravatedTiming, ChargeDamage}
|
import net.psforever.objects.ballistics.{AggravatedDamage, AggravatedInfo, AggravatedTiming, ChargeDamage}
|
||||||
import net.psforever.objects.definition.ProjectileDefinition
|
import net.psforever.objects.definition.ProjectileDefinition
|
||||||
import net.psforever.objects.definition.converter.{
|
import net.psforever.objects.definition.converter.{LittleBuddyProjectileConverter, ProjectileConverter, RadiationCloudConverter}
|
||||||
LittleBuddyProjectileConverter,
|
|
||||||
ProjectileConverter,
|
|
||||||
RadiationCloudConverter
|
|
||||||
}
|
|
||||||
import net.psforever.objects.equipment.{ArmorSiphonRepairHost, EffectTarget, TargetValidation}
|
import net.psforever.objects.equipment.{ArmorSiphonRepairHost, EffectTarget, TargetValidation}
|
||||||
import net.psforever.objects.serverobject.aura.Aura
|
import net.psforever.objects.serverobject.aura.Aura
|
||||||
import net.psforever.objects.vital.base.DamageType
|
import net.psforever.objects.vital.base.DamageType
|
||||||
import net.psforever.objects.vital.damage.{RadialDegrade, SameHit, StandardDamageProfile}
|
import net.psforever.objects.vital.damage.{RadialDegrade, SameHit, StandardDamageProfile}
|
||||||
import net.psforever.objects.vital.etc.{
|
import net.psforever.objects.vital.etc.{
|
||||||
ArmorSiphonMaxDistanceCutoff,
|
ArmorSiphonMaxDistanceCutoff,
|
||||||
ExplosionDamagesOnlyAbove,
|
ExplosionDamagesOnlyAbove
|
||||||
InfantryAggravatedRadiation,
|
|
||||||
InfantryAggravatedRadiationBurn
|
|
||||||
}
|
}
|
||||||
import net.psforever.objects.vital.projectile._
|
import net.psforever.objects.vital.projectile._
|
||||||
|
|
||||||
|
|
@ -1053,6 +1047,9 @@ object GlobalDefinitionsProjectile {
|
||||||
maelstrom_grenade_projectile.InitialVelocity = 30
|
maelstrom_grenade_projectile.InitialVelocity = 30
|
||||||
maelstrom_grenade_projectile.Lifespan = 2f
|
maelstrom_grenade_projectile.Lifespan = 2f
|
||||||
maelstrom_grenade_projectile.DamageProxy = 464 //maelstrom_grenade_damager
|
maelstrom_grenade_projectile.DamageProxy = 464 //maelstrom_grenade_damager
|
||||||
|
maelstrom_grenade_projectile.DamageProxyOnDirectHit = List(
|
||||||
|
TargetValidation(EffectTarget.Category.All, EffectTarget.Validation.Valid)
|
||||||
|
)
|
||||||
ProjectileDefinition.CalculateDerivedFields(maelstrom_grenade_projectile)
|
ProjectileDefinition.CalculateDerivedFields(maelstrom_grenade_projectile)
|
||||||
maelstrom_grenade_projectile.Modifiers = SameHit
|
maelstrom_grenade_projectile.Modifiers = SameHit
|
||||||
|
|
||||||
|
|
@ -1068,6 +1065,9 @@ object GlobalDefinitionsProjectile {
|
||||||
maelstrom_grenade_projectile_contact.InitialVelocity = 30
|
maelstrom_grenade_projectile_contact.InitialVelocity = 30
|
||||||
maelstrom_grenade_projectile_contact.Lifespan = 15f
|
maelstrom_grenade_projectile_contact.Lifespan = 15f
|
||||||
maelstrom_grenade_projectile_contact.DamageProxy = 464 //maelstrom_grenade_damager
|
maelstrom_grenade_projectile_contact.DamageProxy = 464 //maelstrom_grenade_damager
|
||||||
|
maelstrom_grenade_projectile_contact.DamageProxyOnDirectHit = List(
|
||||||
|
TargetValidation(EffectTarget.Category.All, EffectTarget.Validation.Valid)
|
||||||
|
)
|
||||||
ProjectileDefinition.CalculateDerivedFields(maelstrom_grenade_projectile_contact)
|
ProjectileDefinition.CalculateDerivedFields(maelstrom_grenade_projectile_contact)
|
||||||
maelstrom_grenade_projectile_contact.Modifiers = SameHit
|
maelstrom_grenade_projectile_contact.Modifiers = SameHit
|
||||||
|
|
||||||
|
|
@ -1529,7 +1529,7 @@ object GlobalDefinitionsProjectile {
|
||||||
ProjectileDefinition.CalculateDerivedFields(quasar_projectile)
|
ProjectileDefinition.CalculateDerivedFields(quasar_projectile)
|
||||||
|
|
||||||
radiator_cloud.Name = "radiator_cloud"
|
radiator_cloud.Name = "radiator_cloud"
|
||||||
radiator_cloud.Damage0 = 1 //2
|
radiator_cloud.Damage0 = 2
|
||||||
radiator_cloud.DamageAtEdge = 1.0f
|
radiator_cloud.DamageAtEdge = 1.0f
|
||||||
radiator_cloud.DamageRadius = 5f
|
radiator_cloud.DamageRadius = 5f
|
||||||
radiator_cloud.DamageToHealthOnly = true
|
radiator_cloud.DamageToHealthOnly = true
|
||||||
|
|
@ -1539,7 +1539,7 @@ object GlobalDefinitionsProjectile {
|
||||||
//custom aggravated information
|
//custom aggravated information
|
||||||
radiator_cloud.ProjectileDamageTypeSecondary = DamageType.Aggravated
|
radiator_cloud.ProjectileDamageTypeSecondary = DamageType.Aggravated
|
||||||
radiator_cloud.Aggravated = AggravatedDamage(
|
radiator_cloud.Aggravated = AggravatedDamage(
|
||||||
AggravatedInfo(DamageType.Splash, 1f, 80),
|
AggravatedInfo(DamageType.Splash, 0f, 80),
|
||||||
Aura.None,
|
Aura.None,
|
||||||
AggravatedTiming(250, 2),
|
AggravatedTiming(250, 2),
|
||||||
0f,
|
0f,
|
||||||
|
|
@ -1552,12 +1552,7 @@ object GlobalDefinitionsProjectile {
|
||||||
radiator_cloud.ExistsOnRemoteClients = true
|
radiator_cloud.ExistsOnRemoteClients = true
|
||||||
radiator_cloud.Packet = radCloudConverter
|
radiator_cloud.Packet = radCloudConverter
|
||||||
//radiator_cloud.Geometry = GeometryForm.representProjectileBySphere()
|
//radiator_cloud.Geometry = GeometryForm.representProjectileBySphere()
|
||||||
radiator_cloud.Modifiers = List(
|
radiator_cloud.Modifiers = MaxDistanceCutoff
|
||||||
MaxDistanceCutoff,
|
|
||||||
InfantryAggravatedRadiation,
|
|
||||||
InfantryAggravatedRadiationBurn,
|
|
||||||
ShieldAgainstRadiation
|
|
||||||
)
|
|
||||||
|
|
||||||
radiator_grenade_projectile.Name = "radiator_grenade_projectile" // Todo : Radiator damages ?
|
radiator_grenade_projectile.Name = "radiator_grenade_projectile" // Todo : Radiator damages ?
|
||||||
radiator_grenade_projectile.GrenadeProjectile = true //not really, but technically yes
|
radiator_grenade_projectile.GrenadeProjectile = true //not really, but technically yes
|
||||||
|
|
@ -1565,6 +1560,9 @@ object GlobalDefinitionsProjectile {
|
||||||
radiator_grenade_projectile.InitialVelocity = 30
|
radiator_grenade_projectile.InitialVelocity = 30
|
||||||
radiator_grenade_projectile.Lifespan = 3f
|
radiator_grenade_projectile.Lifespan = 3f
|
||||||
radiator_grenade_projectile.DamageProxy = 717 //radiator_cloud
|
radiator_grenade_projectile.DamageProxy = 717 //radiator_cloud
|
||||||
|
radiator_grenade_projectile.DamageProxyOnDirectHit = List(
|
||||||
|
TargetValidation(EffectTarget.Category.Player, EffectTarget.Validation.Player)
|
||||||
|
)
|
||||||
ProjectileDefinition.CalculateDerivedFields(radiator_grenade_projectile)
|
ProjectileDefinition.CalculateDerivedFields(radiator_grenade_projectile)
|
||||||
|
|
||||||
radiator_sticky_projectile.Name = "radiator_sticky_projectile"
|
radiator_sticky_projectile.Name = "radiator_sticky_projectile"
|
||||||
|
|
@ -1574,6 +1572,9 @@ object GlobalDefinitionsProjectile {
|
||||||
radiator_sticky_projectile.InitialVelocity = 30
|
radiator_sticky_projectile.InitialVelocity = 30
|
||||||
radiator_sticky_projectile.Lifespan = 4f
|
radiator_sticky_projectile.Lifespan = 4f
|
||||||
radiator_sticky_projectile.DamageProxy = 717 //radiator_cloud
|
radiator_sticky_projectile.DamageProxy = 717 //radiator_cloud
|
||||||
|
radiator_sticky_projectile.DamageProxyOnDirectHit = List(
|
||||||
|
TargetValidation(EffectTarget.Category.All, EffectTarget.Validation.Valid)
|
||||||
|
)
|
||||||
ProjectileDefinition.CalculateDerivedFields(radiator_sticky_projectile)
|
ProjectileDefinition.CalculateDerivedFields(radiator_sticky_projectile)
|
||||||
|
|
||||||
reaver_rocket_projectile.Name = "reaver_rocket_projectile"
|
reaver_rocket_projectile.Name = "reaver_rocket_projectile"
|
||||||
|
|
@ -2040,12 +2041,7 @@ object GlobalDefinitionsProjectile {
|
||||||
aphelion_plasma_cloud.ExistsOnRemoteClients = true
|
aphelion_plasma_cloud.ExistsOnRemoteClients = true
|
||||||
aphelion_plasma_cloud.Packet = radCloudConverter
|
aphelion_plasma_cloud.Packet = radCloudConverter
|
||||||
//aphelion_plasma_cloud.Geometry = GeometryForm.representProjectileBySphere()
|
//aphelion_plasma_cloud.Geometry = GeometryForm.representProjectileBySphere()
|
||||||
aphelion_plasma_cloud.Modifiers = List( //TODO placeholder values
|
aphelion_plasma_cloud.Modifiers = MaxDistanceCutoff
|
||||||
MaxDistanceCutoff,
|
|
||||||
InfantryAggravatedRadiation,
|
|
||||||
InfantryAggravatedRadiationBurn,
|
|
||||||
ShieldAgainstRadiation
|
|
||||||
)
|
|
||||||
|
|
||||||
aphelion_plasma_rocket_projectile.Name = "aphelion_plasma_rocket_projectile"
|
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
|
//has property aggravated_damage_max_factor, but it's the aphelion_plasma_cloud that performs aggravated damage
|
||||||
|
|
@ -2060,6 +2056,9 @@ object GlobalDefinitionsProjectile {
|
||||||
aphelion_plasma_rocket_projectile.DamageRadius = 3f
|
aphelion_plasma_rocket_projectile.DamageRadius = 3f
|
||||||
aphelion_plasma_rocket_projectile.ProjectileDamageType = DamageType.Splash
|
aphelion_plasma_rocket_projectile.ProjectileDamageType = DamageType.Splash
|
||||||
//aphelion_plasma_rocket_projectile.DamageProxy = 96 //aphelion_plama_cloud
|
//aphelion_plasma_rocket_projectile.DamageProxy = 96 //aphelion_plama_cloud
|
||||||
|
aphelion_plasma_rocket_projectile.DamageProxyOnDirectHit = List(
|
||||||
|
TargetValidation(EffectTarget.Category.All, EffectTarget.Validation.Valid)
|
||||||
|
)
|
||||||
aphelion_plasma_rocket_projectile.InitialVelocity = 75
|
aphelion_plasma_rocket_projectile.InitialVelocity = 75
|
||||||
aphelion_plasma_rocket_projectile.Lifespan = 5f
|
aphelion_plasma_rocket_projectile.Lifespan = 5f
|
||||||
ProjectileDefinition.CalculateDerivedFields(aphelion_plasma_rocket_projectile)
|
ProjectileDefinition.CalculateDerivedFields(aphelion_plasma_rocket_projectile)
|
||||||
|
|
@ -2225,6 +2224,9 @@ object GlobalDefinitionsProjectile {
|
||||||
peregrine_particle_cannon_projectile.DamageRadius = 3f
|
peregrine_particle_cannon_projectile.DamageRadius = 3f
|
||||||
peregrine_particle_cannon_projectile.ProjectileDamageType = DamageType.Splash
|
peregrine_particle_cannon_projectile.ProjectileDamageType = DamageType.Splash
|
||||||
//peregrine_particle_cannon_projectile.DamageProxy = 655 //peregrine_particle_cannon_radiation_cloud
|
//peregrine_particle_cannon_projectile.DamageProxy = 655 //peregrine_particle_cannon_radiation_cloud
|
||||||
|
peregrine_particle_cannon_projectile.DamageProxyOnDirectHit = List(
|
||||||
|
TargetValidation(EffectTarget.Category.All, EffectTarget.Validation.Valid)
|
||||||
|
)
|
||||||
peregrine_particle_cannon_projectile.InitialVelocity = 500
|
peregrine_particle_cannon_projectile.InitialVelocity = 500
|
||||||
peregrine_particle_cannon_projectile.Lifespan = .6f
|
peregrine_particle_cannon_projectile.Lifespan = .6f
|
||||||
ProjectileDefinition.CalculateDerivedFields(peregrine_particle_cannon_projectile)
|
ProjectileDefinition.CalculateDerivedFields(peregrine_particle_cannon_projectile)
|
||||||
|
|
@ -2243,10 +2245,7 @@ object GlobalDefinitionsProjectile {
|
||||||
peregrine_particle_cannon_radiation_cloud.ExistsOnRemoteClients = true
|
peregrine_particle_cannon_radiation_cloud.ExistsOnRemoteClients = true
|
||||||
peregrine_particle_cannon_radiation_cloud.Packet = radCloudConverter
|
peregrine_particle_cannon_radiation_cloud.Packet = radCloudConverter
|
||||||
//peregrine_particle_cannon_radiation_cloud.Geometry = GeometryForm.representProjectileBySphere()
|
//peregrine_particle_cannon_radiation_cloud.Geometry = GeometryForm.representProjectileBySphere()
|
||||||
peregrine_particle_cannon_radiation_cloud.Modifiers = List(
|
peregrine_particle_cannon_radiation_cloud.Modifiers = MaxDistanceCutoff
|
||||||
MaxDistanceCutoff,
|
|
||||||
ShieldAgainstRadiation
|
|
||||||
)
|
|
||||||
|
|
||||||
peregrine_rocket_pod_projectile.Name = "peregrine_rocket_pod_projectile"
|
peregrine_rocket_pod_projectile.Name = "peregrine_rocket_pod_projectile"
|
||||||
peregrine_rocket_pod_projectile.Damage0 = 30
|
peregrine_rocket_pod_projectile.Damage0 = 30
|
||||||
|
|
|
||||||
|
|
@ -1634,6 +1634,7 @@ object GlobalDefinitionsVehicle {
|
||||||
droppod.Packet = new DroppodConverter()
|
droppod.Packet = new DroppodConverter()
|
||||||
droppod.DeconstructionTime = Some(5 seconds)
|
droppod.DeconstructionTime = Some(5 seconds)
|
||||||
droppod.DestroyedModel = None //the adb calls out a droppod; the cyclic nature of this confounds me
|
droppod.DestroyedModel = None //the adb calls out a droppod; the cyclic nature of this confounds me
|
||||||
|
droppod.RadiationShielding = 1.0f
|
||||||
droppod.DamageUsing = DamageCalculations.AgainstAircraft
|
droppod.DamageUsing = DamageCalculations.AgainstAircraft
|
||||||
droppod.DrownAtMaxDepth = false
|
droppod.DrownAtMaxDepth = false
|
||||||
droppod.mass = 2500f
|
droppod.mass = 2500f
|
||||||
|
|
@ -1667,6 +1668,7 @@ object GlobalDefinitionsVehicle {
|
||||||
orbital_shuttle.Packet = new OrbitalShuttleConverter
|
orbital_shuttle.Packet = new OrbitalShuttleConverter
|
||||||
orbital_shuttle.DeconstructionTime = None
|
orbital_shuttle.DeconstructionTime = None
|
||||||
orbital_shuttle.DestroyedModel = None
|
orbital_shuttle.DestroyedModel = None
|
||||||
|
orbital_shuttle.RadiationShielding = 1.0f
|
||||||
orbital_shuttle.DamageUsing = DamageCalculations.AgainstNothing
|
orbital_shuttle.DamageUsing = DamageCalculations.AgainstNothing
|
||||||
orbital_shuttle.DrownAtMaxDepth = false
|
orbital_shuttle.DrownAtMaxDepth = false
|
||||||
orbital_shuttle.mass = 25000f
|
orbital_shuttle.mass = 25000f
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment}
|
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment}
|
||||||
import net.psforever.objects.zones._
|
import net.psforever.objects.zones._
|
||||||
import net.psforever.objects.zones.blockmap.{BlockMapEntity, SectorGroup, SectorPopulation}
|
import net.psforever.objects.zones.blockmap.{BlockMapEntity, SectorGroup, SectorPopulation}
|
||||||
|
import net.psforever.objects.zones.interaction.{InteractsWithZone, ZoneInteraction, ZoneInteractionType}
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package net.psforever.objects.serverobject.environment.interaction
|
package net.psforever.objects.serverobject.environment.interaction
|
||||||
|
|
||||||
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment}
|
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment}
|
||||||
import net.psforever.objects.zones.InteractsWithZone
|
import net.psforever.objects.zones.interaction.InteractsWithZone
|
||||||
|
|
||||||
trait InteractionWith {
|
trait InteractionWith {
|
||||||
def attribute: EnvironmentTrait
|
def attribute: EnvironmentTrait
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ package net.psforever.objects.serverobject.environment.interaction
|
||||||
import akka.actor.{Actor, ActorRef, Cancellable}
|
import akka.actor.{Actor, ActorRef, Cancellable}
|
||||||
import net.psforever.objects.Default
|
import net.psforever.objects.Default
|
||||||
import net.psforever.objects.serverobject.environment.EnvironmentTrait
|
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.collection.mutable
|
||||||
import scala.concurrent.duration.FiniteDuration
|
import scala.concurrent.duration.FiniteDuration
|
||||||
|
|
|
||||||
|
|
@ -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.InteractWithEnvironment
|
||||||
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
||||||
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, PieceOfEnvironment}
|
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}
|
import net.psforever.types.{OxygenState, PlanetSideGUID}
|
||||||
|
|
||||||
trait Watery {
|
trait Watery {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import net.psforever.objects.sourcing.SourceEntry
|
||||||
import net.psforever.objects.vital.etc.SuicideReason
|
import net.psforever.objects.vital.etc.SuicideReason
|
||||||
import net.psforever.objects.vital.interaction.DamageInteraction
|
import net.psforever.objects.vital.interaction.DamageInteraction
|
||||||
import net.psforever.objects.vital.{IncarnationActivity, Vitality}
|
import net.psforever.objects.vital.{IncarnationActivity, Vitality}
|
||||||
import net.psforever.objects.zones.InteractsWithZone
|
import net.psforever.objects.zones.interaction.InteractsWithZone
|
||||||
|
|
||||||
import scala.annotation.unused
|
import scala.annotation.unused
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects.serverobject.environment.interaction.common
|
||||||
|
|
||||||
import net.psforever.objects.serverobject.environment._
|
import net.psforever.objects.serverobject.environment._
|
||||||
import net.psforever.objects.serverobject.environment.interaction.InteractionWith
|
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
|
import scala.annotation.unused
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects.serverobject.interior
|
||||||
|
|
||||||
import net.psforever.objects.avatar.interaction.WithEntrance
|
import net.psforever.objects.avatar.interaction.WithEntrance
|
||||||
import net.psforever.objects.serverobject.environment.interaction.InteractWithEnvironment
|
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
|
import scala.annotation.unused
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,91 +8,43 @@ import net.psforever.objects.vital.base.DamageResolution
|
||||||
import net.psforever.objects.vital.etc.RadiationReason
|
import net.psforever.objects.vital.etc.RadiationReason
|
||||||
import net.psforever.objects.vital.interaction.DamageInteraction
|
import net.psforever.objects.vital.interaction.DamageInteraction
|
||||||
import net.psforever.objects.vital.resistance.StandardResistanceProfile
|
import net.psforever.objects.vital.resistance.StandardResistanceProfile
|
||||||
import net.psforever.objects.zones.blockmap.SectorPopulation
|
import net.psforever.objects.zones.interaction.{InteractsWithZone, RadiationCloudInteraction, ZoneInteractionType}
|
||||||
import net.psforever.objects.zones.{InteractsWithZone, Zone, ZoneInteraction}
|
|
||||||
import net.psforever.types.PlanetSideGUID
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This game entity may infrequently test whether it may interact with radiation cloud projectiles
|
* 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.
|
* 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(
|
class InteractWithRadiationCloudsSeatedInEntity(
|
||||||
private val obj: Mountable with StandardResistanceProfile,
|
private val obj: Mountable with StandardResistanceProfile,
|
||||||
val range: Float
|
val range: Float
|
||||||
) extends ZoneInteraction {
|
) extends RadiationCloudInteraction {
|
||||||
/**
|
def Type: ZoneInteractionType = RadiationInMountableInteraction
|
||||||
* 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()
|
|
||||||
|
|
||||||
def Type: RadiationInMountableInteraction.type = RadiationInMountableInteraction
|
def performInteractionWithTarget(projectiles: List[Projectile], target: InteractsWithZone): Unit = {
|
||||||
|
val mountedTargets = obj.Seats
|
||||||
/**
|
.values
|
||||||
* Drive into a radiation cloud and all the vehicle's occupants suffer the consequences.
|
.collect { case seat => seat.occupant }
|
||||||
* @param sector the portion of the block map being tested
|
.flatten
|
||||||
* @param target the fixed element in this test
|
if (projectiles.nonEmpty && mountedTargets.nonEmpty) {
|
||||||
*/
|
val position = target.Position
|
||||||
override def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit = {
|
val shielding = RadiationCloudInteraction.RadiationShieldingFrom(target)
|
||||||
val position = target.Position
|
mountedTargets
|
||||||
val targetList = List(target)
|
.flatMap(t => projectiles.map(p => (t, p)))
|
||||||
//collect all projectiles in sector/range
|
.foreach { case (t, p) =>
|
||||||
val projectiles = sector
|
t.Actor ! Vitality.Damage(
|
||||||
.projectileList
|
DamageInteraction(
|
||||||
.filter { cloud =>
|
SourceEntry(t),
|
||||||
val definition = cloud.Definition
|
RadiationReason(
|
||||||
val radius = definition.DamageRadius
|
ProjectileQuality.modifiers(p, DamageResolution.Radiation, t, t.Position, None),
|
||||||
definition.radiation_cloud &&
|
t.DamageModel,
|
||||||
Zone.allOnSameSide(cloud, definition, targetList).nonEmpty &&
|
shielding
|
||||||
Zone.distanceCheck(target, cloud, radius * radius)
|
),
|
||||||
}
|
position
|
||||||
.distinct
|
).calculate()
|
||||||
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 _ => ()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
package net.psforever.objects.serverobject.mount
|
package net.psforever.objects.serverobject.mount
|
||||||
|
|
||||||
import net.psforever.objects.zones.ZoneInteractionType
|
import net.psforever.objects.zones.interaction.ZoneInteractionType
|
||||||
|
|
||||||
case object RadiationInMountableInteraction extends ZoneInteractionType
|
case object RadiationInMountableInteraction extends ZoneInteractionType
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@
|
||||||
package net.psforever.objects.serverobject.terminals.implant
|
package net.psforever.objects.serverobject.terminals.implant
|
||||||
|
|
||||||
import net.psforever.objects.serverobject.hackable.Hackable
|
import net.psforever.objects.serverobject.hackable.Hackable
|
||||||
import net.psforever.objects.serverobject.mount.{Mountable, Seat}
|
import net.psforever.objects.serverobject.mount.{InteractWithRadiationCloudsSeatedInEntity, Mountable, Seat}
|
||||||
import net.psforever.objects.serverobject.structures.Amenity
|
import net.psforever.objects.serverobject.structures.Amenity
|
||||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAware
|
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAware
|
||||||
|
import net.psforever.objects.vital.resistance.StandardResistanceProfile
|
||||||
|
import net.psforever.objects.zones.interaction.InteractsWithZone
|
||||||
import net.psforever.packet.game.TriggeredSound
|
import net.psforever.packet.game.TriggeredSound
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
|
|
||||||
|
|
@ -17,7 +19,10 @@ class ImplantTerminalMech(private val idef: ImplantTerminalMechDefinition)
|
||||||
extends Amenity
|
extends Amenity
|
||||||
with Mountable
|
with Mountable
|
||||||
with Hackable
|
with Hackable
|
||||||
|
with StandardResistanceProfile
|
||||||
|
with InteractsWithZone
|
||||||
with CaptureTerminalAware {
|
with CaptureTerminalAware {
|
||||||
|
interaction(new InteractWithRadiationCloudsSeatedInEntity(obj = this, range = 50f))
|
||||||
seats = Map(0 -> new Seat(idef.Seats.head._2))
|
seats = Map(0 -> new Seat(idef.Seats.head._2))
|
||||||
|
|
||||||
HackSound = TriggeredSound.HackTerminal
|
HackSound = TriggeredSound.HackTerminal
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,23 @@ package net.psforever.objects.serverobject.turret
|
||||||
|
|
||||||
import net.psforever.objects.equipment.JammableUnit
|
import net.psforever.objects.equipment.JammableUnit
|
||||||
import net.psforever.objects.serverobject.interior.Sidedness
|
import net.psforever.objects.serverobject.interior.Sidedness
|
||||||
|
import net.psforever.objects.serverobject.mount.InteractWithRadiationCloudsSeatedInEntity
|
||||||
import net.psforever.objects.serverobject.structures.{Amenity, AmenityOwner, Building}
|
import net.psforever.objects.serverobject.structures.{Amenity, AmenityOwner, Building}
|
||||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAware
|
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAware
|
||||||
import net.psforever.objects.serverobject.turret.auto.AutomatedTurret
|
import net.psforever.objects.serverobject.turret.auto.AutomatedTurret
|
||||||
import net.psforever.objects.sourcing.SourceEntry
|
import net.psforever.objects.sourcing.SourceEntry
|
||||||
|
import net.psforever.objects.vital.resistance.StandardResistanceProfile
|
||||||
|
import net.psforever.objects.zones.interaction.InteractsWithZone
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
|
|
||||||
class FacilityTurret(tDef: FacilityTurretDefinition)
|
class FacilityTurret(tDef: FacilityTurretDefinition)
|
||||||
extends Amenity
|
extends Amenity
|
||||||
with AutomatedTurret
|
with AutomatedTurret
|
||||||
|
with StandardResistanceProfile
|
||||||
with JammableUnit
|
with JammableUnit
|
||||||
|
with InteractsWithZone
|
||||||
with CaptureTerminalAware {
|
with CaptureTerminalAware {
|
||||||
|
interaction(new InteractWithRadiationCloudsSeatedInEntity(obj = this, range = 100f))
|
||||||
WeaponTurret.LoadDefinition(turret = this)
|
WeaponTurret.LoadDefinition(turret = this)
|
||||||
WhichSide = Sidedness.OutsideOf
|
WhichSide = Sidedness.OutsideOf
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, SourceUniquene
|
||||||
import net.psforever.objects.vital.Vitality
|
import net.psforever.objects.vital.Vitality
|
||||||
import net.psforever.objects.vital.interaction.DamageResult
|
import net.psforever.objects.vital.interaction.DamageResult
|
||||||
import net.psforever.objects.zones.exp.ToDatabase
|
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.objects.{Default, PlanetSideGameObject, Player}
|
||||||
import net.psforever.packet.game.{ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ObjectDetectedMessage}
|
import net.psforever.packet.game.{ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ObjectDetectedMessage}
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,24 @@ package net.psforever.objects.vehicles
|
||||||
import net.psforever.objects.Vehicle
|
import net.psforever.objects.Vehicle
|
||||||
import net.psforever.objects.serverobject.mount.{InteractWithRadiationCloudsSeatedInEntity, RadiationInMountableInteraction}
|
import net.psforever.objects.serverobject.mount.{InteractWithRadiationCloudsSeatedInEntity, RadiationInMountableInteraction}
|
||||||
import net.psforever.objects.zones.blockmap.SectorPopulation
|
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
|
* 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.
|
* 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 a vehicle, the occupants of the vehicle's mounted vehicles get tested for their interaction.
|
||||||
*/
|
*/
|
||||||
class InteractWithRadiationCloudsSeatedInVehicle(
|
class InteractWithRadiationCloudsSeatedInVehicle(
|
||||||
private val obj: Vehicle,
|
private val obj: Vehicle,
|
||||||
override val range: Float
|
override val range: Float
|
||||||
) extends InteractWithRadiationCloudsSeatedInEntity(obj, range) {
|
) extends InteractWithRadiationCloudsSeatedInEntity(obj, range) {
|
||||||
/**
|
/**
|
||||||
* Drive into a radiation cloud and all the vehicle's occupants suffer the consequences.
|
* 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 sector the portion of the block map being tested
|
||||||
* @param target the fixed element in this test
|
* @param target the fixed element in this test
|
||||||
*/
|
*/
|
||||||
override def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit = {
|
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
|
obj.CargoHolds
|
||||||
.values
|
.values
|
||||||
.collect {
|
.collect {
|
||||||
|
|
@ -30,7 +30,7 @@ class InteractWithRadiationCloudsSeatedInVehicle(
|
||||||
target
|
target
|
||||||
.interaction()
|
.interaction()
|
||||||
.find(_.Type == RadiationInMountableInteraction)
|
.find(_.Type == RadiationInMountableInteraction)
|
||||||
.foreach(func => func.interaction(sector, target))
|
.foreach(func => func.interaction(sector, obj))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -288,11 +288,11 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
final def Enabled: Receive =
|
final def Enabled: Receive =
|
||||||
commonEnabledBehavior
|
commonEnabledBehavior
|
||||||
.orElse {
|
.orElse {
|
||||||
case VehicleControl.RadiationTick =>
|
case VehicleControl.RadiationTick if !passengerRadiationCloudTimer.isCancelled =>
|
||||||
vehicle.interaction().find { _.Type == RadiationInMountableInteraction } match {
|
vehicle
|
||||||
case Some(func) => func.interaction(vehicle.getInteractionSector, vehicle)
|
.interaction()
|
||||||
case _ => ()
|
.find(_.Type == RadiationInMountableInteraction)
|
||||||
}
|
.foreach(_.interaction(vehicle.getInteractionSector, vehicle))
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -355,13 +355,12 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
}
|
}
|
||||||
|
|
||||||
def mountCleanup(mount_point: Int, user: Player): Unit = {
|
def mountCleanup(mount_point: Int, user: Player): Unit = {
|
||||||
val obj = MountableObject
|
vehicle.PassengerInSeat(user) match {
|
||||||
obj.PassengerInSeat(user) match {
|
case Some(0) => //driver seat
|
||||||
case Some(seatNumber) =>
|
|
||||||
val vsrc = VehicleSource(vehicle)
|
val vsrc = VehicleSource(vehicle)
|
||||||
user.LogActivity(VehicleMountActivity(vsrc, PlayerSource.inSeat(user, vsrc, seatNumber), vehicle.Zone.Number))
|
user.LogActivity(VehicleMountActivity(vsrc, PlayerSource.inSeat(user, vsrc, seatNumber = 0), vehicle.Zone.Number))
|
||||||
//if the driver mount, change ownership if that is permissible for this vehicle
|
//if the driver mount, change ownership if that is permissible for this vehicle
|
||||||
if (seatNumber == 0 && !obj.OwnerName.contains(user.Name) && obj.Definition.CanBeOwned.nonEmpty) {
|
if (!vehicle.OwnerName.contains(user.Name) && vehicle.Definition.CanBeOwned.nonEmpty) {
|
||||||
//whatever vehicle was previously owned
|
//whatever vehicle was previously owned
|
||||||
vehicle.Zone.GUID(user.avatar.vehicle) match {
|
vehicle.Zone.GUID(user.avatar.vehicle) match {
|
||||||
case Some(v: Vehicle) =>
|
case Some(v: Vehicle) =>
|
||||||
|
|
@ -370,13 +369,24 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
user.avatar.vehicle = None
|
user.avatar.vehicle = None
|
||||||
}
|
}
|
||||||
GainOwnership(user) //gain new ownership
|
GainOwnership(user) //gain new ownership
|
||||||
passengerRadiationCloudTimer.cancel()
|
|
||||||
} else {
|
} else {
|
||||||
decaying = false
|
decaying = false
|
||||||
decayTimer.cancel()
|
decayTimer.cancel()
|
||||||
}
|
}
|
||||||
|
passengerRadiationCloudTimer.cancel()
|
||||||
updateZoneInteractionProgressUI(user)
|
updateZoneInteractionProgressUI(user)
|
||||||
case None => ;
|
|
||||||
|
case Some(seatNumber) => //literally any other seat
|
||||||
|
val vsrc = VehicleSource(vehicle)
|
||||||
|
user.LogActivity(VehicleMountActivity(vsrc, PlayerSource.inSeat(user, vsrc, seatNumber), vehicle.Zone.Number))
|
||||||
|
decaying = false
|
||||||
|
decayTimer.cancel()
|
||||||
|
if (!vehicle.Seats(0).isOccupied && passengerRadiationCloudTimer.isCancelled) {
|
||||||
|
StartRadiationSelfReporting()
|
||||||
|
}
|
||||||
|
updateZoneInteractionProgressUI(user)
|
||||||
|
|
||||||
|
case None => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -390,19 +400,17 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
|
|
||||||
def dismountCleanup(seatBeingDismounted: Int, user: Player): Unit = {
|
def dismountCleanup(seatBeingDismounted: Int, user: Player): Unit = {
|
||||||
val obj = MountableObject
|
val obj = MountableObject
|
||||||
|
val allSeatsUnoccupied = !obj.Seats.values.exists(_.isOccupied)
|
||||||
// Reset velocity to zero when driver dismounts, to allow jacking/repair if vehicle was moving slightly before dismount
|
// Reset velocity to zero when driver dismounts, to allow jacking/repair if vehicle was moving slightly before dismount
|
||||||
if (!obj.Seats(0).isOccupied) {
|
if (!obj.Seats(0).isOccupied) {
|
||||||
obj.Velocity = Some(Vector3.Zero)
|
obj.Velocity = Some(Vector3.Zero)
|
||||||
}
|
}
|
||||||
if (seatBeingDismounted == 0) {
|
if (allSeatsUnoccupied) {
|
||||||
passengerRadiationCloudTimer = context.system.scheduler.scheduleWithFixedDelay(
|
passengerRadiationCloudTimer.cancel()
|
||||||
250.milliseconds,
|
} else if (seatBeingDismounted == 0) {
|
||||||
250.milliseconds,
|
StartRadiationSelfReporting()
|
||||||
self,
|
|
||||||
VehicleControl.RadiationTick
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (!obj.Seats(seatBeingDismounted).isOccupied) { //seat was vacated
|
if (!obj.Seats(seatBeingDismounted).isOccupied) { //this seat really was vacated
|
||||||
user.LogActivity(VehicleDismountActivity(VehicleSource(vehicle), PlayerSource(user), vehicle.Zone.Number))
|
user.LogActivity(VehicleDismountActivity(VehicleSource(vehicle), PlayerSource(user), vehicle.Zone.Number))
|
||||||
//we were only owning the vehicle while we sat in its driver seat
|
//we were only owning the vehicle while we sat in its driver seat
|
||||||
val canBeOwned = obj.Definition.CanBeOwned
|
val canBeOwned = obj.Definition.CanBeOwned
|
||||||
|
|
@ -411,9 +419,9 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
}
|
}
|
||||||
//are we already decaying? are we unowned? is no one seated anywhere?
|
//are we already decaying? are we unowned? is no one seated anywhere?
|
||||||
if (!decaying &&
|
if (!decaying &&
|
||||||
obj.Definition.undergoesDecay &&
|
obj.Definition.undergoesDecay &&
|
||||||
obj.OwnerGuid.isEmpty &&
|
obj.OwnerGuid.isEmpty &&
|
||||||
obj.Seats.values.forall(!_.isOccupied)) {
|
allSeatsUnoccupied) {
|
||||||
decaying = true
|
decaying = true
|
||||||
decayTimer = context.system.scheduler.scheduleOnce(
|
decayTimer = context.system.scheduler.scheduleOnce(
|
||||||
MountableObject.Definition.DeconstructionTime.getOrElse(5 minutes),
|
MountableObject.Definition.DeconstructionTime.getOrElse(5 minutes),
|
||||||
|
|
@ -424,6 +432,16 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def StartRadiationSelfReporting(): Unit = {
|
||||||
|
passengerRadiationCloudTimer.cancel()
|
||||||
|
passengerRadiationCloudTimer = context.system.scheduler.scheduleWithFixedDelay(
|
||||||
|
250.milliseconds,
|
||||||
|
250.milliseconds,
|
||||||
|
self,
|
||||||
|
VehicleControl.RadiationTick
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def PrepareForDisabled(kickPassengers: Boolean) : Unit = {
|
def PrepareForDisabled(kickPassengers: Boolean) : Unit = {
|
||||||
val guid = vehicle.GUID
|
val guid = vehicle.GUID
|
||||||
val zone = vehicle.Zone
|
val zone = vehicle.Zone
|
||||||
|
|
@ -492,7 +510,7 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
case Some(_) =>
|
case Some(_) =>
|
||||||
decaying = false
|
decaying = false
|
||||||
decayTimer.cancel()
|
decayTimer.cancel()
|
||||||
case None => ;
|
case None => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -507,9 +525,9 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
self.toString,
|
self.toString,
|
||||||
AvatarAction.SendResponse(Service.defaultPlayerGUID, ObjectAttachMessage(obj.GUID, item.GUID, slot))
|
AvatarAction.SendResponse(Service.defaultPlayerGUID, ObjectAttachMessage(obj.GUID, item.GUID, slot))
|
||||||
)
|
)
|
||||||
case None => ;
|
case None => ()
|
||||||
}
|
}
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import net.psforever.objects.Vehicle
|
||||||
import net.psforever.objects.avatar.interaction.WithEntrance
|
import net.psforever.objects.avatar.interaction.WithEntrance
|
||||||
import net.psforever.objects.serverobject.doors.InteriorDoorPassage
|
import net.psforever.objects.serverobject.doors.InteriorDoorPassage
|
||||||
import net.psforever.objects.serverobject.environment.PieceOfEnvironment
|
import net.psforever.objects.serverobject.environment.PieceOfEnvironment
|
||||||
import net.psforever.objects.zones.InteractsWithZone
|
import net.psforever.objects.zones.interaction.InteractsWithZone
|
||||||
|
|
||||||
class WithEntranceInVehicle
|
class WithEntranceInVehicle
|
||||||
extends WithEntrance() {
|
extends WithEntrance() {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import net.psforever.objects.sourcing.SourceEntry
|
||||||
import net.psforever.objects.vital.Vitality
|
import net.psforever.objects.vital.Vitality
|
||||||
import net.psforever.objects.vital.environment.EnvironmentReason
|
import net.psforever.objects.vital.environment.EnvironmentReason
|
||||||
import net.psforever.objects.vital.interaction.DamageInteraction
|
import net.psforever.objects.vital.interaction.DamageInteraction
|
||||||
import net.psforever.objects.zones.InteractsWithZone
|
import net.psforever.objects.zones.interaction.InteractsWithZone
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.interaction.common.Watery.OxygenStateTarget
|
||||||
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment, interaction}
|
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment, interaction}
|
||||||
import net.psforever.objects.vehicles.control.VehicleControl
|
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 net.psforever.types.OxygenState
|
||||||
|
|
||||||
import scala.annotation.unused
|
import scala.annotation.unused
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,12 @@ import net.psforever.objects.vital.damage.DamageCalculations
|
||||||
import net.psforever.objects.vital.prop.DamageProperties
|
import net.psforever.objects.vital.prop.DamageProperties
|
||||||
import net.psforever.objects.vital.resolution.{DamageAndResistance, DamageResistanceModel}
|
import net.psforever.objects.vital.resolution.{DamageAndResistance, DamageResistanceModel}
|
||||||
import net.psforever.objects.vital.{NoResistanceSelection, SimpleResolutions}
|
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
|
* A wrapper for a "damage source" in damage calculations
|
||||||
* that parameterizes information necessary to explain the environment being antagonistic.
|
* that parameterizes information necessary to explain the environment being antagonistic.
|
||||||
|
*
|
||||||
* @see `DamageCalculations`
|
* @see `DamageCalculations`
|
||||||
* @param body a representative of an element of the environment
|
* @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
|
* @param against for the purposes of damage, what kind of target is being acted upon
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/** 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. */
|
* An exception to this rule, however, happens when retaliating against something that damaged it first. */
|
||||||
case object CerberusTurretWrongTarget extends ProjectileDamageModifiers.Mod {
|
case object CerberusTurretWrongTarget extends ProjectileDamageModifiers.Mod {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
package net.psforever.objects.vital.prop
|
package net.psforever.objects.vital.prop
|
||||||
|
|
||||||
import net.psforever.objects.ballistics.{AggravatedDamage, ChargeDamage}
|
import net.psforever.objects.ballistics.{AggravatedDamage, ChargeDamage}
|
||||||
import net.psforever.objects.equipment.JammingUnit
|
import net.psforever.objects.equipment.{JammingUnit, TargetValidation}
|
||||||
import net.psforever.objects.vital.base.{DamageModifiers, DamageType}
|
import net.psforever.objects.vital.base.{DamageModifiers, DamageType}
|
||||||
import net.psforever.objects.vital.damage.StandardDamageProfile
|
import net.psforever.objects.vital.damage.StandardDamageProfile
|
||||||
|
|
||||||
|
|
@ -37,6 +37,9 @@ trait DamageProperties
|
||||||
* usually corresponding to a projectile;
|
* usually corresponding to a projectile;
|
||||||
* also used to produce staged projectiles */
|
* also used to produce staged projectiles */
|
||||||
private var damageProxy: List[Int] = Nil
|
private var damageProxy: List[Int] = Nil
|
||||||
|
/** damage proxies are expected to activate upon general detonation
|
||||||
|
* this damage proxy will also activate upon direct hit of these specific types of targets */
|
||||||
|
private var damageProxyOnDirectHit: List[TargetValidation] = Nil
|
||||||
/** na;
|
/** na;
|
||||||
* currently used with jammer properties only;
|
* currently used with jammer properties only;
|
||||||
* used sepcifically to indicate jammering effect targets explosive deployables */
|
* used sepcifically to indicate jammering effect targets explosive deployables */
|
||||||
|
|
@ -118,6 +121,18 @@ trait DamageProperties
|
||||||
DamageProxy
|
DamageProxy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def DamageProxyOnDirectHit: List[TargetValidation] = damageProxyOnDirectHit
|
||||||
|
|
||||||
|
def DamageProxyOnDirectHit_=(elem: TargetValidation): List[TargetValidation] = {
|
||||||
|
damageProxyOnDirectHit = List(elem)
|
||||||
|
DamageProxyOnDirectHit
|
||||||
|
}
|
||||||
|
|
||||||
|
def DamageProxyOnDirectHit_=(list: List[TargetValidation]): List[TargetValidation] = {
|
||||||
|
damageProxyOnDirectHit = list
|
||||||
|
DamageProxyOnDirectHit
|
||||||
|
}
|
||||||
|
|
||||||
def AdditionalEffect: Boolean = additionalEffect
|
def AdditionalEffect: Boolean = additionalEffect
|
||||||
|
|
||||||
def AdditionalEffect_=(effect: Boolean): Boolean = {
|
def AdditionalEffect_=(effect: Boolean): Boolean = {
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ import net.psforever.objects.vital.damage.DamageProfile
|
||||||
* based on the assumption that the implementing object's `Definition` is the primary `ResistanceProfile`.
|
* based on the assumption that the implementing object's `Definition` is the primary `ResistanceProfile`.
|
||||||
*/
|
*/
|
||||||
trait StandardResistanceProfile extends ResistanceProfile {
|
trait StandardResistanceProfile extends ResistanceProfile {
|
||||||
this: PlanetSideGameObject =>
|
_: PlanetSideGameObject =>
|
||||||
//actually check that this will work for this implementing class
|
//actually check that this will work for this implementing class
|
||||||
assert(Definition.isInstanceOf[ResistanceProfile], s"$this object definition must extend ResistanceProfile")
|
assert(Definition.isInstanceOf[ResistanceProfile], s"${this.getClass.getSimpleName} object definition must extend ResistanceProfile")
|
||||||
private val resistDef = Definition.asInstanceOf[ResistanceProfile] //cast only once
|
private val resistDef = Definition.asInstanceOf[ResistanceProfile] //cast only once
|
||||||
|
|
||||||
def Subtract: DamageProfile = resistDef.Subtract
|
def Subtract: DamageProfile = resistDef.Subtract
|
||||||
|
|
@ -23,5 +23,5 @@ trait StandardResistanceProfile extends ResistanceProfile {
|
||||||
|
|
||||||
def ResistanceAggravated: Int = resistDef.ResistanceDirectHit
|
def ResistanceAggravated: Int = resistDef.ResistanceDirectHit
|
||||||
|
|
||||||
def RadiationShielding: Float = resistDef.ResistanceDirectHit.toFloat
|
def RadiationShielding: Float = resistDef.RadiationShielding
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2021 PSForever
|
// 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.definition.ObjectDefinition
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
|
@ -72,39 +72,3 @@ trait InteractsWithZone
|
||||||
|
|
||||||
override def Definition: ObjectDefinition with VitalityDefinition
|
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
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,8 @@ import net.psforever.objects.serverobject.environment.interaction.InteractWithEn
|
||||||
import net.psforever.objects.serverobject.llu.CaptureFlag
|
import net.psforever.objects.serverobject.llu.CaptureFlag
|
||||||
import net.psforever.objects.serverobject.structures.{Building, WarpGate}
|
import net.psforever.objects.serverobject.structures.{Building, WarpGate}
|
||||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
|
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.packet.game._
|
||||||
import net.psforever.services.{Service, ServiceManager}
|
import net.psforever.services.{Service, ServiceManager}
|
||||||
import net.psforever.services.ServiceManager.{Lookup, LookupResult}
|
import net.psforever.services.ServiceManager.{Lookup, LookupResult}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ import net.psforever.objects.serverobject.aura.{Aura, AuraEffectBehavior}
|
||||||
import net.psforever.objects.serverobject.environment._
|
import net.psforever.objects.serverobject.environment._
|
||||||
import net.psforever.objects.serverobject.environment.interaction.RespondsToZoneEnvironment
|
import net.psforever.objects.serverobject.environment.interaction.RespondsToZoneEnvironment
|
||||||
import net.psforever.objects.vital.Vitality
|
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 net.psforever.types.{CharacterSex, CharacterVoice, PlanetSideEmpire, PlanetSideGUID, Vector3}
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue