From 92c9e19a06c3ed5e95c333bde873559acb95d27a Mon Sep 17 00:00:00 2001 From: Subsonic154 Date: Tue, 7 Apr 2026 04:21:44 -0400 Subject: [PATCH] Revert VR zone invulnerability, replace with friendly-fire immunity --- .../session/support/GeneralOperations.scala | 6 +++ .../actors/session/support/SessionData.scala | 28 ++++++++++++-- .../session/support/ZoningOperations.scala | 1 + .../scala/net/psforever/objects/Player.scala | 6 +-- .../scala/net/psforever/objects/Vehicle.scala | 8 ---- .../net/psforever/objects/ce/Deployable.scala | 8 ---- .../global/GlobalDefinitionsDeployable.scala | 10 ----- .../interaction/common/WithDeath.scala | 38 +++++-------------- .../serverobject/structures/Amenity.scala | 8 ---- .../objects/vital/VitalityDefinition.scala | 10 ----- .../net/psforever/objects/zones/MapInfo.scala | 4 +- .../net/psforever/objects/zones/Zone.scala | 8 +++- 12 files changed, 50 insertions(+), 85 deletions(-) diff --git a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala index b7dc548eb..a9692605a 100644 --- a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala @@ -1059,6 +1059,12 @@ class GeneralOperations( sendResponse(ChatMsg(ChatMessageType.UNK_227, wideContents=false, "", "@charsaved", None)) } + def trainingGriefWarning(): Unit = { + //don't know the correct ChatMessageType for this one yet; + //it's supposed to use a pop-up that takes 5 seconds before you are allowed to close it, so disabled for now + //sendResponse(ChatMsg(ChatMessageType.CMT_QUIT, wideContents=true, "", "@TrainingGriefWarning", None)) + } + def noVoicedChat(pkt: PlanetSideGamePacket): Unit = { log.debug(s"$pkt") sendResponse(VoiceHostKill()) diff --git a/src/main/scala/net/psforever/actors/session/support/SessionData.scala b/src/main/scala/net/psforever/actors/session/support/SessionData.scala index 44769b870..f812504fd 100644 --- a/src/main/scala/net/psforever/actors/session/support/SessionData.scala +++ b/src/main/scala/net/psforever/actors/session/support/SessionData.scala @@ -422,7 +422,12 @@ class SessionData( if (obj.spectator && obj != player) { administrativeKick(player) } else { - obj.Actor ! Vitality.Damage(func) + if (obj.IsInVRZone && obj.Faction == player.Faction && obj.CharId != player.CharId) { + //don't do friendly-fire in VR zones + general.trainingGriefWarning() + } else { + obj.Actor ! Vitality.Damage(func) + } } case obj: Vehicle if obj.CanDamage => @@ -433,10 +438,20 @@ class SessionData( } else { log.info(s"$name is attacking $ownerName's ${obj.Definition.Name}") } - obj.Actor ! Vitality.Damage(func) + if (obj.IsInVRZone && obj.Faction == player.Faction && !ownerName.equals(name)) { + //don't do friendly-fire in VR zones + general.trainingGriefWarning() + } else { + obj.Actor ! Vitality.Damage(func) + } case obj: Amenity if obj.CanDamage => - obj.Actor ! Vitality.Damage(func) + if (obj.IsInVRZone && obj.Faction == player.Faction) { + //don't do friendly-fire in VR zones + general.trainingGriefWarning() + } else { + obj.Actor ! Vitality.Damage(func) + } case obj: Deployable if obj.CanDamage => val name = player.Name @@ -446,7 +461,12 @@ class SessionData( } else { log.info(s"$name is attacking $ownerName's ${obj.Definition.Name}") } - obj.Actor ! Vitality.Damage(func) + if (obj.IsInVRZone && obj.Faction == player.Faction && !ownerName.equals(name)) { + //don't do friendly-fire in VR zones + general.trainingGriefWarning() + } else { + obj.Actor ! Vitality.Damage(func) + } case _ => () } diff --git a/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala b/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala index b1290f379..99edd6d02 100644 --- a/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala @@ -993,6 +993,7 @@ class ZoningOperations( if (player.Faction == PlanetSideEmpire.NC) Zoning.Time.Friendly else Zoning.Time.None case "tzshvs" | "tzdrvs" | "tzcovs" => if (player.Faction == PlanetSideEmpire.VS) Zoning.Time.Friendly else Zoning.Time.None + case _ => Zoning.Time.None } } else { ZoningOperations.findBuildingsBySoiOccupancy(continent, player.Position) match { diff --git a/src/main/scala/net/psforever/objects/Player.scala b/src/main/scala/net/psforever/objects/Player.scala index eafeb137e..c0023ebb6 100644 --- a/src/main/scala/net/psforever/objects/Player.scala +++ b/src/main/scala/net/psforever/objects/Player.scala @@ -575,11 +575,7 @@ class Player(var avatar: Avatar) } override def CanDamage: Boolean = { - if (IsInVRZone && !Definition.DamageableInVr) { - false - } else { - death_by < 1 && super.CanDamage - } + death_by < 1 && super.CanDamage } def DamageModel: DamageResistanceModel = exosuit.asInstanceOf[DamageResistanceModel] diff --git a/src/main/scala/net/psforever/objects/Vehicle.scala b/src/main/scala/net/psforever/objects/Vehicle.scala index b98c7ecf2..3658294d5 100644 --- a/src/main/scala/net/psforever/objects/Vehicle.scala +++ b/src/main/scala/net/psforever/objects/Vehicle.scala @@ -512,14 +512,6 @@ class Vehicle(private val vehicleDef: VehicleDefinition) def PreviousGatingManifest(): Option[VehicleManifest] = previousVehicleGatingManifest - override def CanDamage: Boolean = { - if (IsInVRZone && !Definition.DamageableInVr) { - false - } else { - !Destroyed && super.CanDamage - } - } - def DamageModel: DamageResistanceModel = Definition.asInstanceOf[DamageResistanceModel] override def BailProtection_=(protect: Boolean): Boolean = { diff --git a/src/main/scala/net/psforever/objects/ce/Deployable.scala b/src/main/scala/net/psforever/objects/ce/Deployable.scala index 0cadcb291..ed2114172 100644 --- a/src/main/scala/net/psforever/objects/ce/Deployable.scala +++ b/src/main/scala/net/psforever/objects/ce/Deployable.scala @@ -42,14 +42,6 @@ trait BaseDeployable Faction } - override def CanDamage: Boolean = { - if (IsInVRZone && !Definition.DamageableInVr) { - false - } else { - super.CanDamage - } - } - def DamageModel: DamageResistanceModel = Definition.asInstanceOf[DamageResistanceModel] def Definition: DeployableDefinition diff --git a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsDeployable.scala b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsDeployable.scala index eef2dd310..9a241373c 100644 --- a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsDeployable.scala +++ b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsDeployable.scala @@ -37,7 +37,6 @@ object GlobalDefinitionsDeployable { boomer.MaxHealth = 50 boomer.Damageable = true boomer.DamageableByFriendlyFire = false - boomer.DamageableInVr = true boomer.Repairable = false boomer.DeployCategory = DeployableCategory.Boomers boomer.DeployTime = Duration.create(1000, "ms") @@ -63,7 +62,6 @@ object GlobalDefinitionsDeployable { he_mine.MaxHealth = 25 he_mine.Damageable = true he_mine.DamageableByFriendlyFire = false - he_mine.DamageableInVr = true he_mine.Repairable = false he_mine.DeployTime = Duration.create(1000, "ms") he_mine.deployAnimation = DeployAnimation.Standard @@ -88,7 +86,6 @@ object GlobalDefinitionsDeployable { jammer_mine.MaxHealth = 50 jammer_mine.Damageable = true jammer_mine.DamageableByFriendlyFire = false - jammer_mine.DamageableInVr = true jammer_mine.Repairable = false jammer_mine.DeployTime = Duration.create(1000, "ms") jammer_mine.deployAnimation = DeployAnimation.Standard @@ -132,7 +129,6 @@ object GlobalDefinitionsDeployable { spitfire_turret.Descriptor = "Spitfires" spitfire_turret.MaxHealth = 100 spitfire_turret.Damageable = true - spitfire_turret.DamageableInVr = true spitfire_turret.Repairable = true spitfire_turret.RepairIfDestroyed = false spitfire_turret.WeaponPaths += 1 -> new mutable.HashMap() @@ -178,7 +174,6 @@ object GlobalDefinitionsDeployable { spitfire_cloaked.Descriptor = "CloakingSpitfires" spitfire_cloaked.MaxHealth = 100 spitfire_cloaked.Damageable = true - spitfire_cloaked.DamageableInVr = true spitfire_cloaked.Repairable = true spitfire_cloaked.RepairIfDestroyed = false spitfire_cloaked.WeaponPaths += 1 -> new mutable.HashMap() @@ -230,7 +225,6 @@ object GlobalDefinitionsDeployable { spitfire_aa.Descriptor = "FlakSpitfires" spitfire_aa.MaxHealth = 100 spitfire_aa.Damageable = true - spitfire_aa.DamageableInVr = true spitfire_aa.Repairable = true spitfire_aa.RepairIfDestroyed = false spitfire_aa.WeaponPaths += 1 -> new mutable.HashMap() @@ -273,7 +267,6 @@ object GlobalDefinitionsDeployable { motionalarmsensor.Descriptor = "MotionSensors" motionalarmsensor.MaxHealth = 100 motionalarmsensor.Damageable = true - motionalarmsensor.DamageableInVr = true motionalarmsensor.Repairable = true motionalarmsensor.RepairIfDestroyed = false motionalarmsensor.DeployTime = Duration.create(1000, "ms") @@ -285,7 +278,6 @@ object GlobalDefinitionsDeployable { sensor_shield.Descriptor = "SensorShields" sensor_shield.MaxHealth = 100 sensor_shield.Damageable = true - sensor_shield.DamageableInVr = true sensor_shield.Repairable = true sensor_shield.RepairIfDestroyed = false sensor_shield.DeployTime = Duration.create(5000, "ms") @@ -297,7 +289,6 @@ object GlobalDefinitionsDeployable { tank_traps.Descriptor = "TankTraps" tank_traps.MaxHealth = 5000 tank_traps.Damageable = true - tank_traps.DamageableInVr = true tank_traps.Repairable = true tank_traps.RepairIfDestroyed = false tank_traps.DeployCategory = DeployableCategory.TankTraps @@ -462,7 +453,6 @@ object GlobalDefinitionsDeployable { deployable_shield_generator.Descriptor = "ShieldGenerators" deployable_shield_generator.MaxHealth = 1700 deployable_shield_generator.Damageable = true - deployable_shield_generator.DamageableInVr = true deployable_shield_generator.Repairable = true deployable_shield_generator.RepairIfDestroyed = false deployable_shield_generator.DeployTime = Duration.create(6000, "ms") diff --git a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/WithDeath.scala b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/WithDeath.scala index 4b74e1f0c..daed8dd77 100644 --- a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/WithDeath.scala +++ b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/common/WithDeath.scala @@ -1,13 +1,11 @@ // Copyright (c) 2024 PSForever package net.psforever.objects.serverobject.environment.interaction.common -import net.psforever.objects.{Player, Vehicle} -import net.psforever.objects.serverobject.damage.DamageableVehicle import net.psforever.objects.serverobject.environment.interaction.InteractionWith import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, PieceOfEnvironment} -import net.psforever.objects.sourcing.{SourceEntry, VehicleSource} +import net.psforever.objects.sourcing.SourceEntry import net.psforever.objects.vital.etc.SuicideReason -import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult} +import net.psforever.objects.vital.interaction.DamageInteraction import net.psforever.objects.vital.{IncarnationActivity, Vitality} import net.psforever.objects.zones.interaction.InteractsWithZone @@ -33,31 +31,13 @@ class WithDeath() if (!obj.Destroyed) { obj.History.findLast { entry => entry.isInstanceOf[IncarnationActivity] } match { case Some(entry) if System.currentTimeMillis() - entry.time > 4000L => - obj match { - //bypass the damagable property, kill players and destroy vehicles directly; needed for map edge kill planes to work in VR zones - case player: Player => - player.Actor ! Player.Die() - case vehicle: Vehicle => - vehicle.Actor ! DamageableVehicle.Destruction( - DamageResult( - VehicleSource(vehicle), - VehicleSource(vehicle), - DamageInteraction( - SourceEntry(vehicle), - SuicideReason(), - vehicle.Position - ) - ) - ) - case _ => - obj.Actor ! Vitality.Damage( - DamageInteraction( - SourceEntry(obj), - SuicideReason(), - obj.Position - ).calculate() - ) - } + obj.Actor ! Vitality.Damage( + DamageInteraction( + SourceEntry(obj), + SuicideReason(), + obj.Position + ).calculate() + ) case _ => } } diff --git a/src/main/scala/net/psforever/objects/serverobject/structures/Amenity.scala b/src/main/scala/net/psforever/objects/serverobject/structures/Amenity.scala index 5d955d438..7c5034b63 100644 --- a/src/main/scala/net/psforever/objects/serverobject/structures/Amenity.scala +++ b/src/main/scala/net/psforever/objects/serverobject/structures/Amenity.scala @@ -87,14 +87,6 @@ abstract class Amenity LocationOffset } - override def CanDamage: Boolean = { - if (IsInVRZone && !Definition.DamageableInVr) { - false - } else { - super.CanDamage - } - } - def DamageModel: DamageAndResistance = Definition.asInstanceOf[DamageAndResistance] def Definition: AmenityDefinition diff --git a/src/main/scala/net/psforever/objects/vital/VitalityDefinition.scala b/src/main/scala/net/psforever/objects/vital/VitalityDefinition.scala index 1e9b3920e..6d6db09c0 100644 --- a/src/main/scala/net/psforever/objects/vital/VitalityDefinition.scala +++ b/src/main/scala/net/psforever/objects/vital/VitalityDefinition.scala @@ -49,9 +49,6 @@ trait VitalityDefinition extends DamageModifiers { */ private var damageableByFriendlyFire: Boolean = true - /** whether the object type accepts damage in VR training zones */ - private var damageableInVr: Boolean = false - /** at what `Health` value the object type is considered "destroyed" */ private var damageDestroysAt: Int = 0 @@ -74,13 +71,6 @@ trait VitalityDefinition extends DamageModifiers { DamageableByFriendlyFire } - def DamageableInVr: Boolean = damageableInVr - - def DamageableInVr_=(state: Boolean): Boolean = { - damageableInVr = state - DamageableInVr - } - def DamageDisablesAt: Int = damageDisablesAt.getOrElse(MaxHealth / 2) def DamageDisablesAt_=(value: Int): Int = DamageDisablesAt_=(Some(value)) diff --git a/src/main/scala/net/psforever/objects/zones/MapInfo.scala b/src/main/scala/net/psforever/objects/zones/MapInfo.scala index bcf8b540f..7100d1f14 100644 --- a/src/main/scala/net/psforever/objects/zones/MapInfo.scala +++ b/src/main/scala/net/psforever/objects/zones/MapInfo.scala @@ -312,7 +312,7 @@ case object MapInfo extends StringEnum[MapInfo] { checksum = 4276645952L, scale = MapScale.Dim1024, hotSpotSpan = 0, - environment = List(SeaLevel(EnvironmentAttribute.Water, 9.95f)) ++ + environment = List(SeaLevel(EnvironmentAttribute.Water, 10)) ++ MapEnvironment.dim1024MapEdgeKillPlanes ) @@ -322,7 +322,7 @@ case object MapInfo extends StringEnum[MapInfo] { checksum = 3628825458L, scale = MapScale.Dim4096, hotSpotSpan = 0, - environment = List(SeaLevel(EnvironmentAttribute.Water, 7.98f)) ++ + environment = List(SeaLevel(EnvironmentAttribute.Water, 8)) ++ MapEnvironment.dim4096MapEdgeKillPlanes ) diff --git a/src/main/scala/net/psforever/objects/zones/Zone.scala b/src/main/scala/net/psforever/objects/zones/Zone.scala index 1caf87d72..05a871fa2 100644 --- a/src/main/scala/net/psforever/objects/zones/Zone.scala +++ b/src/main/scala/net/psforever/objects/zones/Zone.scala @@ -1871,7 +1871,13 @@ object Zone { val allAffectedTargets = pssos.filter { target => testTargetsFromZone(source, target, radius) } //inform remaining targets that they have suffered damage allAffectedTargets - .foreach { target => target.Actor ! Vitality.Damage(createInteraction(source, target).calculate()) } + .foreach { target => + if (zone.id.startsWith("tz") && source.Faction == target.Faction) { + //do not perform friendly-fire in VR zones + } else { + target.Actor ! Vitality.Damage(createInteraction(source, target).calculate()) + } + } allAffectedTargets }