diff --git a/common/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala b/common/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala index 9199f097..cbc58a62 100644 --- a/common/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala +++ b/common/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala @@ -2,6 +2,7 @@ package net.psforever.objects.equipment import net.psforever.objects.PlanetSideGameObject +import net.psforever.objects.ballistics.ResolvedProjectile import net.psforever.objects.serverobject.terminals.TargetValidation import scala.collection.mutable @@ -19,6 +20,12 @@ trait JammableUnit { object JammableUnit { final case class Jammer() + + final case class Jammered(cause : ResolvedProjectile) + + final case class ClearJammeredSound() + + final case class ClearJammeredStatus() } trait JammingUnit { diff --git a/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala index 906e49b5..2d79b22e 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala @@ -1,10 +1,24 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.turret -import akka.actor.Actor +import akka.actor.{Actor, Cancellable} +import net.psforever.objects.{DefaultCancellable, Tool} +import net.psforever.objects.ballistics.ResolvedProjectile +import net.psforever.objects.equipment.{JammableUnit, JammingUnit} +import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior} import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} +import net.psforever.objects.vehicles.MountedWeapons import net.psforever.objects.vital.Vitality +import net.psforever.objects.zones.Zone +import net.psforever.packet.game.PlanetSideGUID +import net.psforever.types.Vector3 +import services.Service +import services.avatar.{AvatarAction, AvatarServiceMessage} +import services.vehicle.{VehicleAction, VehicleServiceMessage} +import services.vehicle.support.TurretUpgrader + +import scala.concurrent.duration._ /** * An `Actor` that handles messages being dispatched to a specific `MannedTurret`.
@@ -17,6 +31,9 @@ import net.psforever.objects.vital.Vitality class FacilityTurretControl(turret : FacilityTurret) extends Actor with FactionAffinityBehavior.Check with MountableBehavior.Dismount { + var jammeredSoundTimer : Cancellable = DefaultCancellable.obj + var jammeredStatusTimer : Cancellable = DefaultCancellable.obj + def MountableObject = turret //do not add type! def FactionObject : FactionAffinity = turret @@ -45,12 +62,149 @@ class FacilityTurretControl(turret : FacilityTurret) extends Actor val cause = damage_func(turret) val health = turret.Health val damageToHealth = originalHealth - health - val name = turret.Actor.toString - val slashPoint = name.lastIndexOf("/") - org.log4s.getLogger("DamageResolution").info(s"${name.substring(slashPoint+1, name.length-1)}: BEFORE=$originalHealth, AFTER=$health, CHANGE=$damageToHealth") - sender ! Vitality.DamageResolution(turret, cause) + FacilityTurretControl.HandleDamageResolution(turret, cause, damageToHealth) + if(damageToHealth > 0) { + val name = turret.Actor.toString + val slashPoint = name.lastIndexOf("/") + org.log4s.getLogger("DamageResolution").info(s"${name.substring(slashPoint + 1, name.length - 1)}: BEFORE=$originalHealth, AFTER=$health, CHANGE=$damageToHealth") + } } + case JammableUnit.Jammered(cause) => + TryJammerWithProjectile(turret, cause) + + case JammableUnit.ClearJammeredSound() => + CancelJammeredSound(turret) + + case JammableUnit.ClearJammeredStatus() => + StopJammeredStatus(turret) + case _ => ; } + + def TryJammerWithProjectile(target : FacilityTurret, cause : ResolvedProjectile) : Unit = { + val radius = cause.projectile.profile.DamageRadius + JammingUnit.FindJammerDuration(cause.projectile.profile, target) match { + case Some(dur) if Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius => + //jammered sound + target.Zone.VehicleEvents ! VehicleServiceMessage(target.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 54, 1)) + import scala.concurrent.ExecutionContext.Implicits.global + jammeredSoundTimer = context.system.scheduler.scheduleOnce(30 seconds, self, JammableUnit.ClearJammeredSound()) + //jammered status + StartJammeredStatus(target, dur) + case _ => ; + } + } + + def StartJammeredStatus(target : PlanetSideServerObject with MountedWeapons, dur : Int) : Unit = { + jammeredStatusTimer.cancel + FacilityTurretControl.JammeredStatus(target, 1) + import scala.concurrent.ExecutionContext.Implicits.global + jammeredStatusTimer = context.system.scheduler.scheduleOnce(dur milliseconds, self, JammableUnit.ClearJammeredStatus()) + } + + def StopJammeredStatus(target : PlanetSideServerObject with MountedWeapons) : Boolean = { + FacilityTurretControl.JammeredStatus(target, 0) + jammeredStatusTimer.cancel + } + + def CancelJammeredSound(target : PlanetSideServerObject) : Unit = { + jammeredSoundTimer.cancel + target.Zone.VehicleEvents ! VehicleServiceMessage(target.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 54, 0)) + } +} + +object FacilityTurretControl { + def HandleDamageResolution(target : FacilityTurret, cause : ResolvedProjectile, damage : Int) : Unit = { + val zone = target.Zone + val targetGUID = target.GUID + val playerGUID = target.Zone.LivePlayers.find { p => cause.projectile.owner.Name.equals(p.Name) } match { + case Some(player) => player.GUID + case _ => targetGUID + } + val continentId = zone.Id + if(target.Health > 1) { + //alert occupants to damage source + if(damage > 0) { + zone.Activity ! Zone.HotSpot.Activity(cause.target, cause.projectile.owner, cause.hit_pos) + //alert occupants to damage source + HandleDamageAwareness(target, playerGUID, cause) + } + if(cause.projectile.profile.JammerProjectile) { + target.Actor ! JammableUnit.Jammered(cause) + } + } + else { + //alert to vehicle death (hence, occupants' deaths) + HandleDestructionAwareness(target, playerGUID, cause) + } + zone.VehicleEvents ! VehicleServiceMessage(continentId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health)) + } + + /** + * na + * @param target na + * @param attribution na + * @param lastShot na + */ + def HandleDamageAwareness(target : FacilityTurret, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = { + val zone = target.Zone + val zoneId = zone.Id + //alert occupants to damage source + target.Seats.values.filter(seat => { + seat.isOccupied && seat.Occupant.get.isAlive + }).foreach(seat => { + val tplayer = seat.Occupant.get + zone.AvatarEvents ! AvatarServiceMessage(zoneId, AvatarAction.HitHint(attribution, tplayer.GUID)) + }) + } + + /** + * na + * @param target na + * @param attribution na + * @param lastShot na + */ + def HandleDestructionAwareness(target : FacilityTurret, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = { + target.Actor ! JammableUnit.ClearJammeredSound() + target.Actor ! JammableUnit.ClearJammeredStatus() + val zone = target.Zone + val zoneId = zone.Id + target.Seats.values.filter(seat => { + seat.isOccupied && seat.Occupant.get.isAlive + }).foreach(seat => { + val tplayer = seat.Occupant.get + val tplayerGUID = tplayer.GUID + zone.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID)) + zone.AvatarEvents ! AvatarServiceMessage(zoneId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self + }) + //turret wreckage has no weapons + // target.Weapons.values + // .filter { + // _.Equipment.nonEmpty + // } + // .foreach(slot => { + // val wep = slot.Equipment.get + // zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID)) + // }) + // zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.Destroy(targetGUID, playerGUID, playerGUID, player.Position)) + target.Health = 1 //TODO turret "death" at 0, as is proper + zone.VehicleEvents ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 0, target.Health)) //TODO not necessary + if(target.Upgrade != TurretUpgrade.None) { + zone.VehicleEvents ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.ClearSpecific(List(target), zone)) + zone.VehicleEvents ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(target, zone, TurretUpgrade.None)) + } + } + + def JammeredStatus(target : PlanetSideServerObject with MountedWeapons, statusCode : Int) : Unit = { + val zone = target.Zone + val zoneId = zone.Id + zone.VehicleEvents ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 27, statusCode)) + target.Weapons.values + .map { _.Equipment } + .collect { + case Some(item : Tool) => + zone.VehicleEvents ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, item.GUID, 27, statusCode)) + } + } } diff --git a/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala b/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala index 765ff003..cb091b58 100644 --- a/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala +++ b/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala @@ -4,7 +4,8 @@ package net.psforever.objects.vehicles import akka.actor.{Actor, ActorRef, Cancellable} import net.psforever.objects.{DefaultCancellable, GlobalDefinitions, Tool, Vehicle} import net.psforever.objects.ballistics.{ResolvedProjectile, VehicleSource} -import net.psforever.objects.equipment.JammingUnit +import net.psforever.objects.equipment.{JammableUnit, JammingUnit} +import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior} import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} import net.psforever.objects.serverobject.deploy.{Deployment, DeploymentBehavior} @@ -90,7 +91,7 @@ class VehicleControl(vehicle : Vehicle) extends Actor val shields = vehicle.Shields val damageToHealth = originalHealth - health val damageToShields = originalShields - shields - VehicleControl.HandleVehicleDamageResolution(vehicle, cause, damageToHealth + damageToShields) + VehicleControl.HandleDamageResolution(vehicle, cause, damageToHealth + damageToShields) if(damageToHealth > 0 || damageToShields > 0) { val name = vehicle.Actor.toString val slashPoint = name.lastIndexOf("/") @@ -115,13 +116,13 @@ class VehicleControl(vehicle : Vehicle) extends Actor } sender ! FactionAffinity.AssertFactionAffinity(vehicle, faction) - case VehicleControl.Jammered(cause) => - TryJammerVehicleWithProjectile(vehicle, cause) + case JammableUnit.Jammered(cause) => + TryJammerWithProjectile(vehicle, cause) - case VehicleControl.ClearJammeredSound() => + case JammableUnit.ClearJammeredSound() => CancelJammeredSound(vehicle) - case VehicleControl.ClearJammeredStatus() => + case JammableUnit.ClearJammeredStatus() => StopJammeredStatus(vehicle) case Vehicle.PrepareForDeletion => @@ -133,10 +134,10 @@ class VehicleControl(vehicle : Vehicle) extends Actor def Disabled : Receive = checkBehavior .orElse(dismountBehavior) .orElse { - case VehicleControl.ClearJammeredSound() => + case JammableUnit.ClearJammeredSound() => CancelJammeredSound(vehicle) - case VehicleControl.ClearJammeredStatus() => + case JammableUnit.ClearJammeredStatus() => StopJammeredStatus(vehicle) case Vehicle.Reactivate => @@ -145,49 +146,40 @@ class VehicleControl(vehicle : Vehicle) extends Actor case _ => ; } - def TryJammerVehicleWithProjectile(target : Vehicle, cause : ResolvedProjectile) : Unit = { + def TryJammerWithProjectile(target : Vehicle, cause : ResolvedProjectile) : Unit = { val radius = cause.projectile.profile.DamageRadius JammingUnit.FindJammerDuration(cause.projectile.profile, target) match { case Some(dur) if Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius => //jammered sound + jammeredSoundTimer.cancel target.Zone.VehicleEvents ! VehicleServiceMessage(target.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 54, 1)) import scala.concurrent.ExecutionContext.Implicits.global - jammeredSoundTimer = context.system.scheduler.scheduleOnce(30 seconds, self, VehicleControl.ClearJammeredSound()) + jammeredSoundTimer = context.system.scheduler.scheduleOnce(30 seconds, self, JammableUnit.ClearJammeredSound()) //jammered status StartJammeredStatus(target, dur) case _ => ; } } - def StartJammeredStatus(target : Vehicle, dur : Int) : Boolean = { - if(jammeredStatusTimer.isCancelled) { - VehicleControl.JammeredStatus(target, 1) - import scala.concurrent.ExecutionContext.Implicits.global - jammeredStatusTimer = context.system.scheduler.scheduleOnce(dur milliseconds, self, VehicleControl.ClearJammeredStatus()) - true - } - else { - false - } + def StartJammeredStatus(target : PlanetSideServerObject with MountedWeapons, dur : Int) : Unit = { + jammeredStatusTimer.cancel + VehicleControl.JammeredStatus(target, 1) + import scala.concurrent.ExecutionContext.Implicits.global + jammeredStatusTimer = context.system.scheduler.scheduleOnce(dur milliseconds, self, JammableUnit.ClearJammeredStatus()) } - def StopJammeredStatus(target : Vehicle) : Boolean = { + def StopJammeredStatus(target : PlanetSideServerObject with MountedWeapons) : Boolean = { VehicleControl.JammeredStatus(target, 0) jammeredStatusTimer.cancel } - def CancelJammeredSound(target : Vehicle) : Unit = { + def CancelJammeredSound(target : PlanetSideServerObject) : Unit = { jammeredSoundTimer.cancel target.Zone.VehicleEvents ! VehicleServiceMessage(target.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 54, 0)) } } object VehicleControl { - private final case class Jammered(cause : ResolvedProjectile) - - private final case class ClearJammeredSound() - - private final case class ClearJammeredStatus() import net.psforever.objects.vital.{DamageFromProjectile, VehicleShieldCharge, VitalsActivity} import scala.concurrent.duration._ @@ -211,29 +203,30 @@ object VehicleControl { * na * @param target na */ - def HandleVehicleDamageResolution(target : Vehicle, cause : ResolvedProjectile, damage : Int) : Unit = { + def HandleDamageResolution(target : Vehicle, cause : ResolvedProjectile, damage : Int) : Unit = { + val zone = target.Zone val targetGUID = target.GUID - val playerGUID = target.Zone.LivePlayers.find { p => cause.projectile.owner.Name.equals(p.Name) } match { + val playerGUID = zone.LivePlayers.find { p => cause.projectile.owner.Name.equals(p.Name) } match { case Some(player) => player.GUID case _ => PlanetSideGUID(0) } if(target.Health > 0) { //activity on map if(damage > 0) { - target.Zone.Activity ! Zone.HotSpot.Activity(cause.target, cause.projectile.owner, cause.hit_pos) + zone.Activity ! Zone.HotSpot.Activity(cause.target, cause.projectile.owner, cause.hit_pos) //alert occupants to damage source - HandleVehicleDamageAwareness(target, playerGUID, cause) + HandleDamageAwareness(target, playerGUID, cause) } if(cause.projectile.profile.JammerProjectile) { - target.Actor ! VehicleControl.Jammered(cause) + target.Actor ! JammableUnit.Jammered(cause) } } else { //alert to vehicle death (hence, occupants' deaths) - HandleVehicleDestructionAwareness(target, playerGUID, cause) + HandleDestructionAwareness(target, playerGUID, cause) } - target.Zone.VehicleEvents ! VehicleServiceMessage(target.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health)) - target.Zone.VehicleEvents ! VehicleServiceMessage(s"${target.Actor}", VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 68, target.Shields)) + zone.VehicleEvents ! VehicleServiceMessage(zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health)) + zone.VehicleEvents ! VehicleServiceMessage(s"${target.Actor}", VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 68, target.Shields)) } /** @@ -242,13 +235,14 @@ object VehicleControl { * @param attribution na * @param lastShot na */ - def HandleVehicleDamageAwareness(target : Vehicle, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = { + def HandleDamageAwareness(target : Vehicle, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = { + val zone = target.Zone //alert occupants to damage source target.Seats.values.filter(seat => { seat.isOccupied && seat.Occupant.get.isAlive }).foreach(seat => { val tplayer = seat.Occupant.get - target.Zone.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(attribution, tplayer.GUID)) + zone.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(attribution, tplayer.GUID)) }) //alert cargo occupants to damage source target.CargoHolds.values.foreach(hold => { @@ -257,7 +251,7 @@ object VehicleControl { cargo.Health = 0 cargo.Shields = 0 cargo.History(lastShot) - HandleVehicleDamageAwareness(cargo, attribution, lastShot) + HandleDamageAwareness(cargo, attribution, lastShot) case None => ; } }) @@ -269,16 +263,19 @@ object VehicleControl { * @param attribution na * @param lastShot na */ - def HandleVehicleDestructionAwareness(target : Vehicle, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = { - val continentId = target.Zone.Id + def HandleDestructionAwareness(target : Vehicle, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = { + target.Actor ! JammableUnit.ClearJammeredSound() + target.Actor ! JammableUnit.ClearJammeredStatus() + val zone = target.Zone + val continentId = zone.Id //alert to vehicle death (hence, occupants' deaths) target.Seats.values.filter(seat => { seat.isOccupied && seat.Occupant.get.isAlive }).foreach(seat => { val tplayer = seat.Occupant.get val tplayerGUID = tplayer.GUID - target.Zone.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID)) - target.Zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self + zone.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID)) + zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self }) //vehicle wreckage has no weapons target.Weapons.values @@ -287,7 +284,7 @@ object VehicleControl { } .foreach(slot => { val wep = slot.Equipment.get - target.Zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID)) + zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID)) }) target.CargoHolds.values.foreach(hold => { hold.Occupant match { @@ -296,7 +293,7 @@ object VehicleControl { cargo.Shields = 0 cargo.Position += Vector3.z(1) cargo.History(lastShot) //necessary to kill cargo vehicle occupants //TODO: collision damage - HandleVehicleDestructionAwareness(cargo, attribution, lastShot) //might cause redundant packets + HandleDestructionAwareness(cargo, attribution, lastShot) //might cause redundant packets case None => ; } }) @@ -305,22 +302,24 @@ object VehicleControl { target.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying) case GlobalDefinitions.router => target.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying) - VehicleService.BeforeUnloadVehicle(target, target.Zone) - target.Zone.LocalEvents ! LocalServiceMessage(target.Zone.Id, LocalAction.ToggleTeleportSystem(PlanetSideGUID(0), target, None)) + VehicleService.BeforeUnloadVehicle(target, zone) + zone.LocalEvents ! LocalServiceMessage(zone.Id, LocalAction.ToggleTeleportSystem(PlanetSideGUID(0), target, None)) case _ => ; } - target.Zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.Destroy(target.GUID, attribution, attribution, target.Position)) - target.Zone.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(target), target.Zone)) - target.Zone.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(target, target.Zone, Some(1 minute))) + zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.Destroy(target.GUID, attribution, attribution, target.Position)) + zone.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(target), zone)) + zone.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(target, zone, Some(1 minute))) } - def JammeredStatus(target : Vehicle, statusCode : Int) : Unit = { - target.Zone.VehicleEvents ! VehicleServiceMessage(target.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 27, statusCode)) + def JammeredStatus(target : PlanetSideServerObject with MountedWeapons, statusCode : Int) : Unit = { + val zone = target.Zone + val zoneId = zone.Id + zone.VehicleEvents ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 27, statusCode)) target.Weapons.values .map { _.Equipment } .collect { case Some(item : Tool) => - target.Zone.VehicleEvents ! VehicleServiceMessage(target.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, item.GUID, 27, statusCode)) + zone.VehicleEvents ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, item.GUID, 27, statusCode)) } } } diff --git a/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala b/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala index 014df10d..b09ffb41 100644 --- a/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala @@ -118,7 +118,7 @@ import scodec.codecs._ * `27 - PA_JAMMED - plays jammed buzzing sound`
* `28 - PA_IMPLANT_ACTIVE - Plays implant sounds. Valid values seem to be up to 20.`
* `29 - PA_VAPORIZED - Visible ?! That's not the cloaked effect, Maybe for spectator mode ?. Value is 0 to visible, 1 to invisible.`
- * `31 - Looking for Squad info (marquee and ui):
+ * `31 - Looking for Squad info (marquee and ui):`
* ` - 0 is LFS`
* ` - 1 is LFSM (Looking for Squad Members)`
* ` - n is the supplemental squad identifier number; same as "LFS;" for the leader, sets "LFSM" after the first manual flagging`
diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index c551b170..6db3e6d7 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -1143,9 +1143,6 @@ class WorldSessionActor extends Actor with MDCContextAware { AnnounceDestroyDeployable(target, None) } - case Vitality.DamageResolution(target : FacilityTurret, _) => - HandleFacilityTurretDamageResolution(target) - case Vitality.DamageResolution(target : PlanetSideGameObject, _) => log.warn(s"Vital target ${target.Definition.Name} damage resolution not supported using this method") @@ -1335,16 +1332,18 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(PlanetsideAttributeMessage(player.GUID, 54, 1)) continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 54, 1)) import scala.concurrent.ExecutionContext.Implicits.global + jammeredSoundTimer.cancel jammeredSoundTimer = context.system.scheduler.scheduleOnce(30 seconds, self, ClearJammeredSound()) //jammered status skipStaminaRegenForTurns = 5 - jammeredEquipment = player.Holsters() + jammeredEquipment = (jammeredEquipment ++ player.Holsters() .map { _.Equipment } .collect { case Some(item) if item.Size != EquipmentSize.Melee => - sendResponse(PlanetsideAttributeMessage(item.GUID, 24, 1)) + sendResponse(PlanetsideAttributeMessage(item.GUID, 27, 1)) item.GUID - } + }).distinct + jammeredStatusTimer.cancel jammeredStatusTimer = context.system.scheduler.scheduleOnce(dur milliseconds, self, ClearJammeredStatus()) case _ => ; } @@ -2995,48 +2994,6 @@ class WorldSessionActor extends Actor with MDCContextAware { continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.PlanetsideAttribute(guid, 0, health)) } - def HandleFacilityTurretDamageResolution(target : FacilityTurret) : Unit = { - val targetGUID = target.GUID - val playerGUID = player.GUID - val continentId = continent.Id - val players = target.Seats.values.filter(seat => { - seat.isOccupied && seat.Occupant.get.isAlive - }) - if(target.Health > 1) { //TODO turret "death" at 0, as is proper - //alert occupants to damage source - players.foreach(seat => { - val tplayer = seat.Occupant.get - continent.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(playerGUID, tplayer.GUID)) - }) - } - else { - //alert to vehicle death (hence, occupants' deaths) - players.foreach(seat => { - val tplayer = seat.Occupant.get - val tplayerGUID = tplayer.GUID - continent.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID)) - continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self - }) - //turret wreckage has no weapons -// target.Weapons.values -// .filter { -// _.Equipment.nonEmpty -// } -// .foreach(slot => { -// val wep = slot.Equipment.get -// continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID)) -// }) -// continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.Destroy(targetGUID, playerGUID, playerGUID, player.Position)) - target.Health = 1 - continent.VehicleEvents ! VehicleServiceMessage(continentId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.MaxHealth)) //TODO not necessary - if(target.Upgrade != TurretUpgrade.None) { - continent.VehicleEvents ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.ClearSpecific(List(target), continent)) - continent.VehicleEvents ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(target, continent, TurretUpgrade.None)) - } - } - continent.VehicleEvents ! VehicleServiceMessage(continentId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health)) - } - /** * na * @param tplayer na @@ -4691,7 +4648,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } case msg @ UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType) => - log.info("UseItem: " + msg) + //log.info("UseItem: " + msg) // TODO: Not all fields in the response are identical to source in real packet logs (but seems to be ok) // TODO: Not all incoming UseItemMessage's respond with another UseItemMessage (i.e. doors only send out GenericObjectStateMsg) continent.GUID(object_guid) match { @@ -7844,10 +7801,8 @@ class WorldSessionActor extends Actor with MDCContextAware { * This is not a complete list but, for the purpose of enforcement, some pointers will be documented here. */ def PlayerActionsToCancel() : Unit = { - if(!jammeredSoundTimer.isCancelled) { - CancelJammeredSound() - } - jammeredStatusTimer.cancel + CancelJammeredSound() + CancelJammeredStatus() progressBarUpdate.cancel progressBarValue = None lastTerminalOrderFulfillment = true @@ -8571,14 +8526,14 @@ class WorldSessionActor extends Actor with MDCContextAware { //damage is synchronized on the target player's `WSA` (results distributed from there) continent.AvatarEvents ! AvatarServiceMessage(obj.Name, AvatarAction.Damage(player.GUID, obj, func)) case obj : Vehicle => - //damage is synchronized on the vehicle actor (results returned to and distributed from this `WSA`) + //damage is synchronized on the vehicle actor + obj.Actor ! Vitality.Damage(func) + case obj : FacilityTurret => + //damage is synchronized on the turret actor obj.Actor ! Vitality.Damage(func) case obj : Deployable => //damage is synchronized on `LSA` (results returned to and distributed from this `WSA`) continent.LocalEvents ! Vitality.DamageOn(obj, func) - case obj : FacilityTurret => - //damage is synchronized on the turret actor (results returned to and distributed from this `WSA`) - obj.Actor ! Vitality.Damage(func) case _ => ; } } @@ -10294,10 +10249,8 @@ class WorldSessionActor extends Actor with MDCContextAware { } def CancelJammeredStatus() : Unit = { - if(!jammeredSoundTimer.isCancelled) { - CancelJammeredSound() - } - jammeredEquipment.foreach { id => sendResponse(PlanetsideAttributeMessage(id, 24, 0)) } + jammeredStatusTimer.cancel + jammeredEquipment.foreach { id => sendResponse(PlanetsideAttributeMessage(id, 27, 0)) } jammeredEquipment = Nil }