diff --git a/common/src/main/scala/net/psforever/objects/Player.scala b/common/src/main/scala/net/psforever/objects/Player.scala
index a0c84a0b..08e7150a 100644
--- a/common/src/main/scala/net/psforever/objects/Player.scala
+++ b/common/src/main/scala/net/psforever/objects/Player.scala
@@ -3,8 +3,9 @@ package net.psforever.objects
import net.psforever.objects.avatar.LoadoutManager
import net.psforever.objects.definition.{AvatarDefinition, ExoSuitDefinition, SpecialExoSuitDefinition}
-import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot}
+import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot, JammableUnit}
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
+import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.vital.resistance.ResistanceProfile
import net.psforever.objects.vital.{DamageResistanceModel, Vitality}
@@ -16,11 +17,12 @@ import net.psforever.types._
import scala.annotation.tailrec
import scala.util.{Success, Try}
-class Player(private val core : Avatar) extends PlanetSideGameObject
+class Player(private val core : Avatar) extends PlanetSideServerObject
with FactionAffinity
with Vitality
with ResistanceProfile
with Container
+ with JammableUnit
with ZoneAware {
private var alive : Boolean = false
private var backpack : Boolean = false
diff --git a/common/src/main/scala/net/psforever/objects/Vehicle.scala b/common/src/main/scala/net/psforever/objects/Vehicle.scala
index 1330af04..a9adc2ba 100644
--- a/common/src/main/scala/net/psforever/objects/Vehicle.scala
+++ b/common/src/main/scala/net/psforever/objects/Vehicle.scala
@@ -3,7 +3,7 @@ package net.psforever.objects
import akka.actor.ActorRef
import net.psforever.objects.definition.VehicleDefinition
-import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot}
+import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot, JammableUnit}
import net.psforever.objects.inventory.{Container, GridInventory, InventoryTile}
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.PlanetSideServerObject
@@ -73,6 +73,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
with Vitality
with OwnableByPlayer
with StandardResistanceProfile
+ with JammableUnit
with Container {
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.TR
private var health : Int = 1
diff --git a/common/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala b/common/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala
new file mode 100644
index 00000000..6071b018
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala
@@ -0,0 +1,15 @@
+// Copyright (c) 2019 PSForever
+package net.psforever.objects.avatar
+
+import akka.actor.Actor
+import net.psforever.objects.Player
+
+/**
+ * na;
+ * stub for future development
+ */
+class PlayerControl(player : Player) extends Actor {
+ def receive : Receive = {
+ case _ => ;
+ }
+}
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 cbc58a62..a6c6705c 100644
--- a/common/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala
+++ b/common/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala
@@ -1,11 +1,19 @@
// Copyright (c) 2019 PSForever
package net.psforever.objects.equipment
-import net.psforever.objects.PlanetSideGameObject
+import akka.actor.{Actor, Cancellable}
+import net.psforever.objects.{DefaultCancellable, PlanetSideGameObject, Tool}
import net.psforever.objects.ballistics.ResolvedProjectile
+import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.terminals.TargetValidation
+import net.psforever.objects.vehicles.MountedWeapons
+import net.psforever.objects.zones.ZoneAware
+import net.psforever.types.Vector3
+import services.Service
+import services.vehicle.{VehicleAction, VehicleServiceMessage}
import scala.collection.mutable
+import scala.concurrent.duration._
trait JammableUnit {
private var jammed : Boolean = false
@@ -49,3 +57,104 @@ object JammingUnit {
targets.map { target => FindJammerDuration(jammer, target) }
}
}
+
+trait JammableBehavior {
+ _ : Actor =>
+ protected var jammeredSoundTimer : Cancellable = DefaultCancellable.obj
+ protected var jammeredStatusTimer : Cancellable = DefaultCancellable.obj
+
+ def JammableObject : PlanetSideServerObject with JammableUnit with ZoneAware
+
+ def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit
+
+ def StartJammeredSound(target : Any, dur : Int = 30000) : Unit = {
+ import scala.concurrent.ExecutionContext.Implicits.global
+ jammeredSoundTimer.cancel
+ jammeredSoundTimer = context.system.scheduler.scheduleOnce(30 seconds, self, JammableUnit.ClearJammeredSound())
+ }
+
+ def StartJammeredStatus(target : Any, dur : Int) : Unit = {
+ JammableObject.Jammed = true
+ jammeredStatusTimer.cancel
+ import scala.concurrent.ExecutionContext.Implicits.global
+ jammeredStatusTimer = context.system.scheduler.scheduleOnce(dur milliseconds, self, JammableUnit.ClearJammeredStatus())
+ }
+
+ def CancelJammeredSound(target : Any) : Unit = {
+ jammeredSoundTimer.cancel
+ }
+
+ def CancelJammeredStatus(target : Any) : Unit = {
+ JammableObject.Jammed = false
+ jammeredStatusTimer.cancel
+ }
+
+ def jammableBehavior : Receive = {
+ case JammableUnit.Jammered(cause) =>
+ TryJammerEffectActivate(JammableObject, cause)
+
+ case JammableUnit.ClearJammeredSound() =>
+ CancelJammeredSound(JammableObject)
+
+ case JammableUnit.ClearJammeredStatus() =>
+ CancelJammeredStatus(JammableObject)
+ }
+}
+
+trait JammableMountedWeapons extends Actor with JammableBehavior {
+ _ : Actor =>
+
+ def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit = target match {
+ case obj : PlanetSideServerObject with MountedWeapons =>
+ val radius = cause.projectile.profile.DamageRadius
+ JammingUnit.FindJammerDuration(cause.projectile.profile, obj) match {
+ case Some(dur) if Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius =>
+ StartJammeredSound(obj)
+ StartJammeredStatus(obj, dur)
+ case _ => ;
+ }
+ case _ => ;
+ }
+
+ override def StartJammeredSound(target : Any, dur : Int) : Unit = target match {
+ case obj : PlanetSideServerObject with MountedWeapons =>
+ obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 1))
+ super.StartJammeredSound(obj, dur)
+ case _ => ;
+ }
+
+ override def StartJammeredStatus(target : Any, dur : Int) : Unit = target match {
+ case obj : PlanetSideServerObject with MountedWeapons =>
+ JammableMountedWeapons.JammeredStatus(obj, 1)
+ super.StartJammeredStatus(obj, dur)
+ case _ => ;
+ }
+
+ override def CancelJammeredSound(target : Any) : Unit = target match {
+ case obj : PlanetSideServerObject =>
+ obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 0))
+ super.CancelJammeredSound(obj)
+ case _ => ;
+ }
+
+ override def CancelJammeredStatus(target : Any) : Unit = target match {
+ case obj : PlanetSideServerObject with MountedWeapons =>
+ JammableMountedWeapons.JammeredStatus(obj, 0)
+ super.CancelJammeredStatus(obj)
+ case _ => ;
+ }
+}
+
+object JammableMountedWeapons {
+ 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/serverobject/turret/FacilityTurret.scala b/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala
index 4a09e220..5edb2384 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala
@@ -1,12 +1,14 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.turret
+import net.psforever.objects.equipment.JammableUnit
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.types.Vector3
import net.psforever.objects.vital.{DamageResistanceModel, StandardResistanceProfile, Vitality}
class FacilityTurret(tDef : TurretDefinition) extends Amenity
with WeaponTurret
+ with JammableUnit
with Vitality
with StandardResistanceProfile {
/** some turrets can be updated; they all start without updates */
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 2d79b22e..dbb8e7b1 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,25 +1,19 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.turret
-import akka.actor.{Actor, Cancellable}
-import net.psforever.objects.{DefaultCancellable, Tool}
+import akka.actor.Actor
import net.psforever.objects.ballistics.ResolvedProjectile
-import net.psforever.objects.equipment.{JammableUnit, JammingUnit}
-import net.psforever.objects.serverobject.PlanetSideServerObject
+import net.psforever.objects.equipment.{JammableMountedWeapons, JammableUnit}
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`.
*
@@ -30,11 +24,12 @@ import scala.concurrent.duration._
*/
class FacilityTurretControl(turret : FacilityTurret) extends Actor
with FactionAffinityBehavior.Check
- with MountableBehavior.Dismount {
- var jammeredSoundTimer : Cancellable = DefaultCancellable.obj
- var jammeredStatusTimer : Cancellable = DefaultCancellable.obj
+ with MountableBehavior.Dismount
+ with JammableMountedWeapons {
- def MountableObject = turret //do not add type!
+ def MountableObject = turret
+
+ def JammableObject = turret
def FactionObject : FactionAffinity = turret
@@ -70,48 +65,8 @@ class FacilityTurretControl(turret : FacilityTurret) extends Actor
}
}
- 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 {
@@ -195,16 +150,4 @@ object FacilityTurretControl {
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 cb091b58..85933857 100644
--- a/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala
+++ b/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala
@@ -1,11 +1,10 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.vehicles
-import akka.actor.{Actor, ActorRef, Cancellable}
-import net.psforever.objects.{DefaultCancellable, GlobalDefinitions, Tool, Vehicle}
+import akka.actor.{Actor, ActorRef}
+import net.psforever.objects.{GlobalDefinitions, Vehicle}
import net.psforever.objects.ballistics.{ResolvedProjectile, VehicleSource}
-import net.psforever.objects.equipment.{JammableUnit, JammingUnit}
-import net.psforever.objects.serverobject.PlanetSideServerObject
+import net.psforever.objects.equipment.{JammableMountedWeapons, JammableUnit}
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.deploy.{Deployment, DeploymentBehavior}
@@ -18,8 +17,6 @@ import services.avatar.{AvatarAction, AvatarServiceMessage}
import services.local.{LocalAction, LocalServiceMessage}
import services.vehicle.{VehicleAction, VehicleService, VehicleServiceMessage}
-import scala.concurrent.duration._
-
/**
* An `Actor` that handles messages being dispatched to a specific `Vehicle`.
*
@@ -31,15 +28,16 @@ class VehicleControl(vehicle : Vehicle) extends Actor
with FactionAffinityBehavior.Check
with DeploymentBehavior
with MountableBehavior.Mount
- with MountableBehavior.Dismount {
- var jammeredSoundTimer : Cancellable = DefaultCancellable.obj
- var jammeredStatusTimer : Cancellable = DefaultCancellable.obj
+ with MountableBehavior.Dismount
+ with JammableMountedWeapons {
//make control actors belonging to utilities when making control actor belonging to vehicle
vehicle.Utilities.foreach({case (_, util) => util.Setup })
def MountableObject = vehicle
+ def JammableObject = vehicle
+
def FactionObject = vehicle
def DeploymentObject = vehicle
@@ -57,6 +55,7 @@ class VehicleControl(vehicle : Vehicle) extends Actor
def Enabled : Receive = checkBehavior
.orElse(deployBehavior)
.orElse(dismountBehavior)
+ .orElse(jammableBehavior)
.orElse {
case Mountable.TryMount(user, seat_num) =>
val exosuit = user.ExoSuit
@@ -116,16 +115,9 @@ class VehicleControl(vehicle : Vehicle) extends Actor
}
sender ! FactionAffinity.AssertFactionAffinity(vehicle, faction)
- case JammableUnit.Jammered(cause) =>
- TryJammerWithProjectile(vehicle, cause)
-
- case JammableUnit.ClearJammeredSound() =>
- CancelJammeredSound(vehicle)
-
- case JammableUnit.ClearJammeredStatus() =>
- StopJammeredStatus(vehicle)
-
case Vehicle.PrepareForDeletion =>
+ CancelJammeredSound(vehicle)
+ CancelJammeredStatus(vehicle)
context.become(Disabled)
case _ => ;
@@ -134,49 +126,11 @@ class VehicleControl(vehicle : Vehicle) extends Actor
def Disabled : Receive = checkBehavior
.orElse(dismountBehavior)
.orElse {
- case JammableUnit.ClearJammeredSound() =>
- CancelJammeredSound(vehicle)
-
- case JammableUnit.ClearJammeredStatus() =>
- StopJammeredStatus(vehicle)
-
case Vehicle.Reactivate =>
context.become(Enabled)
case _ => ;
}
-
- 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, JammableUnit.ClearJammeredSound())
- //jammered status
- StartJammeredStatus(target, dur)
- case _ => ;
- }
- }
-
- 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 : PlanetSideServerObject with MountedWeapons) : Boolean = {
- VehicleControl.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 VehicleControl {
@@ -310,16 +264,4 @@ object VehicleControl {
zone.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(target), zone))
zone.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(target, zone, Some(1 minute)))
}
-
- 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/zones/ZonePopulationActor.scala b/common/src/main/scala/net/psforever/objects/zones/ZonePopulationActor.scala
index a22e9b43..f43ecb26 100644
--- a/common/src/main/scala/net/psforever/objects/zones/ZonePopulationActor.scala
+++ b/common/src/main/scala/net/psforever/objects/zones/ZonePopulationActor.scala
@@ -1,7 +1,9 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.zones
-import akka.actor.Actor
+import akka.actor.{Actor, ActorRef, Props}
+import net.psforever.objects.avatar.PlayerControl
+import net.psforever.objects.vehicles.VehicleControl
import net.psforever.objects.{Avatar, Player}
import scala.annotation.tailrec
@@ -34,16 +36,22 @@ class ZonePopulationActor(zone : Zone, playerMap : TrieMap[Avatar, Option[Player
case Zone.Population.Spawn(avatar, player) =>
PopulationSpawn(avatar, player, playerMap) match {
case Some(tplayer) =>
+ tplayer.Zone = zone
if(tplayer ne player) {
sender ! Zone.Population.PlayerAlreadySpawned(zone, player)
}
+ else {
+ player.Actor = context.actorOf(Props(classOf[PlayerControl], player), s"${player.Name}_${player.GUID.guid}")
+ }
case None =>
sender ! Zone.Population.PlayerCanNotSpawn(zone, player)
}
case Zone.Population.Release(avatar) =>
PopulationRelease(avatar, playerMap) match {
- case Some(_) => ;
+ case Some(tplayer) =>
+ tplayer.Actor ! akka.actor.PoisonPill
+ tplayer.Actor = ActorRef.noSender
case None =>
sender ! Zone.Population.PlayerHasLeft(zone, None)
}
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 b09ffb41..ba67539b 100644
--- a/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
+++ b/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
@@ -115,7 +115,7 @@ import scodec.codecs._
* 45 : Advanced Engineering (= Fortification Engineering + Assault Engineering) Must have Combat Engineering
* `25 - Forget certifications (same order as 24)`
* `26 - Certification reset timer (in seconds)`
- * `27 - PA_JAMMED - plays jammed buzzing sound`
+ * `27 - PA_JAMMED - plays jammed buzzing sound in vicinity of target, jams weapon discharge`
* `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):`
@@ -162,7 +162,7 @@ import scodec.codecs._
* `13 - Trunk permissions (same)`
* `21 - Declare a player the vehicle's owner, by globally unique identifier`
* `22 - Toggles gunner and passenger mount points (1 = hides, 0 = reveals; this also locks their permissions)`
- * `54 - Vehicle EMP? Plays sound as if vehicle had been hit by EMP`
+ * `54 - Plays jammed buzzing sound in vicinity of target`
* `68 - Vehicle shield health`
* `79 - ???`
* `80 - Damage vehicle (unknown value)`
diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala
index 6db3e6d7..f986a8ad 100644
--- a/pslogin/src/main/scala/WorldSessionActor.scala
+++ b/pslogin/src/main/scala/WorldSessionActor.scala
@@ -71,7 +71,9 @@ import services.support.SupportActor
import scala.collection.mutable
-class WorldSessionActor extends Actor with MDCContextAware {
+class WorldSessionActor extends Actor
+ with MDCContextAware
+ with JammableBehavior {
import WorldSessionActor._
private[this] val log = org.log4s.getLogger
@@ -165,8 +167,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
var cargoDismountTimer : Cancellable = DefaultCancellable.obj
var antChargingTick : Cancellable = DefaultCancellable.obj
var antDischargingTick : Cancellable = DefaultCancellable.obj
- var jammeredSoundTimer : Cancellable = DefaultCancellable.obj
- var jammeredStatusTimer : Cancellable = DefaultCancellable.obj
/**
@@ -178,12 +178,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
import scala.language.implicitConversions
implicit def boolToInt(b : Boolean) : Int = if(b) 1 else 0
+ def JammableObject = player
+
override def postStop() : Unit = {
//TODO normally, player avatar persists a minute or so after disconnect; we are subject to the SessionReaper
clientKeepAlive.cancel
reviveTimer.cancel
respawnTimer.cancel
- PlayerActionsToCancel()
chatService ! Service.Leave()
continent.AvatarEvents ! Service.Leave()
continent.LocalEvents ! Service.Leave()
@@ -191,6 +192,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
galaxyService ! Service.Leave()
LivePlayerList.Remove(sessionId)
if(player != null && player.HasGUID) {
+ PlayerActionsToCancel()
squadService ! Service.Leave(Some(player.CharId.toString))
val player_guid = player.GUID
//handle orphaned deployables
@@ -320,7 +322,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
context.stop(self)
}
- def Started : Receive = {
+ def Started : Receive = jammableBehavior.orElse {
case ServiceManager.LookupResult("chat", endpoint) =>
chatService = endpoint
log.info("ID: " + sessionId + " Got chat service " + endpoint)
@@ -1174,12 +1176,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
case _ => ;
}
- case ClearJammeredSound() =>
- CancelJammeredSound()
-
- case ClearJammeredStatus() =>
- CancelJammeredStatus()
-
case default =>
log.warn(s"Invalid packet class received: $default from $sender")
}
@@ -1323,30 +1319,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
}
if(target.isAlive && cause.projectile.profile.JammerProjectile) {
- 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 =>
- //implants
- DeactivateImplants()
- //jammered sound
- 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 = (jammeredEquipment ++ player.Holsters()
- .map { _.Equipment }
- .collect {
- case Some(item) if item.Size != EquipmentSize.Melee =>
- sendResponse(PlanetsideAttributeMessage(item.GUID, 27, 1))
- item.GUID
- }).distinct
- jammeredStatusTimer.cancel
- jammeredStatusTimer = context.system.scheduler.scheduleOnce(dur milliseconds, self, ClearJammeredStatus())
- case _ => ;
- }
+ self ! JammableUnit.Jammered(cause)
}
}
@@ -3425,6 +3398,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
player.Slot(39).Equipment = SimpleItem(remote_electronics_kit)
player.Locker.Inventory += 0 -> SimpleItem(remote_electronics_kit)
player.Inventory.Items.foreach { _.obj.Faction = faction }
+ player.Actor = self
//TODO end temp player character auto-loading
self ! ListAccountCharacters
import scala.concurrent.ExecutionContext.Implicits.global
@@ -7801,8 +7775,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 = {
- CancelJammeredSound()
- CancelJammeredStatus()
+ CancelJammeredSound(player)
+ CancelJammeredStatus(player)
progressBarUpdate.cancel
progressBarValue = None
lastTerminalOrderFulfillment = true
@@ -10242,16 +10216,55 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
}
- def CancelJammeredSound() : Unit = {
- jammeredSoundTimer.cancel
- sendResponse(PlanetsideAttributeMessage(player.GUID, 54, 0))
- continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 54, 0))
+ def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit = target match {
+ case obj : Player =>
+ val radius = cause.projectile.profile.DamageRadius
+ JammingUnit.FindJammerDuration(cause.projectile.profile, obj) match {
+ case Some(dur) if Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius =>
+ DeactivateImplants()
+ skipStaminaRegenForTurns = 5
+ StartJammeredSound(obj)
+ StartJammeredStatus(obj, dur)
+ case _ => ;
+ }
+ case _ => ;
}
- def CancelJammeredStatus() : Unit = {
- jammeredStatusTimer.cancel
- jammeredEquipment.foreach { id => sendResponse(PlanetsideAttributeMessage(id, 27, 0)) }
- jammeredEquipment = Nil
+ override def StartJammeredSound(target : Any, dur : Int) : Unit = target match {
+ case obj : Player =>
+ sendResponse(PlanetsideAttributeMessage(obj.GUID, 27, 1))
+ continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(obj.GUID, 27, 1))
+ super.StartJammeredSound(obj, dur)
+ case _ => ;
+ }
+
+ override def StartJammeredStatus(target : Any, dur : Int) : Unit = target match {
+ case obj : Player =>
+ jammeredEquipment = (jammeredEquipment ++ obj.Holsters()
+ .map { _.Equipment }
+ .collect {
+ case Some(item) if item.Size != EquipmentSize.Melee =>
+ sendResponse(PlanetsideAttributeMessage(item.GUID, 27, 1))
+ item.GUID
+ }).distinct
+ super.StartJammeredStatus(obj, dur)
+ case _ => ;
+ }
+
+ override def CancelJammeredSound(target : Any) : Unit = target match {
+ case obj : Player =>
+ sendResponse(PlanetsideAttributeMessage(obj.GUID, 27, 0))
+ continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(obj.GUID, 27, 0))
+ super.CancelJammeredSound(obj)
+ case _ => ;
+ }
+
+ override def CancelJammeredStatus(target : Any) : Unit = target match {
+ case obj : Player =>
+ jammeredEquipment.foreach { id => sendResponse(PlanetsideAttributeMessage(id, 27, 0)) }
+ jammeredEquipment = Nil
+ super.CancelJammeredStatus(obj)
+ case _ => ;
}
def failWithError(error : String) = {
@@ -10412,15 +10425,11 @@ object WorldSessionActor {
protected final case class SquadUIElement(name : String, index : Int, zone : Int, health : Int, armor : Int, position : Vector3)
- private final case class NtuCharging(tplayer: Player,
- vehicle: Vehicle)
+ private final case class NtuCharging(tplayer: Player, vehicle: Vehicle)
+
private final case class NtuDischarging(tplayer: Player, vehicle: Vehicle, silo_guid: PlanetSideGUID)
private final case class FinalizeDeployable(obj : PlanetSideGameObject with Deployable, tool : ConstructionItem, index : Int)
private final case class LoadedRemoteProjectile(projectile_guid : PlanetSideGUID, projectile : Option[Projectile])
-
- private final case class ClearJammeredSound()
-
- private final case class ClearJammeredStatus()
}