diff --git a/src/main/scala/net/psforever/actors/session/csr/CustomerServiceRepresentativeMode.scala b/src/main/scala/net/psforever/actors/session/csr/CustomerServiceRepresentativeMode.scala index f0ce6a974..0e454f71b 100644 --- a/src/main/scala/net/psforever/actors/session/csr/CustomerServiceRepresentativeMode.scala +++ b/src/main/scala/net/psforever/actors/session/csr/CustomerServiceRepresentativeMode.scala @@ -110,7 +110,7 @@ class CustomerServiceRepresentativeMode(data: SessionData) extends ModeLogic { private def keepAlivePersistanceCSR(): Unit = { val player = data.player player.allowInteraction = false - topOffHealthOfPlayer(player) + CustomerServiceRepresentativeMode.topOffHealthOfPlayer(data, player) data.zoning.spawn.interimUngunnedVehicle = None data.keepAlivePersistence() if (player.HasGUID) { @@ -119,63 +119,13 @@ class CustomerServiceRepresentativeMode(data: SessionData) extends ModeLogic { data.continent .GUID(player.VehicleSeated) .collect { case obj: PlanetSideGameObject with Vitality => - topOffHealth(obj) + CustomerServiceRepresentativeMode.topOffHealth(data, obj) } data.squad.updateSquad() } else { data.turnCounterFunc(PlanetSideGUID(0)) } } - - private def topOffHealth(obj: PlanetSideGameObject with Vitality): Unit = { - obj match { - case p: Player => topOffHealthOfPlayer(p) - case v: Vehicle => topOffHealthOfVehicle(v) - case o: PlanetSideGameObject with Vitality => topOffHealthOfGeneric(o) - case _ => () - } - } - - private def topOffHealthOfPlayer(player: Player): Unit = { - //driver below half health, full heal - val maxHealthOfPlayer = player.MaxHealth.toLong - if (player.Health < maxHealthOfPlayer * 0.5f) { - player.Health = maxHealthOfPlayer.toInt - player.LogActivity(player.ClearHistory().head) - data.sendResponse(PlanetsideAttributeMessage(player.GUID, 0, maxHealthOfPlayer)) - data.continent.AvatarEvents ! AvatarServiceMessage(data.zoning.zoneChannel, AvatarAction.PlanetsideAttribute(player.GUID, 0, maxHealthOfPlayer)) - } - } - - private def topOffHealthOfVehicle(vehicle: Vehicle): Unit = { - topOffHealthOfGeneric(vehicle) - //vehicle shields below half, full shields - val maxShieldsOfVehicle = vehicle.MaxShields.toLong - val shieldsUi = vehicle.Definition.shieldUiAttribute - if (vehicle.Shields < maxShieldsOfVehicle) { - val guid = vehicle.GUID - vehicle.Shields = maxShieldsOfVehicle.toInt - data.sendResponse(PlanetsideAttributeMessage(guid, shieldsUi, maxShieldsOfVehicle)) - data.continent.VehicleEvents ! VehicleServiceMessage( - data.continent.id, - VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), guid, shieldsUi, maxShieldsOfVehicle) - ) - } - } - - private def topOffHealthOfGeneric(obj: PlanetSideGameObject with Vitality): Unit = { - //below half health, full heal - val guid = obj.GUID - val maxHealthOf = obj.MaxHealth.toLong - if (obj.Health < maxHealthOf) { - obj.Health = maxHealthOf.toInt - data.sendResponse(PlanetsideAttributeMessage(guid, 0, maxHealthOf)) - data.continent.VehicleEvents ! VehicleServiceMessage( - data.continent.id, - VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), guid, 0, maxHealthOf) - ) - } - } } case object CustomerServiceRepresentativeMode extends PlayerMode { @@ -202,4 +152,66 @@ case object CustomerServiceRepresentativeMode extends PlayerMode { None )) } + + def topOffHealth(data: SessionData, obj: PlanetSideGameObject with Vitality): Unit = { + obj match { + case p: Player => topOffHealthOfPlayer(data, p) + case v: Vehicle => topOffHealthOfVehicle(data, v) + case o: PlanetSideGameObject with Vitality => topOffHealthOfGeneric(data, o) + case _ => () + } + } + + def topOffHealthOfPlayer(data: SessionData, player: Player): Unit = { + //below half health, full heal + val maxHealthOfPlayer = player.MaxHealth.toLong + val guid = player.GUID + val zoneid = data.zoning.zoneChannel + if (player.Health < maxHealthOfPlayer * 0.5f) { + if (player.Health == 0) { + player.Revive + } + player.Health = maxHealthOfPlayer.toInt + player.LogActivity(player.ClearHistory().head) + data.sendResponse(PlanetsideAttributeMessage(guid, 0, maxHealthOfPlayer)) + data.continent.AvatarEvents ! AvatarServiceMessage(zoneid, AvatarAction.PlanetsideAttribute(guid, 0, maxHealthOfPlayer)) + } + //below half armor, full armor + val maxArmor = player.MaxArmor.toLong + if (player.Armor < maxArmor) { + player.Armor = maxArmor.toInt + data.sendResponse(PlanetsideAttributeMessage(guid, 4, maxArmor)) + data.continent.AvatarEvents ! AvatarServiceMessage(zoneid, AvatarAction.PlanetsideAttribute(guid, 4, maxArmor)) + } + } + + def topOffHealthOfVehicle(data: SessionData, vehicle: Vehicle): Unit = { + topOffHealthOfGeneric(data, vehicle) + //vehicle shields below half, full shields + val maxShieldsOfVehicle = vehicle.MaxShields.toLong + val shieldsUi = vehicle.Definition.shieldUiAttribute + if (vehicle.Shields < maxShieldsOfVehicle) { + val guid = vehicle.GUID + vehicle.Shields = maxShieldsOfVehicle.toInt + data.sendResponse(PlanetsideAttributeMessage(guid, shieldsUi, maxShieldsOfVehicle)) + data.continent.VehicleEvents ! VehicleServiceMessage( + data.continent.id, + VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), guid, shieldsUi, maxShieldsOfVehicle) + ) + } + } + + def topOffHealthOfGeneric(data: SessionData, obj: PlanetSideGameObject with Vitality): Unit = { + //below half health, full heal + val guid = obj.GUID + val maxHealthOf = obj.MaxHealth.toLong + if (obj.Health < maxHealthOf) { + obj.Health = maxHealthOf.toInt + data.sendResponse(PlanetsideAttributeMessage(guid, 0, maxHealthOf)) + data.continent.VehicleEvents ! VehicleServiceMessage( + data.continent.id, + VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), guid, 0, maxHealthOf) + ) + } + } } diff --git a/src/main/scala/net/psforever/actors/session/csr/GeneralLogic.scala b/src/main/scala/net/psforever/actors/session/csr/GeneralLogic.scala index 76e8f2761..31ca715e4 100644 --- a/src/main/scala/net/psforever/actors/session/csr/GeneralLogic.scala +++ b/src/main/scala/net/psforever/actors/session/csr/GeneralLogic.scala @@ -27,11 +27,8 @@ import net.psforever.objects.serverobject.terminals.{ProximityUnit, Terminal} import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech import net.psforever.objects.serverobject.tube.SpawnTube import net.psforever.objects.serverobject.turret.FacilityTurret -import net.psforever.objects.sourcing.{PlayerSource, SourceEntry} import net.psforever.objects.vehicles.Utility import net.psforever.objects.vital.Vitality -import net.psforever.objects.vital.etc.ForceDomeExposure -import net.psforever.objects.vital.interaction.DamageInteraction import net.psforever.objects.zones.{ZoneProjectile, Zoning} import net.psforever.packet.PlanetSideGamePacket import net.psforever.packet.game.OutfitEventAction.{Initial, OutfitInfo, OutfitRankNames, Unk1} @@ -40,8 +37,8 @@ import net.psforever.services.RemoverActor import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.types.{CapacitorStateType, ChatMessageType, Cosmetic, ExoSuitType, PlanetSideEmpire, PlanetSideGUID, Vector3} -import scodec.bits.ByteVector +import scala.concurrent.duration._ import scala.util.Success object GeneralLogic { @@ -81,28 +78,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex sessionLogic.persist() sessionLogic.turnCounterFunc(avatarGuid) sessionLogic.updateBlockMap(player, pos) - //below half health, full heal - val maxHealth = player.MaxHealth.toLong - if (player.Health < maxHealth) { - player.Health = maxHealth.toInt - player.LogActivity(player.ClearHistory().head) - sendResponse(PlanetsideAttributeMessage(avatarGuid, 0, maxHealth)) - continent.AvatarEvents ! AvatarServiceMessage(continent.id, AvatarAction.PlanetsideAttribute(avatarGuid, 0, maxHealth)) - } - //below half stamina, full stamina - val avatar = player.avatar - val maxStamina = avatar.maxStamina - if (avatar.stamina < maxStamina) { - avatarActor ! AvatarActor.RestoreStamina(maxStamina) - sendResponse(PlanetsideAttributeMessage(player.GUID, 2, maxStamina.toLong)) - } - //below half armor, full armor - val maxArmor = player.MaxArmor.toLong - if (player.Armor < maxArmor) { - player.Armor = maxArmor.toInt - sendResponse(PlanetsideAttributeMessage(avatarGuid, 4, maxArmor)) - continent.AvatarEvents ! AvatarServiceMessage(continent.id, AvatarAction.PlanetsideAttribute(avatarGuid, 4, maxArmor)) - } + topOffHealthOfPlayer() //expected val isMoving = WorldEntity.isMoving(vel) val isMovingPlus = isMoving || isJumping || jumpThrust @@ -559,20 +535,19 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex v.BailProtection = false case (CollisionIs.OfAircraft, Some(v: Vehicle)) if v.Definition.CanFly && v.Seats(0).occupant.contains(player) => () - case (CollisionIs.BetweenThings, Some(field: ForceDomePhysics)) /*if field.Energized*/ => - val target = sessionLogic - .vehicles - .findLocalVehicle - .getOrElse(player) - target.Actor ! Vitality.Damage( - DamageInteraction( - PlayerSource(player), - ForceDomeExposure(SourceEntry(field)), - player.Position - ).calculate() - ) - target.BailProtection = false - player.BailProtection = false + case (CollisionIs.BetweenThings, Some(v: Vehicle)) => + v.Actor ! Vehicle.Deconstruct(Some(1 millisecond)) + continent.GUID(t) match { + case Some(_: ForceDomePhysics) => + player.Actor ! Player.Die() + case _ => () + } + case (CollisionIs.BetweenThings, Some(_: Player)) => + continent.GUID(t) match { + case Some(_: ForceDomePhysics) => + player.Actor ! Player.Die() + case _ => () + } case (CollisionIs.BetweenThings, _) => log.warn(s"GenericCollision: CollisionIs.BetweenThings detected - no handling case for obj id:${t.guid}") case _ => () @@ -823,4 +798,16 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex player.CapacitorState = CapacitorStateType.Idle } } + + def topOffHealthOfPlayer(): Unit = { + //below half health, full heal + CustomerServiceRepresentativeMode.topOffHealthOfPlayer(sessionLogic, player) + //below half stamina, full stamina + val avatar = player.avatar + val maxStamina = avatar.maxStamina + if (avatar.stamina < maxStamina) { + avatarActor ! AvatarActor.RestoreStamina(maxStamina) + sendResponse(PlanetsideAttributeMessage(player.GUID, 2, maxStamina.toLong)) + } + } } diff --git a/src/main/scala/net/psforever/actors/session/csr/VehicleLogic.scala b/src/main/scala/net/psforever/actors/session/csr/VehicleLogic.scala index bc02a8f55..6870f3c12 100644 --- a/src/main/scala/net/psforever/actors/session/csr/VehicleLogic.scala +++ b/src/main/scala/net/psforever/actors/session/csr/VehicleLogic.scala @@ -5,17 +5,15 @@ import akka.actor.{ActorContext, typed} import net.psforever.actors.session.AvatarActor import net.psforever.actors.session.support.{SessionData, VehicleFunctions, VehicleOperations} import net.psforever.objects.serverobject.PlanetSideServerObject -import net.psforever.objects.{PlanetSideGameObject, Player, Vehicle, Vehicles} +import net.psforever.objects.{PlanetSideGameObject, Vehicle, Vehicles} import net.psforever.objects.serverobject.deploy.Deployment import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.vehicles.control.BfrFlight -import net.psforever.objects.vital.Vitality import net.psforever.objects.zones.Zone import net.psforever.objects.zones.interaction.InteractsWithZone -import net.psforever.packet.game.{ChildObjectStateMessage, DeployRequestMessage, FrameVehicleStateMessage, PlanetsideAttributeMessage, VehicleStateMessage, VehicleSubStateMessage} -import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} +import net.psforever.packet.game.{ChildObjectStateMessage, DeployRequestMessage, FrameVehicleStateMessage, VehicleStateMessage, VehicleSubStateMessage} import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} -import net.psforever.types.{DriveState, PlanetSideGUID, Vector3} +import net.psforever.types.{DriveState, Vector3} object VehicleLogic { def apply(ops: VehicleOperations): VehicleLogic = { @@ -51,8 +49,8 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex sessionLogic.zoning.spawn.tryQueuedActivity(vel) sessionLogic.persist() sessionLogic.turnCounterFunc(player.GUID) - topOffHealthOfPlayer() - topOffHealth(obj) + CustomerServiceRepresentativeMode.topOffHealthOfPlayer(sessionLogic, player) + CustomerServiceRepresentativeMode.topOffHealth(sessionLogic, obj) val (position, angle, velocity, notMountedState) = continent.GUID(obj.MountedIn) match { case Some(v: Vehicle) => (pos, v.Orientation - Vector3.z(value = 90f) * Vehicles.CargoOrientation(obj).toFloat, v.Velocity, false) @@ -134,8 +132,8 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex sessionLogic.zoning.spawn.tryQueuedActivity(vel) sessionLogic.persist() sessionLogic.turnCounterFunc(player.GUID) - topOffHealthOfPlayer() - topOffHealth(obj) + CustomerServiceRepresentativeMode.topOffHealthOfPlayer(sessionLogic, player) + CustomerServiceRepresentativeMode.topOffHealth(sessionLogic, obj) val (position, angle, velocity, notMountedState) = continent.GUID(obj.MountedIn) match { case Some(v: Vehicle) => (pos, v.Orientation - Vector3.z(value = 90f) * Vehicles.CargoOrientation(obj).toFloat, v.Velocity, false) @@ -217,8 +215,8 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex sessionLogic.zoning.spawn.tryQueuedActivity(player.Velocity) sessionLogic.persist() sessionLogic.turnCounterFunc(player.GUID) - topOffHealthOfPlayer() - topOffHealth(entity) + CustomerServiceRepresentativeMode.topOffHealthOfPlayer(sessionLogic, player) + CustomerServiceRepresentativeMode.topOffHealth(sessionLogic, entity) sessionLogic.squad.updateSquad() case _ => //we can't disprove that COSM is our primary upstream packet, it's just that we may be missing some details sessionLogic.zoning.spawn.tryQueuedActivity(player.Velocity) @@ -336,56 +334,4 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex ) } } - - private def topOffHealth(obj: PlanetSideGameObject with Vitality): Unit = { - obj match { - case _: Player => topOffHealthOfPlayer() - case v: Vehicle => topOffHealthOfVehicle(v) - case o: PlanetSideGameObject with Vitality => topOffHealthOfGeneric(o) - case _ => () - } - } - - private def topOffHealthOfPlayer(): Unit = { - //driver below half health, full heal - val maxHealthOfPlayer = player.MaxHealth.toLong - if (player.Health < maxHealthOfPlayer * 0.5f) { - player.Health = maxHealthOfPlayer.toInt - player.LogActivity(player.ClearHistory().head) - sendResponse(PlanetsideAttributeMessage(player.GUID, 0, maxHealthOfPlayer)) - continent.AvatarEvents ! AvatarServiceMessage(sessionLogic.zoning.zoneChannel, AvatarAction.PlanetsideAttribute(player.GUID, 0, maxHealthOfPlayer)) - } - } - - private def topOffHealthOfVehicle(vehicle: Vehicle): Unit = { - topOffHealthOfPlayer() - topOffHealthOfGeneric(vehicle) - //vehicle shields below half, full shields - val maxShieldsOfVehicle = vehicle.MaxShields.toLong - val shieldsUi = vehicle.Definition.shieldUiAttribute - if (vehicle.Shields < maxShieldsOfVehicle) { - val guid = vehicle.GUID - vehicle.Shields = maxShieldsOfVehicle.toInt - sendResponse(PlanetsideAttributeMessage(guid, shieldsUi, maxShieldsOfVehicle)) - continent.VehicleEvents ! VehicleServiceMessage( - continent.id, - VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), guid, shieldsUi, maxShieldsOfVehicle) - ) - } - } - - private def topOffHealthOfGeneric(obj: PlanetSideGameObject with Vitality): Unit = { - topOffHealthOfPlayer() - //vehicle below half health, full heal - val guid = obj.GUID - val maxHealthOf = obj.MaxHealth.toLong - if (obj.Health < maxHealthOf) { - obj.Health = maxHealthOf.toInt - sendResponse(PlanetsideAttributeMessage(guid, 0, maxHealthOf)) - continent.VehicleEvents ! VehicleServiceMessage( - continent.id, - VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), guid, 0, maxHealthOf) - ) - } - } } diff --git a/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala b/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala index 1db6ea648..823d09923 100644 --- a/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala @@ -16,6 +16,7 @@ import net.psforever.objects.inventory.Container import net.psforever.objects.serverobject.{PlanetSideServerObject, ServerObject} import net.psforever.objects.serverobject.affinity.FactionAffinity import net.psforever.objects.serverobject.containable.Containable +import net.psforever.objects.serverobject.damage.Damageable import net.psforever.objects.serverobject.dome.ForceDomePhysics import net.psforever.objects.serverobject.doors.Door import net.psforever.objects.serverobject.generator.Generator @@ -23,6 +24,7 @@ import net.psforever.objects.serverobject.interior.Sidedness.OutsideOf import net.psforever.objects.serverobject.llu.CaptureFlag import net.psforever.objects.serverobject.locks.IFFLock import net.psforever.objects.serverobject.mblocker.Locker +import net.psforever.objects.serverobject.mount.MountableEntity import net.psforever.objects.serverobject.resourcesilo.ResourceSilo import net.psforever.objects.serverobject.structures.WarpGate import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal @@ -637,25 +639,15 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex case (CollisionIs.OfAircraft, out @ Some(v: Vehicle)) if v.Definition.CanFly && v.Seats(0).occupant.contains(player) => (out, sessionLogic.validObject(t, decorator = "GenericCollision/Aircraft"), false, pv) - case (CollisionIs.BetweenThings, Some(field: ForceDomePhysics)) /*if field.Energized*/ => - val target = sessionLogic - .vehicles - .findLocalVehicle - .getOrElse(player) - target.Actor ! Vitality.Damage( - DamageInteraction( - PlayerSource(player), - ForceDomeExposure(SourceEntry(field)), - player.Position - ).calculate() - ) + case (CollisionIs.BetweenThings, out @ Some(target: PlanetSideServerObject with MountableEntity)) => target.BailProtection = false player.BailProtection = false + (out, sessionLogic.validObject(t, decorator = "GenericCollision/Surface"), false, pv) + case (_, Some(obj)) => + log.error(s"GenericCollision: $ctype detected: no handling case for ${obj.Definition.Name}") (None, None, false, Vector3.Zero) - case (CollisionIs.BetweenThings, _) => - log.warn("GenericCollision: CollisionIs.BetweenThings detected - no handling case") - (None, None, false, Vector3.Zero) - case _ => + case (_, None) => + log.error(s"GenericCollision: $ctype detected: no entity detected as 'Primary'") (None, None, false, Vector3.Zero) } val curr = System.currentTimeMillis() @@ -677,6 +669,16 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex } } + case (Some(us: PlanetSideServerObject with Vitality with FactionAffinity), _, Some(field: ForceDomePhysics)) => + us.Actor ! Damageable.MakeVulnerable + us.Actor ! Vitality.Damage( + DamageInteraction( + PlayerSource(player), + ForceDomeExposure(SourceEntry(field)), + player.Position + ).calculate() + ) + case (Some(us: Vehicle), _, Some(victim: SensorDeployable)) => collisionBetweenVehicleAndFragileDeployable(us, ppos, victim, tpos, velocity - tv, fallHeight, curr) diff --git a/src/main/scala/net/psforever/actors/session/spectator/GeneralLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/GeneralLogic.scala index 8c332585a..0987bfd1c 100644 --- a/src/main/scala/net/psforever/actors/session/spectator/GeneralLogic.scala +++ b/src/main/scala/net/psforever/actors/session/spectator/GeneralLogic.scala @@ -9,15 +9,18 @@ import net.psforever.objects.avatar.{Avatar, Implant} import net.psforever.objects.ballistics.Projectile import net.psforever.objects.definition.{BasicDefinition, KitDefinition, SpecialExoSuitDefinition} import net.psforever.objects.serverobject.containable.Containable +import net.psforever.objects.serverobject.dome.ForceDomePhysics import net.psforever.objects.serverobject.doors.Door import net.psforever.objects.vehicles.Utility import net.psforever.objects.zones.ZoneProjectile import net.psforever.packet.PlanetSideGamePacket -import net.psforever.packet.game.{ActionCancelMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestMessage, ConnectToWorldRequestMessage, CreateShortcutMessage, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, ImplantAction, InvalidTerrainMessage, LootItemMessage, MoveItemMessage, ObjectDetectedMessage, ObjectHeldMessage, OutfitMembershipRequest, OutfitMembershipResponse, OutfitRequest, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, RequestDestroyMessage, TargetingImplantRequest, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostRequest, ZipLineMessage} +import net.psforever.packet.game.{ActionCancelMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestMessage, CollisionIs, ConnectToWorldRequestMessage, CreateShortcutMessage, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, ImplantAction, InvalidTerrainMessage, LootItemMessage, MoveItemMessage, ObjectDetectedMessage, ObjectHeldMessage, OutfitMembershipRequest, OutfitMembershipResponse, OutfitRequest, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, RequestDestroyMessage, TargetingImplantRequest, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostRequest, ZipLineMessage} import net.psforever.services.account.AccountPersistenceService import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.types.{ExoSuitType, Vector3} +import scala.concurrent.duration.DurationInt + object GeneralLogic { def apply(ops: GeneralOperations): GeneralLogic = { new GeneralLogic(ops, ops.context) @@ -283,7 +286,34 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex } } - def handleGenericCollision(pkt: GenericCollisionMsg): Unit = { /* intentionally blank */ } + def handleGenericCollision(pkt: GenericCollisionMsg): Unit = { + player.BailProtection = false + val GenericCollisionMsg(ctype, p, _, _, pv, t, _, _, _, _, _, _) = pkt + if (pv.z * pv.z >= (pv.x * pv.x + pv.y * pv.y) * 0.5f) { + if (ops.heightTrend) { + ops.heightHistory = ops.heightLast + } + else { + ops.heightLast = ops.heightHistory + } + } + (ctype, sessionLogic.validObject(p, decorator = "GenericCollision/Primary")) match { + case (CollisionIs.BetweenThings, Some(v: Vehicle)) => + v.Actor ! Vehicle.Deconstruct(Some(1 millisecond)) + continent.GUID(t) match { + case Some(_: ForceDomePhysics) => + player.Actor ! Player.Die() + case _ => () + } + case (CollisionIs.BetweenThings, Some(_: Player)) => + continent.GUID(t) match { + case Some(_: ForceDomePhysics) => + player.Actor ! Player.Die() + case _ => () + } + case _ => () + } + } def handleAvatarFirstTimeEvent(pkt: AvatarFirstTimeEventMessage): Unit = { /* intentionally blank */ } 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 c2365a224..3b6e30605 100644 --- a/src/main/scala/net/psforever/objects/avatar/interaction/InteractWithForceDomeProtection.scala +++ b/src/main/scala/net/psforever/objects/avatar/interaction/InteractWithForceDomeProtection.scala @@ -40,7 +40,7 @@ class InteractWithForceDomeProtection case Some(dome) if dome.Perimeter.isEmpty || target.Zone != dome.Zone || - !ForceDomeControl.TargetUnderForceDome(dome.Perimeter)(target, dome, maxDistance = 0f) => + !ForceDomeControl.TargetUnderForceDome(dome.Perimeter)(dome, target, maxDistance = 0f) => resetInteraction(target) case Some(_) => () //no action @@ -69,7 +69,7 @@ class InteractWithForceDomeProtection case _ => None } .find { dome => - ForceDomeControl.TargetUnderForceDome(dome.Perimeter)(target, dome, maxDistance = 0f) + ForceDomeControl.TargetUnderForceDome(dome.Perimeter)(dome, target, maxDistance = 0f) } .map { dome => applyProtection(target, dome) diff --git a/src/main/scala/net/psforever/objects/equipment/ArmorSiphonBehavior.scala b/src/main/scala/net/psforever/objects/equipment/ArmorSiphonBehavior.scala index 9c153e42b..5547f36fd 100644 --- a/src/main/scala/net/psforever/objects/equipment/ArmorSiphonBehavior.scala +++ b/src/main/scala/net/psforever/objects/equipment/ArmorSiphonBehavior.scala @@ -43,7 +43,7 @@ object ArmorSiphonBehavior { val after = item.Discharge() if (before > after) { v.Actor ! ArmorSiphonBehavior.Recharge(iguid) - PerformDamage( + PerformDamageIfVulnerable( obj, DamageInteraction( VehicleSource(obj), diff --git a/src/main/scala/net/psforever/objects/serverobject/damage/Damageable.scala b/src/main/scala/net/psforever/objects/serverobject/damage/Damageable.scala index 976ea1b2c..65d94d0d4 100644 --- a/src/main/scala/net/psforever/objects/serverobject/damage/Damageable.scala +++ b/src/main/scala/net/psforever/objects/serverobject/damage/Damageable.scala @@ -38,10 +38,7 @@ trait Damageable { isVulnerable = false case Vitality.Damage(damage_func) => - val obj = DamageableObject - if (isVulnerable && obj.CanDamage) { - PerformDamage(obj, damage_func) - } + PerformDamageIfVulnerable(DamageableObject, damage_func) } /** a duplicate of the core implementation for the default mixin hook, for use in overriding */ @@ -53,10 +50,20 @@ trait Damageable { isVulnerable = false case Vitality.Damage(damage_func) => - val obj = DamageableObject - if (isVulnerable && obj.CanDamage) { - PerformDamage(obj, damage_func) - } + PerformDamageIfVulnerable(DamageableObject, damage_func) + } + + /** + * Assess if the target is vulnerable to damage. + * If so, attempt damage calculations. + * @see `ResolutionCalculations.Output` + * @param obj the entity to be damaged + * @param applyDamageTo the function that applies the damage to the target in a target-tailored fashion + */ + def PerformDamageIfVulnerable(obj: Damageable.Target, applyDamageTo: ResolutionCalculations.Output): Unit = { + if (isVulnerable && obj.CanDamage) { + PerformDamage(obj, applyDamageTo) + } } /** 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 fa9a8553a..e959dd836 100644 --- a/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala @@ -479,6 +479,8 @@ class ForceDomeControl(dome: ForceDomePhysics) //dome activating context.system.scheduler.scheduleOnce(delay = 1500 milliseconds, self, ForceDomeControl.Purge) context.system.scheduler.scheduleOnce(delay = 4000 milliseconds, self, ForceDomeControl.ApplyProtection) + } else if (oldState && !newState) { + context.system.scheduler.scheduleOnce(delay = 1500 milliseconds, self, ForceDomeControl.RemoveProtection) } newState case Some(state) diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/auto/AffectedByAutomaticTurretFire.scala b/src/main/scala/net/psforever/objects/serverobject/turret/auto/AffectedByAutomaticTurretFire.scala index 7485c3a47..d2b4ecab2 100644 --- a/src/main/scala/net/psforever/objects/serverobject/turret/auto/AffectedByAutomaticTurretFire.scala +++ b/src/main/scala/net/psforever/objects/serverobject/turret/auto/AffectedByAutomaticTurretFire.scala @@ -60,7 +60,7 @@ trait AffectedByAutomaticTurretFire extends Damageable { ProjectileReason(DamageResolution.Hit, modProjectile, target.DamageModel), correctedTargetPosition ) - PerformDamage(target, resolvedProjectile.calculate()) + PerformDamageIfVulnerable(target, resolvedProjectile.calculate()) } } }