mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-07-16 08:55:18 +00:00
force dome provides damage protection to certain amenities, e.g., the generator, the turrets, and any implant machines (cryo); force dome will also suspend hacking attempts under it's envelope, but counter-hacking (resecure) should still be possible; operated turret deployables gain protection while manned; turrets no longer share knowledge of each other's upgrade cycles
This commit is contained in:
parent
94bd315354
commit
73f352490c
17 changed files with 154 additions and 44 deletions
|
|
@ -166,7 +166,7 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
|
||||||
ops.MountingAction(tplayer, obj, seatNumber)
|
ops.MountingAction(tplayer, obj, seatNumber)
|
||||||
|
|
||||||
case Mountable.CanMount(obj: FacilityTurret, seatNumber, _)
|
case Mountable.CanMount(obj: FacilityTurret, seatNumber, _)
|
||||||
if !obj.isUpgrading || System.currentTimeMillis() - GenericHackables.getTurretUpgradeTime >= 1500L =>
|
if !obj.isUpgrading || System.currentTimeMillis() - obj.CheckTurretUpgradeTime >= 1500L =>
|
||||||
obj.setMiddleOfUpgrade(false)
|
obj.setMiddleOfUpgrade(false)
|
||||||
sessionLogic.zoning.CancelZoningProcess()
|
sessionLogic.zoning.CancelZoningProcess()
|
||||||
sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
|
sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
|
||||||
ops.MountingAction(tplayer, obj, seatNumber)
|
ops.MountingAction(tplayer, obj, seatNumber)
|
||||||
|
|
||||||
case Mountable.CanMount(obj: FacilityTurret, seatNumber, _)
|
case Mountable.CanMount(obj: FacilityTurret, seatNumber, _)
|
||||||
if !obj.isUpgrading || System.currentTimeMillis() - GenericHackables.getTurretUpgradeTime >= 1500L =>
|
if !obj.isUpgrading || System.currentTimeMillis() - obj.CheckTurretUpgradeTime >= 1500L =>
|
||||||
log.info(s"${player.Name} mounts the ${obj.Definition.Name}")
|
log.info(s"${player.Name} mounts the ${obj.Definition.Name}")
|
||||||
obj.setMiddleOfUpgrade(false)
|
obj.setMiddleOfUpgrade(false)
|
||||||
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||||
|
|
|
||||||
|
|
@ -109,11 +109,16 @@ case object MajorFacilityLogic
|
||||||
// No map update needed - will be sent by `HackCaptureActor` when required
|
// No map update needed - will be sent by `HackCaptureActor` when required
|
||||||
case dome: ForceDomePhysics =>
|
case dome: ForceDomePhysics =>
|
||||||
val building = details.building
|
val building = details.building
|
||||||
// The force dome being expanded modifies the NTU drain rate
|
// The protection of the force dome modifies the NTU drain rate
|
||||||
val multiplier: Float = calculateNtuDrainMultiplierFrom(details.building, domeOpt = Some(dome))
|
val multiplier: Float = calculateNtuDrainMultiplierFrom(details.building, domeOpt = Some(dome))
|
||||||
building.NtuSource.foreach(_.Actor ! ResourceSiloControl.DrainMultiplier(multiplier))
|
building.NtuSource.foreach(_.Actor ! ResourceSiloControl.DrainMultiplier(multiplier))
|
||||||
// The force dome being expanded marks the generator as being invulnerable; it can be damaged otherwise
|
// The protection of the force dome marks the generator (and some other amenities) as being invulnerable
|
||||||
building.Generator.foreach { _.Actor ! Damageable.Vulnerability(dome.Energized) }
|
val msg = Damageable.Vulnerability(dome.Perimeter.nonEmpty)
|
||||||
|
val applicable = dome.Definition.ApplyProtectionTo
|
||||||
|
building
|
||||||
|
.Amenities
|
||||||
|
.filter(amenity => applicable.contains(amenity.Definition))
|
||||||
|
.foreach { _.Actor ! msg }
|
||||||
case _ =>
|
case _ =>
|
||||||
details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
|
details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
||||||
import net.psforever.objects.serverobject.damage.Damageable
|
import net.psforever.objects.serverobject.damage.Damageable
|
||||||
import net.psforever.objects.serverobject.hackable.Hackable
|
import net.psforever.objects.serverobject.hackable.Hackable
|
||||||
import net.psforever.objects.serverobject.mount.InteractWithRadiationCloudsSeatedInEntity
|
import net.psforever.objects.serverobject.mount.{InteractWithForceDomeProtectionSeatedInEntity, InteractWithRadiationCloudsSeatedInEntity}
|
||||||
import net.psforever.objects.serverobject.turret.auto.{AffectedByAutomaticTurretFire, AutomatedTurret}
|
import net.psforever.objects.serverobject.turret.auto.{AffectedByAutomaticTurretFire, AutomatedTurret}
|
||||||
import net.psforever.objects.serverobject.turret.{TurretControl, TurretDefinition, WeaponTurret}
|
import net.psforever.objects.serverobject.turret.{TurretControl, TurretDefinition, WeaponTurret}
|
||||||
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
|
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
|
||||||
|
|
@ -36,6 +36,7 @@ class TurretDeployable(tdef: TurretDeployableDefinition)
|
||||||
HackDuration = Array(0, 20, 10, 5)
|
HackDuration = Array(0, 20, 10, 5)
|
||||||
|
|
||||||
if (tdef.Seats.nonEmpty) {
|
if (tdef.Seats.nonEmpty) {
|
||||||
|
interaction(new InteractWithForceDomeProtectionSeatedInEntity)
|
||||||
interaction(new InteractWithTurrets())
|
interaction(new InteractWithTurrets())
|
||||||
interaction(new InteractWithRadiationCloudsSeatedInEntity(obj = this, range = 100f))
|
interaction(new InteractWithRadiationCloudsSeatedInEntity(obj = this, range = 100f))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import net.psforever.objects.serverobject.hackable.Hackable
|
||||||
import net.psforever.objects.serverobject.interior.{InteriorAwareFromInteraction, Sidedness}
|
import net.psforever.objects.serverobject.interior.{InteriorAwareFromInteraction, Sidedness}
|
||||||
import net.psforever.objects.serverobject.structures.AmenityOwner
|
import net.psforever.objects.serverobject.structures.AmenityOwner
|
||||||
import net.psforever.objects.vehicles._
|
import net.psforever.objects.vehicles._
|
||||||
import net.psforever.objects.vehicles.interaction.{TriggerOnVehicleRule, WithLava, WithWater}
|
import net.psforever.objects.vehicles.interaction.{InteractWithForceDomeProtectionSeatedInVehicle, TriggerOnVehicleRule, WithLava, WithWater}
|
||||||
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
|
||||||
|
|
@ -94,6 +94,7 @@ class Vehicle(private val vehicleDef: VehicleDefinition)
|
||||||
with AuraContainer
|
with AuraContainer
|
||||||
with MountableEntity
|
with MountableEntity
|
||||||
with InteriorAwareFromInteraction {
|
with InteriorAwareFromInteraction {
|
||||||
|
interaction(new InteractWithForceDomeProtectionSeatedInVehicle)
|
||||||
interaction(environment.interaction.InteractWithEnvironment(Seq(
|
interaction(environment.interaction.InteractWithEnvironment(Seq(
|
||||||
new WithEntrance(),
|
new WithEntrance(),
|
||||||
new WithWater(),
|
new WithWater(),
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ class InteractWithForceDomeProtection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected def applyProtection(target: InteractsWithZone, dome: ForceDomePhysics): Unit = {
|
def applyProtection(target: InteractsWithZone, dome: ForceDomePhysics): Unit = {
|
||||||
protectedBy = Some(dome)
|
protectedBy = Some(dome)
|
||||||
target.Actor ! Damageable.MakeInvulnerable
|
target.Actor ! Damageable.MakeInvulnerable
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -965,6 +965,7 @@ object GlobalDefinitionsMiscellaneous {
|
||||||
Vector3(-90.328125f, -106.90625f, 0f),
|
Vector3(-90.328125f, -106.90625f, 0f),
|
||||||
Vector3(83.05469f, -106.90625f, 0f)
|
Vector3(83.05469f, -106.90625f, 0f)
|
||||||
)
|
)
|
||||||
|
force_dome_amp_physics.ApplyProtectionTo = List(generator, manned_turret)
|
||||||
|
|
||||||
force_dome_comm_physics.Name = "force_dome_comm_physics"
|
force_dome_comm_physics.Name = "force_dome_comm_physics"
|
||||||
force_dome_comm_physics.UseRadius = 121.8149f
|
force_dome_comm_physics.UseRadius = 121.8149f
|
||||||
|
|
@ -976,6 +977,7 @@ object GlobalDefinitionsMiscellaneous {
|
||||||
Vector3(-83.640625f, 45.601562f, 0f),
|
Vector3(-83.640625f, 45.601562f, 0f),
|
||||||
Vector3(-83.640625f, -89.859375f, 0f)
|
Vector3(-83.640625f, -89.859375f, 0f)
|
||||||
)
|
)
|
||||||
|
force_dome_comm_physics.ApplyProtectionTo = List(generator, manned_turret)
|
||||||
|
|
||||||
force_dome_cryo_physics.Name = "force_dome_cryo_physics"
|
force_dome_cryo_physics.Name = "force_dome_cryo_physics"
|
||||||
force_dome_cryo_physics.UseRadius = 127.9241f //127.7963f
|
force_dome_cryo_physics.UseRadius = 127.9241f //127.7963f
|
||||||
|
|
@ -986,6 +988,7 @@ object GlobalDefinitionsMiscellaneous {
|
||||||
Vector3(-74.73426f, -103.47f, 0),
|
Vector3(-74.73426f, -103.47f, 0),
|
||||||
Vector3(72.75476f, -103.47f, 0)
|
Vector3(72.75476f, -103.47f, 0)
|
||||||
)
|
)
|
||||||
|
force_dome_cryo_physics.ApplyProtectionTo = List(generator, implant_terminal_mech, manned_turret)
|
||||||
|
|
||||||
force_dome_dsp_physics.Name = "force_dome_dsp_physics"
|
force_dome_dsp_physics.Name = "force_dome_dsp_physics"
|
||||||
force_dome_dsp_physics.UseRadius = 175.8838f //175.7081f
|
force_dome_dsp_physics.UseRadius = 175.8838f //175.7081f
|
||||||
|
|
@ -997,10 +1000,11 @@ object GlobalDefinitionsMiscellaneous {
|
||||||
Vector3(130.44531f, 188.26562f, 0f),
|
Vector3(130.44531f, 188.26562f, 0f),
|
||||||
Vector3(130.44531f, -93.28125f, 0f)
|
Vector3(130.44531f, -93.28125f, 0f)
|
||||||
)
|
)
|
||||||
|
force_dome_dsp_physics.ApplyProtectionTo = List(generator, manned_turret)
|
||||||
|
|
||||||
force_dome_tech_physics.Name = "force_dome_tech_physics"
|
force_dome_tech_physics.Name = "force_dome_tech_physics"
|
||||||
force_dome_tech_physics.UseRadius = 150.1284f
|
force_dome_tech_physics.UseRadius = 150.1284f
|
||||||
force_dome_tech_physics.PerimeterOffsets = List( //todo double-check eisa, esamir
|
force_dome_tech_physics.PerimeterOffsets = List( //todo double-check, e.g., eisa, esamir
|
||||||
Vector3(130.14636f, -95.20665f, 0f),
|
Vector3(130.14636f, -95.20665f, 0f),
|
||||||
Vector3(130.14636f, 34.441734f, 0f),
|
Vector3(130.14636f, 34.441734f, 0f),
|
||||||
Vector3(103.98575f, 52.58408f, 0f),
|
Vector3(103.98575f, 52.58408f, 0f),
|
||||||
|
|
@ -1011,5 +1015,6 @@ object GlobalDefinitionsMiscellaneous {
|
||||||
Vector3(-73.64424f, -114.65837f, 0f),
|
Vector3(-73.64424f, -114.65837f, 0f),
|
||||||
Vector3(102.12191f, -114.65837f, 0f)
|
Vector3(102.12191f, -114.65837f, 0f)
|
||||||
)
|
)
|
||||||
|
force_dome_tech_physics.ApplyProtectionTo = List(generator, manned_turret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -164,8 +164,8 @@ object ForceDomeControl {
|
||||||
val energizedState = dome.Energized
|
val energizedState = dome.Energized
|
||||||
CheckForceDomeStatus(building, dome).exists {
|
CheckForceDomeStatus(building, dome).exists {
|
||||||
case true if !energizedState =>
|
case true if !energizedState =>
|
||||||
dome.Owner.Actor ! BuildingActor.MapUpdate()
|
|
||||||
ChangeDomeEnergizedState(dome, activationState = true)
|
ChangeDomeEnergizedState(dome, activationState = true)
|
||||||
|
dome.Owner.Actor ! BuildingActor.MapUpdate()
|
||||||
true
|
true
|
||||||
case false if energizedState =>
|
case false if energizedState =>
|
||||||
ChangeDomeEnergizedState(dome, activationState = false)
|
ChangeDomeEnergizedState(dome, activationState = false)
|
||||||
|
|
@ -247,7 +247,7 @@ object ForceDomeControl {
|
||||||
* @param segments ground-level perimeter of the force dome is defined by these segments (as vertex pairs)
|
* @param segments ground-level perimeter of the force dome is defined by these segments (as vertex pairs)
|
||||||
* @param obj1 a game entity, should be the force dome
|
* @param obj1 a game entity, should be the force dome
|
||||||
* @param obj2 a game entity, should be a damageable target of the force dome's wrath
|
* @param obj2 a game entity, should be a damageable target of the force dome's wrath
|
||||||
* @param maxDistance ot applicable
|
* @param maxDistance not applicable
|
||||||
* @return `true`, if target is detected within the force dome kill region
|
* @return `true`, if target is detected within the force dome kill region
|
||||||
* `false`, otherwise
|
* `false`, otherwise
|
||||||
*/
|
*/
|
||||||
|
|
@ -260,12 +260,12 @@ object ForceDomeControl {
|
||||||
@unused maxDistance: Float
|
@unused maxDistance: Float
|
||||||
): Boolean = {
|
): Boolean = {
|
||||||
val centerPos @ Vector3(centerX, centerY, centerZ) = obj1.Position
|
val centerPos @ Vector3(centerX, centerY, centerZ) = obj1.Position
|
||||||
val Vector3(targetX, targetY, targetZ) = obj2.Position - centerPos //deltas of segment of target to dome
|
val Vector3(targetX, targetY, _) = obj2.Position.xy - centerPos.xy //deltas of segment of target to dome
|
||||||
val checkForIntersection = segments.exists { case (point1, point2) =>
|
lazy val checkForIntersection = segments.exists { case (point1, point2) =>
|
||||||
//want targets within the perimeter; if there's an intersection, target is outside of the perimeter
|
//want targets within the perimeter; if there's an intersection, target is outside of the perimeter
|
||||||
segmentIntersectionTestPerSegment(centerX, centerY, targetX, targetY, point1.x, point1.y, point2.x, point2.y)
|
segmentIntersectionTestPerSegment(centerX, centerY, targetX, targetY, point1.x, point1.y, point2.x, point2.y)
|
||||||
}
|
}
|
||||||
!checkForIntersection && (targetZ < centerZ || Zone.distanceCheck(obj1, obj2, math.pow(obj1.Definition.UseRadius, 2).toFloat))
|
segments.nonEmpty && !checkForIntersection && (obj2.Position.z <= centerZ || Zone.distanceCheck(obj1, obj2, math.pow(obj1.Definition.UseRadius, 2).toFloat))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -402,9 +402,11 @@ class ForceDomeControl(dome: ForceDomePhysics)
|
||||||
case ForceDomeControl.ApplyProtection
|
case ForceDomeControl.ApplyProtection
|
||||||
if dome.Energized =>
|
if dome.Energized =>
|
||||||
dome.Perimeter = perimeterSegments
|
dome.Perimeter = perimeterSegments
|
||||||
|
dome.Owner.Actor ! BuildingActor.AmenityStateChange(dome)
|
||||||
|
|
||||||
case ForceDomeControl.RemoveProtection =>
|
case ForceDomeControl.RemoveProtection =>
|
||||||
dome.Perimeter = List.empty
|
dome.Perimeter = List.empty
|
||||||
|
dome.Owner.Actor ! BuildingActor.AmenityStateChange(dome)
|
||||||
|
|
||||||
case ForceDomeControl.Purge =>
|
case ForceDomeControl.Purge =>
|
||||||
ForceDomeControl.ForceDomeKills(dome, perimeterSegments)
|
ForceDomeControl.ForceDomeKills(dome, perimeterSegments)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package net.psforever.objects.serverobject.dome
|
||||||
|
|
||||||
import net.psforever.objects.geometry.d3.{Sphere, VolumetricGeometry}
|
import net.psforever.objects.geometry.d3.{Sphere, VolumetricGeometry}
|
||||||
import net.psforever.objects.serverobject.structures.AmenityDefinition
|
import net.psforever.objects.serverobject.structures.AmenityDefinition
|
||||||
import net.psforever.objects.sourcing.SourceEntry
|
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
|
|
||||||
class ForceDomeDefinition(objectId: Int)
|
class ForceDomeDefinition(objectId: Int)
|
||||||
|
|
@ -22,6 +21,19 @@ class ForceDomeDefinition(objectId: Int)
|
||||||
perimeter = points
|
perimeter = points
|
||||||
PerimeterOffsets
|
PerimeterOffsets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var protects: List[AmenityDefinition] = List()
|
||||||
|
|
||||||
|
def ApplyProtectionTo: List[AmenityDefinition] = protects
|
||||||
|
|
||||||
|
def ApplyProtectionTo_=(protect: AmenityDefinition): List[AmenityDefinition] = {
|
||||||
|
ApplyProtectionTo_=(List(protect))
|
||||||
|
}
|
||||||
|
|
||||||
|
def ApplyProtectionTo_=(protect: List[AmenityDefinition]): List[AmenityDefinition] = {
|
||||||
|
protects = protect
|
||||||
|
ApplyProtectionTo
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ForceDomeDefinition {
|
object ForceDomeDefinition {
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@
|
||||||
package net.psforever.objects.serverobject.hackable
|
package net.psforever.objects.serverobject.hackable
|
||||||
|
|
||||||
import net.psforever.actors.zone.BuildingActor
|
import net.psforever.actors.zone.BuildingActor
|
||||||
import net.psforever.objects.serverobject.structures.{Building, StructureType, WarpGate}
|
import net.psforever.objects.serverobject.dome.ForceDomeControl
|
||||||
|
import net.psforever.objects.serverobject.structures.{Amenity, Building, StructureType, WarpGate}
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
|
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
|
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
|
||||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||||
|
import net.psforever.objects.zones.blockmap.BlockMapEntity
|
||||||
import net.psforever.packet.game.{GenericObjectActionMessage, HackMessage, HackState, HackState1, HackState7, TriggeredSound}
|
import net.psforever.packet.game.{GenericObjectActionMessage, HackMessage, HackState, HackState1, HackState7, TriggeredSound}
|
||||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
|
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
|
|
@ -17,23 +19,7 @@ import scala.util.{Failure, Success}
|
||||||
|
|
||||||
object GenericHackables {
|
object GenericHackables {
|
||||||
private val log = org.log4s.getLogger("HackableBehavior")
|
private val log = org.log4s.getLogger("HackableBehavior")
|
||||||
private var turretUpgradeTime: Long = System.currentTimeMillis()
|
|
||||||
private var turretUpgradeTimeSet: Boolean = false
|
|
||||||
|
|
||||||
def updateTurretUpgradeTime(): Long = {
|
|
||||||
turretUpgradeTime = System.currentTimeMillis()
|
|
||||||
turretUpgradeTimeSet = true
|
|
||||||
turretUpgradeTime
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used for checking the time without updating it
|
|
||||||
def getTurretUpgradeTime: Long = {
|
|
||||||
if (!turretUpgradeTimeSet) {
|
|
||||||
turretUpgradeTime = System.currentTimeMillis()
|
|
||||||
turretUpgradeTimeSet = true
|
|
||||||
}
|
|
||||||
turretUpgradeTime
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* na
|
* na
|
||||||
*
|
*
|
||||||
|
|
@ -79,7 +65,13 @@ object GenericHackables {
|
||||||
* @return `true`, if the next cycle of progress should occur;
|
* @return `true`, if the next cycle of progress should occur;
|
||||||
* `false`, otherwise
|
* `false`, otherwise
|
||||||
*/
|
*/
|
||||||
def HackingTickAction(progressType: HackState1, hacker: Player, target: PlanetSideServerObject, tool_guid: PlanetSideGUID)(
|
def HackingTickAction(
|
||||||
|
progressType: HackState1,
|
||||||
|
hacker: Player,
|
||||||
|
target: PlanetSideServerObject,
|
||||||
|
tool_guid: PlanetSideGUID,
|
||||||
|
additionalCancellationTests: (PlanetSideServerObject, Player) => Boolean = ForceDomeProtectsFromHacking
|
||||||
|
)(
|
||||||
progress: Float
|
progress: Float
|
||||||
): Boolean = {
|
): Boolean = {
|
||||||
//hack state for progress bar visibility
|
//hack state for progress bar visibility
|
||||||
|
|
@ -87,9 +79,7 @@ object GenericHackables {
|
||||||
(HackState.Start, 0)
|
(HackState.Start, 0)
|
||||||
} else if (progress >= 100L) {
|
} else if (progress >= 100L) {
|
||||||
(HackState.Finished, 100)
|
(HackState.Finished, 100)
|
||||||
} else if (target.isMoving(test = 1f) || target.Destroyed || !target.HasGUID) {
|
} else if (target.isMoving(test = 1f) || target.Destroyed || !target.HasGUID || additionalCancellationTests(target, hacker)) {
|
||||||
(HackState.Cancelled, 0)
|
|
||||||
} else if (target.isInstanceOf[CaptureTerminal] && EndHackProgress(target, hacker)) {
|
|
||||||
(HackState.Cancelled, 0)
|
(HackState.Cancelled, 0)
|
||||||
} else {
|
} else {
|
||||||
(HackState.Ongoing, progress.toInt)
|
(HackState.Ongoing, progress.toInt)
|
||||||
|
|
@ -104,6 +94,31 @@ object GenericHackables {
|
||||||
progressState != HackState.Cancelled
|
progressState != HackState.Cancelled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The force dome prevents hacking if its protection has been declared over a capitol.
|
||||||
|
* Under normal circumstances, the dome will be visible in the sky at his point,
|
||||||
|
* blocking enemy encounter within its boundaries,
|
||||||
|
* so anything that can be hacked is on that boundary perimeter,
|
||||||
|
* or an alternate method of entry (Router) has been compromised.
|
||||||
|
* @see `ForceDomeControl.TargetUnderForceDome`
|
||||||
|
* @see `Sector`
|
||||||
|
* @param target the `Hackable` object that has been hacked
|
||||||
|
* @param hacker the player performing the action
|
||||||
|
* @return `true`, if the target is within boundary of a working force dome and thus protected;
|
||||||
|
* `false`, otherwise
|
||||||
|
*/
|
||||||
|
def ForceDomeProtectsFromHacking(target: PlanetSideServerObject, hacker: Player): Boolean = {
|
||||||
|
//explicitly allow friendly hacking which is typically clearing a hack
|
||||||
|
target.Faction != hacker.Faction &&
|
||||||
|
(target match {
|
||||||
|
case obj: Amenity => obj.Owner.asInstanceOf[Building].ForceDome.toList
|
||||||
|
case obj: BlockMapEntity => target.Zone.blockMap.sector(obj).buildingList.flatMap(_.ForceDome)
|
||||||
|
case _ => List()
|
||||||
|
})
|
||||||
|
.filter(_.Perimeter.nonEmpty)
|
||||||
|
.exists(dome => ForceDomeControl.TargetUnderForceDome(dome.Perimeter)(dome, target, maxDistance = 0f))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The process of hacking an object is completed.
|
* The process of hacking an object is completed.
|
||||||
* Pass the message onto the hackable object and onto the local events system.
|
* Pass the message onto the hackable object and onto the local events system.
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ class InteractWithForceDomeProtectionSeatedInEntity
|
||||||
extends InteractWithForceDomeProtection {
|
extends InteractWithForceDomeProtection {
|
||||||
override def range: Float = 30f
|
override def range: Float = 30f
|
||||||
|
|
||||||
override protected def applyProtection(target: InteractsWithZone, dome: ForceDomePhysics): Unit = {
|
override def applyProtection(target: InteractsWithZone, dome: ForceDomePhysics): Unit = {
|
||||||
super.applyProtection(target, dome)
|
super.applyProtection(target, dome)
|
||||||
target
|
target
|
||||||
.asInstanceOf[Mountable]
|
.asInstanceOf[Mountable]
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class CaptureTerminalControl(terminal: CaptureTerminal)
|
||||||
sender() ! CommonMessages.Progress(
|
sender() ! CommonMessages.Progress(
|
||||||
GenericHackables.GetHackSpeed(player, terminal),
|
GenericHackables.GetHackSpeed(player, terminal),
|
||||||
CaptureTerminals.FinishHackingCaptureConsole(terminal, player, unk = -1),
|
CaptureTerminals.FinishHackingCaptureConsole(terminal, player, unk = -1),
|
||||||
GenericHackables.HackingTickAction(HackState1.Unk1, player, terminal, item.GUID)
|
GenericHackables.HackingTickAction(HackState1.Unk1, player, terminal, item.GUID, CaptureTerminals.EndHackProgress)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,18 @@
|
||||||
|
// Copyright (c) 2021 PSForever
|
||||||
package net.psforever.objects.serverobject.terminals.capture
|
package net.psforever.objects.serverobject.terminals.capture
|
||||||
|
|
||||||
import net.psforever.objects.Player
|
import net.psforever.objects.Player
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
import net.psforever.objects.serverobject.hackable.GenericHackables
|
||||||
|
import net.psforever.objects.serverobject.structures.{Building, StructureType, WarpGate}
|
||||||
|
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||||
import net.psforever.objects.sourcing.PlayerSource
|
import net.psforever.objects.sourcing.PlayerSource
|
||||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
|
||||||
|
import scala.concurrent.duration._
|
||||||
import scala.util.{Failure, Success}
|
import scala.util.{Failure, Success}
|
||||||
|
|
||||||
object CaptureTerminals {import scala.concurrent.duration._
|
object CaptureTerminals {
|
||||||
private val log = org.log4s.getLogger("CaptureTerminals")
|
private val log = org.log4s.getLogger("CaptureTerminals")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -55,4 +60,47 @@ object CaptureTerminals {import scala.concurrent.duration._
|
||||||
log.warn(s"Hack message failed on target guid: ${target.GUID}")
|
log.warn(s"Hack message failed on target guid: ${target.GUID}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the state of connected facilities has changed since the hack progress began. It accounts for a friendly facility
|
||||||
|
* on the other side of a warpgate as well in case there are no friendly facilities in the same zone
|
||||||
|
* @param target the `Hackable` object that has been hacked
|
||||||
|
* @param hacker the player performing the action
|
||||||
|
* @return `true`, if the hack should be ended; `false`, otherwise
|
||||||
|
*/
|
||||||
|
def EndHackProgress(target: PlanetSideServerObject, hacker: Player): Boolean = {
|
||||||
|
val building = target.asInstanceOf[CaptureTerminal].Owner.asInstanceOf[Building]
|
||||||
|
val hackerFaction = hacker.Faction
|
||||||
|
if (GenericHackables.ForceDomeProtectsFromHacking(target, hacker)) {
|
||||||
|
true
|
||||||
|
} else if (building.Faction == PlanetSideEmpire.NEUTRAL ||
|
||||||
|
building.BuildingType == StructureType.Tower ||
|
||||||
|
building.Faction == hackerFaction) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
val stopHackingCount = building.Neighbours match {
|
||||||
|
case Some(neighbors) =>
|
||||||
|
neighbors.count {
|
||||||
|
case wg: WarpGate if wg.Faction == hackerFaction =>
|
||||||
|
true
|
||||||
|
case wg: WarpGate =>
|
||||||
|
val friendlyBaseOpt = for {
|
||||||
|
otherWg <- wg.Neighbours.flatMap(_.find(_.isInstanceOf[WarpGate]))
|
||||||
|
friendly <- otherWg.Neighbours.flatMap(_.collectFirst { case b: Building if !b.isInstanceOf[WarpGate] => b })
|
||||||
|
} yield friendly
|
||||||
|
friendlyBaseOpt.exists { fb =>
|
||||||
|
fb.Faction == hackerFaction &&
|
||||||
|
!fb.CaptureTerminalIsHacked &&
|
||||||
|
fb.NtuLevel > 0
|
||||||
|
}
|
||||||
|
case b =>
|
||||||
|
b.Faction == hackerFaction &&
|
||||||
|
!b.CaptureTerminalIsHacked &&
|
||||||
|
b.NtuLevel > 0
|
||||||
|
}
|
||||||
|
case None => 0
|
||||||
|
}
|
||||||
|
stopHackingCount == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,28 @@ class FacilityTurret(tDef: FacilityTurretDefinition)
|
||||||
WeaponTurret.LoadDefinition(turret = this)
|
WeaponTurret.LoadDefinition(turret = this)
|
||||||
WhichSide = Sidedness.OutsideOf
|
WhichSide = Sidedness.OutsideOf
|
||||||
|
|
||||||
|
private var turretUpgradeTime: Long = System.currentTimeMillis()
|
||||||
|
private var turretUpgradeTimeSet: Boolean = false
|
||||||
|
|
||||||
|
def UpdateTurretUpgradeTime(): Long = {
|
||||||
|
turretUpgradeTime = System.currentTimeMillis()
|
||||||
|
turretUpgradeTimeSet = true
|
||||||
|
turretUpgradeTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for checking the time without updating it
|
||||||
|
def CheckTurretUpgradeTime: Long = {
|
||||||
|
if (!turretUpgradeTimeSet) {
|
||||||
|
turretUpgradeTime = System.currentTimeMillis()
|
||||||
|
turretUpgradeTimeSet = true
|
||||||
|
}
|
||||||
|
turretUpgradeTime
|
||||||
|
}
|
||||||
|
|
||||||
|
def FinishedTurretUpgradeReset(): Unit = {
|
||||||
|
turretUpgradeTimeSet = false
|
||||||
|
}
|
||||||
|
|
||||||
def TurretOwner: SourceEntry = {
|
def TurretOwner: SourceEntry = {
|
||||||
Seats
|
Seats
|
||||||
.headOption
|
.headOption
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ class FacilityTurretControl(turret: FacilityTurret)
|
||||||
seatNumber: Int,
|
seatNumber: Int,
|
||||||
player: Player): Boolean = {
|
player: Player): Boolean = {
|
||||||
super.mountTest(obj, seatNumber, player) &&
|
super.mountTest(obj, seatNumber, player) &&
|
||||||
(!TurretObject.isUpgrading || System.currentTimeMillis() - GenericHackables.getTurretUpgradeTime >= 1500L)
|
(!TurretObject.isUpgrading || System.currentTimeMillis() - TurretObject.CheckTurretUpgradeTime >= 1500L)
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected def tryMount(obj: PlanetSideServerObject with Mountable, seatNumber: Int, player: Player): Boolean = {
|
override protected def tryMount(obj: PlanetSideServerObject with Mountable, seatNumber: Int, player: Player): Boolean = {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package net.psforever.objects.serverobject.turret
|
||||||
|
|
||||||
import net.psforever.objects.avatar.Certification
|
import net.psforever.objects.avatar.Certification
|
||||||
import net.psforever.objects.ce.Deployable
|
import net.psforever.objects.ce.Deployable
|
||||||
import net.psforever.objects.serverobject.hackable.GenericHackables.updateTurretUpgradeTime
|
|
||||||
import net.psforever.objects.{Player, Tool, TurretDeployable}
|
import net.psforever.objects.{Player, Tool, TurretDeployable}
|
||||||
import net.psforever.packet.game.{HackMessage, HackState, HackState1, HackState7, InventoryStateMessage}
|
import net.psforever.packet.game.{HackMessage, HackState, HackState1, HackState7, InventoryStateMessage}
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
|
|
@ -83,7 +82,7 @@ object WeaponTurrets {
|
||||||
} else if (turret.Destroyed) {
|
} else if (turret.Destroyed) {
|
||||||
(HackState.Cancelled, 0)
|
(HackState.Cancelled, 0)
|
||||||
} else {
|
} else {
|
||||||
updateTurretUpgradeTime()
|
turret.UpdateTurretUpgradeTime()
|
||||||
(HackState.Ongoing, progress.toInt)
|
(HackState.Ongoing, progress.toInt)
|
||||||
}
|
}
|
||||||
turret.Zone.AvatarEvents ! AvatarServiceMessage(
|
turret.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import net.psforever.objects.zones.InteractsWithZone
|
||||||
|
|
||||||
class InteractWithForceDomeProtectionSeatedInVehicle
|
class InteractWithForceDomeProtectionSeatedInVehicle
|
||||||
extends InteractWithForceDomeProtectionSeatedInEntity {
|
extends InteractWithForceDomeProtectionSeatedInEntity {
|
||||||
override protected def applyProtection(target: InteractsWithZone, dome: ForceDomePhysics): Unit = {
|
override def applyProtection(target: InteractsWithZone, dome: ForceDomePhysics): Unit = {
|
||||||
super.applyProtection(target, dome)
|
super.applyProtection(target, dome)
|
||||||
target
|
target
|
||||||
.asInstanceOf[Vehicle]
|
.asInstanceOf[Vehicle]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue