diff --git a/common/src/main/scala/net/psforever/objects/BoomerDeployable.scala b/common/src/main/scala/net/psforever/objects/BoomerDeployable.scala index f218da87..21d66ea2 100644 --- a/common/src/main/scala/net/psforever/objects/BoomerDeployable.scala +++ b/common/src/main/scala/net/psforever/objects/BoomerDeployable.scala @@ -1,9 +1,9 @@ // Copyright (c) 2017 PSForever package net.psforever.objects -import net.psforever.objects.definition.DeployableDefinition +import net.psforever.objects.definition.SimpleDeployableDefinition -class BoomerDeployable(cdef : DeployableDefinition) extends ExplosiveDeployable(cdef) { +class BoomerDeployable(cdef : SimpleDeployableDefinition) extends ExplosiveDeployable(cdef) { private var trigger : Option[BoomerTrigger] = None def Trigger : Option[BoomerTrigger] = trigger diff --git a/common/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala b/common/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala index 9d03bf74..b324c666 100644 --- a/common/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala +++ b/common/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala @@ -2,9 +2,11 @@ package net.psforever.objects import net.psforever.objects.ce.SimpleDeployable -import net.psforever.objects.definition.DeployableDefinition +import net.psforever.objects.definition.SimpleDeployableDefinition +import net.psforever.objects.equipment.JammableUnit -class ExplosiveDeployable(cdef : DeployableDefinition) extends SimpleDeployable(cdef) { +class ExplosiveDeployable(cdef : SimpleDeployableDefinition) extends SimpleDeployable(cdef) + with JammableUnit { private var exploded : Boolean = false def Exploded : Boolean = exploded diff --git a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala index 0a69c556..13066bd9 100644 --- a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala +++ b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala @@ -17,7 +17,7 @@ import net.psforever.objects.serverobject.terminals._ import net.psforever.objects.serverobject.tube.SpawnTubeDefinition import net.psforever.objects.serverobject.resourcesilo.ResourceSiloDefinition import net.psforever.objects.serverobject.structures.SphereOfInfluence -import net.psforever.objects.serverobject.turret.{TurretDefinition, TurretUpgrade} +import net.psforever.objects.serverobject.turret.{FacilityTurretDefinition, TurretUpgrade} import net.psforever.objects.vehicles.{DestroyedVehicle, SeatArmorRestriction, UtilityType} import net.psforever.objects.vital.{DamageType, StandardMaxDamage, StandardResolutions} import net.psforever.types.{CertificationType, ExoSuitType, PlanetSideEmpire, Vector3} @@ -870,11 +870,11 @@ object GlobalDefinitions { /* combat engineering deployables */ - val boomer = DeployableDefinition(DeployedItem.boomer) + val boomer = SimpleDeployableDefinition(DeployedItem.boomer) - val he_mine = DeployableDefinition(DeployedItem.he_mine) + val he_mine = SimpleDeployableDefinition(DeployedItem.he_mine) - val jammer_mine = DeployableDefinition(DeployedItem.jammer_mine) + val jammer_mine = SimpleDeployableDefinition(DeployedItem.jammer_mine) val spitfire_turret = TurretDeployableDefinition(DeployedItem.spitfire_turret) @@ -882,11 +882,11 @@ object GlobalDefinitions { val spitfire_aa = TurretDeployableDefinition(DeployedItem.spitfire_aa) - val motionalarmsensor = DeployableDefinition(DeployedItem.motionalarmsensor) + val motionalarmsensor = SimpleDeployableDefinition(DeployedItem.motionalarmsensor) - val sensor_shield = DeployableDefinition(DeployedItem.sensor_shield) + val sensor_shield = SimpleDeployableDefinition(DeployedItem.sensor_shield) - val tank_traps = DeployableDefinition(DeployedItem.tank_traps) + val tank_traps = SimpleDeployableDefinition(DeployedItem.tank_traps) val portable_manned_turret = TurretDeployableDefinition(DeployedItem.portable_manned_turret) @@ -898,10 +898,10 @@ object GlobalDefinitions { val deployable_shield_generator = new ShieldGeneratorDefinition - val router_telepad_deployable = DeployableDefinition(DeployedItem.router_telepad_deployable) + val router_telepad_deployable = SimpleDeployableDefinition(DeployedItem.router_telepad_deployable) //this is only treated like a deployable - val internal_router_telepad_deployable = DeployableDefinition(DeployedItem.router_telepad_deployable) + val internal_router_telepad_deployable = SimpleDeployableDefinition(DeployedItem.router_telepad_deployable) init_deployables() /* @@ -989,7 +989,7 @@ object GlobalDefinitions { val ground_rearm_terminal = new OrderTerminalDefinition(384) - val manned_turret = new TurretDefinition(480) + val manned_turret = new FacilityTurretDefinition(480) val painbox = new PainboxDefinition(622) val painbox_continuous = new PainboxDefinition(623) diff --git a/common/src/main/scala/net/psforever/objects/SensorDeployable.scala b/common/src/main/scala/net/psforever/objects/SensorDeployable.scala index eccfcc7e..1c886cd9 100644 --- a/common/src/main/scala/net/psforever/objects/SensorDeployable.scala +++ b/common/src/main/scala/net/psforever/objects/SensorDeployable.scala @@ -2,8 +2,10 @@ package net.psforever.objects import net.psforever.objects.ce.SimpleDeployable -import net.psforever.objects.definition.DeployableDefinition +import net.psforever.objects.definition.SimpleDeployableDefinition +import net.psforever.objects.equipment.JammableUnit import net.psforever.objects.serverobject.hackable.Hackable -class SensorDeployable(cdef : DeployableDefinition) extends SimpleDeployable(cdef) +class SensorDeployable(cdef : SimpleDeployableDefinition) extends SimpleDeployable(cdef) with Hackable + with JammableUnit diff --git a/common/src/main/scala/net/psforever/objects/ShieldGeneratorDeployable.scala b/common/src/main/scala/net/psforever/objects/ShieldGeneratorDeployable.scala index bbdedd91..ffe8dcb1 100644 --- a/common/src/main/scala/net/psforever/objects/ShieldGeneratorDeployable.scala +++ b/common/src/main/scala/net/psforever/objects/ShieldGeneratorDeployable.scala @@ -1,15 +1,139 @@ // Copyright (c) 2017 PSForever package net.psforever.objects -import net.psforever.objects.ce.{ComplexDeployable, DeployableCategory} -import net.psforever.objects.definition.DeployableDefinition +import akka.actor.{Actor, ActorContext, Props} +import net.psforever.objects.ballistics.ResolvedProjectile +import net.psforever.objects.ce.{ComplexDeployable, Deployable, DeployableCategory} +import net.psforever.objects.definition.{ComplexDeployableDefinition, SimpleDeployableDefinition} import net.psforever.objects.definition.converter.ShieldGeneratorConverter +import net.psforever.objects.equipment.{JammableBehavior, JammableUnit} +import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.hackable.Hackable +import net.psforever.objects.vital.Vitality +import net.psforever.objects.zones.Zone +import net.psforever.packet.game.{DeployableInfo, DeploymentAction, PlanetSideGUID} +import services.avatar.{AvatarAction, AvatarServiceMessage} +import services.local.{LocalAction, LocalServiceMessage} +import services.{RemoverActor, Service} +import services.vehicle.{VehicleAction, VehicleServiceMessage} + +import scala.concurrent.duration.FiniteDuration class ShieldGeneratorDeployable(cdef : ShieldGeneratorDefinition) extends ComplexDeployable(cdef) with Hackable + with JammableUnit -class ShieldGeneratorDefinition extends DeployableDefinition(240) { +class ShieldGeneratorDefinition extends ComplexDeployableDefinition(240) { Packet = new ShieldGeneratorConverter DeployCategory = DeployableCategory.ShieldGenerators + + override def Initialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { + obj.Actor = context.actorOf(Props(classOf[ShieldGeneratorControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}") + } + + override def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { + SimpleDeployableDefinition.SimpleUninitialize(obj, context) + } +} + +class ShieldGeneratorControl(gen : ShieldGeneratorDeployable) extends Actor + with JammableBehavior { + + def JammableObject = gen + + def receive : Receive = jammableBehavior + .orElse { + case Vitality.Damage(damage_func) => //note: damage status is reported as vehicle events, not local events + if(gen.Health > 0) { + val originalHealth = gen.Health + val cause = damage_func(gen) + val health = gen.Health + val damageToHealth = originalHealth - health + ShieldGeneratorControl.HandleDamageResolution(gen, cause, damageToHealth) + if(damageToHealth > 0) { + val name = gen.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 _ => ; + } + + override def StartJammeredSound(target : Any, dur : Int) : Unit = { } + + override def StartJammeredStatus(target : Any, dur : Int) : Unit = target match { + case obj : PlanetSideServerObject => + obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 1)) + super.StartJammeredStatus(obj, dur) + case _ => ; + } + + override def CancelJammeredSound(target : Any) : Unit = { } + + override def CancelJammeredStatus(target : Any) : Unit = target match { + case obj : PlanetSideServerObject => + obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 0)) + super.CancelJammeredStatus(obj) + case _ => ; + } +} + +object ShieldGeneratorControl { + /** + * na + * @param target na + */ + def HandleDamageResolution(target : ShieldGeneratorDeployable, cause : ResolvedProjectile, damage : Int) : Unit = { + val zone = target.Zone + val targetGUID = target.GUID + 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) { + zone.Activity ! Zone.HotSpot.Activity(cause.target, cause.projectile.owner, cause.hit_pos) + } + if(cause.projectile.profile.JammerProjectile) { + target.Actor ! JammableUnit.Jammered(cause) + } + } + else { + HandleDestructionAwareness(target, playerGUID, cause) + } + zone.VehicleEvents ! VehicleServiceMessage(zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health)) + } + + /** + * na + * @param target na + * @param attribution na + * @param lastShot na + */ + def HandleDestructionAwareness(target : ShieldGeneratorDeployable, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = { + target.Actor ! JammableUnit.ClearJammeredSound() + target.Actor ! JammableUnit.ClearJammeredStatus() + val zone = target.Zone + AnnounceDestroyDeployable(target, None) + zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.Destroy(target.GUID, attribution, attribution, target.Position)) + } + + def AnnounceDestroyDeployable(target : PlanetSideServerObject with Deployable, time : Option[FiniteDuration]) : Unit = { + val zone = target.Zone + target.OwnerName match { + case Some(owner) => + target.OwnerName = None + zone.LocalEvents ! LocalServiceMessage(owner, LocalAction.AlertDestroyDeployable(PlanetSideGUID(0), target)) + case None => ; + } + zone.LocalEvents ! LocalServiceMessage(s"${target.Faction}", LocalAction.DeployableMapIcon( + PlanetSideGUID(0), + DeploymentAction.Dismiss, + DeployableInfo(target.GUID, Deployable.Icon(target.Definition.Item), target.Position, PlanetSideGUID(0))) + ) + zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(target), zone)) + zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(target, zone, time)) + } } diff --git a/common/src/main/scala/net/psforever/objects/TelepadDeployable.scala b/common/src/main/scala/net/psforever/objects/TelepadDeployable.scala index 3916384b..42774eec 100644 --- a/common/src/main/scala/net/psforever/objects/TelepadDeployable.scala +++ b/common/src/main/scala/net/psforever/objects/TelepadDeployable.scala @@ -2,7 +2,7 @@ package net.psforever.objects import net.psforever.objects.ce.{SimpleDeployable, TelepadLike} -import net.psforever.objects.definition.DeployableDefinition +import net.psforever.objects.definition.SimpleDeployableDefinition -class TelepadDeployable(ddef : DeployableDefinition) extends SimpleDeployable(ddef) +class TelepadDeployable(ddef : SimpleDeployableDefinition) extends SimpleDeployable(ddef) with TelepadLike diff --git a/common/src/main/scala/net/psforever/objects/TrapDeployable.scala b/common/src/main/scala/net/psforever/objects/TrapDeployable.scala index 488c4bc6..e330e999 100644 --- a/common/src/main/scala/net/psforever/objects/TrapDeployable.scala +++ b/common/src/main/scala/net/psforever/objects/TrapDeployable.scala @@ -2,6 +2,6 @@ package net.psforever.objects import net.psforever.objects.ce.SimpleDeployable -import net.psforever.objects.definition.DeployableDefinition +import net.psforever.objects.definition.SimpleDeployableDefinition -class TrapDeployable(cdef : DeployableDefinition) extends SimpleDeployable(cdef) +class TrapDeployable(cdef : SimpleDeployableDefinition) extends SimpleDeployable(cdef) diff --git a/common/src/main/scala/net/psforever/objects/TurretDeployable.scala b/common/src/main/scala/net/psforever/objects/TurretDeployable.scala index c72d59cd..23b57441 100644 --- a/common/src/main/scala/net/psforever/objects/TurretDeployable.scala +++ b/common/src/main/scala/net/psforever/objects/TurretDeployable.scala @@ -2,65 +2,59 @@ package net.psforever.objects import akka.actor.{Actor, ActorContext, Props} -import net.psforever.objects.ce.{Deployable, DeployedItem} -import net.psforever.objects.definition.{BaseDeployableDefinition, DeployableDefinition} +import net.psforever.objects.ballistics.ResolvedProjectile +import net.psforever.objects.ce.{ComplexDeployable, Deployable, DeployedItem} +import net.psforever.objects.definition.{ComplexDeployableDefinition, SimpleDeployableDefinition} import net.psforever.objects.definition.converter.SmallTurretConverter +import net.psforever.objects.equipment.{JammableMountedWeapons, JammableUnit} import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} import net.psforever.objects.serverobject.hackable.Hackable import net.psforever.objects.serverobject.mount.MountableBehavior import net.psforever.objects.serverobject.turret.{TurretDefinition, WeaponTurret} +import net.psforever.objects.vital.{StandardResolutions, StandardVehicleDamage, StandardVehicleResistance, Vitality} +import net.psforever.objects.zones.Zone +import net.psforever.packet.game.{DeployableInfo, DeploymentAction, PlanetSideGUID} +import services.{RemoverActor, Service} +import services.avatar.{AvatarAction, AvatarServiceMessage} +import services.local.{LocalAction, LocalServiceMessage} +import services.vehicle.{VehicleAction, VehicleServiceMessage} -class TurretDeployable(tdef : TurretDeployableDefinition) extends PlanetSideServerObject - with Deployable +class TurretDeployable(tdef : TurretDeployableDefinition) extends ComplexDeployable(tdef) with WeaponTurret + with JammableUnit with Hackable { - private var shields : Int = 0 - WeaponTurret.LoadDefinition(this) //calls the equivalent of Health = Definition.MaxHealth - def MaxHealth : Int = Definition.MaxHealth - - def Shields : Int = shields - - def Shields_=(toShields : Int) : Int = { - shields = math.min(math.max(0, toShields), MaxShields) - Shields - } - - def MaxShields : Int = { - 0//Definition.MaxShields - } - def MountPoints : Map[Int, Int] = Definition.MountPoints.toMap //override to clarify inheritance conflict - override def Health : Int = super[Deployable].Health + override def Health : Int = super[ComplexDeployable].Health //override to clarify inheritance conflict - override def Health_=(toHealth : Int) : Int = super[Deployable].Health_=(toHealth) + override def Health_=(toHealth : Int) : Int = super[ComplexDeployable].Health_=(toHealth) override def Definition = tdef } -class TurretDeployableDefinition(private val objectId : Int) extends TurretDefinition(objectId) - with BaseDeployableDefinition { - private val item = DeployedItem(objectId) //let throw NoSuchElementException +class TurretDeployableDefinition(private val objectId : Int) extends ComplexDeployableDefinition(objectId) + with TurretDefinition { Name = "turret_deployable" Packet = new SmallTurretConverter - - def Item : DeployedItem.Value = item + Damage = StandardVehicleDamage + Resistance = StandardVehicleResistance + Model = StandardResolutions.FacilityTurrets //override to clarify inheritance conflict - override def MaxHealth : Int = super[BaseDeployableDefinition].MaxHealth + override def MaxHealth : Int = super[ComplexDeployableDefinition].MaxHealth //override to clarify inheritance conflict - override def MaxHealth_=(max : Int) : Int = super[BaseDeployableDefinition].MaxHealth_=(max) + override def MaxHealth_=(max : Int) : Int = super[ComplexDeployableDefinition].MaxHealth_=(max) override def Initialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { obj.Actor = context.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}") } override def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { - DeployableDefinition.SimpleUninitialize(obj, context) + SimpleDeployableDefinition.SimpleUninitialize(obj, context) } } @@ -74,16 +68,134 @@ object TurretDeployableDefinition { class TurretControl(turret : TurretDeployable) extends Actor with FactionAffinityBehavior.Check + with JammableMountedWeapons //note: jammable status is reported as vehicle events, not local events with MountableBehavior.Mount with MountableBehavior.Dismount { def MountableObject = turret //do not add type! + def JammableObject = turret + def FactionObject : FactionAffinity = turret def receive : Receive = checkBehavior + .orElse(jammableBehavior) .orElse(dismountBehavior) .orElse(turretMountBehavior) .orElse { + case Vitality.Damage(damage_func) => //note: damage status is reported as vehicle events, not local events + if(turret.Health > 0) { + val originalHealth = turret.Health + val cause = damage_func(turret) + val health = turret.Health + val damageToHealth = originalHealth - health + TurretControl.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 _ => ; } } + +object TurretControl { + import scala.concurrent.duration._ + + /** + * na + * @param target na + */ + def HandleDamageResolution(target : TurretDeployable, cause : ResolvedProjectile, damage : Int) : Unit = { + val zone = target.Zone + val targetGUID = target.GUID + 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) { + 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 turret death (hence, occupants' deaths) + HandleDestructionAwareness(target, playerGUID, cause) + } + zone.VehicleEvents ! VehicleServiceMessage(zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health)) + } + + /** + * na + * @param target na + * @param attribution na + * @param lastShot na + */ + def HandleDamageAwareness(target : TurretDeployable, 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 + zone.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(attribution, tplayer.GUID)) + }) + } + + /** + * na + * @param target na + * @param attribution na + * @param lastShot na + */ + def HandleDestructionAwareness(target : TurretDeployable, 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 + 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 + .filter { + _.Equipment.nonEmpty + } + .foreach(slot => { + val wep = slot.Equipment.get + zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID)) + }) + AnnounceDestroyDeployable(target, None) + zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.Destroy(target.GUID, attribution, attribution, target.Position)) + } + + def AnnounceDestroyDeployable(target : PlanetSideServerObject with Deployable, time : Option[FiniteDuration]) : Unit = { + val zone = target.Zone + target.OwnerName match { + case Some(owner) => + target.OwnerName = None + zone.LocalEvents ! LocalServiceMessage(owner, LocalAction.AlertDestroyDeployable(PlanetSideGUID(0), target)) + case None => ; + } + zone.LocalEvents ! LocalServiceMessage(s"${target.Faction}", LocalAction.DeployableMapIcon( + PlanetSideGUID(0), + DeploymentAction.Dismiss, + DeployableInfo(target.GUID, Deployable.Icon(target.Definition.Item), target.Position, PlanetSideGUID(0))) + ) + zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(target), zone)) + zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(target, zone, time)) + } +} diff --git a/common/src/main/scala/net/psforever/objects/ballistics/SourceEntry.scala b/common/src/main/scala/net/psforever/objects/ballistics/SourceEntry.scala index bb050e9c..442d1739 100644 --- a/common/src/main/scala/net/psforever/objects/ballistics/SourceEntry.scala +++ b/common/src/main/scala/net/psforever/objects/ballistics/SourceEntry.scala @@ -3,7 +3,7 @@ package net.psforever.objects.ballistics import net.psforever.objects.ce.{ComplexDeployable, SimpleDeployable} import net.psforever.objects.definition.ObjectDefinition -import net.psforever.objects.{PlanetSideGameObject, Player, TurretDeployable, Vehicle} +import net.psforever.objects.{PlanetSideGameObject, Player, Vehicle} import net.psforever.objects.entity.WorldEntity import net.psforever.objects.serverobject.affinity.FactionAffinity import net.psforever.objects.vital.resistance.ResistanceProfile @@ -34,7 +34,6 @@ object SourceEntry { case obj : Player => PlayerSource(obj) case obj : Vehicle => VehicleSource(obj) case obj : ComplexDeployable => ComplexDeployableSource(obj) - case obj : TurretDeployable => ComplexDeployableSource(obj) case obj : SimpleDeployable => DeployableSource(obj) case _ => ObjectSource(target) } diff --git a/common/src/main/scala/net/psforever/objects/ce/ComplexDeployable.scala b/common/src/main/scala/net/psforever/objects/ce/ComplexDeployable.scala index 5dec6c65..65665c9e 100644 --- a/common/src/main/scala/net/psforever/objects/ce/ComplexDeployable.scala +++ b/common/src/main/scala/net/psforever/objects/ce/ComplexDeployable.scala @@ -1,10 +1,10 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.ce -import net.psforever.objects.definition.DeployableDefinition +import net.psforever.objects.definition.ComplexDeployableDefinition import net.psforever.objects.serverobject.PlanetSideServerObject -abstract class ComplexDeployable(cdef : DeployableDefinition) extends PlanetSideServerObject +abstract class ComplexDeployable(cdef : ComplexDeployableDefinition) extends PlanetSideServerObject with Deployable { Health = Definition.MaxHealth diff --git a/common/src/main/scala/net/psforever/objects/ce/Deployable.scala b/common/src/main/scala/net/psforever/objects/ce/Deployable.scala index 799751cf..b552874e 100644 --- a/common/src/main/scala/net/psforever/objects/ce/Deployable.scala +++ b/common/src/main/scala/net/psforever/objects/ce/Deployable.scala @@ -5,12 +5,14 @@ import net.psforever.objects._ import net.psforever.objects.definition.{BaseDeployableDefinition, ObjectDefinition} import net.psforever.objects.serverobject.affinity.FactionAffinity import net.psforever.objects.vital.{DamageResistanceModel, Vitality} -import net.psforever.packet.game.{DeployableIcon, PlanetSideGUID} +import net.psforever.objects.zones.ZoneAware +import net.psforever.packet.game.DeployableIcon import net.psforever.types.PlanetSideEmpire trait Deployable extends FactionAffinity with Vitality - with OwnableByPlayer { + with OwnableByPlayer + with ZoneAware { this : PlanetSideGameObject => private var health : Int = 1 private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL diff --git a/common/src/main/scala/net/psforever/objects/ce/SimpleDeployable.scala b/common/src/main/scala/net/psforever/objects/ce/SimpleDeployable.scala index 38200737..76362ea9 100644 --- a/common/src/main/scala/net/psforever/objects/ce/SimpleDeployable.scala +++ b/common/src/main/scala/net/psforever/objects/ce/SimpleDeployable.scala @@ -2,9 +2,9 @@ package net.psforever.objects.ce import net.psforever.objects.PlanetSideGameObject -import net.psforever.objects.definition.DeployableDefinition +import net.psforever.objects.definition.SimpleDeployableDefinition -abstract class SimpleDeployable(cdef : DeployableDefinition) extends PlanetSideGameObject +abstract class SimpleDeployable(cdef : SimpleDeployableDefinition) extends PlanetSideGameObject with Deployable { Health = Definition.MaxHealth diff --git a/common/src/main/scala/net/psforever/objects/definition/DeployableDefinition.scala b/common/src/main/scala/net/psforever/objects/definition/SimpleDeployableDefinition.scala similarity index 80% rename from common/src/main/scala/net/psforever/objects/definition/DeployableDefinition.scala rename to common/src/main/scala/net/psforever/objects/definition/SimpleDeployableDefinition.scala index d3c1b7c2..fc9e0cbb 100644 --- a/common/src/main/scala/net/psforever/objects/definition/DeployableDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/definition/SimpleDeployableDefinition.scala @@ -7,7 +7,7 @@ import net.psforever.objects.ce.{Deployable, DeployableCategory, DeployedItem} import net.psforever.objects.definition.converter.SmallDeployableConverter import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.vital.resistance.ResistanceProfileMutators -import net.psforever.objects.vital.{DamageResistanceModel, NoResistanceSelection, StandardDeployableDamage, StandardResistanceProfile} +import net.psforever.objects.vital.{DamageResistanceModel, NoResistanceSelection, StandardDeployableDamage} import scala.concurrent.duration._ @@ -53,7 +53,7 @@ trait BaseDeployableDefinition extends DamageResistanceModel def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) : Unit = { } } -class DeployableDefinition(private val objectId : Int) extends ObjectDefinition(objectId) +class SimpleDeployableDefinition(private val objectId : Int) extends ObjectDefinition(objectId) with BaseDeployableDefinition { private val item = DeployedItem(objectId) //let throw NoSuchElementException Packet = new SmallDeployableConverter @@ -61,9 +61,16 @@ class DeployableDefinition(private val objectId : Int) extends ObjectDefinition( def Item : DeployedItem.Value = item } -object DeployableDefinition { - def apply(item : DeployedItem.Value) : DeployableDefinition = - new DeployableDefinition(item.id) +abstract class ComplexDeployableDefinition(private val objectId : Int) extends ObjectDefinition(objectId) + with BaseDeployableDefinition { + private val item = DeployedItem(objectId) //let throw NoSuchElementException + + def Item : DeployedItem.Value = item +} + +object SimpleDeployableDefinition { + def apply(item : DeployedItem.Value) : SimpleDeployableDefinition = + new SimpleDeployableDefinition(item.id) def SimpleUninitialize(obj : PlanetSideGameObject, context : ActorContext) : Unit = { } 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 a6c6705c..cab7622a 100644 --- a/common/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala +++ b/common/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala @@ -65,7 +65,17 @@ trait JammableBehavior { def JammableObject : PlanetSideServerObject with JammableUnit with ZoneAware - def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit + def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit = target match { + case obj : PlanetSideServerObject => + 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 _ => ; + } def StartJammeredSound(target : Any, dur : Int = 30000) : Unit = { import scala.concurrent.ExecutionContext.Implicits.global @@ -89,7 +99,7 @@ trait JammableBehavior { jammeredStatusTimer.cancel } - def jammableBehavior : Receive = { + val jammableBehavior : Receive = { case JammableUnit.Jammered(cause) => TryJammerEffectActivate(JammableObject, cause) @@ -101,21 +111,9 @@ trait JammableBehavior { } } -trait JammableMountedWeapons extends Actor with JammableBehavior { +trait JammableMountedWeapons extends 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)) 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 5edb2384..8d4bc7c3 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 @@ -6,7 +6,7 @@ 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 +class FacilityTurret(tDef : FacilityTurretDefinition) extends Amenity with WeaponTurret with JammableUnit with Vitality @@ -55,7 +55,7 @@ class FacilityTurret(tDef : TurretDefinition) extends Amenity def DamageModel = Definition.asInstanceOf[DamageResistanceModel] - def Definition : TurretDefinition = tDef + def Definition : FacilityTurretDefinition = tDef } object FacilityTurret { @@ -64,7 +64,7 @@ object FacilityTurret { * @param tDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields * @return a `FacilityTurret` object */ - def apply(tDef : TurretDefinition) : FacilityTurret = { + def apply(tDef : FacilityTurretDefinition) : FacilityTurret = { new FacilityTurret(tDef) } @@ -75,14 +75,14 @@ object FacilityTurret { * @param context a context to allow the object to properly set up `ActorSystem` functionality * @return the `MannedTurret` object */ - def Constructor(tdef : TurretDefinition)(id : Int, context : ActorContext) : FacilityTurret = { + def Constructor(tdef : FacilityTurretDefinition)(id : Int, context : ActorContext) : FacilityTurret = { import akka.actor.Props val obj = FacilityTurret(tdef) obj.Actor = context.actorOf(Props(classOf[FacilityTurretControl], obj), s"${tdef.Name}_$id") obj } - def Constructor(pos: Vector3, tdef : TurretDefinition)(id : Int, context : ActorContext) : FacilityTurret = { + def Constructor(pos: Vector3, tdef : FacilityTurretDefinition)(id : Int, context : ActorContext) : FacilityTurret = { import akka.actor.Props val obj = FacilityTurret(tdef) obj.Position = pos 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 dbb8e7b1..4a1bb4b3 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 @@ -34,6 +34,7 @@ class FacilityTurretControl(turret : FacilityTurret) extends Actor def FactionObject : FactionAffinity = turret def receive : Receive = checkBehavior + .orElse(jammableBehavior) .orElse(dismountBehavior) .orElse { case Mountable.TryMount(user, seat_num) => diff --git a/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretDefinition.scala new file mode 100644 index 00000000..43dd4db0 --- /dev/null +++ b/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretDefinition.scala @@ -0,0 +1,17 @@ +// Copyright (c) 2019 PSForever +package net.psforever.objects.serverobject.turret + +import net.psforever.objects.definition.ObjectDefinition +import net.psforever.objects.vital.{StandardResolutions, StandardVehicleDamage, StandardVehicleResistance} + +/** + * The definition for any `FacilityTurret`. + * @param objectId the object's identifier number + */ +class FacilityTurretDefinition(private val objectId : Int) extends ObjectDefinition(objectId) + with TurretDefinition { + Damage = StandardVehicleDamage + Resistance = StandardVehicleResistance + Model = StandardResolutions.FacilityTurrets +} + diff --git a/common/src/main/scala/net/psforever/objects/serverobject/turret/TurretDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/turret/TurretDefinition.scala index 90abe882..d9a7eae2 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/turret/TurretDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/turret/TurretDefinition.scala @@ -3,19 +3,18 @@ package net.psforever.objects.serverobject.turret import net.psforever.objects.definition.{ObjectDefinition, ToolDefinition} import net.psforever.objects.vehicles.Turrets -import net.psforever.objects.vital.{DamageResistanceModel, StandardResolutions, StandardVehicleDamage, StandardVehicleResistance} +import net.psforever.objects.vital.DamageResistanceModel import net.psforever.objects.vital.resistance.ResistanceProfileMutators import scala.collection.mutable /** * The definition for any `MannedTurret`. - * @param objectId the object's identifier number */ -class TurretDefinition(private val objectId : Int) extends ObjectDefinition(objectId) - with ResistanceProfileMutators +trait TurretDefinition extends ResistanceProfileMutators with DamageResistanceModel { - Turrets(objectId) //let throw NoSuchElementException + odef : ObjectDefinition => + Turrets(odef.ObjectId) //let throw NoSuchElementException private var maxHealth : Int = 100 /* key - entry point index, value - seat index */ @@ -29,9 +28,6 @@ class TurretDefinition(private val objectId : Int) extends ObjectDefinition(obje /** creates internal ammunition reserves that can not become depleted * see `MannedTurret.TurretAmmoBox` for details */ private var hasReserveAmmunition : Boolean = false - Damage = StandardVehicleDamage - Resistance = StandardVehicleResistance - Model = StandardResolutions.FacilityTurrets def MaxHealth : Int = maxHealth diff --git a/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala b/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala index 97a8e745..64f1b9af 100644 --- a/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala +++ b/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala @@ -2,7 +2,7 @@ package net.psforever.objects.vehicles import akka.actor.ActorContext -import net.psforever.objects.definition.DeployableDefinition +import net.psforever.objects.definition.SimpleDeployableDefinition import net.psforever.objects._ import net.psforever.objects.ce.TelepadLike import net.psforever.objects.serverobject.structures.Amenity @@ -193,7 +193,7 @@ object Utility { * and allows it to serve as one of the terminal points of a Router-telepad teleportation system. * @param ddef na */ - class InternalTelepad(ddef : DeployableDefinition) extends Amenity + class InternalTelepad(ddef : SimpleDeployableDefinition) extends Amenity with TelepadLike { /** a link to the telepad that serves as the other endpoint of this teleportation system */ private var activeTelepad : Option[PlanetSideGUID] = None diff --git a/common/src/main/scala/net/psforever/objects/zones/ZoneDeployableActor.scala b/common/src/main/scala/net/psforever/objects/zones/ZoneDeployableActor.scala index 593d1847..a53ea99d 100644 --- a/common/src/main/scala/net/psforever/objects/zones/ZoneDeployableActor.scala +++ b/common/src/main/scala/net/psforever/objects/zones/ZoneDeployableActor.scala @@ -25,6 +25,7 @@ class ZoneDeployableActor(zone : Zone, deployableList : ListBuffer[PlanetSideGam case _ => obj.Definition.Initialize(obj, context) } + obj.Zone = zone sender ! Zone.Deployable.DeployableIsBuilt(obj, tool) } diff --git a/common/src/test/scala/objects/FacilityTurretTest.scala b/common/src/test/scala/objects/FacilityTurretTest.scala index 8c8ffe30..09f73b9f 100644 --- a/common/src/test/scala/objects/FacilityTurretTest.scala +++ b/common/src/test/scala/objects/FacilityTurretTest.scala @@ -19,7 +19,7 @@ import scala.concurrent.duration._ class FacilityTurretTest extends Specification { "FacilityTurretTest" should { "define" in { - val obj = new TurretDefinition(480) + val obj = new FacilityTurretDefinition(480) obj.Weapons mustEqual mutable.HashMap.empty[TurretUpgrade.Value, ToolDefinition] obj.ReserveAmmunition mustEqual false obj.FactionLocked mustEqual true @@ -152,7 +152,7 @@ class FacilityTurretControl3Test extends ActorTest { class FacilityTurretControl4Test extends ActorTest { val player = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - val objDef = new TurretDefinition(480) + val objDef = new FacilityTurretDefinition(480) objDef.FactionLocked = false val obj = FacilityTurret(objDef) obj.GUID = PlanetSideGUID(1) diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index f986a8ad..4459a930 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -915,16 +915,8 @@ class WorldSessionActor extends Actor continent.Deployables ! Zone.Deployable.Dismiss(obj) } - case WorldSessionActor.FinalizeDeployable(obj : TurretDeployable, tool, index) => - //spitfires and deployable field turrets - StartBundlingPackets() - DeployableBuildActivity(obj) - CommonDestroyConstructionItem(tool, index) - FindReplacementConstructionItem(tool, index) - StopBundlingPackets() - case WorldSessionActor.FinalizeDeployable(obj : ComplexDeployable, tool, index) => - //deployable_shield_generator + //spitfires and deployable field turrets and the deployable_shield_generator StartBundlingPackets() DeployableBuildActivity(obj) CommonDestroyConstructionItem(tool, index) @@ -1017,7 +1009,7 @@ class WorldSessionActor extends Actor StartBundlingPackets() sendResponse(GenericObjectActionMessage(guid, 21)) //reset build cooldown sendResponse(ObjectDeployedMessage.Failure(definition.Name)) - log.warn(s"FinalizeDeployable: deployable ${definition.asInstanceOf[DeployableDefinition].Item}@$guid not handled by specific case") + log.warn(s"FinalizeDeployable: deployable ${definition.asInstanceOf[SimpleDeployableDefinition].Item}@$guid not handled by specific case") log.warn(s"FinalizeDeployable: deployable will be cleaned up, but may not get unregistered properly") TryDropConstructionTool(tool, index, obj.Position) obj.Position = Vector3.Zero @@ -1133,18 +1125,6 @@ class WorldSessionActor extends Actor AnnounceDestroyDeployable(target, Some(0 seconds)) } - case Vitality.DamageResolution(target : TurretDeployable, _) => - HandleTurretDeployableDamageResolution(target) - - case Vitality.DamageResolution(target : ComplexDeployable, _) => - //shield_generators - val health = target.Health - val guid = target.GUID - continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(guid, 0, health)) - if(health <= 0) { - AnnounceDestroyDeployable(target, None) - } - case Vitality.DamageResolution(target : PlanetSideGameObject, _) => log.warn(s"Vital target ${target.Definition.Name} damage resolution not supported using this method") @@ -1243,22 +1223,19 @@ class WorldSessionActor extends Actor sendResponse(GenericObjectActionMessage(guid, 9)) case AvatarResponse.EnvironmentalDamage(target, amount) => - if(player.isAlive) { + if(player.isAlive && amount != 0) { + val armor = player.Armor + val capacitor = player.Capacitor val originalHealth = player.Health - player.Health = player.Health - amount + player.Health = originalHealth - amount sendResponse(PlanetsideAttributeMessage(target, 0, player.Health)) continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(target, 0, player.Health)) - damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth, AFTER=${player.Health}, CHANGE=$amount") - if(amount != 0) { - val playerGUID = player.GUID - sendResponse(PlanetsideAttributeMessage(playerGUID, 0, player.Health)) - continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 0, player.Health)) - if(player.Health == 0 && player.isAlive) { - KillPlayer(player) - } - else { - //todo: History? - } + damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth/$armor/$capacitor, AFTER=${player.Health}/$armor/$capacitor, CHANGE=$amount/0/0") + if(player.Health == 0 && player.isAlive) { + KillPlayer(player) + } + else { + //todo: History? } } @@ -1274,19 +1251,17 @@ class WorldSessionActor extends Actor val damageToHealth = originalHealth - health val damageToArmor = originalArmor - armor val damageToCapacitor = originalCapacitor - capacitor - damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth/$originalArmor/$originalCapacitor, AFTER=$health/$armor/$capacitor, CHANGE=$damageToHealth/$damageToArmor/$damageToCapacitor") if(damageToHealth != 0 || damageToArmor != 0 || damageToCapacitor != 0) { + damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth/$originalArmor/$originalCapacitor, AFTER=$health/$armor/$capacitor, CHANGE=$damageToHealth/$damageToArmor/$damageToCapacitor") val playerGUID = player.GUID if(damageToHealth > 0) { sendResponse(PlanetsideAttributeMessage(playerGUID, 0, health)) continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 0, health)) } - if(damageToArmor > 0) { sendResponse(PlanetsideAttributeMessage(playerGUID, 4, armor)) continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 4, armor)) } - if(damageToCapacitor > 0) { sendResponse(PlanetsideAttributeMessage(playerGUID, 7, capacitor)) } @@ -2933,40 +2908,6 @@ class WorldSessionActor extends Actor msgs } - /** - * na - * @param target na - */ - def HandleTurretDeployableDamageResolution(target : TurretDeployable) : Unit = { - //spitfires and field turrets - val health = target.Health - val guid = target.GUID - val continentId = continent.Id - if(health <= 0) { - //if occupants, kill them - target.Seats.values - .filter(seat => { - seat.isOccupied && seat.Occupant.get.isAlive - }) - .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 - }) - //destroy weapons - target.Weapons.values - .map(slot => slot.Equipment) - .collect { case Some(weapon) => - val wguid = weapon.GUID - sendResponse(ObjectDeleteMessage(wguid, 0)) - continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(player.GUID, wguid)) - } - AnnounceDestroyDeployable(target, None) - } - continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.PlanetsideAttribute(guid, 0, health)) - } - /** * na * @param tplayer na @@ -8499,13 +8440,12 @@ class WorldSessionActor extends Actor case obj : Player => //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 - obj.Actor ! Vitality.Damage(func) - case obj : FacilityTurret => - //damage is synchronized on the turret actor - obj.Actor ! Vitality.Damage(func) - case obj : Deployable => + + case obj : Vehicle => obj.Actor ! Vitality.Damage(func) + case obj : FacilityTurret => obj.Actor ! Vitality.Damage(func) + case obj : ComplexDeployable => obj.Actor ! Vitality.Damage(func) + + case obj : SimpleDeployable => //damage is synchronized on `LSA` (results returned to and distributed from this `WSA`) continent.LocalEvents ! Vitality.DamageOn(obj, func) case _ => ; @@ -10216,7 +10156,7 @@ class WorldSessionActor extends Actor } } - def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit = target match { + override 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 {