diff --git a/src/main/scala/net/psforever/actors/session/csr/MountHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/csr/MountHandlerLogic.scala index 4e9480d54..1965825ab 100644 --- a/src/main/scala/net/psforever/actors/session/csr/MountHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/csr/MountHandlerLogic.scala @@ -166,7 +166,7 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act ops.MountingAction(tplayer, obj, 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) sessionLogic.zoning.CancelZoningProcess() sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health)) diff --git a/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala index f7230008f..86e42e942 100644 --- a/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala @@ -181,7 +181,7 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act ops.MountingAction(tplayer, obj, 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}") obj.setMiddleOfUpgrade(false) sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount") diff --git a/src/main/scala/net/psforever/actors/zone/building/MajorFacilityLogic.scala b/src/main/scala/net/psforever/actors/zone/building/MajorFacilityLogic.scala index 24825d7f4..c90579c55 100644 --- a/src/main/scala/net/psforever/actors/zone/building/MajorFacilityLogic.scala +++ b/src/main/scala/net/psforever/actors/zone/building/MajorFacilityLogic.scala @@ -109,11 +109,16 @@ case object MajorFacilityLogic // No map update needed - will be sent by `HackCaptureActor` when required case dome: ForceDomePhysics => 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)) building.NtuSource.foreach(_.Actor ! ResourceSiloControl.DrainMultiplier(multiplier)) - // The force dome being expanded marks the generator as being invulnerable; it can be damaged otherwise - building.Generator.foreach { _.Actor ! Damageable.Vulnerability(dome.Energized) } + // The protection of the force dome marks the generator (and some other amenities) as being invulnerable + val msg = Damageable.Vulnerability(dome.Perimeter.nonEmpty) + val applicable = dome.Definition.ApplyProtectionTo + building + .Amenities + .filter(amenity => applicable.contains(amenity.Definition)) + .foreach { _.Actor ! msg } case _ => details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage())) } diff --git a/src/main/scala/net/psforever/objects/TurretDeployable.scala b/src/main/scala/net/psforever/objects/TurretDeployable.scala index 17dd8dc3b..5d385f072 100644 --- a/src/main/scala/net/psforever/objects/TurretDeployable.scala +++ b/src/main/scala/net/psforever/objects/TurretDeployable.scala @@ -10,7 +10,7 @@ import net.psforever.objects.guid.{GUIDTask, TaskWorkflow} import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior import net.psforever.objects.serverobject.damage.Damageable 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.{TurretControl, TurretDefinition, WeaponTurret} import net.psforever.objects.sourcing.{PlayerSource, SourceEntry} @@ -36,6 +36,7 @@ class TurretDeployable(tdef: TurretDeployableDefinition) HackDuration = Array(0, 20, 10, 5) if (tdef.Seats.nonEmpty) { + interaction(new InteractWithForceDomeProtectionSeatedInEntity) interaction(new InteractWithTurrets()) interaction(new InteractWithRadiationCloudsSeatedInEntity(obj = this, range = 100f)) } diff --git a/src/main/scala/net/psforever/objects/Vehicle.scala b/src/main/scala/net/psforever/objects/Vehicle.scala index 3658294d5..122618c39 100644 --- a/src/main/scala/net/psforever/objects/Vehicle.scala +++ b/src/main/scala/net/psforever/objects/Vehicle.scala @@ -16,7 +16,7 @@ import net.psforever.objects.serverobject.hackable.Hackable import net.psforever.objects.serverobject.interior.{InteriorAwareFromInteraction, Sidedness} import net.psforever.objects.serverobject.structures.AmenityOwner 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.Vitality import net.psforever.objects.vital.resolution.DamageResistanceModel @@ -94,6 +94,7 @@ class Vehicle(private val vehicleDef: VehicleDefinition) with AuraContainer with MountableEntity with InteriorAwareFromInteraction { + interaction(new InteractWithForceDomeProtectionSeatedInVehicle) interaction(environment.interaction.InteractWithEnvironment(Seq( new WithEntrance(), new WithWater(), diff --git a/src/main/scala/net/psforever/objects/avatar/interaction/InteractWithForceDomeProtection.scala b/src/main/scala/net/psforever/objects/avatar/interaction/InteractWithForceDomeProtection.scala index 145c8514e..66b92688d 100644 --- a/src/main/scala/net/psforever/objects/avatar/interaction/InteractWithForceDomeProtection.scala +++ b/src/main/scala/net/psforever/objects/avatar/interaction/InteractWithForceDomeProtection.scala @@ -77,7 +77,7 @@ class InteractWithForceDomeProtection } } - protected def applyProtection(target: InteractsWithZone, dome: ForceDomePhysics): Unit = { + def applyProtection(target: InteractsWithZone, dome: ForceDomePhysics): Unit = { protectedBy = Some(dome) target.Actor ! Damageable.MakeInvulnerable } diff --git a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala index 6a5e90721..b85b9e872 100644 --- a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala +++ b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala @@ -965,6 +965,7 @@ object GlobalDefinitionsMiscellaneous { Vector3(-90.328125f, -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.UseRadius = 121.8149f @@ -976,6 +977,7 @@ object GlobalDefinitionsMiscellaneous { Vector3(-83.640625f, 45.601562f, 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.UseRadius = 127.9241f //127.7963f @@ -986,6 +988,7 @@ object GlobalDefinitionsMiscellaneous { Vector3(-74.73426f, -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.UseRadius = 175.8838f //175.7081f @@ -997,10 +1000,11 @@ object GlobalDefinitionsMiscellaneous { Vector3(130.44531f, 188.26562f, 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.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, 34.441734f, 0f), Vector3(103.98575f, 52.58408f, 0f), @@ -1011,5 +1015,6 @@ object GlobalDefinitionsMiscellaneous { Vector3(-73.64424f, -114.65837f, 0f), Vector3(102.12191f, -114.65837f, 0f) ) + force_dome_tech_physics.ApplyProtectionTo = List(generator, manned_turret) } } diff --git a/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala b/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala index 28b665866..53bec2242 100644 --- a/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala @@ -164,8 +164,8 @@ object ForceDomeControl { val energizedState = dome.Energized CheckForceDomeStatus(building, dome).exists { case true if !energizedState => - dome.Owner.Actor ! BuildingActor.MapUpdate() ChangeDomeEnergizedState(dome, activationState = true) + dome.Owner.Actor ! BuildingActor.MapUpdate() true case false if energizedState => 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 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 maxDistance ot applicable + * @param maxDistance not applicable * @return `true`, if target is detected within the force dome kill region * `false`, otherwise */ @@ -260,12 +260,12 @@ object ForceDomeControl { @unused maxDistance: Float ): Boolean = { val centerPos @ Vector3(centerX, centerY, centerZ) = obj1.Position - val Vector3(targetX, targetY, targetZ) = obj2.Position - centerPos //deltas of segment of target to dome - val checkForIntersection = segments.exists { case (point1, point2) => + val Vector3(targetX, targetY, _) = obj2.Position.xy - centerPos.xy //deltas of segment of target to dome + lazy val checkForIntersection = segments.exists { case (point1, point2) => //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) } - !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 if dome.Energized => dome.Perimeter = perimeterSegments + dome.Owner.Actor ! BuildingActor.AmenityStateChange(dome) case ForceDomeControl.RemoveProtection => dome.Perimeter = List.empty + dome.Owner.Actor ! BuildingActor.AmenityStateChange(dome) case ForceDomeControl.Purge => ForceDomeControl.ForceDomeKills(dome, perimeterSegments) diff --git a/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeDefinition.scala b/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeDefinition.scala index 5f4d50450..efca36455 100644 --- a/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeDefinition.scala +++ b/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeDefinition.scala @@ -3,7 +3,6 @@ package net.psforever.objects.serverobject.dome import net.psforever.objects.geometry.d3.{Sphere, VolumetricGeometry} import net.psforever.objects.serverobject.structures.AmenityDefinition -import net.psforever.objects.sourcing.SourceEntry import net.psforever.types.Vector3 class ForceDomeDefinition(objectId: Int) @@ -22,6 +21,19 @@ class ForceDomeDefinition(objectId: Int) perimeter = points 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 { diff --git a/src/main/scala/net/psforever/objects/serverobject/hackable/GenericHackables.scala b/src/main/scala/net/psforever/objects/serverobject/hackable/GenericHackables.scala index 5933beb0d..c7c598d8d 100644 --- a/src/main/scala/net/psforever/objects/serverobject/hackable/GenericHackables.scala +++ b/src/main/scala/net/psforever/objects/serverobject/hackable/GenericHackables.scala @@ -2,11 +2,13 @@ package net.psforever.objects.serverobject.hackable 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.capture.CaptureTerminal import net.psforever.objects.{GlobalDefinitions, Player, Vehicle} 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.types.{PlanetSideEmpire, PlanetSideGUID} import net.psforever.services.Service @@ -17,23 +19,7 @@ import scala.util.{Failure, Success} object GenericHackables { 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 * @@ -79,7 +65,13 @@ object GenericHackables { * @return `true`, if the next cycle of progress should occur; * `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 ): Boolean = { //hack state for progress bar visibility @@ -87,9 +79,7 @@ object GenericHackables { (HackState.Start, 0) } else if (progress >= 100L) { (HackState.Finished, 100) - } else if (target.isMoving(test = 1f) || target.Destroyed || !target.HasGUID) { - (HackState.Cancelled, 0) - } else if (target.isInstanceOf[CaptureTerminal] && EndHackProgress(target, hacker)) { + } else if (target.isMoving(test = 1f) || target.Destroyed || !target.HasGUID || additionalCancellationTests(target, hacker)) { (HackState.Cancelled, 0) } else { (HackState.Ongoing, progress.toInt) @@ -104,6 +94,31 @@ object GenericHackables { 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. * Pass the message onto the hackable object and onto the local events system. diff --git a/src/main/scala/net/psforever/objects/serverobject/mount/InteractWithForceDomeProtectionSeatedInEntity.scala b/src/main/scala/net/psforever/objects/serverobject/mount/InteractWithForceDomeProtectionSeatedInEntity.scala index fdbf6d081..2dddc5ba0 100644 --- a/src/main/scala/net/psforever/objects/serverobject/mount/InteractWithForceDomeProtectionSeatedInEntity.scala +++ b/src/main/scala/net/psforever/objects/serverobject/mount/InteractWithForceDomeProtectionSeatedInEntity.scala @@ -10,7 +10,7 @@ class InteractWithForceDomeProtectionSeatedInEntity extends InteractWithForceDomeProtection { 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) target .asInstanceOf[Mountable] diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalControl.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalControl.scala index f5dc91a72..fef28d51f 100644 --- a/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminalControl.scala @@ -29,7 +29,7 @@ class CaptureTerminalControl(terminal: CaptureTerminal) sender() ! CommonMessages.Progress( GenericHackables.GetHackSpeed(player, terminal), CaptureTerminals.FinishHackingCaptureConsole(terminal, player, unk = -1), - GenericHackables.HackingTickAction(HackState1.Unk1, player, terminal, item.GUID) + GenericHackables.HackingTickAction(HackState1.Unk1, player, terminal, item.GUID, CaptureTerminals.EndHackProgress) ) } diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala index 399d45d84..9f07bce14 100644 --- a/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala +++ b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala @@ -1,13 +1,18 @@ +// Copyright (c) 2021 PSForever package net.psforever.objects.serverobject.terminals.capture 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.services.local.{LocalAction, LocalServiceMessage} +import net.psforever.types.PlanetSideEmpire +import scala.concurrent.duration._ import scala.util.{Failure, Success} -object CaptureTerminals {import scala.concurrent.duration._ +object 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}") } } + + /** + * 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 + } + } } diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala index 28d975950..699fdccee 100644 --- a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala +++ b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala @@ -23,6 +23,28 @@ class FacilityTurret(tDef: FacilityTurretDefinition) WeaponTurret.LoadDefinition(turret = this) 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 = { Seats .headOption diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala index 12be65269..01613cd27 100644 --- a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala @@ -100,7 +100,7 @@ class FacilityTurretControl(turret: FacilityTurret) seatNumber: Int, player: Player): Boolean = { 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 = { diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurrets.scala b/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurrets.scala index 9dd64c311..03b8925ae 100644 --- a/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurrets.scala +++ b/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurrets.scala @@ -3,7 +3,6 @@ package net.psforever.objects.serverobject.turret import net.psforever.objects.avatar.Certification import net.psforever.objects.ce.Deployable -import net.psforever.objects.serverobject.hackable.GenericHackables.updateTurretUpgradeTime import net.psforever.objects.{Player, Tool, TurretDeployable} import net.psforever.packet.game.{HackMessage, HackState, HackState1, HackState7, InventoryStateMessage} import net.psforever.services.Service @@ -83,7 +82,7 @@ object WeaponTurrets { } else if (turret.Destroyed) { (HackState.Cancelled, 0) } else { - updateTurretUpgradeTime() + turret.UpdateTurretUpgradeTime() (HackState.Ongoing, progress.toInt) } turret.Zone.AvatarEvents ! AvatarServiceMessage( diff --git a/src/main/scala/net/psforever/objects/vehicles/interaction/InteractWithForceDomeProtectionSeatedInVehicle.scala b/src/main/scala/net/psforever/objects/vehicles/interaction/InteractWithForceDomeProtectionSeatedInVehicle.scala index 181ca2cfe..0a988f818 100644 --- a/src/main/scala/net/psforever/objects/vehicles/interaction/InteractWithForceDomeProtectionSeatedInVehicle.scala +++ b/src/main/scala/net/psforever/objects/vehicles/interaction/InteractWithForceDomeProtectionSeatedInVehicle.scala @@ -9,7 +9,7 @@ import net.psforever.objects.zones.InteractsWithZone class InteractWithForceDomeProtectionSeatedInVehicle extends InteractWithForceDomeProtectionSeatedInEntity { - override protected def applyProtection(target: InteractsWithZone, dome: ForceDomePhysics): Unit = { + override def applyProtection(target: InteractsWithZone, dome: ForceDomePhysics): Unit = { super.applyProtection(target, dome) target .asInstanceOf[Vehicle]