mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-12 06:55:10 +00:00
commit
a5f1638fd6
72 changed files with 1936 additions and 832 deletions
|
|
@ -1,9 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.definition.DeployableDefinition
|
class BoomerDeployable(cdef : ExplosiveDeployableDefinition) extends ExplosiveDeployable(cdef) {
|
||||||
|
|
||||||
class BoomerDeployable(cdef : DeployableDefinition) extends ExplosiveDeployable(cdef) {
|
|
||||||
private var trigger : Option[BoomerTrigger] = None
|
private var trigger : Option[BoomerTrigger] = None
|
||||||
|
|
||||||
def Trigger : Option[BoomerTrigger] = trigger
|
def Trigger : Option[BoomerTrigger] = trigger
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,12 @@
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.ce.{Deployable, DeployedItem}
|
import net.psforever.objects.ce.{Deployable, DeployedItem}
|
||||||
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
import net.psforever.packet.game.{DeployableInfo, DeploymentAction, PlanetSideGUID}
|
||||||
|
import services.RemoverActor
|
||||||
|
import services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
|
||||||
|
import scala.concurrent.duration.FiniteDuration
|
||||||
|
|
||||||
object Deployables {
|
object Deployables {
|
||||||
object Make {
|
object Make {
|
||||||
|
|
@ -26,4 +32,43 @@ object Deployables {
|
||||||
DeployedItem.router_telepad_deployable -> { () => new TelepadDeployable(GlobalDefinitions.router_telepad_deployable) }
|
DeployedItem.router_telepad_deployable -> { () => new TelepadDeployable(GlobalDefinitions.router_telepad_deployable) }
|
||||||
).withDefaultValue( { ()=> new ExplosiveDeployable(GlobalDefinitions.boomer) } )
|
).withDefaultValue( { ()=> new ExplosiveDeployable(GlobalDefinitions.boomer) } )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Distribute information that a deployable has been destroyed.
|
||||||
|
* The deployable may not have yet been eliminated from the game world (client or server),
|
||||||
|
* but its health is zero and it has entered the conditions where it is nearly irrelevant.<br>
|
||||||
|
* <br>
|
||||||
|
* The typical use case of this function involves destruction via weapon fire, attributed to a particular player.
|
||||||
|
* Contrast this to simply destroying a deployable by being the deployable's owner and using the map icon controls.
|
||||||
|
* This function eventually invokes the same routine
|
||||||
|
* but mainly goes into effect when the deployable has been destroyed
|
||||||
|
* and may still leave a physical component in the game world to be cleaned up later.
|
||||||
|
* That is the task `EliminateDeployable` performs.
|
||||||
|
* Additionally, since the player who destroyed the deployable isn't necessarily the owner,
|
||||||
|
* and the real owner will still be aware of the existence of the deployable,
|
||||||
|
* that player must be informed of the loss of the deployable directly.
|
||||||
|
* @see `DeployableRemover`
|
||||||
|
* @see `Vitality.DamageResolution`
|
||||||
|
* @see `LocalResponse.EliminateDeployable`
|
||||||
|
* @see `DeconstructDeployable`
|
||||||
|
* @param target the deployable that is destroyed
|
||||||
|
* @param time length of time that the deployable is allowed to exist in the game world;
|
||||||
|
* `None` indicates the normal un-owned existence time (180 seconds)
|
||||||
|
*/
|
||||||
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,23 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.ce.SimpleDeployable
|
import akka.actor.{Actor, ActorContext, Props}
|
||||||
import net.psforever.objects.definition.DeployableDefinition
|
import net.psforever.objects.ballistics.ResolvedProjectile
|
||||||
|
import net.psforever.objects.ce._
|
||||||
|
import net.psforever.objects.definition.{ComplexDeployableDefinition, SimpleDeployableDefinition}
|
||||||
|
import net.psforever.objects.definition.converter.SmallDeployableConverter
|
||||||
|
import net.psforever.objects.equipment.JammableUnit
|
||||||
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
import net.psforever.objects.vital.{StandardResolutions, Vitality}
|
||||||
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
import net.psforever.types.Vector3
|
||||||
|
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
import services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
|
||||||
class ExplosiveDeployable(cdef : DeployableDefinition) extends SimpleDeployable(cdef) {
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
class ExplosiveDeployable(cdef : ExplosiveDeployableDefinition) extends ComplexDeployable(cdef)
|
||||||
|
with JammableUnit {
|
||||||
private var exploded : Boolean = false
|
private var exploded : Boolean = false
|
||||||
|
|
||||||
def Exploded : Boolean = exploded
|
def Exploded : Boolean = exploded
|
||||||
|
|
@ -13,4 +26,86 @@ class ExplosiveDeployable(cdef : DeployableDefinition) extends SimpleDeployable(
|
||||||
exploded = fuse
|
exploded = fuse
|
||||||
Exploded
|
Exploded
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def Definition : ExplosiveDeployableDefinition = cdef
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ExplosiveDeployableDefinition(private val objectId : Int) extends ComplexDeployableDefinition(objectId) {
|
||||||
|
Name = "explosive_deployable"
|
||||||
|
DeployCategory = DeployableCategory.Mines
|
||||||
|
Model = StandardResolutions.SimpleDeployables
|
||||||
|
Packet = new SmallDeployableConverter
|
||||||
|
|
||||||
|
private var detonateOnJamming : Boolean = true
|
||||||
|
|
||||||
|
def DetonateOnJamming : Boolean = detonateOnJamming
|
||||||
|
|
||||||
|
def DetonateOnJamming_=(detonate : Boolean) : Boolean = {
|
||||||
|
detonateOnJamming = detonate
|
||||||
|
DetonateOnJamming
|
||||||
|
}
|
||||||
|
|
||||||
|
override def Initialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = {
|
||||||
|
obj.Actor = context.actorOf(Props(classOf[ExplosiveDeployableControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = {
|
||||||
|
SimpleDeployableDefinition.SimpleUninitialize(obj, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ExplosiveDeployableDefinition {
|
||||||
|
def apply(dtype : DeployedItem.Value) : ExplosiveDeployableDefinition = {
|
||||||
|
new ExplosiveDeployableDefinition(dtype.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExplosiveDeployableControl(mine : ExplosiveDeployable) extends Actor {
|
||||||
|
def receive : Receive = {
|
||||||
|
case Vitality.Damage(damage_func) =>
|
||||||
|
val originalHealth = mine.Health
|
||||||
|
if(originalHealth > 0) {
|
||||||
|
val cause = damage_func(mine)
|
||||||
|
ExplosiveDeployableControl.HandleDamageResolution(mine, cause, originalHealth - mine.Health)
|
||||||
|
}
|
||||||
|
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ExplosiveDeployableControl {
|
||||||
|
def HandleDamageResolution(target : ExplosiveDeployable, cause : ResolvedProjectile, damage : Int) : Unit = {
|
||||||
|
val zone = target.Zone
|
||||||
|
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) {
|
||||||
|
HandleDestructionAwareness(target, playerGUID, cause)
|
||||||
|
}
|
||||||
|
else if(!target.Jammed && cause.projectile.profile.JammerProjectile) {
|
||||||
|
if(target.Jammed = {
|
||||||
|
val radius = cause.projectile.profile.DamageRadius
|
||||||
|
Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius
|
||||||
|
}) {
|
||||||
|
if(target.Definition.DetonateOnJamming) {
|
||||||
|
target.Zone.LocalEvents ! LocalServiceMessage(target.Zone.Id, LocalAction.Detonate(target.GUID, target))
|
||||||
|
}
|
||||||
|
HandleDestructionAwareness(target, playerGUID, cause)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param target na
|
||||||
|
* @param attribution na
|
||||||
|
* @param lastShot na
|
||||||
|
*/
|
||||||
|
def HandleDestructionAwareness(target : ExplosiveDeployable, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = {
|
||||||
|
val zone = target.Zone
|
||||||
|
Deployables.AnnounceDestroyDeployable(target, Some(if(target.Jammed) 0 seconds else 500 milliseconds))
|
||||||
|
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.Destroy(target.GUID, attribution, attribution, target.Position))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import net.psforever.objects.serverobject.terminals._
|
||||||
import net.psforever.objects.serverobject.tube.SpawnTubeDefinition
|
import net.psforever.objects.serverobject.tube.SpawnTubeDefinition
|
||||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSiloDefinition
|
import net.psforever.objects.serverobject.resourcesilo.ResourceSiloDefinition
|
||||||
import net.psforever.objects.serverobject.structures.SphereOfInfluence
|
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.vehicles.{DestroyedVehicle, SeatArmorRestriction, UtilityType}
|
||||||
import net.psforever.objects.vital.{DamageType, StandardMaxDamage, StandardResolutions}
|
import net.psforever.objects.vital.{DamageType, StandardMaxDamage, StandardResolutions}
|
||||||
import net.psforever.types.{CertificationType, ExoSuitType, PlanetSideEmpire, Vector3}
|
import net.psforever.types.{CertificationType, ExoSuitType, PlanetSideEmpire, Vector3}
|
||||||
|
|
@ -870,11 +870,11 @@ object GlobalDefinitions {
|
||||||
/*
|
/*
|
||||||
combat engineering deployables
|
combat engineering deployables
|
||||||
*/
|
*/
|
||||||
val boomer = DeployableDefinition(DeployedItem.boomer)
|
val boomer = ExplosiveDeployableDefinition(DeployedItem.boomer)
|
||||||
|
|
||||||
val he_mine = DeployableDefinition(DeployedItem.he_mine)
|
val he_mine = ExplosiveDeployableDefinition(DeployedItem.he_mine)
|
||||||
|
|
||||||
val jammer_mine = DeployableDefinition(DeployedItem.jammer_mine)
|
val jammer_mine = ExplosiveDeployableDefinition(DeployedItem.jammer_mine)
|
||||||
|
|
||||||
val spitfire_turret = TurretDeployableDefinition(DeployedItem.spitfire_turret)
|
val spitfire_turret = TurretDeployableDefinition(DeployedItem.spitfire_turret)
|
||||||
|
|
||||||
|
|
@ -882,11 +882,11 @@ object GlobalDefinitions {
|
||||||
|
|
||||||
val spitfire_aa = TurretDeployableDefinition(DeployedItem.spitfire_aa)
|
val spitfire_aa = TurretDeployableDefinition(DeployedItem.spitfire_aa)
|
||||||
|
|
||||||
val motionalarmsensor = DeployableDefinition(DeployedItem.motionalarmsensor)
|
val motionalarmsensor = SensorDeployableDefinition(DeployedItem.motionalarmsensor)
|
||||||
|
|
||||||
val sensor_shield = DeployableDefinition(DeployedItem.sensor_shield)
|
val sensor_shield = SensorDeployableDefinition(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)
|
val portable_manned_turret = TurretDeployableDefinition(DeployedItem.portable_manned_turret)
|
||||||
|
|
||||||
|
|
@ -898,10 +898,10 @@ object GlobalDefinitions {
|
||||||
|
|
||||||
val deployable_shield_generator = new ShieldGeneratorDefinition
|
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
|
//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()
|
init_deployables()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -989,7 +989,7 @@ object GlobalDefinitions {
|
||||||
|
|
||||||
val ground_rearm_terminal = new OrderTerminalDefinition(384)
|
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 = new PainboxDefinition(622)
|
||||||
val painbox_continuous = new PainboxDefinition(623)
|
val painbox_continuous = new PainboxDefinition(623)
|
||||||
|
|
@ -2686,6 +2686,14 @@ object GlobalDefinitions {
|
||||||
jammer_cartridge_projectile.ProjectileDamageType = DamageType.Splash
|
jammer_cartridge_projectile.ProjectileDamageType = DamageType.Splash
|
||||||
jammer_cartridge_projectile.InitialVelocity = 30
|
jammer_cartridge_projectile.InitialVelocity = 30
|
||||||
jammer_cartridge_projectile.Lifespan = 15f
|
jammer_cartridge_projectile.Lifespan = 15f
|
||||||
|
jammer_cartridge_projectile.AdditionalEffect = true
|
||||||
|
jammer_cartridge_projectile.JammerProjectile = true
|
||||||
|
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Player, EffectTarget.Validation.Player) -> 1000
|
||||||
|
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.AMS) -> 5000
|
||||||
|
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.MotionSensor) -> 30000
|
||||||
|
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.Spitfire) -> 30000
|
||||||
|
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Turret, EffectTarget.Validation.Turret) -> 30000
|
||||||
|
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.VehicleNotAMS) -> 10000
|
||||||
ProjectileDefinition.CalculateDerivedFields(jammer_cartridge_projectile)
|
ProjectileDefinition.CalculateDerivedFields(jammer_cartridge_projectile)
|
||||||
|
|
||||||
jammer_cartridge_projectile_b.Name = "jammer_cartridge_projectile_b"
|
jammer_cartridge_projectile_b.Name = "jammer_cartridge_projectile_b"
|
||||||
|
|
@ -2697,6 +2705,14 @@ object GlobalDefinitions {
|
||||||
jammer_cartridge_projectile_b.ProjectileDamageType = DamageType.Splash
|
jammer_cartridge_projectile_b.ProjectileDamageType = DamageType.Splash
|
||||||
jammer_cartridge_projectile_b.InitialVelocity = 30
|
jammer_cartridge_projectile_b.InitialVelocity = 30
|
||||||
jammer_cartridge_projectile_b.Lifespan = 2f
|
jammer_cartridge_projectile_b.Lifespan = 2f
|
||||||
|
jammer_cartridge_projectile_b.AdditionalEffect = true
|
||||||
|
jammer_cartridge_projectile_b.JammerProjectile = true
|
||||||
|
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(EffectTarget.Category.Player, EffectTarget.Validation.Player) -> 1000
|
||||||
|
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.AMS) -> 5000
|
||||||
|
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.MotionSensor) -> 30000
|
||||||
|
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.Spitfire) -> 30000
|
||||||
|
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(EffectTarget.Category.Turret, EffectTarget.Validation.Turret) -> 30000
|
||||||
|
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.VehicleNotAMS) -> 10000
|
||||||
ProjectileDefinition.CalculateDerivedFields(jammer_cartridge_projectile_b)
|
ProjectileDefinition.CalculateDerivedFields(jammer_cartridge_projectile_b)
|
||||||
|
|
||||||
jammer_grenade_projectile.Name = "jammer_grenade_projectile"
|
jammer_grenade_projectile.Name = "jammer_grenade_projectile"
|
||||||
|
|
@ -2707,6 +2723,14 @@ object GlobalDefinitions {
|
||||||
jammer_grenade_projectile.ProjectileDamageType = DamageType.Splash
|
jammer_grenade_projectile.ProjectileDamageType = DamageType.Splash
|
||||||
jammer_grenade_projectile.InitialVelocity = 30
|
jammer_grenade_projectile.InitialVelocity = 30
|
||||||
jammer_grenade_projectile.Lifespan = 15f
|
jammer_grenade_projectile.Lifespan = 15f
|
||||||
|
jammer_grenade_projectile.AdditionalEffect = true
|
||||||
|
jammer_grenade_projectile.JammerProjectile = true
|
||||||
|
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Player, EffectTarget.Validation.Player) -> 1000
|
||||||
|
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.AMS) -> 5000
|
||||||
|
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.MotionSensor) -> 30000
|
||||||
|
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.Spitfire) -> 30000
|
||||||
|
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Turret, EffectTarget.Validation.Turret) -> 30000
|
||||||
|
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.VehicleNotAMS) -> 10000
|
||||||
ProjectileDefinition.CalculateDerivedFields(jammer_grenade_projectile)
|
ProjectileDefinition.CalculateDerivedFields(jammer_grenade_projectile)
|
||||||
|
|
||||||
jammer_grenade_projectile_enh.Name = "jammer_grenade_projectile_enh"
|
jammer_grenade_projectile_enh.Name = "jammer_grenade_projectile_enh"
|
||||||
|
|
@ -2718,6 +2742,14 @@ object GlobalDefinitions {
|
||||||
jammer_grenade_projectile_enh.ProjectileDamageType = DamageType.Splash
|
jammer_grenade_projectile_enh.ProjectileDamageType = DamageType.Splash
|
||||||
jammer_grenade_projectile_enh.InitialVelocity = 30
|
jammer_grenade_projectile_enh.InitialVelocity = 30
|
||||||
jammer_grenade_projectile_enh.Lifespan = 3f
|
jammer_grenade_projectile_enh.Lifespan = 3f
|
||||||
|
jammer_grenade_projectile_enh.AdditionalEffect = true
|
||||||
|
jammer_grenade_projectile_enh.JammerProjectile = true
|
||||||
|
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(EffectTarget.Category.Player, EffectTarget.Validation.Player) -> 1000
|
||||||
|
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.AMS) -> 5000
|
||||||
|
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.MotionSensor) -> 30000
|
||||||
|
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.Spitfire) -> 30000
|
||||||
|
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(EffectTarget.Category.Turret, EffectTarget.Validation.Turret) -> 30000
|
||||||
|
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.VehicleNotAMS) -> 10000
|
||||||
ProjectileDefinition.CalculateDerivedFields(jammer_grenade_projectile_enh)
|
ProjectileDefinition.CalculateDerivedFields(jammer_grenade_projectile_enh)
|
||||||
|
|
||||||
katana_projectile.Name = "katana_projectile"
|
katana_projectile.Name = "katana_projectile"
|
||||||
|
|
@ -5870,24 +5902,20 @@ object GlobalDefinitions {
|
||||||
boomer.MaxHealth = 100
|
boomer.MaxHealth = 100
|
||||||
boomer.DeployCategory = DeployableCategory.Boomers
|
boomer.DeployCategory = DeployableCategory.Boomers
|
||||||
boomer.DeployTime = Duration.create(1000, "ms")
|
boomer.DeployTime = Duration.create(1000, "ms")
|
||||||
boomer.Model = StandardResolutions.SimpleDeployables
|
|
||||||
|
|
||||||
he_mine.Name = "he_mine"
|
he_mine.Name = "he_mine"
|
||||||
he_mine.Descriptor = "Mines"
|
he_mine.Descriptor = "Mines"
|
||||||
he_mine.MaxHealth = 100
|
he_mine.MaxHealth = 100
|
||||||
he_mine.DeployCategory = DeployableCategory.Mines
|
|
||||||
he_mine.DeployTime = Duration.create(1000, "ms")
|
he_mine.DeployTime = Duration.create(1000, "ms")
|
||||||
he_mine.Model = StandardResolutions.SimpleDeployables
|
|
||||||
|
|
||||||
jammer_mine.Name = "jammer_mine"
|
jammer_mine.Name = "jammer_mine"
|
||||||
jammer_mine.Descriptor = "JammerMines"
|
jammer_mine.Descriptor = "JammerMines"
|
||||||
jammer_mine.MaxHealth = 100
|
jammer_mine.MaxHealth = 100
|
||||||
jammer_mine.DeployCategory = DeployableCategory.Mines
|
|
||||||
jammer_mine.DeployTime = Duration.create(1000, "ms")
|
jammer_mine.DeployTime = Duration.create(1000, "ms")
|
||||||
jammer_mine.Model = StandardResolutions.SimpleDeployables
|
jammer_mine.DetonateOnJamming = false
|
||||||
|
|
||||||
spitfire_turret.Name = "spitfire_turret"
|
spitfire_turret.Name = "spitfire_turret"
|
||||||
spitfire_turret.Descriptor= "Spitfires"
|
spitfire_turret.Descriptor = "Spitfires"
|
||||||
spitfire_turret.MaxHealth = 100
|
spitfire_turret.MaxHealth = 100
|
||||||
spitfire_turret.Weapons += 1 -> new mutable.HashMap()
|
spitfire_turret.Weapons += 1 -> new mutable.HashMap()
|
||||||
spitfire_turret.Weapons(1) += TurretUpgrade.None -> spitfire_weapon
|
spitfire_turret.Weapons(1) += TurretUpgrade.None -> spitfire_weapon
|
||||||
|
|
@ -5897,7 +5925,7 @@ object GlobalDefinitions {
|
||||||
spitfire_turret.Model = StandardResolutions.ComplexDeployables
|
spitfire_turret.Model = StandardResolutions.ComplexDeployables
|
||||||
|
|
||||||
spitfire_cloaked.Name = "spitfire_cloaked"
|
spitfire_cloaked.Name = "spitfire_cloaked"
|
||||||
spitfire_cloaked.Descriptor= "CloakingSpitfires"
|
spitfire_cloaked.Descriptor = "CloakingSpitfires"
|
||||||
spitfire_cloaked.MaxHealth = 100
|
spitfire_cloaked.MaxHealth = 100
|
||||||
spitfire_cloaked.Weapons += 1 -> new mutable.HashMap()
|
spitfire_cloaked.Weapons += 1 -> new mutable.HashMap()
|
||||||
spitfire_cloaked.Weapons(1) += TurretUpgrade.None -> spitfire_weapon
|
spitfire_cloaked.Weapons(1) += TurretUpgrade.None -> spitfire_weapon
|
||||||
|
|
@ -5907,7 +5935,7 @@ object GlobalDefinitions {
|
||||||
spitfire_cloaked.Model = StandardResolutions.ComplexDeployables
|
spitfire_cloaked.Model = StandardResolutions.ComplexDeployables
|
||||||
|
|
||||||
spitfire_aa.Name = "spitfire_aa"
|
spitfire_aa.Name = "spitfire_aa"
|
||||||
spitfire_aa.Descriptor= "FlakSpitfires"
|
spitfire_aa.Descriptor = "FlakSpitfires"
|
||||||
spitfire_aa.MaxHealth = 100
|
spitfire_aa.MaxHealth = 100
|
||||||
spitfire_aa.Weapons += 1 -> new mutable.HashMap()
|
spitfire_aa.Weapons += 1 -> new mutable.HashMap()
|
||||||
spitfire_aa.Weapons(1) += TurretUpgrade.None -> spitfire_aa_weapon
|
spitfire_aa.Weapons(1) += TurretUpgrade.None -> spitfire_aa_weapon
|
||||||
|
|
@ -5919,16 +5947,12 @@ object GlobalDefinitions {
|
||||||
motionalarmsensor.Name = "motionalarmsensor"
|
motionalarmsensor.Name = "motionalarmsensor"
|
||||||
motionalarmsensor.Descriptor = "MotionSensors"
|
motionalarmsensor.Descriptor = "MotionSensors"
|
||||||
motionalarmsensor.MaxHealth = 100
|
motionalarmsensor.MaxHealth = 100
|
||||||
motionalarmsensor.DeployCategory = DeployableCategory.Sensors
|
|
||||||
motionalarmsensor.DeployTime = Duration.create(1000, "ms")
|
motionalarmsensor.DeployTime = Duration.create(1000, "ms")
|
||||||
motionalarmsensor.Model = StandardResolutions.SimpleDeployables
|
|
||||||
|
|
||||||
sensor_shield.Name = "sensor_shield"
|
sensor_shield.Name = "sensor_shield"
|
||||||
sensor_shield.Descriptor = "SensorShields"
|
sensor_shield.Descriptor = "SensorShields"
|
||||||
sensor_shield.MaxHealth = 100
|
sensor_shield.MaxHealth = 100
|
||||||
sensor_shield.DeployCategory = DeployableCategory.Sensors
|
|
||||||
sensor_shield.DeployTime = Duration.create(5000, "ms")
|
sensor_shield.DeployTime = Duration.create(5000, "ms")
|
||||||
sensor_shield.Model = StandardResolutions.SimpleDeployables
|
|
||||||
|
|
||||||
tank_traps.Name = "tank_traps"
|
tank_traps.Name = "tank_traps"
|
||||||
tank_traps.Descriptor = "TankTraps"
|
tank_traps.Descriptor = "TankTraps"
|
||||||
|
|
@ -6096,62 +6120,62 @@ object GlobalDefinitions {
|
||||||
teleportpad_terminal.Name = "teleportpad_terminal"
|
teleportpad_terminal.Name = "teleportpad_terminal"
|
||||||
teleportpad_terminal.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.routerTerminal)
|
teleportpad_terminal.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.routerTerminal)
|
||||||
|
|
||||||
adv_med_terminal.Name = "adv_med_terminal"
|
|
||||||
adv_med_terminal.Interval = 500
|
|
||||||
adv_med_terminal.HealAmount = 8
|
|
||||||
adv_med_terminal.ArmorAmount = 15
|
|
||||||
adv_med_terminal.UseRadius = 0.75f
|
|
||||||
adv_med_terminal.TargetValidation += ProximityTarget.Player -> ProximityTerminalControl.Validation.Medical
|
|
||||||
|
|
||||||
crystals_health_a.Name = "crystals_health_a"
|
|
||||||
crystals_health_a.Interval = 500
|
|
||||||
crystals_health_a.HealAmount = 4
|
|
||||||
crystals_health_a.UseRadius = 5
|
|
||||||
crystals_health_a.TargetValidation += ProximityTarget.Player -> ProximityTerminalControl.Validation.HealthCrystal
|
|
||||||
|
|
||||||
crystals_health_b.Name = "crystals_health_b"
|
|
||||||
crystals_health_b.Interval = 500
|
|
||||||
crystals_health_b.HealAmount = 4
|
|
||||||
crystals_health_b.UseRadius = 1.3f
|
|
||||||
crystals_health_b.TargetValidation += ProximityTarget.Player -> ProximityTerminalControl.Validation.HealthCrystal
|
|
||||||
|
|
||||||
medical_terminal.Name = "medical_terminal"
|
medical_terminal.Name = "medical_terminal"
|
||||||
medical_terminal.Interval = 500
|
medical_terminal.Interval = 500
|
||||||
medical_terminal.HealAmount = 5
|
medical_terminal.HealAmount = 5
|
||||||
medical_terminal.ArmorAmount = 10
|
medical_terminal.ArmorAmount = 10
|
||||||
medical_terminal.UseRadius = 0.75f
|
medical_terminal.UseRadius = 0.75f
|
||||||
medical_terminal.TargetValidation += ProximityTarget.Player -> ProximityTerminalControl.Validation.Medical
|
medical_terminal.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.Medical
|
||||||
|
|
||||||
|
adv_med_terminal.Name = "adv_med_terminal"
|
||||||
|
adv_med_terminal.Interval = 500
|
||||||
|
adv_med_terminal.HealAmount = 8
|
||||||
|
adv_med_terminal.ArmorAmount = 15
|
||||||
|
adv_med_terminal.UseRadius = 0.75f
|
||||||
|
adv_med_terminal.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.Medical
|
||||||
|
|
||||||
|
crystals_health_a.Name = "crystals_health_a"
|
||||||
|
crystals_health_a.Interval = 500
|
||||||
|
crystals_health_a.HealAmount = 4
|
||||||
|
crystals_health_a.UseRadius = 5
|
||||||
|
crystals_health_a.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.HealthCrystal
|
||||||
|
|
||||||
|
crystals_health_b.Name = "crystals_health_b"
|
||||||
|
crystals_health_b.Interval = 500
|
||||||
|
crystals_health_b.HealAmount = 4
|
||||||
|
crystals_health_b.UseRadius = 1.3f
|
||||||
|
crystals_health_b.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.HealthCrystal
|
||||||
|
|
||||||
portable_med_terminal.Name = "portable_med_terminal"
|
portable_med_terminal.Name = "portable_med_terminal"
|
||||||
portable_med_terminal.Interval = 500
|
portable_med_terminal.Interval = 500
|
||||||
portable_med_terminal.HealAmount = 5
|
portable_med_terminal.HealAmount = 5
|
||||||
portable_med_terminal.ArmorAmount = 10
|
portable_med_terminal.ArmorAmount = 10
|
||||||
portable_med_terminal.UseRadius = 3
|
portable_med_terminal.UseRadius = 3
|
||||||
portable_med_terminal.TargetValidation += ProximityTarget.Player -> ProximityTerminalControl.Validation.Medical
|
portable_med_terminal.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.Medical
|
||||||
|
|
||||||
pad_landing_frame.Name = "pad_landing_frame"
|
pad_landing_frame.Name = "pad_landing_frame"
|
||||||
pad_landing_frame.Interval = 1000
|
pad_landing_frame.Interval = 1000
|
||||||
pad_landing_frame.HealAmount = 60
|
pad_landing_frame.HealAmount = 60
|
||||||
pad_landing_frame.UseRadius = 20
|
pad_landing_frame.UseRadius = 20
|
||||||
pad_landing_frame.TargetValidation += ProximityTarget.Aircraft -> ProximityTerminalControl.Validation.PadLanding
|
pad_landing_frame.TargetValidation += EffectTarget.Category.Aircraft -> EffectTarget.Validation.PadLanding
|
||||||
|
|
||||||
pad_landing_tower_frame.Name = "pad_landing_tower_frame"
|
pad_landing_tower_frame.Name = "pad_landing_tower_frame"
|
||||||
pad_landing_tower_frame.Interval = 1000
|
pad_landing_tower_frame.Interval = 1000
|
||||||
pad_landing_tower_frame.HealAmount = 60
|
pad_landing_tower_frame.HealAmount = 60
|
||||||
pad_landing_tower_frame.UseRadius = 20
|
pad_landing_tower_frame.UseRadius = 20
|
||||||
pad_landing_tower_frame.TargetValidation += ProximityTarget.Aircraft -> ProximityTerminalControl.Validation.PadLanding
|
pad_landing_tower_frame.TargetValidation += EffectTarget.Category.Aircraft -> EffectTarget.Validation.PadLanding
|
||||||
|
|
||||||
repair_silo.Name = "repair_silo"
|
repair_silo.Name = "repair_silo"
|
||||||
repair_silo.Interval = 1000
|
repair_silo.Interval = 1000
|
||||||
repair_silo.HealAmount = 60
|
repair_silo.HealAmount = 60
|
||||||
repair_silo.UseRadius = 20
|
repair_silo.UseRadius = 20
|
||||||
repair_silo.TargetValidation += ProximityTarget.Vehicle -> ProximityTerminalControl.Validation.RepairSilo
|
repair_silo.TargetValidation += EffectTarget.Category.Vehicle -> EffectTarget.Validation.RepairSilo
|
||||||
|
|
||||||
lodestar_repair_terminal.Name = "lodestar_repair_terminal"
|
lodestar_repair_terminal.Name = "lodestar_repair_terminal"
|
||||||
lodestar_repair_terminal.Interval = 1000
|
lodestar_repair_terminal.Interval = 1000
|
||||||
lodestar_repair_terminal.HealAmount = 60
|
lodestar_repair_terminal.HealAmount = 60
|
||||||
lodestar_repair_terminal.UseRadius = 20
|
lodestar_repair_terminal.UseRadius = 20
|
||||||
lodestar_repair_terminal.TargetValidation += ProximityTarget.Vehicle -> ProximityTerminalControl.Validation.RepairSilo
|
lodestar_repair_terminal.TargetValidation += EffectTarget.Category.Vehicle -> EffectTarget.Validation.RepairSilo
|
||||||
|
|
||||||
multivehicle_rearm_terminal.Name = "multivehicle_rearm_terminal"
|
multivehicle_rearm_terminal.Name = "multivehicle_rearm_terminal"
|
||||||
multivehicle_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
multivehicle_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@ package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.avatar.LoadoutManager
|
import net.psforever.objects.avatar.LoadoutManager
|
||||||
import net.psforever.objects.definition.{AvatarDefinition, ExoSuitDefinition, SpecialExoSuitDefinition}
|
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.inventory.{Container, GridInventory, InventoryItem}
|
||||||
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
import net.psforever.objects.vital.resistance.ResistanceProfile
|
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||||
import net.psforever.objects.vital.{DamageResistanceModel, Vitality}
|
import net.psforever.objects.vital.{DamageResistanceModel, Vitality}
|
||||||
|
|
@ -16,11 +17,12 @@ import net.psforever.types._
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.util.{Success, Try}
|
import scala.util.{Success, Try}
|
||||||
|
|
||||||
class Player(private val core : Avatar) extends PlanetSideGameObject
|
class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
with FactionAffinity
|
with FactionAffinity
|
||||||
with Vitality
|
with Vitality
|
||||||
with ResistanceProfile
|
with ResistanceProfile
|
||||||
with Container
|
with Container
|
||||||
|
with JammableUnit
|
||||||
with ZoneAware {
|
with ZoneAware {
|
||||||
private var alive : Boolean = false
|
private var alive : Boolean = false
|
||||||
private var backpack : Boolean = false
|
private var backpack : Boolean = false
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,133 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.ce.SimpleDeployable
|
import akka.actor.{Actor, ActorContext, Props}
|
||||||
import net.psforever.objects.definition.DeployableDefinition
|
import net.psforever.objects.ballistics.ResolvedProjectile
|
||||||
|
import net.psforever.objects.ce._
|
||||||
|
import net.psforever.objects.definition.converter.SmallDeployableConverter
|
||||||
|
import net.psforever.objects.definition.{ComplexDeployableDefinition, SimpleDeployableDefinition}
|
||||||
|
import net.psforever.objects.equipment.{JammableBehavior, JammableUnit}
|
||||||
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.hackable.Hackable
|
import net.psforever.objects.serverobject.hackable.Hackable
|
||||||
|
import net.psforever.objects.vital.{StandardResolutions, Vitality}
|
||||||
|
import net.psforever.objects.zones.Zone
|
||||||
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
import services.Service
|
||||||
|
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
import services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
|
||||||
class SensorDeployable(cdef : DeployableDefinition) extends SimpleDeployable(cdef)
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
class SensorDeployable(cdef : SensorDeployableDefinition) extends ComplexDeployable(cdef)
|
||||||
with Hackable
|
with Hackable
|
||||||
|
with JammableUnit
|
||||||
|
|
||||||
|
class SensorDeployableDefinition(private val objectId : Int) extends ComplexDeployableDefinition(objectId) {
|
||||||
|
Name = "sensor_deployable"
|
||||||
|
DeployCategory = DeployableCategory.Sensors
|
||||||
|
Model = StandardResolutions.SimpleDeployables
|
||||||
|
Packet = new SmallDeployableConverter
|
||||||
|
|
||||||
|
override def Initialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = {
|
||||||
|
obj.Actor = context.actorOf(Props(classOf[SensorDeployableControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = {
|
||||||
|
SimpleDeployableDefinition.SimpleUninitialize(obj, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object SensorDeployableDefinition {
|
||||||
|
def apply(dtype : DeployedItem.Value) : SensorDeployableDefinition = {
|
||||||
|
new SensorDeployableDefinition(dtype.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SensorDeployableControl(sensor : SensorDeployable) extends Actor
|
||||||
|
with JammableBehavior {
|
||||||
|
|
||||||
|
def JammableObject = sensor
|
||||||
|
|
||||||
|
def receive : Receive = jammableBehavior.orElse {
|
||||||
|
case Vitality.Damage(damage_func) =>
|
||||||
|
val originalHealth = sensor.Health
|
||||||
|
if(originalHealth > 0) {
|
||||||
|
val cause = damage_func(sensor)
|
||||||
|
SensorDeployableControl.HandleDamageResolution(sensor, cause, originalHealth - sensor.Health)
|
||||||
|
}
|
||||||
|
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
override def StartJammeredSound(target : Any, dur : Int) : Unit = target match {
|
||||||
|
case obj : PlanetSideServerObject if !jammedSound =>
|
||||||
|
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 JammableUnit if !obj.Jammed =>
|
||||||
|
sensor.Zone.LocalEvents ! LocalServiceMessage(sensor.Zone.Id, LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", obj.GUID, false, 1000))
|
||||||
|
super.StartJammeredStatus(obj, dur)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
override def CancelJammeredSound(target : Any) : Unit = {
|
||||||
|
target match {
|
||||||
|
case obj : PlanetSideServerObject if jammedSound =>
|
||||||
|
obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 0))
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
super.CancelJammeredSound(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def CancelJammeredStatus(target : Any) : Unit = {
|
||||||
|
target match {
|
||||||
|
case obj : PlanetSideServerObject with JammableUnit if obj.Jammed =>
|
||||||
|
sensor.Zone.LocalEvents ! LocalServiceMessage(sensor.Zone.Id, LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", obj.GUID, true, 1000))
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
super.CancelJammeredStatus(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object SensorDeployableControl {
|
||||||
|
def HandleDamageResolution(target : SensorDeployable, 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.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttribute(targetGUID, 0, target.Health))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param target na
|
||||||
|
* @param attribution na
|
||||||
|
* @param lastShot na
|
||||||
|
*/
|
||||||
|
def HandleDestructionAwareness(target : SensorDeployable, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = {
|
||||||
|
target.Actor ! JammableUnit.ClearJammeredSound()
|
||||||
|
target.Actor ! JammableUnit.ClearJammeredStatus()
|
||||||
|
val zone = target.Zone
|
||||||
|
Deployables.AnnounceDestroyDeployable(target, Some(0 seconds))
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(zone.Id, LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", target.GUID, false, 1000))
|
||||||
|
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.Destroy(target.GUID, attribution, attribution, target.Position))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,125 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.ce.{ComplexDeployable, DeployableCategory}
|
import akka.actor.{Actor, ActorContext, Props}
|
||||||
import net.psforever.objects.definition.DeployableDefinition
|
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.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.serverobject.hackable.Hackable
|
||||||
|
import net.psforever.objects.vital.Vitality
|
||||||
|
import net.psforever.objects.zones.Zone
|
||||||
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
import services.Service
|
||||||
|
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
|
||||||
class ShieldGeneratorDeployable(cdef : ShieldGeneratorDefinition) extends ComplexDeployable(cdef)
|
class ShieldGeneratorDeployable(cdef : ShieldGeneratorDefinition) extends ComplexDeployable(cdef)
|
||||||
with Hackable
|
with Hackable
|
||||||
|
with JammableUnit
|
||||||
|
|
||||||
class ShieldGeneratorDefinition extends DeployableDefinition(240) {
|
class ShieldGeneratorDefinition extends ComplexDeployableDefinition(240) {
|
||||||
Packet = new ShieldGeneratorConverter
|
Packet = new ShieldGeneratorConverter
|
||||||
DeployCategory = DeployableCategory.ShieldGenerators
|
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 _ => ;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
while the shield generator is technically a supported jammable target, how that works is currently unknown
|
||||||
|
electing to use a "status only, no sound" approach by overriding one with an empty function is not entirely arbitrary
|
||||||
|
the superclass of "status" calls also sets the jammed object property
|
||||||
|
*/
|
||||||
|
override def StartJammeredSound(target : Any, dur : Int) : Unit = { }
|
||||||
|
|
||||||
|
override def StartJammeredStatus(target : Any, dur : Int) : Unit = target match {
|
||||||
|
case obj : PlanetSideServerObject with JammableUnit if !obj.Jammed =>
|
||||||
|
obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 1))
|
||||||
|
super.StartJammeredStatus(obj, dur)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
override def CancelJammeredSound(target : Any) : Unit = { }
|
||||||
|
|
||||||
|
override def CancelJammeredStatus(target : Any) : Unit = {
|
||||||
|
target match {
|
||||||
|
case obj : PlanetSideServerObject with JammableUnit if obj.Jammed =>
|
||||||
|
obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 0))
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
super.CancelJammeredStatus(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttribute(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
|
||||||
|
Deployables.AnnounceDestroyDeployable(target, None)
|
||||||
|
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.Destroy(target.GUID, attribution, attribution, target.Position))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.ce.{SimpleDeployable, TelepadLike}
|
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
|
with TelepadLike
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import scala.annotation.tailrec
|
||||||
* @param toolDef the `ObjectDefinition` that constructs this item and maintains some of its immutable fields
|
* @param toolDef the `ObjectDefinition` that constructs this item and maintains some of its immutable fields
|
||||||
*/
|
*/
|
||||||
class Tool(private val toolDef : ToolDefinition) extends Equipment
|
class Tool(private val toolDef : ToolDefinition) extends Equipment
|
||||||
with FireModeSwitch[FireModeDefinition] {
|
with FireModeSwitch[FireModeDefinition]
|
||||||
|
with JammableUnit {
|
||||||
/** index of the current fire mode on the `ToolDefinition`'s list of fire modes */
|
/** index of the current fire mode on the `ToolDefinition`'s list of fire modes */
|
||||||
private var fireModeIndex : Int = toolDef.DefaultFireModeIndex
|
private var fireModeIndex : Int = toolDef.DefaultFireModeIndex
|
||||||
/** current ammunition slot being used by this fire mode */
|
/** current ammunition slot being used by this fire mode */
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,6 @@
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.ce.SimpleDeployable
|
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)
|
||||||
|
|
|
||||||
|
|
@ -2,65 +2,58 @@
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorContext, Props}
|
import akka.actor.{Actor, ActorContext, Props}
|
||||||
import net.psforever.objects.ce.{Deployable, DeployedItem}
|
import net.psforever.objects.ballistics.ResolvedProjectile
|
||||||
import net.psforever.objects.definition.{BaseDeployableDefinition, DeployableDefinition}
|
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.definition.converter.SmallTurretConverter
|
||||||
|
import net.psforever.objects.equipment.{JammableMountedWeapons, JammableUnit}
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||||
import net.psforever.objects.serverobject.hackable.Hackable
|
import net.psforever.objects.serverobject.hackable.Hackable
|
||||||
import net.psforever.objects.serverobject.mount.MountableBehavior
|
import net.psforever.objects.serverobject.mount.MountableBehavior
|
||||||
import net.psforever.objects.serverobject.turret.{TurretDefinition, WeaponTurret}
|
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.PlanetSideGUID
|
||||||
|
import services.Service
|
||||||
|
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
|
||||||
class TurretDeployable(tdef : TurretDeployableDefinition) extends PlanetSideServerObject
|
class TurretDeployable(tdef : TurretDeployableDefinition) extends ComplexDeployable(tdef)
|
||||||
with Deployable
|
|
||||||
with WeaponTurret
|
with WeaponTurret
|
||||||
|
with JammableUnit
|
||||||
with Hackable {
|
with Hackable {
|
||||||
private var shields : Int = 0
|
|
||||||
|
|
||||||
WeaponTurret.LoadDefinition(this) //calls the equivalent of Health = Definition.MaxHealth
|
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
|
def MountPoints : Map[Int, Int] = Definition.MountPoints.toMap
|
||||||
|
|
||||||
//override to clarify inheritance conflict
|
//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 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
|
override def Definition = tdef
|
||||||
}
|
}
|
||||||
|
|
||||||
class TurretDeployableDefinition(private val objectId : Int) extends TurretDefinition(objectId)
|
class TurretDeployableDefinition(private val objectId : Int) extends ComplexDeployableDefinition(objectId)
|
||||||
with BaseDeployableDefinition {
|
with TurretDefinition {
|
||||||
private val item = DeployedItem(objectId) //let throw NoSuchElementException
|
|
||||||
Name = "turret_deployable"
|
Name = "turret_deployable"
|
||||||
Packet = new SmallTurretConverter
|
Packet = new SmallTurretConverter
|
||||||
|
Damage = StandardVehicleDamage
|
||||||
def Item : DeployedItem.Value = item
|
Resistance = StandardVehicleResistance
|
||||||
|
Model = StandardResolutions.FacilityTurrets
|
||||||
|
|
||||||
//override to clarify inheritance conflict
|
//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 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) = {
|
override def Initialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = {
|
||||||
obj.Actor = context.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}")
|
obj.Actor = context.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}")
|
||||||
}
|
}
|
||||||
|
|
||||||
override def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = {
|
override def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = {
|
||||||
DeployableDefinition.SimpleUninitialize(obj, context)
|
SimpleDeployableDefinition.SimpleUninitialize(obj, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,16 +67,115 @@ object TurretDeployableDefinition {
|
||||||
|
|
||||||
class TurretControl(turret : TurretDeployable) extends Actor
|
class TurretControl(turret : TurretDeployable) extends Actor
|
||||||
with FactionAffinityBehavior.Check
|
with FactionAffinityBehavior.Check
|
||||||
|
with JammableMountedWeapons //note: jammable status is reported as vehicle events, not local events
|
||||||
with MountableBehavior.Mount
|
with MountableBehavior.Mount
|
||||||
with MountableBehavior.Dismount {
|
with MountableBehavior.Dismount {
|
||||||
def MountableObject = turret //do not add type!
|
def MountableObject = turret //do not add type!
|
||||||
|
|
||||||
|
def JammableObject = turret
|
||||||
|
|
||||||
def FactionObject : FactionAffinity = turret
|
def FactionObject : FactionAffinity = turret
|
||||||
|
|
||||||
def receive : Receive = checkBehavior
|
def receive : Receive = checkBehavior
|
||||||
|
.orElse(jammableBehavior)
|
||||||
.orElse(dismountBehavior)
|
.orElse(dismountBehavior)
|
||||||
.orElse(turretMountBehavior)
|
.orElse(turretMountBehavior)
|
||||||
.orElse {
|
.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 _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object TurretControl {
|
||||||
|
/**
|
||||||
|
* 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))
|
||||||
|
})
|
||||||
|
Deployables.AnnounceDestroyDeployable(target, None)
|
||||||
|
zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.Destroy(target.GUID, attribution, attribution, target.Position))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.definition.VehicleDefinition
|
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.inventory.{Container, GridInventory, InventoryTile}
|
||||||
import net.psforever.objects.serverobject.mount.Mountable
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
|
@ -73,6 +73,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
|
||||||
with Vitality
|
with Vitality
|
||||||
with OwnableByPlayer
|
with OwnableByPlayer
|
||||||
with StandardResistanceProfile
|
with StandardResistanceProfile
|
||||||
|
with JammableUnit
|
||||||
with Container {
|
with Container {
|
||||||
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.TR
|
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.TR
|
||||||
private var health : Int = 1
|
private var health : Int = 1
|
||||||
|
|
|
||||||
|
|
@ -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 _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects.ballistics
|
||||||
|
|
||||||
import net.psforever.objects.ce.{ComplexDeployable, SimpleDeployable}
|
import net.psforever.objects.ce.{ComplexDeployable, SimpleDeployable}
|
||||||
import net.psforever.objects.definition.ObjectDefinition
|
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.entity.WorldEntity
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
import net.psforever.objects.vital.resistance.ResistanceProfile
|
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||||
|
|
@ -34,7 +34,6 @@ object SourceEntry {
|
||||||
case obj : Player => PlayerSource(obj)
|
case obj : Player => PlayerSource(obj)
|
||||||
case obj : Vehicle => VehicleSource(obj)
|
case obj : Vehicle => VehicleSource(obj)
|
||||||
case obj : ComplexDeployable => ComplexDeployableSource(obj)
|
case obj : ComplexDeployable => ComplexDeployableSource(obj)
|
||||||
case obj : TurretDeployable => ComplexDeployableSource(obj)
|
|
||||||
case obj : SimpleDeployable => DeployableSource(obj)
|
case obj : SimpleDeployable => DeployableSource(obj)
|
||||||
case _ => ObjectSource(target)
|
case _ => ObjectSource(target)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.ce
|
package net.psforever.objects.ce
|
||||||
|
|
||||||
import net.psforever.objects.definition.DeployableDefinition
|
import net.psforever.objects.definition.ComplexDeployableDefinition
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
|
||||||
abstract class ComplexDeployable(cdef : DeployableDefinition) extends PlanetSideServerObject
|
abstract class ComplexDeployable(cdef : ComplexDeployableDefinition) extends PlanetSideServerObject
|
||||||
with Deployable {
|
with Deployable {
|
||||||
Health = Definition.MaxHealth
|
Health = Definition.MaxHealth
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,14 @@ import net.psforever.objects._
|
||||||
import net.psforever.objects.definition.{BaseDeployableDefinition, ObjectDefinition}
|
import net.psforever.objects.definition.{BaseDeployableDefinition, ObjectDefinition}
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
import net.psforever.objects.vital.{DamageResistanceModel, Vitality}
|
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
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
|
||||||
trait Deployable extends FactionAffinity
|
trait Deployable extends FactionAffinity
|
||||||
with Vitality
|
with Vitality
|
||||||
with OwnableByPlayer {
|
with OwnableByPlayer
|
||||||
|
with ZoneAware {
|
||||||
this : PlanetSideGameObject =>
|
this : PlanetSideGameObject =>
|
||||||
private var health : Int = 1
|
private var health : Int = 1
|
||||||
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
package net.psforever.objects.ce
|
package net.psforever.objects.ce
|
||||||
|
|
||||||
import net.psforever.objects.PlanetSideGameObject
|
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 {
|
with Deployable {
|
||||||
Health = Definition.MaxHealth
|
Health = Definition.MaxHealth
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
package net.psforever.objects.definition
|
package net.psforever.objects.definition
|
||||||
|
|
||||||
import net.psforever.objects.ballistics.Projectiles
|
import net.psforever.objects.ballistics.Projectiles
|
||||||
|
import net.psforever.objects.equipment.JammingUnit
|
||||||
import net.psforever.objects.vital.{DamageType, StandardDamageProfile}
|
import net.psforever.objects.vital.{DamageType, StandardDamageProfile}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -10,6 +11,7 @@ import net.psforever.objects.vital.{DamageType, StandardDamageProfile}
|
||||||
* @param objectId the object's identifier number
|
* @param objectId the object's identifier number
|
||||||
*/
|
*/
|
||||||
class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId)
|
class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId)
|
||||||
|
with JammingUnit
|
||||||
with StandardDamageProfile {
|
with StandardDamageProfile {
|
||||||
private val projectileType : Projectiles.Value = Projectiles(objectId) //let throw NoSuchElementException
|
private val projectileType : Projectiles.Value = Projectiles(objectId) //let throw NoSuchElementException
|
||||||
private var acceleration : Int = 0
|
private var acceleration : Int = 0
|
||||||
|
|
@ -26,6 +28,8 @@ class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId)
|
||||||
private var existsOnRemoteClients : Boolean = false //`true` spawns a server-managed object
|
private var existsOnRemoteClients : Boolean = false //`true` spawns a server-managed object
|
||||||
private var remoteClientData : (Int, Int) = (0, 0) //artificial values; for ObjectCreateMessage packet (oicw_little_buddy is undefined)
|
private var remoteClientData : (Int, Int) = (0, 0) //artificial values; for ObjectCreateMessage packet (oicw_little_buddy is undefined)
|
||||||
private var autoLock : Boolean = false
|
private var autoLock : Boolean = false
|
||||||
|
private var additionalEffect : Boolean = false
|
||||||
|
private var jammerProjectile : Boolean = false
|
||||||
//derived calculations
|
//derived calculations
|
||||||
private var distanceMax : Float = 0f
|
private var distanceMax : Float = 0f
|
||||||
private var distanceFromAcceleration : Float = 0f
|
private var distanceFromAcceleration : Float = 0f
|
||||||
|
|
@ -133,6 +137,20 @@ class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId)
|
||||||
AutoLock
|
AutoLock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def AdditionalEffect : Boolean = additionalEffect
|
||||||
|
|
||||||
|
def AdditionalEffect_=(effect : Boolean) : Boolean = {
|
||||||
|
additionalEffect = effect
|
||||||
|
AdditionalEffect
|
||||||
|
}
|
||||||
|
|
||||||
|
def JammerProjectile : Boolean = jammerProjectile
|
||||||
|
|
||||||
|
def JammerProjectile_=(effect : Boolean) : Boolean = {
|
||||||
|
jammerProjectile = effect
|
||||||
|
JammerProjectile
|
||||||
|
}
|
||||||
|
|
||||||
def DistanceMax : Float = distanceMax //accessor only
|
def DistanceMax : Float = distanceMax //accessor only
|
||||||
|
|
||||||
def DistanceFromAcceleration : Float = distanceFromAcceleration //accessor only
|
def DistanceFromAcceleration : Float = distanceFromAcceleration //accessor only
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import net.psforever.objects.ce.{Deployable, DeployableCategory, DeployedItem}
|
||||||
import net.psforever.objects.definition.converter.SmallDeployableConverter
|
import net.psforever.objects.definition.converter.SmallDeployableConverter
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
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._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ trait BaseDeployableDefinition extends DamageResistanceModel
|
||||||
def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) : Unit = { }
|
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 {
|
with BaseDeployableDefinition {
|
||||||
private val item = DeployedItem(objectId) //let throw NoSuchElementException
|
private val item = DeployedItem(objectId) //let throw NoSuchElementException
|
||||||
Packet = new SmallDeployableConverter
|
Packet = new SmallDeployableConverter
|
||||||
|
|
@ -61,9 +61,16 @@ class DeployableDefinition(private val objectId : Int) extends ObjectDefinition(
|
||||||
def Item : DeployedItem.Value = item
|
def Item : DeployedItem.Value = item
|
||||||
}
|
}
|
||||||
|
|
||||||
object DeployableDefinition {
|
abstract class ComplexDeployableDefinition(private val objectId : Int) extends ObjectDefinition(objectId)
|
||||||
def apply(item : DeployedItem.Value) : DeployableDefinition =
|
with BaseDeployableDefinition {
|
||||||
new DeployableDefinition(item.id)
|
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 = { }
|
def SimpleUninitialize(obj : PlanetSideGameObject, context : ActorContext) : Unit = { }
|
||||||
|
|
||||||
|
|
@ -74,7 +74,7 @@ object AvatarConverter {
|
||||||
alt_model_flag,
|
alt_model_flag,
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
false,
|
obj.Jammed,
|
||||||
None,
|
None,
|
||||||
v5 = None,
|
v5 = None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.Player
|
import net.psforever.objects.{Player, Tool}
|
||||||
import net.psforever.objects.equipment.{Equipment, EquipmentSlot}
|
import net.psforever.objects.equipment.{Equipment, EquipmentSlot}
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.packet.game.objectcreate._
|
import net.psforever.packet.game.objectcreate._
|
||||||
|
|
@ -136,17 +136,38 @@ class CharacterSelectConverter extends AvatarConverter {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val slot : EquipmentSlot = iter.next
|
val slot : EquipmentSlot = iter.next
|
||||||
if(slot.Equipment.isDefined) {
|
slot.Equipment match {
|
||||||
val equip : Equipment = slot.Equipment.get
|
case Some(equip : Tool) =>
|
||||||
recursiveMakeHolsters(
|
val jammed = equip.Jammed
|
||||||
iter,
|
equip.Jammed = false
|
||||||
list :+ AvatarConverter.BuildDetailedEquipment(index, equip),
|
val slot = AvatarConverter.BuildDetailedEquipment(index, equip)
|
||||||
index + 1
|
equip.Jammed = jammed
|
||||||
)
|
recursiveMakeHolsters(
|
||||||
}
|
iter,
|
||||||
else {
|
list :+ slot,
|
||||||
recursiveMakeHolsters(iter, list, index + 1)
|
index + 1
|
||||||
|
)
|
||||||
|
case Some(equip) =>
|
||||||
|
recursiveMakeHolsters(
|
||||||
|
iter,
|
||||||
|
list :+ AvatarConverter.BuildDetailedEquipment(index, equip),
|
||||||
|
index + 1
|
||||||
|
)
|
||||||
|
case _ =>
|
||||||
|
recursiveMakeHolsters(iter, list, index + 1)
|
||||||
}
|
}
|
||||||
|
// if(slot.Equipment.isDefined) {
|
||||||
|
//
|
||||||
|
// val equip : Equipment = slot.Equipment.get
|
||||||
|
// recursiveMakeHolsters(
|
||||||
|
// iter,
|
||||||
|
// list :+ AvatarConverter.BuildDetailedEquipment(index, equip),
|
||||||
|
// index + 1
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// recursiveMakeHolsters(iter, list, index + 1)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
||||||
alternate = false,
|
alternate = false,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = obj.Jammed,
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
obj.Owner match {
|
obj.Owner match {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class ShieldGeneratorConverter extends ObjectCreateConverter[ShieldGeneratorDepl
|
||||||
alternate = false,
|
alternate = false,
|
||||||
v1 = false,
|
v1 = false,
|
||||||
v2 = None,
|
v2 = None,
|
||||||
v3 = false,
|
jammered = obj.Jammed,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
obj.Owner match {
|
obj.Owner match {
|
||||||
|
|
@ -45,7 +45,7 @@ class ShieldGeneratorConverter extends ObjectCreateConverter[ShieldGeneratorDepl
|
||||||
alternate = true,
|
alternate = true,
|
||||||
v1 = false,
|
v1 = false,
|
||||||
v2 = None,
|
v2 = None,
|
||||||
v3 = false,
|
jammered = obj.Jammed,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.ce.Deployable
|
import net.psforever.objects.ce.Deployable
|
||||||
import net.psforever.objects.PlanetSideGameObject
|
import net.psforever.objects.PlanetSideGameObject
|
||||||
|
import net.psforever.objects.equipment.JammableUnit
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.packet.game.objectcreate._
|
import net.psforever.packet.game.objectcreate._
|
||||||
|
|
||||||
|
|
@ -15,11 +16,14 @@ class SmallDeployableConverter extends ObjectCreateConverter[PlanetSideGameObjec
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
obj.Faction,
|
obj.Faction,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = obj match {
|
||||||
|
case o : JammableUnit => o.Jammed
|
||||||
|
case _ => false
|
||||||
|
},
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
obj.Owner match {
|
obj.Owner match {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ class SmallTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
||||||
alternate = false,
|
alternate = false,
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = obj.Jammed,
|
||||||
Some(true),
|
Some(true),
|
||||||
None,
|
None,
|
||||||
obj.Owner match {
|
obj.Owner match {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class ToolConverter extends ObjectCreateConverter[Tool]() {
|
||||||
alternate = false,
|
alternate = false,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
false,
|
obj.Jammed,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -45,7 +45,7 @@ class ToolConverter extends ObjectCreateConverter[Tool]() {
|
||||||
alternate = false,
|
alternate = false,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
false,
|
obj.Jammed,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
||||||
alternate = false,
|
alternate = false,
|
||||||
v1 = false,
|
v1 = false,
|
||||||
v2 = None,
|
v2 = None,
|
||||||
v3 = false,
|
jammered = obj.Jammed,
|
||||||
v4 = Some(false),
|
v4 = Some(false),
|
||||||
v5 = None,
|
v5 = None,
|
||||||
obj.Owner match {
|
obj.Owner match {
|
||||||
|
|
@ -56,7 +56,7 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
||||||
alternate = true,
|
alternate = true,
|
||||||
v1 = false,
|
v1 = false,
|
||||||
v2 = None,
|
v2 = None,
|
||||||
v3 = false,
|
jammered = obj.Jammed,
|
||||||
v4 = Some(false),
|
v4 = Some(false),
|
||||||
v5 = None,
|
v5 = None,
|
||||||
guid = PlanetSideGUID(0)
|
guid = PlanetSideGUID(0)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.objects.equipment
|
||||||
|
|
||||||
|
import net.psforever.objects._
|
||||||
|
import net.psforever.objects.ce.DeployableCategory
|
||||||
|
import net.psforever.objects.serverobject.turret.FacilityTurret
|
||||||
|
|
||||||
|
final case class TargetValidation(category : EffectTarget.Category.Value, test : EffectTarget.Validation.Value)
|
||||||
|
|
||||||
|
object EffectTarget {
|
||||||
|
/**
|
||||||
|
* A classification of the target of interactions.
|
||||||
|
* Arbitrary, but useful.
|
||||||
|
*/
|
||||||
|
object Category extends Enumeration {
|
||||||
|
val
|
||||||
|
Aircraft,
|
||||||
|
Deployable,
|
||||||
|
Equipment,
|
||||||
|
Player,
|
||||||
|
Turret,
|
||||||
|
Vehicle
|
||||||
|
= Value
|
||||||
|
}
|
||||||
|
|
||||||
|
object Validation {
|
||||||
|
type Value = PlanetSideGameObject => Boolean
|
||||||
|
|
||||||
|
def Invalid(target : PlanetSideGameObject) : Boolean = false
|
||||||
|
|
||||||
|
def Medical(target : PlanetSideGameObject) : Boolean = target match {
|
||||||
|
case p : Player =>
|
||||||
|
p.Health > 0 && (p.Health < p.MaxHealth || p.Armor < p.MaxArmor)
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
def HealthCrystal(target : PlanetSideGameObject) : Boolean = target match {
|
||||||
|
case p : Player =>
|
||||||
|
p.Health > 0 && p.Health < p.MaxHealth
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
def RepairSilo(target : PlanetSideGameObject) : Boolean = target match {
|
||||||
|
case v : Vehicle =>
|
||||||
|
!GlobalDefinitions.isFlightVehicle(v.Definition) && v.Health > 0 && v.Health < v.MaxHealth
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
def PadLanding(target : PlanetSideGameObject) : Boolean = target match {
|
||||||
|
case v : Vehicle =>
|
||||||
|
GlobalDefinitions.isFlightVehicle(v.Definition) && v.Health > 0 && v.Health < v.MaxHealth
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
def Player(target : PlanetSideGameObject) : Boolean = target match {
|
||||||
|
case p : Player =>
|
||||||
|
p.isAlive
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
def MotionSensor(target : PlanetSideGameObject) : Boolean = target match {
|
||||||
|
case s : SensorDeployable =>
|
||||||
|
s.Health > 0
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
def Spitfire(target : PlanetSideGameObject) : Boolean = target match {
|
||||||
|
case t : TurretDeployable =>
|
||||||
|
t.Definition.DeployCategory == DeployableCategory.SmallTurrets && t.Health > 0
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
def Turret(target : PlanetSideGameObject) : Boolean = target match {
|
||||||
|
case t : TurretDeployable =>
|
||||||
|
t.Definition.DeployCategory == DeployableCategory.FieldTurrets && t.Health > 0
|
||||||
|
case t : FacilityTurret =>
|
||||||
|
t.Health > 0
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
def AMS(target : PlanetSideGameObject) : Boolean = target match {
|
||||||
|
case v : Vehicle =>
|
||||||
|
v.Health > 0 && v.Definition == GlobalDefinitions.ams
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
def VehicleNotAMS(target : PlanetSideGameObject) : Boolean = target match {
|
||||||
|
case v : Vehicle =>
|
||||||
|
v.Health > 0 && v.Definition != GlobalDefinitions.ams
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,271 @@
|
||||||
|
// Copyright (c) 2019 PSForever
|
||||||
|
package net.psforever.objects.equipment
|
||||||
|
|
||||||
|
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.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._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A property conferred to game objects that can be affected by an electromagnetic pulse.
|
||||||
|
* Being "jammered" is a status that causes weakness due to temporary equipment disabling or the elimination of certain objects.
|
||||||
|
*/
|
||||||
|
trait JammableUnit {
|
||||||
|
/** being jammed (jammered) is an on/off state */
|
||||||
|
private var jammed : Boolean = false
|
||||||
|
|
||||||
|
def Jammed : Boolean = jammed
|
||||||
|
|
||||||
|
def Jammed_=(state : Boolean) : Boolean = {
|
||||||
|
jammed = state
|
||||||
|
Jammed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object JammableUnit {
|
||||||
|
/**
|
||||||
|
* A message for generic jammering.
|
||||||
|
* Currently, unused.
|
||||||
|
*/
|
||||||
|
final case class Jammer()
|
||||||
|
/**
|
||||||
|
* A message for jammering due to a projectile.
|
||||||
|
* @param cause information pertaining to the projectile
|
||||||
|
*/
|
||||||
|
final case class Jammered(cause : ResolvedProjectile)
|
||||||
|
/**
|
||||||
|
* Stop the auditory aspect of being jammered.
|
||||||
|
*/
|
||||||
|
final case class ClearJammeredSound()
|
||||||
|
/**
|
||||||
|
* Stop the status effects of being jammered.
|
||||||
|
*/
|
||||||
|
final case class ClearJammeredStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A property conferred onto game objects that can induce the effects of an electromagnetic pulse.
|
||||||
|
* @see `TargetValidation`
|
||||||
|
* @see `EffectTarget`
|
||||||
|
*/
|
||||||
|
trait JammingUnit {
|
||||||
|
/** a list of qualifying conditional tests for determining if an object is to be affected by the jammered status;
|
||||||
|
* if qualifying, that object will be inflicted with a number of milliseconds of the jammered status */
|
||||||
|
private val jammedEffectDuration : mutable.ListBuffer[(TargetValidation, Int)] = new mutable.ListBuffer()
|
||||||
|
|
||||||
|
def HasJammedEffectDuration : Boolean = jammedEffectDuration.isEmpty
|
||||||
|
|
||||||
|
def JammedEffectDuration : mutable.ListBuffer[(TargetValidation, Int)] = jammedEffectDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
object JammingUnit {
|
||||||
|
/**
|
||||||
|
* Determine whether an object that can be jammered is to be jammered by this source,
|
||||||
|
* and for how long.
|
||||||
|
* If the object succeeds for multiple qualification tests,
|
||||||
|
* prioritize the lengthiest duration.
|
||||||
|
* @param jammer the source of the "jammered" status
|
||||||
|
* @param target the object to be determined if affected by the source's jammering
|
||||||
|
* @return the duration to be jammered, if any, in milliseconds
|
||||||
|
*/
|
||||||
|
def FindJammerDuration(jammer : JammingUnit, target : PlanetSideGameObject) : Option[Int] = {
|
||||||
|
jammer.JammedEffectDuration
|
||||||
|
.collect { case (TargetValidation(_, test), duration) if test(target) => duration }
|
||||||
|
.toList
|
||||||
|
.sortWith(_ > _)
|
||||||
|
.headOption
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether a group of objects that can be jammered is to be jammered by this source,
|
||||||
|
* and for how long.
|
||||||
|
* If the object succeeds for multiple qualification tests,
|
||||||
|
* prioritize the lengthiest duration.
|
||||||
|
* @param jammer the source of the "jammered" status
|
||||||
|
* @param targets the objects to be determined if affected by the source's jammering
|
||||||
|
* @return the indexed durations to be jammered, if any, in milliseconds
|
||||||
|
*/
|
||||||
|
def FindJammerDuration(jammer : JammingUnit, targets : Seq[PlanetSideGameObject]) : Seq[Option[Int]] = {
|
||||||
|
targets.map { target => FindJammerDuration(jammer, target) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An `Actor` control object mix-in that manages common responses to the "jammerable" status.
|
||||||
|
* Two aspects to jammering are supported -
|
||||||
|
* a telling buzzing sound that follows the affected target
|
||||||
|
* and actual effects upon the target's actions -
|
||||||
|
* and are controlled independently.
|
||||||
|
* The primary purpose of this behavior is to control timers that toggle the states of these two aspects.
|
||||||
|
*/
|
||||||
|
trait JammableBehavior {
|
||||||
|
this : Actor =>
|
||||||
|
/** flag for jammed sound */
|
||||||
|
protected var jammedSound : Boolean = false
|
||||||
|
/** the sound timer */
|
||||||
|
protected var jammeredSoundTimer : Cancellable = DefaultCancellable.obj
|
||||||
|
/** the effect timer */
|
||||||
|
protected var jammeredStatusTimer : Cancellable = DefaultCancellable.obj
|
||||||
|
|
||||||
|
/** `ZoneAware` is used for callback to the event systems */
|
||||||
|
def JammableObject : PlanetSideServerObject with JammableUnit with ZoneAware
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the target can be validated against, affect it with the jammered status.
|
||||||
|
* @param target the objects to be determined if affected by the source's jammering
|
||||||
|
* @param cause the source of the "jammered" status
|
||||||
|
*/
|
||||||
|
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, dur)
|
||||||
|
StartJammeredStatus(obj, dur)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate a distinctive buzzing sound effect.
|
||||||
|
* Due to considerations of the object that is the target, this is left to be implemented by a subclass.
|
||||||
|
* We merely start the timer.
|
||||||
|
* @param target an object that can be affected by the jammered status
|
||||||
|
* @param dur the duration of the timer, in milliseconds;
|
||||||
|
* by default, 30000
|
||||||
|
*/
|
||||||
|
def StartJammeredSound(target : Any, dur : Int = 30000) : Unit = {
|
||||||
|
if(!jammedSound) {
|
||||||
|
jammedSound = true
|
||||||
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
jammeredSoundTimer.cancel
|
||||||
|
jammeredSoundTimer = context.system.scheduler.scheduleOnce(dur seconds, self, JammableUnit.ClearJammeredSound())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deactivate the effects of the jammered status.
|
||||||
|
* Due to considerations of the object that is the target, this is left to be implemented by a subclass.
|
||||||
|
* We merely stop the timer.
|
||||||
|
* @param target an object that can be affected by the jammered status
|
||||||
|
* @param dur the duration of the timer, in milliseconds
|
||||||
|
*/
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deactivate a distinctive buzzing sound effect.
|
||||||
|
* Due to considerations of the object that is the target, this is left to be implemented by a subclass.
|
||||||
|
* We merely stop the timer.
|
||||||
|
* @param target an object that can be affected by the jammered status
|
||||||
|
*/
|
||||||
|
def CancelJammeredSound(target : Any) : Unit = {
|
||||||
|
jammedSound = false
|
||||||
|
jammeredSoundTimer.cancel
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deactivate the effects of the jammered status.
|
||||||
|
* Due to considerations of the object that is the target, this is left to be implemented by a subclass.
|
||||||
|
* We merely stop the timer.
|
||||||
|
* @param target an object that can be affected by the jammered status
|
||||||
|
*/
|
||||||
|
def CancelJammeredStatus(target : Any) : Unit = {
|
||||||
|
JammableObject.Jammed = false
|
||||||
|
jammeredStatusTimer.cancel
|
||||||
|
}
|
||||||
|
|
||||||
|
val jammableBehavior : Receive = {
|
||||||
|
case JammableUnit.Jammered(cause) =>
|
||||||
|
TryJammerEffectActivate(JammableObject, cause)
|
||||||
|
|
||||||
|
case JammableUnit.ClearJammeredSound() =>
|
||||||
|
CancelJammeredSound(JammableObject)
|
||||||
|
|
||||||
|
case JammableUnit.ClearJammeredStatus() =>
|
||||||
|
CancelJammeredStatus(JammableObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A common mix-in variation to manage common responses to the "jammerable" status for game objects with mounted weapons.
|
||||||
|
* @see `MountedWeapons`
|
||||||
|
* @see `Service`
|
||||||
|
* @see `VehicleAction`
|
||||||
|
* @see `VehicleService`
|
||||||
|
* @see `VehicleServiceMessage`
|
||||||
|
* @see `Zone.VehicleEvents`
|
||||||
|
*/
|
||||||
|
trait JammableMountedWeapons extends JammableBehavior {
|
||||||
|
_ : Actor =>
|
||||||
|
|
||||||
|
override def StartJammeredSound(target : Any, dur : Int) : Unit = {
|
||||||
|
target match {
|
||||||
|
case obj : PlanetSideServerObject with MountedWeapons with JammableUnit if !jammedSound =>
|
||||||
|
obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 1))
|
||||||
|
super.StartJammeredSound(target, dur)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override def StartJammeredStatus(target : Any, dur : Int) : Unit = {
|
||||||
|
target match {
|
||||||
|
case obj : PlanetSideServerObject with MountedWeapons with JammableUnit if !obj.Jammed =>
|
||||||
|
JammableMountedWeapons.JammeredStatus(obj, 1)
|
||||||
|
super.StartJammeredStatus(target, dur)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override def CancelJammeredSound(target : Any) : Unit = {
|
||||||
|
target match {
|
||||||
|
case obj : PlanetSideServerObject if jammedSound =>
|
||||||
|
obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 0))
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
super.CancelJammeredSound(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def CancelJammeredStatus(target : Any) : Unit = {
|
||||||
|
target match {
|
||||||
|
case obj : PlanetSideServerObject with MountedWeapons with JammableUnit if obj.Jammed =>
|
||||||
|
JammableMountedWeapons.JammeredStatus(obj, 0)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
super.CancelJammeredStatus(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object JammableMountedWeapons {
|
||||||
|
/**
|
||||||
|
* Retrieve all of the weapons on a `MountedWeapons` target object and apply a jammered status effect to each.
|
||||||
|
* @param target an object that can be affected by the jammered status
|
||||||
|
* @param statusCode the jammered status condition;
|
||||||
|
* 0 for deactivation;
|
||||||
|
* 1 for activation
|
||||||
|
*/
|
||||||
|
def JammeredStatus(target : PlanetSideServerObject with MountedWeapons, statusCode : Int) : Unit = {
|
||||||
|
val zone = target.Zone
|
||||||
|
val zoneId = zone.Id
|
||||||
|
target.Weapons.values
|
||||||
|
.map { _.Equipment }
|
||||||
|
.collect {
|
||||||
|
case Some(item : Tool) =>
|
||||||
|
item.Jammed = statusCode==1
|
||||||
|
zone.VehicleEvents ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, item.GUID, 27, statusCode))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package net.psforever.objects.serverobject.terminals
|
||||||
|
|
||||||
import net.psforever.objects.PlanetSideGameObject
|
import net.psforever.objects.PlanetSideGameObject
|
||||||
import net.psforever.objects.definition.ObjectDefinition
|
import net.psforever.objects.definition.ObjectDefinition
|
||||||
|
import net.psforever.objects.equipment.EffectTarget
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
|
|
@ -17,7 +18,7 @@ trait ProximityDefinition {
|
||||||
this : ObjectDefinition =>
|
this : ObjectDefinition =>
|
||||||
|
|
||||||
private var useRadius : Float = 0f //TODO belongs on a wider range of object definitions
|
private var useRadius : Float = 0f //TODO belongs on a wider range of object definitions
|
||||||
private val targetValidation : mutable.HashMap[ProximityTarget.Value, PlanetSideGameObject=>Boolean] = new mutable.HashMap[ProximityTarget.Value, PlanetSideGameObject=>Boolean]()
|
private val targetValidation : mutable.HashMap[EffectTarget.Category.Value, PlanetSideGameObject=>Boolean] = new mutable.HashMap[EffectTarget.Category.Value, PlanetSideGameObject=>Boolean]()
|
||||||
|
|
||||||
def UseRadius : Float = useRadius
|
def UseRadius : Float = useRadius
|
||||||
|
|
||||||
|
|
@ -26,18 +27,14 @@ trait ProximityDefinition {
|
||||||
UseRadius
|
UseRadius
|
||||||
}
|
}
|
||||||
|
|
||||||
def TargetValidation : mutable.HashMap[ProximityTarget.Value, PlanetSideGameObject=>Boolean] = targetValidation
|
def TargetValidation : mutable.HashMap[EffectTarget.Category.Value, PlanetSideGameObject=>Boolean] = targetValidation
|
||||||
|
|
||||||
def Validations : Seq[PlanetSideGameObject=>Boolean] = {
|
def Validations : Seq[PlanetSideGameObject=>Boolean] = {
|
||||||
targetValidation.headOption match {
|
targetValidation.headOption match {
|
||||||
case Some(_) =>
|
case Some(_) =>
|
||||||
targetValidation.values.toSeq
|
targetValidation.values.toSeq
|
||||||
case None =>
|
case None =>
|
||||||
Seq(ProximityDefinition.Invalid)
|
Seq(EffectTarget.Validation.Invalid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ProximityDefinition {
|
|
||||||
protected val Invalid : PlanetSideGameObject=>Boolean = (_ : PlanetSideGameObject) => false
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
// Copyright (c) 2017 PSForever
|
|
||||||
package net.psforever.objects.serverobject.terminals
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A classification of the target of this terminal's interactions.
|
|
||||||
* Arbitrary, but useful.
|
|
||||||
*/
|
|
||||||
object ProximityTarget extends Enumeration {
|
|
||||||
val
|
|
||||||
Aircraft,
|
|
||||||
Equipment,
|
|
||||||
Player,
|
|
||||||
Vehicle
|
|
||||||
= Value
|
|
||||||
}
|
|
||||||
|
|
@ -126,35 +126,5 @@ class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor
|
||||||
}
|
}
|
||||||
|
|
||||||
object ProximityTerminalControl {
|
object ProximityTerminalControl {
|
||||||
object Validation {
|
|
||||||
def Medical(target : PlanetSideGameObject) : Boolean = target match {
|
|
||||||
case p : Player =>
|
|
||||||
p.Health > 0 && (p.Health < p.MaxHealth || p.Armor < p.MaxArmor)
|
|
||||||
case _ =>
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
def HealthCrystal(target : PlanetSideGameObject) : Boolean = target match {
|
|
||||||
case p : Player =>
|
|
||||||
p.Health > 0 && p.Health < p.MaxHealth
|
|
||||||
case _ =>
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
def RepairSilo(target : PlanetSideGameObject) : Boolean = target match {
|
|
||||||
case v : Vehicle =>
|
|
||||||
!GlobalDefinitions.isFlightVehicle(v.Definition) && v.Health > 0 && v.Health < v.MaxHealth
|
|
||||||
case _ =>
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
def PadLanding(target : PlanetSideGameObject) : Boolean = target match {
|
|
||||||
case v : Vehicle =>
|
|
||||||
GlobalDefinitions.isFlightVehicle(v.Definition) && v.Health > 0 && v.Health < v.MaxHealth
|
|
||||||
case _ =>
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private case class TerminalAction()
|
private case class TerminalAction()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.turret
|
package net.psforever.objects.serverobject.turret
|
||||||
|
|
||||||
|
import net.psforever.objects.equipment.JammableUnit
|
||||||
import net.psforever.objects.serverobject.structures.Amenity
|
import net.psforever.objects.serverobject.structures.Amenity
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
import net.psforever.objects.vital.{DamageResistanceModel, StandardResistanceProfile, Vitality}
|
import net.psforever.objects.vital.{DamageResistanceModel, StandardResistanceProfile, Vitality}
|
||||||
|
|
||||||
class FacilityTurret(tDef : TurretDefinition) extends Amenity
|
class FacilityTurret(tDef : FacilityTurretDefinition) extends Amenity
|
||||||
with WeaponTurret
|
with WeaponTurret
|
||||||
|
with JammableUnit
|
||||||
with Vitality
|
with Vitality
|
||||||
with StandardResistanceProfile {
|
with StandardResistanceProfile {
|
||||||
/** some turrets can be updated; they all start without updates */
|
/** some turrets can be updated; they all start without updates */
|
||||||
|
|
@ -53,7 +55,7 @@ class FacilityTurret(tDef : TurretDefinition) extends Amenity
|
||||||
|
|
||||||
def DamageModel = Definition.asInstanceOf[DamageResistanceModel]
|
def DamageModel = Definition.asInstanceOf[DamageResistanceModel]
|
||||||
|
|
||||||
def Definition : TurretDefinition = tDef
|
def Definition : FacilityTurretDefinition = tDef
|
||||||
}
|
}
|
||||||
|
|
||||||
object FacilityTurret {
|
object FacilityTurret {
|
||||||
|
|
@ -62,7 +64,7 @@ object FacilityTurret {
|
||||||
* @param tDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
* @param tDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
||||||
* @return a `FacilityTurret` object
|
* @return a `FacilityTurret` object
|
||||||
*/
|
*/
|
||||||
def apply(tDef : TurretDefinition) : FacilityTurret = {
|
def apply(tDef : FacilityTurretDefinition) : FacilityTurret = {
|
||||||
new FacilityTurret(tDef)
|
new FacilityTurret(tDef)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,14 +75,14 @@ object FacilityTurret {
|
||||||
* @param context a context to allow the object to properly set up `ActorSystem` functionality
|
* @param context a context to allow the object to properly set up `ActorSystem` functionality
|
||||||
* @return the `MannedTurret` object
|
* @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
|
import akka.actor.Props
|
||||||
val obj = FacilityTurret(tdef)
|
val obj = FacilityTurret(tdef)
|
||||||
obj.Actor = context.actorOf(Props(classOf[FacilityTurretControl], obj), s"${tdef.Name}_$id")
|
obj.Actor = context.actorOf(Props(classOf[FacilityTurretControl], obj), s"${tdef.Name}_$id")
|
||||||
obj
|
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
|
import akka.actor.Props
|
||||||
val obj = FacilityTurret(tdef)
|
val obj = FacilityTurret(tdef)
|
||||||
obj.Position = pos
|
obj.Position = pos
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,17 @@
|
||||||
package net.psforever.objects.serverobject.turret
|
package net.psforever.objects.serverobject.turret
|
||||||
|
|
||||||
import akka.actor.Actor
|
import akka.actor.Actor
|
||||||
|
import net.psforever.objects.ballistics.ResolvedProjectile
|
||||||
|
import net.psforever.objects.equipment.{JammableMountedWeapons, JammableUnit}
|
||||||
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
||||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||||
import net.psforever.objects.vital.Vitality
|
import net.psforever.objects.vital.Vitality
|
||||||
|
import net.psforever.objects.zones.Zone
|
||||||
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
import services.Service
|
||||||
|
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
import services.vehicle.support.TurretUpgrader
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An `Actor` that handles messages being dispatched to a specific `MannedTurret`.<br>
|
* An `Actor` that handles messages being dispatched to a specific `MannedTurret`.<br>
|
||||||
|
|
@ -16,12 +24,17 @@ import net.psforever.objects.vital.Vitality
|
||||||
*/
|
*/
|
||||||
class FacilityTurretControl(turret : FacilityTurret) extends Actor
|
class FacilityTurretControl(turret : FacilityTurret) extends Actor
|
||||||
with FactionAffinityBehavior.Check
|
with FactionAffinityBehavior.Check
|
||||||
with MountableBehavior.Dismount {
|
with MountableBehavior.Dismount
|
||||||
def MountableObject = turret //do not add type!
|
with JammableMountedWeapons {
|
||||||
|
|
||||||
|
def MountableObject = turret
|
||||||
|
|
||||||
|
def JammableObject = turret
|
||||||
|
|
||||||
def FactionObject : FactionAffinity = turret
|
def FactionObject : FactionAffinity = turret
|
||||||
|
|
||||||
def receive : Receive = checkBehavior
|
def receive : Receive = checkBehavior
|
||||||
|
.orElse(jammableBehavior)
|
||||||
.orElse(dismountBehavior)
|
.orElse(dismountBehavior)
|
||||||
.orElse {
|
.orElse {
|
||||||
case Mountable.TryMount(user, seat_num) =>
|
case Mountable.TryMount(user, seat_num) =>
|
||||||
|
|
@ -42,15 +55,100 @@ class FacilityTurretControl(turret : FacilityTurret) extends Actor
|
||||||
case Vitality.Damage(damage_func) =>
|
case Vitality.Damage(damage_func) =>
|
||||||
if(turret.Health > 0) {
|
if(turret.Health > 0) {
|
||||||
val originalHealth = turret.Health
|
val originalHealth = turret.Health
|
||||||
damage_func(turret)
|
val cause = damage_func(turret)
|
||||||
val health = turret.Health
|
val health = turret.Health
|
||||||
val damageToHealth = originalHealth - health
|
val damageToHealth = originalHealth - health
|
||||||
val name = turret.Actor.toString
|
FacilityTurretControl.HandleDamageResolution(turret, cause, damageToHealth)
|
||||||
val slashPoint = name.lastIndexOf("/")
|
if(damageToHealth > 0) {
|
||||||
org.log4s.getLogger("DamageResolution").info(s"${name.substring(slashPoint+1, name.length-1)}: BEFORE=$originalHealth, AFTER=$health, CHANGE=$damageToHealth")
|
val name = turret.Actor.toString
|
||||||
sender ! Vitality.DamageResolution(turret)
|
val slashPoint = name.lastIndexOf("/")
|
||||||
|
org.log4s.getLogger("DamageResolution").info(s"${name.substring(slashPoint + 1, name.length - 1)}: BEFORE=$originalHealth, AFTER=$health, CHANGE=$damageToHealth")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -3,19 +3,18 @@ package net.psforever.objects.serverobject.turret
|
||||||
|
|
||||||
import net.psforever.objects.definition.{ObjectDefinition, ToolDefinition}
|
import net.psforever.objects.definition.{ObjectDefinition, ToolDefinition}
|
||||||
import net.psforever.objects.vehicles.Turrets
|
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 net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The definition for any `MannedTurret`.
|
* The definition for any `MannedTurret`.
|
||||||
* @param objectId the object's identifier number
|
|
||||||
*/
|
*/
|
||||||
class TurretDefinition(private val objectId : Int) extends ObjectDefinition(objectId)
|
trait TurretDefinition extends ResistanceProfileMutators
|
||||||
with ResistanceProfileMutators
|
|
||||||
with DamageResistanceModel {
|
with DamageResistanceModel {
|
||||||
Turrets(objectId) //let throw NoSuchElementException
|
odef : ObjectDefinition =>
|
||||||
|
Turrets(odef.ObjectId) //let throw NoSuchElementException
|
||||||
|
|
||||||
private var maxHealth : Int = 100
|
private var maxHealth : Int = 100
|
||||||
/* key - entry point index, value - seat index */
|
/* 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
|
/** creates internal ammunition reserves that can not become depleted
|
||||||
* see `MannedTurret.TurretAmmoBox` for details */
|
* see `MannedTurret.TurretAmmoBox` for details */
|
||||||
private var hasReserveAmmunition : Boolean = false
|
private var hasReserveAmmunition : Boolean = false
|
||||||
Damage = StandardVehicleDamage
|
|
||||||
Resistance = StandardVehicleResistance
|
|
||||||
Model = StandardResolutions.FacilityTurrets
|
|
||||||
|
|
||||||
def MaxHealth : Int = maxHealth
|
def MaxHealth : Int = maxHealth
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
package net.psforever.objects.vehicles
|
package net.psforever.objects.vehicles
|
||||||
|
|
||||||
import akka.actor.ActorContext
|
import akka.actor.ActorContext
|
||||||
import net.psforever.objects.definition.DeployableDefinition
|
import net.psforever.objects.definition.SimpleDeployableDefinition
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.objects.ce.TelepadLike
|
import net.psforever.objects.ce.TelepadLike
|
||||||
import net.psforever.objects.serverobject.structures.Amenity
|
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.
|
* and allows it to serve as one of the terminal points of a Router-telepad teleportation system.
|
||||||
* @param ddef na
|
* @param ddef na
|
||||||
*/
|
*/
|
||||||
class InternalTelepad(ddef : DeployableDefinition) extends Amenity
|
class InternalTelepad(ddef : SimpleDeployableDefinition) extends Amenity
|
||||||
with TelepadLike {
|
with TelepadLike {
|
||||||
/** a link to the telepad that serves as the other endpoint of this teleportation system */
|
/** a link to the telepad that serves as the other endpoint of this teleportation system */
|
||||||
private var activeTelepad : Option[PlanetSideGUID] = None
|
private var activeTelepad : Option[PlanetSideGUID] = None
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,20 @@
|
||||||
package net.psforever.objects.vehicles
|
package net.psforever.objects.vehicles
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorRef}
|
import akka.actor.{Actor, ActorRef}
|
||||||
import net.psforever.objects.Vehicle
|
import net.psforever.objects.{GlobalDefinitions, Vehicle}
|
||||||
import net.psforever.objects.ballistics.VehicleSource
|
import net.psforever.objects.ballistics.{ResolvedProjectile, VehicleSource}
|
||||||
|
import net.psforever.objects.equipment.{JammableMountedWeapons, JammableUnit}
|
||||||
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
||||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||||
import net.psforever.objects.serverobject.deploy.DeploymentBehavior
|
import net.psforever.objects.serverobject.deploy.{Deployment, DeploymentBehavior}
|
||||||
import net.psforever.objects.vital.{VehicleShieldCharge, Vitality}
|
import net.psforever.objects.vital.{VehicleShieldCharge, Vitality}
|
||||||
import net.psforever.types.ExoSuitType
|
import net.psforever.objects.zones.Zone
|
||||||
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
import net.psforever.types.{DriveState, ExoSuitType, Vector3}
|
||||||
|
import services.{RemoverActor, Service}
|
||||||
|
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
import services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
import services.vehicle.{VehicleAction, VehicleService, VehicleServiceMessage}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An `Actor` that handles messages being dispatched to a specific `Vehicle`.<br>
|
* An `Actor` that handles messages being dispatched to a specific `Vehicle`.<br>
|
||||||
|
|
@ -21,12 +28,16 @@ class VehicleControl(vehicle : Vehicle) extends Actor
|
||||||
with FactionAffinityBehavior.Check
|
with FactionAffinityBehavior.Check
|
||||||
with DeploymentBehavior
|
with DeploymentBehavior
|
||||||
with MountableBehavior.Mount
|
with MountableBehavior.Mount
|
||||||
with MountableBehavior.Dismount {
|
with MountableBehavior.Dismount
|
||||||
|
with JammableMountedWeapons {
|
||||||
|
|
||||||
//make control actors belonging to utilities when making control actor belonging to vehicle
|
//make control actors belonging to utilities when making control actor belonging to vehicle
|
||||||
vehicle.Utilities.foreach({case (_, util) => util.Setup })
|
vehicle.Utilities.foreach({case (_, util) => util.Setup })
|
||||||
|
|
||||||
def MountableObject = vehicle
|
def MountableObject = vehicle
|
||||||
|
|
||||||
|
def JammableObject = vehicle
|
||||||
|
|
||||||
def FactionObject = vehicle
|
def FactionObject = vehicle
|
||||||
|
|
||||||
def DeploymentObject = vehicle
|
def DeploymentObject = vehicle
|
||||||
|
|
@ -44,6 +55,7 @@ class VehicleControl(vehicle : Vehicle) extends Actor
|
||||||
def Enabled : Receive = checkBehavior
|
def Enabled : Receive = checkBehavior
|
||||||
.orElse(deployBehavior)
|
.orElse(deployBehavior)
|
||||||
.orElse(dismountBehavior)
|
.orElse(dismountBehavior)
|
||||||
|
.orElse(jammableBehavior)
|
||||||
.orElse {
|
.orElse {
|
||||||
case Mountable.TryMount(user, seat_num) =>
|
case Mountable.TryMount(user, seat_num) =>
|
||||||
val exosuit = user.ExoSuit
|
val exosuit = user.ExoSuit
|
||||||
|
|
@ -73,15 +85,17 @@ class VehicleControl(vehicle : Vehicle) extends Actor
|
||||||
if(vehicle.Health > 0) {
|
if(vehicle.Health > 0) {
|
||||||
val originalHealth = vehicle.Health
|
val originalHealth = vehicle.Health
|
||||||
val originalShields = vehicle.Shields
|
val originalShields = vehicle.Shields
|
||||||
damage_func(vehicle)
|
val cause = damage_func(vehicle)
|
||||||
val health = vehicle.Health
|
val health = vehicle.Health
|
||||||
val shields = vehicle.Shields
|
val shields = vehicle.Shields
|
||||||
val damageToHealth = originalHealth - health
|
val damageToHealth = originalHealth - health
|
||||||
val damageToShields = originalShields - shields
|
val damageToShields = originalShields - shields
|
||||||
val name = vehicle.Actor.toString
|
VehicleControl.HandleDamageResolution(vehicle, cause, damageToHealth + damageToShields)
|
||||||
val slashPoint = name.lastIndexOf("/")
|
if(damageToHealth > 0 || damageToShields > 0) {
|
||||||
org.log4s.getLogger("DamageResolution").info(s"${name.substring(slashPoint+1, name.length-1)}: BEFORE=$originalHealth/$originalShields, AFTER=$health/$shields, CHANGE=$damageToHealth/$damageToShields")
|
val name = vehicle.Actor.toString
|
||||||
sender ! Vitality.DamageResolution(vehicle)
|
val slashPoint = name.lastIndexOf("/")
|
||||||
|
org.log4s.getLogger("DamageResolution").info(s"${name.substring(slashPoint + 1, name.length - 1)}: BEFORE=$originalHealth/$originalShields, AFTER=$health/$shields, CHANGE=$damageToHealth/$damageToShields")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case Vehicle.ChargeShields(amount) =>
|
case Vehicle.ChargeShields(amount) =>
|
||||||
|
|
@ -91,7 +105,7 @@ class VehicleControl(vehicle : Vehicle) extends Actor
|
||||||
!vehicle.History.exists(VehicleControl.LastShieldChargeOrDamage(now))) {
|
!vehicle.History.exists(VehicleControl.LastShieldChargeOrDamage(now))) {
|
||||||
vehicle.History(VehicleShieldCharge(VehicleSource(vehicle), amount))
|
vehicle.History(VehicleShieldCharge(VehicleSource(vehicle), amount))
|
||||||
vehicle.Shields = vehicle.Shields + amount
|
vehicle.Shields = vehicle.Shields + amount
|
||||||
sender ! Vehicle.UpdateShieldsCharge(vehicle)
|
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(s"${vehicle.Actor}", VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), vehicle.GUID, 68, vehicle.Shields))
|
||||||
}
|
}
|
||||||
|
|
||||||
case FactionAffinity.ConvertFactionAffinity(faction) =>
|
case FactionAffinity.ConvertFactionAffinity(faction) =>
|
||||||
|
|
@ -101,7 +115,9 @@ class VehicleControl(vehicle : Vehicle) extends Actor
|
||||||
}
|
}
|
||||||
sender ! FactionAffinity.AssertFactionAffinity(vehicle, faction)
|
sender ! FactionAffinity.AssertFactionAffinity(vehicle, faction)
|
||||||
|
|
||||||
case Vehicle.PrepareForDeletion =>
|
case Vehicle.PrepareForDeletion() =>
|
||||||
|
CancelJammeredSound(vehicle)
|
||||||
|
CancelJammeredStatus(vehicle)
|
||||||
context.become(Disabled)
|
context.become(Disabled)
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
|
|
@ -110,10 +126,10 @@ class VehicleControl(vehicle : Vehicle) extends Actor
|
||||||
def Disabled : Receive = checkBehavior
|
def Disabled : Receive = checkBehavior
|
||||||
.orElse(dismountBehavior)
|
.orElse(dismountBehavior)
|
||||||
.orElse {
|
.orElse {
|
||||||
case Vehicle.Reactivate =>
|
case Vehicle.Reactivate() =>
|
||||||
context.become(Enabled)
|
context.become(Enabled)
|
||||||
|
|
||||||
case _ => ;
|
case _ =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,4 +152,116 @@ object VehicleControl {
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param target na
|
||||||
|
*/
|
||||||
|
def HandleDamageResolution(target : Vehicle, 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 vehicle death (hence, occupants' deaths)
|
||||||
|
HandleDestructionAwareness(target, playerGUID, cause)
|
||||||
|
}
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param target na
|
||||||
|
* @param attribution na
|
||||||
|
* @param lastShot na
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
zone.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(attribution, tplayer.GUID))
|
||||||
|
})
|
||||||
|
//alert cargo occupants to damage source
|
||||||
|
target.CargoHolds.values.foreach(hold => {
|
||||||
|
hold.Occupant match {
|
||||||
|
case Some(cargo) =>
|
||||||
|
cargo.Health = 0
|
||||||
|
cargo.Shields = 0
|
||||||
|
cargo.History(lastShot)
|
||||||
|
HandleDamageAwareness(cargo, attribution, lastShot)
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param target na
|
||||||
|
* @param attribution na
|
||||||
|
* @param lastShot na
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
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))
|
||||||
|
})
|
||||||
|
target.CargoHolds.values.foreach(hold => {
|
||||||
|
hold.Occupant match {
|
||||||
|
case Some(cargo) =>
|
||||||
|
cargo.Health = 0
|
||||||
|
cargo.Shields = 0
|
||||||
|
cargo.Position += Vector3.z(1)
|
||||||
|
cargo.History(lastShot) //necessary to kill cargo vehicle occupants //TODO: collision damage
|
||||||
|
HandleDestructionAwareness(cargo, attribution, lastShot) //might cause redundant packets
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
target.Definition match {
|
||||||
|
case GlobalDefinitions.ams =>
|
||||||
|
target.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying)
|
||||||
|
case GlobalDefinitions.router =>
|
||||||
|
target.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying)
|
||||||
|
VehicleService.BeforeUnloadVehicle(target, zone)
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(zone.Id, LocalAction.ToggleTeleportSystem(PlanetSideGUID(0), target, None))
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
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)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import net.psforever.objects.PlanetSideGameObject
|
||||||
import net.psforever.objects.ballistics.{PlayerSource, ResolvedProjectile, SourceEntry, VehicleSource}
|
import net.psforever.objects.ballistics.{PlayerSource, ResolvedProjectile, SourceEntry, VehicleSource}
|
||||||
import net.psforever.objects.definition.KitDefinition
|
import net.psforever.objects.definition.KitDefinition
|
||||||
import net.psforever.objects.serverobject.terminals.TerminalDefinition
|
import net.psforever.objects.serverobject.terminals.TerminalDefinition
|
||||||
|
import net.psforever.objects.vital.resolution.ResolutionCalculations
|
||||||
import net.psforever.types.{ExoSuitType, ImplantType}
|
import net.psforever.types.{ExoSuitType, ImplantType}
|
||||||
|
|
||||||
abstract class VitalsActivity(target : SourceEntry) {
|
abstract class VitalsActivity(target : SourceEntry) {
|
||||||
|
|
@ -102,13 +103,13 @@ object Vitality {
|
||||||
* upon a given vital object.
|
* upon a given vital object.
|
||||||
* @param func a function literal
|
* @param func a function literal
|
||||||
*/
|
*/
|
||||||
final case class Damage(func : (Any)=>Unit)
|
final case class Damage(func : ResolutionCalculations.Output)
|
||||||
|
|
||||||
final case class DamageOn(obj : Vitality, func : (Any)=>Unit)
|
final case class DamageOn(obj : Vitality, func : ResolutionCalculations.Output)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report that a vitals object must be updated due to damage.
|
* Report that a vitals object must be updated due to damage.
|
||||||
* @param obj the vital object
|
* @param obj the vital object
|
||||||
*/
|
*/
|
||||||
final case class DamageResolution(obj : Vitality)
|
final case class DamageResolution(obj : Vitality, cause : ResolvedProjectile)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import net.psforever.objects.vital.projectile.ProjectileCalculations
|
||||||
* @tparam A an internal type that converts between `calcFunc`'s output and `applyFunc`'s input;
|
* @tparam A an internal type that converts between `calcFunc`'s output and `applyFunc`'s input;
|
||||||
* never has to be defined explicitly, but will be checked upon object definition
|
* never has to be defined explicitly, but will be checked upon object definition
|
||||||
*/
|
*/
|
||||||
abstract class DamageResistCalculations[A](calcFunc : (ResolvedProjectile)=>((Int, Int)=>A),
|
abstract class DamageResistCalculations[A](calcFunc : ResolvedProjectile=>(Int, Int)=>A,
|
||||||
applyFunc : (A, ResolvedProjectile)=>ResolutionCalculations.Output)
|
applyFunc : (A, ResolvedProjectile)=>ResolutionCalculations.Output)
|
||||||
extends ResolutionCalculations {
|
extends ResolutionCalculations {
|
||||||
def Calculate(damages : ProjectileCalculations.Form, resistances : ProjectileCalculations.Form, data : ResolvedProjectile) : ResolutionCalculations.Output = {
|
def Calculate(damages : ProjectileCalculations.Form, resistances : ProjectileCalculations.Form, data : ResolvedProjectile) : ResolutionCalculations.Output = {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects.vital.resolution
|
||||||
|
|
||||||
import net.psforever.objects.{Player, TurretDeployable, Vehicle}
|
import net.psforever.objects.{Player, TurretDeployable, Vehicle}
|
||||||
import net.psforever.objects.ballistics.{PlayerSource, ResolvedProjectile}
|
import net.psforever.objects.ballistics.{PlayerSource, ResolvedProjectile}
|
||||||
import net.psforever.objects.ce.{ComplexDeployable, SimpleDeployable}
|
import net.psforever.objects.ce.{ComplexDeployable, Deployable}
|
||||||
import net.psforever.objects.serverobject.turret.FacilityTurret
|
import net.psforever.objects.serverobject.turret.FacilityTurret
|
||||||
import net.psforever.objects.vital.projectile.ProjectileCalculations
|
import net.psforever.objects.vital.projectile.ProjectileCalculations
|
||||||
|
|
||||||
|
|
@ -22,7 +22,7 @@ trait ResolutionCalculations {
|
||||||
}
|
}
|
||||||
|
|
||||||
object ResolutionCalculations {
|
object ResolutionCalculations {
|
||||||
type Output = (Any)=>Unit
|
type Output = Any=>ResolvedProjectile
|
||||||
type Form = (ProjectileCalculations.Form, ProjectileCalculations.Form, ResolvedProjectile)=>Output
|
type Form = (ProjectileCalculations.Form, ProjectileCalculations.Form, ResolvedProjectile)=>Output
|
||||||
|
|
||||||
def NoDamage(data : ResolvedProjectile)(a : Int, b : Int) : Int = 0
|
def NoDamage(data : ResolvedProjectile)(a : Int, b : Int) : Int = 0
|
||||||
|
|
@ -107,7 +107,7 @@ object ResolutionCalculations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def NoApplication(damageValue : Int, data : ResolvedProjectile)(target : Any) : Unit = { }
|
def NoApplication(damageValue : Int, data : ResolvedProjectile)(target : Any) : ResolvedProjectile = data
|
||||||
|
|
||||||
def SubtractWithRemainder(current : Int, damage : Int) : (Int, Int) = {
|
def SubtractWithRemainder(current : Int, damage : Int) : (Int, Int) = {
|
||||||
val a = Math.max(0, current - damage)
|
val a = Math.max(0, current - damage)
|
||||||
|
|
@ -123,41 +123,44 @@ object ResolutionCalculations {
|
||||||
* @param data the historical `ResolvedProjectile` information
|
* @param data the historical `ResolvedProjectile` information
|
||||||
* @param target the `Player` object to be affected by these damage values (at some point)
|
* @param target the `Player` object to be affected by these damage values (at some point)
|
||||||
*/
|
*/
|
||||||
def InfantryApplication(damageValues : (Int, Int), data : ResolvedProjectile)(target : Any) : Unit = target match {
|
def InfantryApplication(damageValues : (Int, Int), data : ResolvedProjectile)(target : Any) : ResolvedProjectile = {
|
||||||
case player : Player =>
|
target match {
|
||||||
var (a, b) = damageValues
|
case player : Player =>
|
||||||
var result = (0, 0)
|
var (a, b) = damageValues
|
||||||
//TODO Personal Shield implant test should go here and modify the values a and b
|
var result = (0, 0)
|
||||||
if(player.isAlive && !(a == 0 && b == 0)) {
|
//TODO Personal Shield implant test should go here and modify the values a and b
|
||||||
player.History(data)
|
if(player.isAlive && !(a == 0 && b == 0)) {
|
||||||
if(player.Capacitor.toInt > 0 && player.isShielded) {
|
player.History(data)
|
||||||
// Subtract armour damage from capacitor
|
if(player.Capacitor.toInt > 0 && player.isShielded) {
|
||||||
result = SubtractWithRemainder(player.Capacitor.toInt, b)
|
// Subtract armour damage from capacitor
|
||||||
player.Capacitor = result._1
|
result = SubtractWithRemainder(player.Capacitor.toInt, b)
|
||||||
|
player.Capacitor = result._1
|
||||||
|
b = result._2
|
||||||
|
|
||||||
|
// Then follow up with health damage if any capacitor is left
|
||||||
|
result = SubtractWithRemainder(player.Capacitor.toInt, a)
|
||||||
|
player.Capacitor = result._1
|
||||||
|
a = result._2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract any remaining armour damage from armour
|
||||||
|
result = SubtractWithRemainder(player.Armor, b)
|
||||||
|
player.Armor = result._1
|
||||||
b = result._2
|
b = result._2
|
||||||
|
|
||||||
// Then follow up with health damage if any capacitor is left
|
// Then bleed through to health if armour ran out
|
||||||
result = SubtractWithRemainder(player.Capacitor.toInt, a)
|
result = SubtractWithRemainder(player.Health, b)
|
||||||
player.Capacitor = result._1
|
player.Health = result._1
|
||||||
|
b = result._2
|
||||||
|
|
||||||
|
// Finally, apply health damage to health
|
||||||
|
result = SubtractWithRemainder(player.Health, a)
|
||||||
|
player.Health = result._1
|
||||||
a = result._2
|
a = result._2
|
||||||
}
|
}
|
||||||
|
case _ =>
|
||||||
// Subtract any remaining armour damage from armour
|
}
|
||||||
result = SubtractWithRemainder(player.Armor, b)
|
data
|
||||||
player.Armor = result._1
|
|
||||||
b = result._2
|
|
||||||
|
|
||||||
// Then bleed through to health if armour ran out
|
|
||||||
result = SubtractWithRemainder(player.Health, b)
|
|
||||||
player.Health = result._1
|
|
||||||
b = result._2
|
|
||||||
|
|
||||||
// Finally, apply health damage to health
|
|
||||||
result = SubtractWithRemainder(player.Health, a)
|
|
||||||
player.Health = result._1
|
|
||||||
a = result._2
|
|
||||||
}
|
|
||||||
case _ =>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -167,9 +170,9 @@ object ResolutionCalculations {
|
||||||
* @param data the historical `ResolvedProjectile` information
|
* @param data the historical `ResolvedProjectile` information
|
||||||
* @param target the `Vehicle` object to be affected by these damage values (at some point)
|
* @param target the `Vehicle` object to be affected by these damage values (at some point)
|
||||||
*/
|
*/
|
||||||
def VehicleApplication(damage : Int, data : ResolvedProjectile)(target : Any) : Unit = target match {
|
def VehicleApplication(damage : Int, data : ResolvedProjectile)(target : Any) : ResolvedProjectile = {
|
||||||
case vehicle : Vehicle =>
|
target match {
|
||||||
if(vehicle.Health > 0) {
|
case vehicle : Vehicle if vehicle.Health > 0 && damage > 0 =>
|
||||||
vehicle.History(data)
|
vehicle.History(data)
|
||||||
val shields = vehicle.Shields
|
val shields = vehicle.Shields
|
||||||
if(shields > damage) {
|
if(shields > damage) {
|
||||||
|
|
@ -182,57 +185,58 @@ object ResolutionCalculations {
|
||||||
else {
|
else {
|
||||||
vehicle.Health = vehicle.Health - damage
|
vehicle.Health = vehicle.Health - damage
|
||||||
}
|
}
|
||||||
}
|
case _ => ;
|
||||||
case _ => ;
|
}
|
||||||
|
data
|
||||||
}
|
}
|
||||||
|
|
||||||
def SimpleApplication(damage : Int, data : ResolvedProjectile)(target : Any) : Unit = target match {
|
def SimpleApplication(damage : Int, data : ResolvedProjectile)(target : Any) : ResolvedProjectile = {
|
||||||
case ce : SimpleDeployable =>
|
target match {
|
||||||
if(ce.Health > 0) {
|
case obj : Deployable if obj.Health > 0 =>
|
||||||
ce.Health -= damage
|
obj.Health -= damage
|
||||||
ce.History(data)
|
obj.History(data)
|
||||||
}
|
case turret : FacilityTurret if turret.Health > 0 =>
|
||||||
case turret : FacilityTurret =>
|
|
||||||
if(turret.Health > 0) {
|
|
||||||
turret.Health -= damage
|
turret.Health -= damage
|
||||||
turret.History(data)
|
turret.History(data)
|
||||||
}
|
case _ => ;
|
||||||
case _ =>
|
}
|
||||||
|
data
|
||||||
}
|
}
|
||||||
|
|
||||||
def ComplexDeployableApplication(damage : Int, data : ResolvedProjectile)(target : Any) : Unit = target match {
|
def ComplexDeployableApplication(damage : Int, data : ResolvedProjectile)(target : Any) : ResolvedProjectile = {
|
||||||
case ce : ComplexDeployable =>
|
target match {
|
||||||
if(ce.Shields > 0) {
|
case ce : ComplexDeployable if ce.Health > 0 && damage > 0 =>
|
||||||
if(damage > ce.Shields) {
|
ce.History(data)
|
||||||
ce.Health -= (damage - ce.Shields)
|
if(ce.Shields > 0) {
|
||||||
ce.Shields = 0
|
if(damage > ce.Shields) {
|
||||||
|
ce.Health -= (damage - ce.Shields)
|
||||||
|
ce.Shields = 0
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ce.Shields -= damage
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ce.Shields -= damage
|
ce.Health -= damage
|
||||||
}
|
}
|
||||||
ce.History(data)
|
|
||||||
}
|
|
||||||
else if(ce.Health > 0) {
|
|
||||||
ce.Health -= damage
|
|
||||||
ce.History(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
case ce : TurretDeployable =>
|
case ce : TurretDeployable if ce.Health > 0 && damage > 0 =>
|
||||||
if(ce.Shields > 0) {
|
ce.History(data)
|
||||||
if(damage > ce.Shields) {
|
if(ce.Shields > 0) {
|
||||||
ce.Health -= (damage - ce.Shields)
|
if(damage > ce.Shields) {
|
||||||
ce.Shields = 0
|
ce.Health -= (damage - ce.Shields)
|
||||||
|
ce.Shields = 0
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ce.Shields -= damage
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ce.Shields -= damage
|
ce.Health -= damage
|
||||||
}
|
}
|
||||||
ce.History(data)
|
|
||||||
}
|
|
||||||
else if(ce.Health > 0) {
|
|
||||||
ce.Health -= damage
|
|
||||||
ce.History(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
|
}
|
||||||
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ class ZoneDeployableActor(zone : Zone, deployableList : ListBuffer[PlanetSideGam
|
||||||
case _ =>
|
case _ =>
|
||||||
obj.Definition.Initialize(obj, context)
|
obj.Definition.Initialize(obj, context)
|
||||||
}
|
}
|
||||||
|
obj.Zone = zone
|
||||||
sender ! Zone.Deployable.DeployableIsBuilt(obj, tool)
|
sender ! Zone.Deployable.DeployableIsBuilt(obj, tool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.zones
|
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 net.psforever.objects.{Avatar, Player}
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
|
|
@ -34,16 +36,22 @@ class ZonePopulationActor(zone : Zone, playerMap : TrieMap[Avatar, Option[Player
|
||||||
case Zone.Population.Spawn(avatar, player) =>
|
case Zone.Population.Spawn(avatar, player) =>
|
||||||
PopulationSpawn(avatar, player, playerMap) match {
|
PopulationSpawn(avatar, player, playerMap) match {
|
||||||
case Some(tplayer) =>
|
case Some(tplayer) =>
|
||||||
|
tplayer.Zone = zone
|
||||||
if(tplayer ne player) {
|
if(tplayer ne player) {
|
||||||
sender ! Zone.Population.PlayerAlreadySpawned(zone, player)
|
sender ! Zone.Population.PlayerAlreadySpawned(zone, player)
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
player.Actor = context.actorOf(Props(classOf[PlayerControl], player), s"${player.Name}_${player.GUID.guid}")
|
||||||
|
}
|
||||||
case None =>
|
case None =>
|
||||||
sender ! Zone.Population.PlayerCanNotSpawn(zone, player)
|
sender ! Zone.Population.PlayerCanNotSpawn(zone, player)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Zone.Population.Release(avatar) =>
|
case Zone.Population.Release(avatar) =>
|
||||||
PopulationRelease(avatar, playerMap) match {
|
PopulationRelease(avatar, playerMap) match {
|
||||||
case Some(_) => ;
|
case Some(tplayer) =>
|
||||||
|
tplayer.Actor ! akka.actor.PoisonPill
|
||||||
|
tplayer.Actor = ActorRef.noSender
|
||||||
case None =>
|
case None =>
|
||||||
sender ! Zone.Population.PlayerHasLeft(zone, None)
|
sender ! Zone.Population.PlayerHasLeft(zone, None)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import shapeless.{::, HNil}
|
||||||
* 15 - Displays "This facility's generator is under attack!"
|
* 15 - Displays "This facility's generator is under attack!"
|
||||||
* 16 - Displays "Generator has Overloaded! Evacuate Generator Room Immediately!"
|
* 16 - Displays "Generator has Overloaded! Evacuate Generator Room Immediately!"
|
||||||
* 17 - Displays "This facility's generator is back on line"
|
* 17 - Displays "This facility's generator is back on line"
|
||||||
|
* 19 - Cause mines to explode
|
||||||
* 20 - Hit flinch? (orig, 82->80)
|
* 20 - Hit flinch? (orig, 82->80)
|
||||||
* 21 - Reset build cooldown from using an ACE
|
* 21 - Reset build cooldown from using an ACE
|
||||||
* 22 - ???? (Has been seen on vehicle pad objects, possibly some sort of reset flag after base faction flip / hack clear?)
|
* 22 - ???? (Has been seen on vehicle pad objects, possibly some sort of reset flag after base faction flip / hack clear?)
|
||||||
|
|
|
||||||
|
|
@ -115,10 +115,10 @@ import scodec.codecs._
|
||||||
* 45 : Advanced Engineering (= Fortification Engineering + Assault Engineering) Must have Combat Engineering<br>
|
* 45 : Advanced Engineering (= Fortification Engineering + Assault Engineering) Must have Combat Engineering<br>
|
||||||
* `25 - Forget certifications (same order as 24)`<br>
|
* `25 - Forget certifications (same order as 24)`<br>
|
||||||
* `26 - Certification reset timer (in seconds)`
|
* `26 - Certification reset timer (in seconds)`
|
||||||
* `27 - PA_JAMMED - plays jammed buzzing sound`<br>
|
* `27 - PA_JAMMED - plays jammed buzzing sound in vicinity of target, jams weapon discharge`<br>
|
||||||
* `28 - PA_IMPLANT_ACTIVE - Plays implant sounds. Valid values seem to be up to 20.`<br>
|
* `28 - PA_IMPLANT_ACTIVE - Plays implant sounds. Valid values seem to be up to 20.`<br>
|
||||||
* `29 - PA_VAPORIZED - Visible ?! That's not the cloaked effect, Maybe for spectator mode ?. Value is 0 to visible, 1 to invisible.`<br>
|
* `29 - PA_VAPORIZED - Visible ?! That's not the cloaked effect, Maybe for spectator mode ?. Value is 0 to visible, 1 to invisible.`<br>
|
||||||
* `31 - Looking for Squad info (marquee and ui):<br>
|
* `31 - Looking for Squad info (marquee and ui):`<br>
|
||||||
* ` - 0 is LFS`<br>
|
* ` - 0 is LFS`<br>
|
||||||
* ` - 1 is LFSM (Looking for Squad Members)`<br>
|
* ` - 1 is LFSM (Looking for Squad Members)`<br>
|
||||||
* ` - n is the supplemental squad identifier number; same as "LFS;" for the leader, sets "LFSM" after the first manual flagging`<br>
|
* ` - n is the supplemental squad identifier number; same as "LFS;" for the leader, sets "LFSM" after the first manual flagging`<br>
|
||||||
|
|
@ -162,7 +162,7 @@ import scodec.codecs._
|
||||||
* `13 - Trunk permissions (same)`<br>
|
* `13 - Trunk permissions (same)`<br>
|
||||||
* `21 - Declare a player the vehicle's owner, by globally unique identifier`<br>
|
* `21 - Declare a player the vehicle's owner, by globally unique identifier`<br>
|
||||||
* `22 - Toggles gunner and passenger mount points (1 = hides, 0 = reveals; this also locks their permissions)`<br>
|
* `22 - Toggles gunner and passenger mount points (1 = hides, 0 = reveals; this also locks their permissions)`<br>
|
||||||
* `54 - Vehicle EMP? Plays sound as if vehicle had been hit by EMP`<br>
|
* `54 - Plays jammed buzzing sound in vicinity of target`<br>
|
||||||
* `68 - Vehicle shield health`<br>
|
* `68 - Vehicle shield health`<br>
|
||||||
* `79 - ???`<br>
|
* `79 - ???`<br>
|
||||||
* `80 - Damage vehicle (unknown value)`<br>
|
* `80 - Damage vehicle (unknown value)`<br>
|
||||||
|
|
|
||||||
|
|
@ -327,7 +327,7 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] {
|
||||||
}
|
}
|
||||||
else if(data.faction == PlanetSideEmpire.NEUTRAL) {
|
else if(data.faction == PlanetSideEmpire.NEUTRAL) {
|
||||||
Attempt.successful(
|
Attempt.successful(
|
||||||
CommonFieldData(faction, data.bops, data.alternate, data.v1, data.v2, data.v3, None, data.v5, PlanetSideGUID(0)) ::
|
CommonFieldData(faction, data.bops, data.alternate, data.v1, data.v2, data.jammered, None, data.v5, PlanetSideGUID(0)) ::
|
||||||
name :: suit :: u5 :: sex :: head :: v1 :: u6 :: u7 :: u8 :: u9 :: uA :: HNil
|
name :: suit :: u5 :: sex :: head :: v1 :: u6 :: u7 :: u8 :: u9 :: uA :: HNil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ import scodec.{Attempt, Codec, Err}
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
import shapeless.{::, HNil}
|
import shapeless.{::, HNil}
|
||||||
|
|
||||||
final case class CommonFieldDataExtra(unk1 : Int, unk2 : Boolean) extends StreamBitSize {
|
final case class CommonFieldDataExtra(unk1 : Option[Int], unk2 : Boolean) extends StreamBitSize {
|
||||||
override def bitsize : Long = 17L
|
override def bitsize : Long = 17L
|
||||||
}
|
}
|
||||||
|
|
||||||
object CommonFieldDataExtra {
|
object CommonFieldDataExtra {
|
||||||
implicit val codec : Codec[CommonFieldDataExtra] = (
|
def codec(unk1 : Boolean) : Codec[CommonFieldDataExtra] = (
|
||||||
("unk1" | uint16L) ::
|
("unk1" | conditional(unk1, uint16L)) :: //not sure what flags this field
|
||||||
("unk2" | bool)
|
("unk2" | bool)
|
||||||
).as[CommonFieldDataExtra]
|
).as[CommonFieldDataExtra]
|
||||||
}
|
}
|
||||||
|
|
@ -28,10 +28,9 @@ object CommonFieldDataExtra {
|
||||||
* when set on a tool, that tool will be rendered nonfunctional instead (though it can still be equipped)
|
* when set on a tool, that tool will be rendered nonfunctional instead (though it can still be equipped)
|
||||||
* @param v1 na
|
* @param v1 na
|
||||||
* @param v2 na;
|
* @param v2 na;
|
||||||
* optional data whose reading is triggered in unknown conditions;
|
* optional data whose reading is triggered in unknown conditions
|
||||||
* flag a weapon as "jammered"
|
* @param jammered flag as "jammered;"
|
||||||
* @param v3 na;
|
* set on most game objects, that object will produce the characteristic jammered buzz
|
||||||
* for weapons, works like `alternate`
|
|
||||||
* @param v4 na;
|
* @param v4 na;
|
||||||
* a field used by a second encoding format for this data
|
* a field used by a second encoding format for this data
|
||||||
* @param v5 na;
|
* @param v5 na;
|
||||||
|
|
@ -43,7 +42,7 @@ final case class CommonFieldData(faction : PlanetSideEmpire.Value,
|
||||||
alternate : Boolean,
|
alternate : Boolean,
|
||||||
v1 : Boolean,
|
v1 : Boolean,
|
||||||
v2 : Option[CommonFieldDataExtra],
|
v2 : Option[CommonFieldDataExtra],
|
||||||
v3 : Boolean,
|
jammered : Boolean,
|
||||||
v4 : Option[Boolean],
|
v4 : Option[Boolean],
|
||||||
v5 : Option[Int],
|
v5 : Option[Int],
|
||||||
guid : PlanetSideGUID
|
guid : PlanetSideGUID
|
||||||
|
|
@ -64,7 +63,7 @@ final case class CommonFieldData(faction : PlanetSideEmpire.Value,
|
||||||
23L + extraSize + v4Size + v5Size
|
23L + extraSize + v4Size + v5Size
|
||||||
}
|
}
|
||||||
|
|
||||||
def apply(flag : Boolean) : CommonFieldData = CommonFieldData(faction, bops, alternate, v1, v2, v3, Some(flag), v5, guid)
|
def apply(flag : Boolean) : CommonFieldData = CommonFieldData(faction, bops, alternate, v1, v2, jammered, Some(flag), v5, guid)
|
||||||
}
|
}
|
||||||
|
|
||||||
object CommonFieldData extends Marshallable[CommonFieldData] {
|
object CommonFieldData extends Marshallable[CommonFieldData] {
|
||||||
|
|
@ -100,8 +99,8 @@ object CommonFieldData extends Marshallable[CommonFieldData] {
|
||||||
("bops" | bool) ::
|
("bops" | bool) ::
|
||||||
("alternate" | bool) ::
|
("alternate" | bool) ::
|
||||||
("v1" | bool) :: //the purpose of this bit changes depending on the previous bit
|
("v1" | bool) :: //the purpose of this bit changes depending on the previous bit
|
||||||
conditional(extra, "v2" | CommonFieldDataExtra.codec) ::
|
conditional(extra, "v2" | CommonFieldDataExtra.codec(unk1 = false)) ::
|
||||||
("v3" | bool) ::
|
("jammered" | bool) ::
|
||||||
optional(bool, "v5" | uint16L) ::
|
optional(bool, "v5" | uint16L) ::
|
||||||
("guid" | PlanetSideGUID.codec)
|
("guid" | PlanetSideGUID.codec)
|
||||||
).xmap[CommonFieldData] (
|
).xmap[CommonFieldData] (
|
||||||
|
|
@ -122,8 +121,8 @@ object CommonFieldData extends Marshallable[CommonFieldData] {
|
||||||
("bops" | bool) ::
|
("bops" | bool) ::
|
||||||
("alternate" | bool) ::
|
("alternate" | bool) ::
|
||||||
("v1" | bool) :: //though the code path differs depending on the previous bit, this one gets read one way or another
|
("v1" | bool) :: //though the code path differs depending on the previous bit, this one gets read one way or another
|
||||||
conditional(extra, "v2" | CommonFieldDataExtra.codec) ::
|
conditional(extra, "v2" | CommonFieldDataExtra.codec(unk1 = false)) ::
|
||||||
("v3" | bool) ::
|
("jammered" | bool) ::
|
||||||
optional(bool, "v5" | uint16L) ::
|
optional(bool, "v5" | uint16L) ::
|
||||||
("v4" | bool) ::
|
("v4" | bool) ::
|
||||||
("guid" | PlanetSideGUID.codec)
|
("guid" | PlanetSideGUID.codec)
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ object OneMannedFieldTurretData extends Marshallable[OneMannedFieldTurretData] {
|
||||||
OneMannedFieldTurretData(
|
OneMannedFieldTurretData(
|
||||||
CommonFieldDataWithPlacement(
|
CommonFieldDataWithPlacement(
|
||||||
deploy.pos,
|
deploy.pos,
|
||||||
CommonFieldData(data.faction, data.bops, data.alternate, data.v1, data.v2, data.v3, data.v4, data.v5, player)
|
CommonFieldData(data.faction, data.bops, data.alternate, data.v1, data.v2, data.jammered, data.v4, data.v5, player)
|
||||||
),
|
),
|
||||||
newHealth,
|
newHealth,
|
||||||
newInternals
|
newInternals
|
||||||
|
|
@ -92,7 +92,7 @@ object OneMannedFieldTurretData extends Marshallable[OneMannedFieldTurretData] {
|
||||||
Attempt.successful(
|
Attempt.successful(
|
||||||
CommonFieldDataWithPlacement(
|
CommonFieldDataWithPlacement(
|
||||||
pos,
|
pos,
|
||||||
CommonFieldData(data.faction, data.bops, data.alternate, data.v1, data.v2, data.v3, data.v4, data.v5, PlanetSideGUID(0))
|
CommonFieldData(data.faction, data.bops, data.alternate, data.v1, data.v2, data.jammered, data.v4, data.v5, PlanetSideGUID(0))
|
||||||
) :: data.guid :: false :: newHealth :: 0 :: 0xF :: 0 :: newInternals :: HNil
|
) :: data.guid :: false :: newHealth :: 0 :: 0xF :: 0 :: newInternals :: HNil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import net.psforever.objects.ballistics.{Projectile, SourceEntry}
|
||||||
import net.psforever.objects.ce.Deployable
|
import net.psforever.objects.ce.Deployable
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.objects.inventory.Container
|
import net.psforever.objects.inventory.Container
|
||||||
|
import net.psforever.objects.vital.resolution.ResolutionCalculations
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.PlanetSideGamePacket
|
import net.psforever.packet.PlanetSideGamePacket
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
|
@ -31,7 +32,7 @@ object AvatarAction {
|
||||||
final case class ChangeFireState_Stop(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action
|
final case class ChangeFireState_Stop(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action
|
||||||
final case class ConcealPlayer(player_guid : PlanetSideGUID) extends Action
|
final case class ConcealPlayer(player_guid : PlanetSideGUID) extends Action
|
||||||
final case class EnvironmentalDamage(player_guid : PlanetSideGUID, amount: Int) extends Action
|
final case class EnvironmentalDamage(player_guid : PlanetSideGUID, amount: Int) extends Action
|
||||||
final case class Damage(player_guid : PlanetSideGUID, target : Player, resolution_function : Any=>Unit) extends Action
|
final case class Damage(player_guid : PlanetSideGUID, target : Player, resolution_function : ResolutionCalculations.Output) extends Action
|
||||||
final case class DeployItem(player_guid : PlanetSideGUID, item : PlanetSideGameObject with Deployable) extends Action
|
final case class DeployItem(player_guid : PlanetSideGUID, item : PlanetSideGameObject with Deployable) extends Action
|
||||||
final case class Destroy(victim : PlanetSideGUID, killer : PlanetSideGUID, weapon : PlanetSideGUID, pos : Vector3) extends Action
|
final case class Destroy(victim : PlanetSideGUID, killer : PlanetSideGUID, weapon : PlanetSideGUID, pos : Vector3) extends Action
|
||||||
final case class DestroyDisplay(killer : SourceEntry, victim : SourceEntry, method : Int, unk : Int = 121) extends Action
|
final case class DestroyDisplay(killer : SourceEntry, victim : SourceEntry, method : Int, unk : Int = 121) extends Action
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package services.avatar
|
||||||
import net.psforever.objects.Player
|
import net.psforever.objects.Player
|
||||||
import net.psforever.objects.ballistics.{Projectile, SourceEntry}
|
import net.psforever.objects.ballistics.{Projectile, SourceEntry}
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
|
import net.psforever.objects.vital.resolution.ResolutionCalculations
|
||||||
import net.psforever.packet.PlanetSideGamePacket
|
import net.psforever.packet.PlanetSideGamePacket
|
||||||
import net.psforever.packet.game.objectcreate.ConstructorData
|
import net.psforever.packet.game.objectcreate.ConstructorData
|
||||||
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
|
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
|
||||||
|
|
@ -25,7 +26,7 @@ object AvatarResponse {
|
||||||
final case class ChangeFireState_Stop(weapon_guid : PlanetSideGUID) extends Response
|
final case class ChangeFireState_Stop(weapon_guid : PlanetSideGUID) extends Response
|
||||||
final case class ConcealPlayer() extends Response
|
final case class ConcealPlayer() extends Response
|
||||||
final case class EnvironmentalDamage(target : PlanetSideGUID, amount : Int) extends Response
|
final case class EnvironmentalDamage(target : PlanetSideGUID, amount : Int) extends Response
|
||||||
final case class DamageResolution(target : Player, resolution_function : Any=>Unit) extends Response
|
final case class DamageResolution(target : Player, resolution_function : ResolutionCalculations.Output) extends Response
|
||||||
final case class Destroy(victim : PlanetSideGUID, killer : PlanetSideGUID, weapon : PlanetSideGUID, pos : Vector3) extends Response
|
final case class Destroy(victim : PlanetSideGUID, killer : PlanetSideGUID, weapon : PlanetSideGUID, pos : Vector3) extends Response
|
||||||
final case class DestroyDisplay(killer : SourceEntry, victim : SourceEntry, method : Int, unk : Int) extends Response
|
final case class DestroyDisplay(killer : SourceEntry, victim : SourceEntry, method : Int, unk : Int) extends Response
|
||||||
final case class DropItem(pkt : ObjectCreateMessage) extends Response
|
final case class DropItem(pkt : ObjectCreateMessage) extends Response
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,10 @@ class LocalService(zone : Zone) extends Actor {
|
||||||
LocalEvents.publish(
|
LocalEvents.publish(
|
||||||
LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.DeployableMapIcon(behavior, deployInfo))
|
LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.DeployableMapIcon(behavior, deployInfo))
|
||||||
)
|
)
|
||||||
|
case LocalAction.Detonate(guid, obj) =>
|
||||||
|
LocalEvents.publish(
|
||||||
|
LocalServiceResponse(s"/$forChannel/Local", Service.defaultPlayerGUID, LocalResponse.Detonate(guid, obj))
|
||||||
|
)
|
||||||
case LocalAction.DoorOpens(player_guid, _, door) =>
|
case LocalAction.DoorOpens(player_guid, _, door) =>
|
||||||
doorCloser ! DoorCloseActor.DoorIsOpen(door, zone)
|
doorCloser ! DoorCloseActor.DoorIsOpen(door, zone)
|
||||||
LocalEvents.publish(
|
LocalEvents.publish(
|
||||||
|
|
@ -282,9 +286,9 @@ class LocalService(zone : Zone) extends Actor {
|
||||||
}
|
}
|
||||||
|
|
||||||
//synchronized damage calculations
|
//synchronized damage calculations
|
||||||
case Vitality.DamageOn(target : Deployable, func) =>
|
case Vitality.DamageOn(target : Deployable, damage_func) =>
|
||||||
func(target)
|
val cause = damage_func(target)
|
||||||
sender ! Vitality.DamageResolution(target)
|
sender ! Vitality.DamageResolution(target, cause)
|
||||||
|
|
||||||
case msg =>
|
case msg =>
|
||||||
log.warn(s"Unhandled message $msg from $sender")
|
log.warn(s"Unhandled message $msg from $sender")
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ object LocalAction {
|
||||||
|
|
||||||
final case class AlertDestroyDeployable(player_guid : PlanetSideGUID, obj : PlanetSideGameObject with Deployable) extends Action
|
final case class AlertDestroyDeployable(player_guid : PlanetSideGUID, obj : PlanetSideGameObject with Deployable) extends Action
|
||||||
final case class DeployableMapIcon(player_guid : PlanetSideGUID, behavior : DeploymentAction.Value, deployInfo : DeployableInfo) extends Action
|
final case class DeployableMapIcon(player_guid : PlanetSideGUID, behavior : DeploymentAction.Value, deployInfo : DeployableInfo) extends Action
|
||||||
|
final case class Detonate(guid : PlanetSideGUID, obj : PlanetSideGameObject) extends Action
|
||||||
final case class DoorOpens(player_guid : PlanetSideGUID, continent : Zone, door : Door) extends Action
|
final case class DoorOpens(player_guid : PlanetSideGUID, continent : Zone, door : Door) extends Action
|
||||||
final case class DoorCloses(player_guid : PlanetSideGUID, door_guid : PlanetSideGUID) extends Action
|
final case class DoorCloses(player_guid : PlanetSideGUID, door_guid : PlanetSideGUID) extends Action
|
||||||
final case class HackClear(player_guid : PlanetSideGUID, target : PlanetSideServerObject, unk1 : Long, unk2 : Long = 8L) extends Action
|
final case class HackClear(player_guid : PlanetSideGUID, target : PlanetSideServerObject, unk1 : Long, unk2 : Long = 8L) extends Action
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ object LocalResponse {
|
||||||
|
|
||||||
final case class AlertDestroyDeployable(obj : PlanetSideGameObject with Deployable) extends Response
|
final case class AlertDestroyDeployable(obj : PlanetSideGameObject with Deployable) extends Response
|
||||||
final case class DeployableMapIcon(action : DeploymentAction.Value, deployInfo : DeployableInfo) extends Response
|
final case class DeployableMapIcon(action : DeploymentAction.Value, deployInfo : DeployableInfo) extends Response
|
||||||
|
final case class Detonate(guid : PlanetSideGUID, obj : PlanetSideGameObject) extends Response
|
||||||
final case class DoorOpens(door_guid : PlanetSideGUID) extends Response
|
final case class DoorOpens(door_guid : PlanetSideGUID) extends Response
|
||||||
final case class DoorCloses(door_guid : PlanetSideGUID) extends Response
|
final case class DoorCloses(door_guid : PlanetSideGUID) extends Response
|
||||||
final case class EliminateDeployable(obj : PlanetSideGameObject with Deployable, object_guid : PlanetSideGUID, pos : Vector3) extends Response
|
final case class EliminateDeployable(obj : PlanetSideGameObject with Deployable, object_guid : PlanetSideGUID, pos : Vector3) extends Response
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,18 @@
|
||||||
package services.vehicle
|
package services.vehicle
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorRef, Props}
|
import akka.actor.{Actor, ActorRef, Props}
|
||||||
import net.psforever.objects.Vehicle
|
import net.psforever.objects.{GlobalDefinitions, TelepadDeployable, Vehicle}
|
||||||
import net.psforever.objects.ballistics.VehicleSource
|
import net.psforever.objects.ballistics.VehicleSource
|
||||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||||
import net.psforever.objects.serverobject.terminals.{MedicalTerminalDefinition, ProximityUnit}
|
import net.psforever.objects.serverobject.terminals.{MedicalTerminalDefinition, ProximityUnit}
|
||||||
|
import net.psforever.objects.vehicles.{Utility, UtilityType}
|
||||||
import net.psforever.objects.vital.RepairFromTerm
|
import net.psforever.objects.vital.RepairFromTerm
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
|
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
|
||||||
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
|
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
|
||||||
import services.vehicle.support.{TurretUpgrader, VehicleRemover}
|
import services.vehicle.support.{TurretUpgrader, VehicleRemover}
|
||||||
import net.psforever.types.DriveState
|
import net.psforever.types.DriveState
|
||||||
|
import services.local.LocalServiceMessage
|
||||||
import services.{GenericEventBus, RemoverActor, Service}
|
import services.{GenericEventBus, RemoverActor, Service}
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
@ -253,3 +255,36 @@ class VehicleService(zone : Zone) extends Actor {
|
||||||
.map(util => util().asInstanceOf[SpawnTube])
|
.map(util => util().asInstanceOf[SpawnTube])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object VehicleService {
|
||||||
|
/**
|
||||||
|
* Before a vehicle is removed from the game world, the following actions must be performed.
|
||||||
|
* @param vehicle the vehicle
|
||||||
|
*/
|
||||||
|
def BeforeUnloadVehicle(vehicle : Vehicle, zone : Zone) : Unit = {
|
||||||
|
vehicle.Definition match {
|
||||||
|
case GlobalDefinitions.ams =>
|
||||||
|
zone.VehicleEvents ! VehicleServiceMessage.AMSDeploymentChange(zone)
|
||||||
|
case GlobalDefinitions.router =>
|
||||||
|
RemoveTelepads(vehicle, zone)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def RemoveTelepads(vehicle: Vehicle, zone : Zone) : Unit = {
|
||||||
|
(vehicle.Utility(UtilityType.internal_router_telepad_deployable) match {
|
||||||
|
case Some(util : Utility.InternalTelepad) =>
|
||||||
|
val telepad = util.Telepad
|
||||||
|
util.Telepad = None
|
||||||
|
zone.GUID(telepad)
|
||||||
|
case _ =>
|
||||||
|
None
|
||||||
|
}) match {
|
||||||
|
case Some(telepad : TelepadDeployable) =>
|
||||||
|
telepad.Active = false
|
||||||
|
zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(telepad), zone))
|
||||||
|
zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(telepad, zone, Some(0 seconds)))
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ class VehicleRemover extends RemoverActor {
|
||||||
val vehicle = entry.obj.asInstanceOf[Vehicle]
|
val vehicle = entry.obj.asInstanceOf[Vehicle]
|
||||||
val vehicleGUID = vehicle.GUID
|
val vehicleGUID = vehicle.GUID
|
||||||
val zoneId = entry.zone.Id
|
val zoneId = entry.zone.Id
|
||||||
vehicle.Actor ! Vehicle.PrepareForDeletion
|
vehicle.Actor ! Vehicle.PrepareForDeletion()
|
||||||
//escape being someone else's cargo
|
//escape being someone else's cargo
|
||||||
(vehicle.MountedIn match {
|
(vehicle.MountedIn match {
|
||||||
case Some(carrierGUID) =>
|
case Some(carrierGUID) =>
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class AegisShieldGeneratorDataTest extends Specification {
|
||||||
basic.data.alternate mustEqual false
|
basic.data.alternate mustEqual false
|
||||||
basic.data.v1 mustEqual true
|
basic.data.v1 mustEqual true
|
||||||
basic.data.v2.isDefined mustEqual false
|
basic.data.v2.isDefined mustEqual false
|
||||||
basic.data.v3 mustEqual false
|
basic.data.jammered mustEqual false
|
||||||
basic.data.v5.isDefined mustEqual false
|
basic.data.v5.isDefined mustEqual false
|
||||||
basic.data.guid mustEqual PlanetSideGUID(2366)
|
basic.data.guid mustEqual PlanetSideGUID(2366)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ class CharacterDataTest extends Specification {
|
||||||
a.data.bops mustEqual false
|
a.data.bops mustEqual false
|
||||||
a.data.v1 mustEqual false
|
a.data.v1 mustEqual false
|
||||||
a.data.v2.isEmpty mustEqual true
|
a.data.v2.isEmpty mustEqual true
|
||||||
a.data.v3 mustEqual false
|
a.data.jammered mustEqual false
|
||||||
a.data.v4.isEmpty mustEqual true
|
a.data.v4.isEmpty mustEqual true
|
||||||
a.data.v5.isEmpty mustEqual true
|
a.data.v5.isEmpty mustEqual true
|
||||||
a.exosuit mustEqual ExoSuitType.Reinforced
|
a.exosuit mustEqual ExoSuitType.Reinforced
|
||||||
|
|
@ -162,7 +162,7 @@ class CharacterDataTest extends Specification {
|
||||||
a.data.bops mustEqual false
|
a.data.bops mustEqual false
|
||||||
a.data.v1 mustEqual false
|
a.data.v1 mustEqual false
|
||||||
a.data.v2.isEmpty mustEqual true
|
a.data.v2.isEmpty mustEqual true
|
||||||
a.data.v3 mustEqual false
|
a.data.jammered mustEqual false
|
||||||
a.data.v4.isEmpty mustEqual true
|
a.data.v4.isEmpty mustEqual true
|
||||||
a.data.v5.isEmpty mustEqual true
|
a.data.v5.isEmpty mustEqual true
|
||||||
a.exosuit mustEqual ExoSuitType.Reinforced
|
a.exosuit mustEqual ExoSuitType.Reinforced
|
||||||
|
|
@ -231,7 +231,7 @@ class CharacterDataTest extends Specification {
|
||||||
a.data.bops mustEqual false
|
a.data.bops mustEqual false
|
||||||
a.data.v1 mustEqual false
|
a.data.v1 mustEqual false
|
||||||
a.data.v2.isEmpty mustEqual true
|
a.data.v2.isEmpty mustEqual true
|
||||||
a.data.v3 mustEqual false
|
a.data.jammered mustEqual false
|
||||||
a.data.v4.isEmpty mustEqual true
|
a.data.v4.isEmpty mustEqual true
|
||||||
a.data.v5.isEmpty mustEqual true
|
a.data.v5.isEmpty mustEqual true
|
||||||
a.exosuit mustEqual ExoSuitType.MAX
|
a.exosuit mustEqual ExoSuitType.MAX
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class OneMannedFieldTurretDataTest extends Specification {
|
||||||
deploy.alternate mustEqual false
|
deploy.alternate mustEqual false
|
||||||
deploy.v1 mustEqual true
|
deploy.v1 mustEqual true
|
||||||
deploy.v2.isEmpty mustEqual true
|
deploy.v2.isEmpty mustEqual true
|
||||||
deploy.v3 mustEqual false
|
deploy.jammered mustEqual false
|
||||||
deploy.v4.contains(false) mustEqual true
|
deploy.v4.contains(false) mustEqual true
|
||||||
deploy.v5.isEmpty mustEqual true
|
deploy.v5.isEmpty mustEqual true
|
||||||
deploy.guid mustEqual PlanetSideGUID(2502)
|
deploy.guid mustEqual PlanetSideGUID(2502)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class RemoteProjectileDataTest extends Specification {
|
||||||
deploy.alternate mustEqual false
|
deploy.alternate mustEqual false
|
||||||
deploy.v1 mustEqual true
|
deploy.v1 mustEqual true
|
||||||
deploy.v2.isEmpty mustEqual true
|
deploy.v2.isEmpty mustEqual true
|
||||||
deploy.v3 mustEqual false
|
deploy.jammered mustEqual false
|
||||||
deploy.v4.isEmpty mustEqual true
|
deploy.v4.isEmpty mustEqual true
|
||||||
deploy.v5.isEmpty mustEqual true
|
deploy.v5.isEmpty mustEqual true
|
||||||
deploy.guid mustEqual PlanetSideGUID(0)
|
deploy.guid mustEqual PlanetSideGUID(0)
|
||||||
|
|
@ -63,7 +63,7 @@ class RemoteProjectileDataTest extends Specification {
|
||||||
deploy.alternate mustEqual false
|
deploy.alternate mustEqual false
|
||||||
deploy.v1 mustEqual true
|
deploy.v1 mustEqual true
|
||||||
deploy.v2.isEmpty mustEqual true
|
deploy.v2.isEmpty mustEqual true
|
||||||
deploy.v3 mustEqual false
|
deploy.jammered mustEqual false
|
||||||
deploy.v4.isEmpty mustEqual true
|
deploy.v4.isEmpty mustEqual true
|
||||||
deploy.v5.isEmpty mustEqual true
|
deploy.v5.isEmpty mustEqual true
|
||||||
deploy.guid mustEqual PlanetSideGUID(0)
|
deploy.guid mustEqual PlanetSideGUID(0)
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ class SmallTurretDataTest extends Specification {
|
||||||
deploy.alternate mustEqual true
|
deploy.alternate mustEqual true
|
||||||
deploy.v1 mustEqual true
|
deploy.v1 mustEqual true
|
||||||
deploy.v2.isEmpty mustEqual true
|
deploy.v2.isEmpty mustEqual true
|
||||||
deploy.v3 mustEqual false
|
deploy.jammered mustEqual false
|
||||||
deploy.v4.contains(false) mustEqual true
|
deploy.v4.contains(false) mustEqual true
|
||||||
deploy.v5.isEmpty mustEqual true
|
deploy.v5.isEmpty mustEqual true
|
||||||
deploy.guid mustEqual PlanetSideGUID(7742)
|
deploy.guid mustEqual PlanetSideGUID(7742)
|
||||||
|
|
@ -61,7 +61,7 @@ class SmallTurretDataTest extends Specification {
|
||||||
deploy.alternate mustEqual false
|
deploy.alternate mustEqual false
|
||||||
deploy.v1 mustEqual true
|
deploy.v1 mustEqual true
|
||||||
deploy.v2.isEmpty mustEqual true
|
deploy.v2.isEmpty mustEqual true
|
||||||
deploy.v3 mustEqual false
|
deploy.jammered mustEqual false
|
||||||
deploy.v4.contains(true) mustEqual true
|
deploy.v4.contains(true) mustEqual true
|
||||||
deploy.v5.isEmpty mustEqual true
|
deploy.v5.isEmpty mustEqual true
|
||||||
deploy.guid mustEqual PlanetSideGUID(8208)
|
deploy.guid mustEqual PlanetSideGUID(8208)
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class TRAPDataTest extends Specification {
|
||||||
deploy.alternate mustEqual false
|
deploy.alternate mustEqual false
|
||||||
deploy.v1 mustEqual true
|
deploy.v1 mustEqual true
|
||||||
deploy.v2.isEmpty mustEqual true
|
deploy.v2.isEmpty mustEqual true
|
||||||
deploy.v3 mustEqual false
|
deploy.jammered mustEqual false
|
||||||
deploy.v4.contains(true) mustEqual true
|
deploy.v4.contains(true) mustEqual true
|
||||||
deploy.v5.isEmpty mustEqual true
|
deploy.v5.isEmpty mustEqual true
|
||||||
deploy.guid mustEqual PlanetSideGUID(4748)
|
deploy.guid mustEqual PlanetSideGUID(4748)
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ class DetailedCharacterDataTest extends Specification {
|
||||||
a.data.bops mustEqual false
|
a.data.bops mustEqual false
|
||||||
a.data.v1 mustEqual true
|
a.data.v1 mustEqual true
|
||||||
a.data.v2.isEmpty mustEqual true
|
a.data.v2.isEmpty mustEqual true
|
||||||
a.data.v3 mustEqual false
|
a.data.jammered mustEqual false
|
||||||
a.data.v4.isEmpty mustEqual true
|
a.data.v4.isEmpty mustEqual true
|
||||||
a.data.v5.isEmpty mustEqual true
|
a.data.v5.isEmpty mustEqual true
|
||||||
a.exosuit mustEqual ExoSuitType.Standard
|
a.exosuit mustEqual ExoSuitType.Standard
|
||||||
|
|
@ -259,7 +259,7 @@ class DetailedCharacterDataTest extends Specification {
|
||||||
a.data.bops mustEqual false
|
a.data.bops mustEqual false
|
||||||
a.data.v1 mustEqual false
|
a.data.v1 mustEqual false
|
||||||
a.data.v2.isEmpty mustEqual true
|
a.data.v2.isEmpty mustEqual true
|
||||||
a.data.v3 mustEqual false
|
a.data.jammered mustEqual false
|
||||||
a.data.v4.isEmpty mustEqual true
|
a.data.v4.isEmpty mustEqual true
|
||||||
a.data.v5.isEmpty mustEqual true
|
a.data.v5.isEmpty mustEqual true
|
||||||
a.exosuit mustEqual ExoSuitType.Standard
|
a.exosuit mustEqual ExoSuitType.Standard
|
||||||
|
|
@ -444,7 +444,7 @@ class DetailedCharacterDataTest extends Specification {
|
||||||
a.data.bops mustEqual false
|
a.data.bops mustEqual false
|
||||||
a.data.v1 mustEqual true
|
a.data.v1 mustEqual true
|
||||||
a.data.v2.isEmpty mustEqual true
|
a.data.v2.isEmpty mustEqual true
|
||||||
a.data.v3 mustEqual false
|
a.data.jammered mustEqual false
|
||||||
a.data.v4.isEmpty mustEqual true
|
a.data.v4.isEmpty mustEqual true
|
||||||
a.data.v5.isEmpty mustEqual true
|
a.data.v5.isEmpty mustEqual true
|
||||||
a.exosuit mustEqual ExoSuitType.MAX
|
a.exosuit mustEqual ExoSuitType.MAX
|
||||||
|
|
@ -652,7 +652,7 @@ class DetailedCharacterDataTest extends Specification {
|
||||||
a.data.bops mustEqual false
|
a.data.bops mustEqual false
|
||||||
a.data.v1 mustEqual true
|
a.data.v1 mustEqual true
|
||||||
a.data.v2.isEmpty mustEqual true
|
a.data.v2.isEmpty mustEqual true
|
||||||
a.data.v3 mustEqual false
|
a.data.jammered mustEqual false
|
||||||
a.data.v4.isEmpty mustEqual true
|
a.data.v4.isEmpty mustEqual true
|
||||||
a.data.v5.isEmpty mustEqual true
|
a.data.v5.isEmpty mustEqual true
|
||||||
a.exosuit mustEqual ExoSuitType.Agile
|
a.exosuit mustEqual ExoSuitType.Agile
|
||||||
|
|
@ -1104,7 +1104,7 @@ class DetailedCharacterDataTest extends Specification {
|
||||||
cdata.data.alternate mustEqual false
|
cdata.data.alternate mustEqual false
|
||||||
cdata.data.v1 mustEqual true
|
cdata.data.v1 mustEqual true
|
||||||
cdata.data.v2.isEmpty mustEqual true
|
cdata.data.v2.isEmpty mustEqual true
|
||||||
cdata.data.v3 mustEqual false
|
cdata.data.jammered mustEqual false
|
||||||
cdata.data.v4.isEmpty mustEqual true
|
cdata.data.v4.isEmpty mustEqual true
|
||||||
cdata.data.v5.isEmpty mustEqual true
|
cdata.data.v5.isEmpty mustEqual true
|
||||||
cdata.data.guid mustEqual PlanetSideGUID(0)
|
cdata.data.guid mustEqual PlanetSideGUID(0)
|
||||||
|
|
@ -1160,7 +1160,7 @@ class DetailedCharacterDataTest extends Specification {
|
||||||
a.data.alternate mustEqual false
|
a.data.alternate mustEqual false
|
||||||
a.data.v1 mustEqual false
|
a.data.v1 mustEqual false
|
||||||
a.data.v2.isEmpty mustEqual true
|
a.data.v2.isEmpty mustEqual true
|
||||||
a.data.v3 mustEqual false
|
a.data.jammered mustEqual false
|
||||||
a.data.v4.isEmpty mustEqual true
|
a.data.v4.isEmpty mustEqual true
|
||||||
a.data.v5.isEmpty mustEqual true
|
a.data.v5.isEmpty mustEqual true
|
||||||
a.exosuit mustEqual ExoSuitType.Standard
|
a.exosuit mustEqual ExoSuitType.Standard
|
||||||
|
|
@ -1310,7 +1310,7 @@ class DetailedCharacterDataTest extends Specification {
|
||||||
a.data.alternate mustEqual false
|
a.data.alternate mustEqual false
|
||||||
a.data.v1 mustEqual false
|
a.data.v1 mustEqual false
|
||||||
a.data.v2.isEmpty mustEqual true
|
a.data.v2.isEmpty mustEqual true
|
||||||
a.data.v3 mustEqual false
|
a.data.jammered mustEqual false
|
||||||
a.data.v4.isEmpty mustEqual true
|
a.data.v4.isEmpty mustEqual true
|
||||||
a.data.v5.isEmpty mustEqual true
|
a.data.v5.isEmpty mustEqual true
|
||||||
a.exosuit mustEqual ExoSuitType.Standard
|
a.exosuit mustEqual ExoSuitType.Standard
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ class DetailedConstructionToolDataTest extends Specification {
|
||||||
cdata.alternate mustEqual false
|
cdata.alternate mustEqual false
|
||||||
cdata.v1 mustEqual true
|
cdata.v1 mustEqual true
|
||||||
cdata.v2.isEmpty mustEqual true
|
cdata.v2.isEmpty mustEqual true
|
||||||
cdata.v3 mustEqual false
|
cdata.jammered mustEqual false
|
||||||
cdata.v4.isEmpty mustEqual true
|
cdata.v4.isEmpty mustEqual true
|
||||||
cdata.v5.isEmpty mustEqual true
|
cdata.v5.isEmpty mustEqual true
|
||||||
cdata.guid mustEqual PlanetSideGUID(0)
|
cdata.guid mustEqual PlanetSideGUID(0)
|
||||||
|
|
@ -71,7 +71,7 @@ class DetailedConstructionToolDataTest extends Specification {
|
||||||
cdata.alternate mustEqual false
|
cdata.alternate mustEqual false
|
||||||
cdata.v1 mustEqual true
|
cdata.v1 mustEqual true
|
||||||
cdata.v2.isEmpty mustEqual true
|
cdata.v2.isEmpty mustEqual true
|
||||||
cdata.v3 mustEqual false
|
cdata.jammered mustEqual false
|
||||||
cdata.v4.isEmpty mustEqual true
|
cdata.v4.isEmpty mustEqual true
|
||||||
cdata.v5.isEmpty mustEqual true
|
cdata.v5.isEmpty mustEqual true
|
||||||
cdata.guid mustEqual PlanetSideGUID(0)
|
cdata.guid mustEqual PlanetSideGUID(0)
|
||||||
|
|
@ -111,7 +111,7 @@ class DetailedConstructionToolDataTest extends Specification {
|
||||||
cdata.alternate mustEqual false
|
cdata.alternate mustEqual false
|
||||||
cdata.v1 mustEqual true
|
cdata.v1 mustEqual true
|
||||||
cdata.v2.isEmpty mustEqual true
|
cdata.v2.isEmpty mustEqual true
|
||||||
cdata.v3 mustEqual false
|
cdata.jammered mustEqual false
|
||||||
cdata.v4.isEmpty mustEqual true
|
cdata.v4.isEmpty mustEqual true
|
||||||
cdata.v5.contains(564) mustEqual true
|
cdata.v5.contains(564) mustEqual true
|
||||||
cdata.guid mustEqual PlanetSideGUID(0)
|
cdata.guid mustEqual PlanetSideGUID(0)
|
||||||
|
|
@ -139,7 +139,7 @@ class DetailedConstructionToolDataTest extends Specification {
|
||||||
cdata.alternate mustEqual false
|
cdata.alternate mustEqual false
|
||||||
cdata.v1 mustEqual false
|
cdata.v1 mustEqual false
|
||||||
cdata.v2.isEmpty mustEqual true
|
cdata.v2.isEmpty mustEqual true
|
||||||
cdata.v3 mustEqual false
|
cdata.jammered mustEqual false
|
||||||
cdata.v4.isEmpty mustEqual true
|
cdata.v4.isEmpty mustEqual true
|
||||||
cdata.v5.isEmpty mustEqual true
|
cdata.v5.isEmpty mustEqual true
|
||||||
cdata.guid mustEqual PlanetSideGUID(0)
|
cdata.guid mustEqual PlanetSideGUID(0)
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ class MountedVehiclesTest extends Specification {
|
||||||
vdata.data.bops mustEqual false
|
vdata.data.bops mustEqual false
|
||||||
vdata.data.alternate mustEqual false
|
vdata.data.alternate mustEqual false
|
||||||
vdata.data.v1 mustEqual false
|
vdata.data.v1 mustEqual false
|
||||||
vdata.data.v3 mustEqual false
|
vdata.data.jammered mustEqual false
|
||||||
vdata.data.v5.isEmpty mustEqual true
|
vdata.data.v5.isEmpty mustEqual true
|
||||||
vdata.data.guid mustEqual PlanetSideGUID(3776)
|
vdata.data.guid mustEqual PlanetSideGUID(3776)
|
||||||
vdata.health mustEqual 255
|
vdata.health mustEqual 255
|
||||||
|
|
@ -57,7 +57,7 @@ class MountedVehiclesTest extends Specification {
|
||||||
a.data.bops mustEqual false
|
a.data.bops mustEqual false
|
||||||
a.data.v1 mustEqual false
|
a.data.v1 mustEqual false
|
||||||
a.data.v2.isEmpty mustEqual true
|
a.data.v2.isEmpty mustEqual true
|
||||||
a.data.v3 mustEqual false
|
a.data.jammered mustEqual false
|
||||||
a.data.v4.isEmpty mustEqual true
|
a.data.v4.isEmpty mustEqual true
|
||||||
a.data.v5.isEmpty mustEqual true
|
a.data.v5.isEmpty mustEqual true
|
||||||
a.exosuit mustEqual ExoSuitType.Agile
|
a.exosuit mustEqual ExoSuitType.Agile
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ class NonstandardVehiclesTest extends Specification {
|
||||||
basic.data.alternate mustEqual false
|
basic.data.alternate mustEqual false
|
||||||
basic.data.v1 mustEqual true
|
basic.data.v1 mustEqual true
|
||||||
basic.data.v2.isDefined mustEqual false
|
basic.data.v2.isDefined mustEqual false
|
||||||
basic.data.v3 mustEqual false
|
basic.data.jammered mustEqual false
|
||||||
basic.data.v5.isDefined mustEqual false
|
basic.data.v5.isDefined mustEqual false
|
||||||
basic.data.guid mustEqual PlanetSideGUID(0)
|
basic.data.guid mustEqual PlanetSideGUID(0)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ class NormalVehiclesTest extends Specification {
|
||||||
vdata.faction mustEqual PlanetSideEmpire.NC
|
vdata.faction mustEqual PlanetSideEmpire.NC
|
||||||
vdata.alternate mustEqual false
|
vdata.alternate mustEqual false
|
||||||
vdata.v1 mustEqual true
|
vdata.v1 mustEqual true
|
||||||
vdata.v3 mustEqual false
|
vdata.jammered mustEqual false
|
||||||
vdata.v5.isEmpty mustEqual true
|
vdata.v5.isEmpty mustEqual true
|
||||||
vdata.guid mustEqual PlanetSideGUID(0)
|
vdata.guid mustEqual PlanetSideGUID(0)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class UtilityVehiclesTest extends Specification {
|
||||||
ant.data.faction mustEqual PlanetSideEmpire.VS
|
ant.data.faction mustEqual PlanetSideEmpire.VS
|
||||||
ant.data.alternate mustEqual false
|
ant.data.alternate mustEqual false
|
||||||
ant.data.v1 mustEqual true
|
ant.data.v1 mustEqual true
|
||||||
ant.data.v3 mustEqual false
|
ant.data.jammered mustEqual false
|
||||||
ant.data.v5.isEmpty mustEqual true
|
ant.data.v5.isEmpty mustEqual true
|
||||||
ant.data.guid mustEqual PlanetSideGUID(0)
|
ant.data.guid mustEqual PlanetSideGUID(0)
|
||||||
ant.driveState mustEqual DriveState.Mobile
|
ant.driveState mustEqual DriveState.Mobile
|
||||||
|
|
@ -59,7 +59,7 @@ class UtilityVehiclesTest extends Specification {
|
||||||
ams.data.faction mustEqual PlanetSideEmpire.VS
|
ams.data.faction mustEqual PlanetSideEmpire.VS
|
||||||
ams.data.alternate mustEqual false
|
ams.data.alternate mustEqual false
|
||||||
ams.data.v1 mustEqual false
|
ams.data.v1 mustEqual false
|
||||||
ams.data.v3 mustEqual false
|
ams.data.jammered mustEqual false
|
||||||
ams.data.v5.isEmpty mustEqual true
|
ams.data.v5.isEmpty mustEqual true
|
||||||
ams.data.guid mustEqual PlanetSideGUID(2885)
|
ams.data.guid mustEqual PlanetSideGUID(2885)
|
||||||
ams.driveState mustEqual DriveState.Deployed
|
ams.driveState mustEqual DriveState.Deployed
|
||||||
|
|
|
||||||
|
|
@ -324,7 +324,7 @@ class DamageModelTests extends Specification {
|
||||||
tplayer.Armor mustEqual 50
|
tplayer.Armor mustEqual 50
|
||||||
|
|
||||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(tplayer), tplayer.DamageModel, Vector3.Zero)
|
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(tplayer), tplayer.DamageModel, Vector3.Zero)
|
||||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile)
|
val func : Any=>ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
|
||||||
|
|
||||||
func(tplayer)
|
func(tplayer)
|
||||||
tplayer.Health mustEqual 87
|
tplayer.Health mustEqual 87
|
||||||
|
|
@ -338,7 +338,7 @@ class DamageModelTests extends Specification {
|
||||||
tplayer.Armor mustEqual 50
|
tplayer.Armor mustEqual 50
|
||||||
|
|
||||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(tplayer), tplayer.DamageModel, Vector3.Zero)
|
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(tplayer), tplayer.DamageModel, Vector3.Zero)
|
||||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
|
val func : Any=>ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
|
||||||
|
|
||||||
func(tplayer)
|
func(tplayer)
|
||||||
tplayer.Health mustEqual 98
|
tplayer.Health mustEqual 98
|
||||||
|
|
@ -352,7 +352,7 @@ class DamageModelTests extends Specification {
|
||||||
tplayer.Armor mustEqual 50
|
tplayer.Armor mustEqual 50
|
||||||
|
|
||||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(tplayer), tplayer.DamageModel, Vector3.Zero)
|
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(tplayer), tplayer.DamageModel, Vector3.Zero)
|
||||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile)
|
val func : Any=>ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
|
||||||
tplayer.Armor = 0
|
tplayer.Armor = 0
|
||||||
|
|
||||||
func(tplayer)
|
func(tplayer)
|
||||||
|
|
@ -365,7 +365,7 @@ class DamageModelTests extends Specification {
|
||||||
vehicle.Health mustEqual 650
|
vehicle.Health mustEqual 650
|
||||||
|
|
||||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(vehicle), vehicle.DamageModel, Vector3.Zero)
|
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(vehicle), vehicle.DamageModel, Vector3.Zero)
|
||||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile)
|
val func : Any=>ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
|
||||||
|
|
||||||
func(vehicle)
|
func(vehicle)
|
||||||
vehicle.Health mustEqual 641
|
vehicle.Health mustEqual 641
|
||||||
|
|
@ -378,7 +378,7 @@ class DamageModelTests extends Specification {
|
||||||
vehicle.Shields mustEqual 10
|
vehicle.Shields mustEqual 10
|
||||||
|
|
||||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(vehicle), vehicle.DamageModel, Vector3.Zero)
|
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(vehicle), vehicle.DamageModel, Vector3.Zero)
|
||||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile)
|
val func : Any=>ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
|
||||||
|
|
||||||
func(vehicle)
|
func(vehicle)
|
||||||
vehicle.Health mustEqual 650
|
vehicle.Health mustEqual 650
|
||||||
|
|
@ -392,7 +392,7 @@ class DamageModelTests extends Specification {
|
||||||
vehicle.Shields mustEqual 10
|
vehicle.Shields mustEqual 10
|
||||||
|
|
||||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(vehicle), vehicle.DamageModel, Vector3.Zero)
|
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(vehicle), vehicle.DamageModel, Vector3.Zero)
|
||||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile)
|
val func : Any=>ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
|
||||||
|
|
||||||
func(vehicle)
|
func(vehicle)
|
||||||
vehicle.Health mustEqual 650
|
vehicle.Health mustEqual 650
|
||||||
|
|
@ -407,7 +407,7 @@ class DamageModelTests extends Specification {
|
||||||
vehicle.Health mustEqual 650
|
vehicle.Health mustEqual 650
|
||||||
|
|
||||||
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(vehicle), vehicle.DamageModel, Vector3.Zero)
|
val resprojectile = ResolvedProjectile(ProjectileResolution.Hit, projectile, SourceEntry(vehicle), vehicle.DamageModel, Vector3.Zero)
|
||||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
|
val func : Any=>ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
|
||||||
|
|
||||||
func(vehicle)
|
func(vehicle)
|
||||||
vehicle.Health mustEqual 641
|
vehicle.Health mustEqual 641
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import scala.concurrent.duration._
|
||||||
class FacilityTurretTest extends Specification {
|
class FacilityTurretTest extends Specification {
|
||||||
"FacilityTurretTest" should {
|
"FacilityTurretTest" should {
|
||||||
"define" in {
|
"define" in {
|
||||||
val obj = new TurretDefinition(480)
|
val obj = new FacilityTurretDefinition(480)
|
||||||
obj.Weapons mustEqual mutable.HashMap.empty[TurretUpgrade.Value, ToolDefinition]
|
obj.Weapons mustEqual mutable.HashMap.empty[TurretUpgrade.Value, ToolDefinition]
|
||||||
obj.ReserveAmmunition mustEqual false
|
obj.ReserveAmmunition mustEqual false
|
||||||
obj.FactionLocked mustEqual true
|
obj.FactionLocked mustEqual true
|
||||||
|
|
@ -152,7 +152,7 @@ class FacilityTurretControl3Test extends ActorTest {
|
||||||
|
|
||||||
class FacilityTurretControl4Test extends ActorTest {
|
class FacilityTurretControl4Test extends ActorTest {
|
||||||
val player = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
val player = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||||
val objDef = new TurretDefinition(480)
|
val objDef = new FacilityTurretDefinition(480)
|
||||||
objDef.FactionLocked = false
|
objDef.FactionLocked = false
|
||||||
val obj = FacilityTurret(objDef)
|
val obj = FacilityTurret(objDef)
|
||||||
obj.GUID = PlanetSideGUID(1)
|
obj.GUID = PlanetSideGUID(1)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
package objects
|
package objects
|
||||||
|
|
||||||
import akka.actor.Props
|
import akka.actor.Props
|
||||||
|
import akka.testkit.TestProbe
|
||||||
import base.ActorTest
|
import base.ActorTest
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.objects.ballistics.{PlayerSource, Projectile, ProjectileResolution, ResolvedProjectile}
|
import net.psforever.objects.ballistics.{PlayerSource, Projectile, ProjectileResolution, ResolvedProjectile}
|
||||||
|
|
@ -9,9 +10,11 @@ import net.psforever.objects.definition.{SeatDefinition, VehicleDefinition}
|
||||||
import net.psforever.objects.serverobject.mount.Mountable
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
import net.psforever.objects.vehicles._
|
import net.psforever.objects.vehicles._
|
||||||
import net.psforever.objects.vital.{VehicleShieldCharge, Vitality}
|
import net.psforever.objects.vital.{VehicleShieldCharge, Vitality}
|
||||||
|
import net.psforever.objects.zones.{Zone, ZoneMap}
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
import org.specs2.mutable._
|
import org.specs2.mutable._
|
||||||
|
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
|
@ -324,66 +327,82 @@ class VehicleControlStopMountingTest extends ActorTest {
|
||||||
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
||||||
vehicle.GUID = PlanetSideGUID(3)
|
vehicle.GUID = PlanetSideGUID(3)
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
|
vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
VehicleEvents = new TestProbe(system).ref //necessary
|
||||||
|
}
|
||||||
|
vehicle.Weapons(2).Equipment.get.GUID = PlanetSideGUID(4)
|
||||||
|
val probe = new TestProbe(system)
|
||||||
|
|
||||||
vehicle.Actor ! Mountable.TryMount(player1, 0)
|
vehicle.Actor.tell(Mountable.TryMount(player1, 0), probe.ref)
|
||||||
val reply = receiveOne(Duration.create(100, "ms"))
|
val reply = probe.receiveOne(Duration.create(200, "ms"))
|
||||||
assert(reply.isInstanceOf[Mountable.MountMessages])
|
assert(reply.isInstanceOf[Mountable.MountMessages])
|
||||||
|
|
||||||
vehicle.Actor ! Vehicle.PrepareForDeletion
|
vehicle.Actor.tell(Vehicle.PrepareForDeletion(), probe.ref)
|
||||||
vehicle.Actor ! Mountable.TryMount(player2, 1)
|
vehicle.Actor.tell(Mountable.TryMount(player2, 1), probe.ref)
|
||||||
expectNoMsg(Duration.create(200, "ms"))
|
probe.expectNoMsg(Duration.create(200, "ms")) //assertion failed: received unexpected message MountMessages(CanMount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VehicleControlRestartMountingTest extends ActorTest {
|
class VehicleControlRestartMountingTest extends ActorTest {
|
||||||
|
val player1 = Player(VehicleTest.avatar1)
|
||||||
|
player1.GUID = PlanetSideGUID(1)
|
||||||
|
val player2 = Player(VehicleTest.avatar2)
|
||||||
|
player2.GUID = PlanetSideGUID(2)
|
||||||
|
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
||||||
|
vehicle.GUID = PlanetSideGUID(3)
|
||||||
|
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
|
vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
VehicleEvents = new TestProbe(system).ref
|
||||||
|
}
|
||||||
|
vehicle.Weapons(2).Equipment.get.GUID = PlanetSideGUID(4)
|
||||||
|
val probe = new TestProbe(system)
|
||||||
|
|
||||||
"Vehicle Control" should {
|
"Vehicle Control" should {
|
||||||
"reactivate and resume handling mount messages" in {
|
"reactivate and resume handling mount messages" in {
|
||||||
val player1 = Player(VehicleTest.avatar1)
|
vehicle.Actor.tell(Mountable.TryMount(player1, 0), probe.ref)
|
||||||
player1.GUID = PlanetSideGUID(1)
|
probe.receiveOne(Duration.create(200, "ms")) //discard
|
||||||
val player2 = Player(VehicleTest.avatar2)
|
vehicle.Actor.tell(Vehicle.PrepareForDeletion(), probe.ref)
|
||||||
player2.GUID = PlanetSideGUID(2)
|
vehicle.Actor.tell(Mountable.TryMount(player2, 1), probe.ref)
|
||||||
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
probe.expectNoMsg(Duration.create(200, "ms"))
|
||||||
vehicle.GUID = PlanetSideGUID(3)
|
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
|
||||||
|
|
||||||
vehicle.Actor ! Mountable.TryMount(player1, 0)
|
vehicle.Actor.tell(Vehicle.Reactivate(), probe.ref)
|
||||||
receiveOne(Duration.create(100, "ms")) //discard
|
vehicle.Actor.tell(Mountable.TryMount(player2, 1), probe.ref)
|
||||||
vehicle.Actor ! Vehicle.PrepareForDeletion
|
val reply = probe.receiveOne(Duration.create(200, "ms"))
|
||||||
vehicle.Actor ! Mountable.TryMount(player2, 1)
|
|
||||||
expectNoMsg(Duration.create(200, "ms"))
|
|
||||||
|
|
||||||
vehicle.Actor ! Vehicle.Reactivate
|
|
||||||
vehicle.Actor ! Mountable.TryMount(player2, 1)
|
|
||||||
val reply = receiveOne(Duration.create(100, "ms"))
|
|
||||||
assert(reply.isInstanceOf[Mountable.MountMessages])
|
assert(reply.isInstanceOf[Mountable.MountMessages])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VehicleControlAlwaysDismountTest extends ActorTest {
|
class VehicleControlAlwaysDismountTest extends ActorTest {
|
||||||
|
val probe = new TestProbe(system)
|
||||||
|
val player1 = Player(VehicleTest.avatar1)
|
||||||
|
player1.GUID = PlanetSideGUID(1)
|
||||||
|
val player2 = Player(VehicleTest.avatar2)
|
||||||
|
player2.GUID = PlanetSideGUID(2)
|
||||||
|
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
||||||
|
vehicle.GUID = PlanetSideGUID(3)
|
||||||
|
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
|
vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
VehicleEvents = new TestProbe(system).ref
|
||||||
|
}
|
||||||
|
vehicle.Weapons(2).Equipment.get.GUID = PlanetSideGUID(4)
|
||||||
|
|
||||||
"Vehicle Control" should {
|
"Vehicle Control" should {
|
||||||
"always allow dismount messages" in {
|
"always allow dismount messages" in {
|
||||||
val player1 = Player(VehicleTest.avatar1)
|
vehicle.Actor.tell(Mountable.TryMount(player1, 0), probe.ref)
|
||||||
player1.GUID = PlanetSideGUID(1)
|
probe.receiveOne(Duration.create(100, "ms")) //discard
|
||||||
val player2 = Player(VehicleTest.avatar2)
|
vehicle.Actor.tell(Mountable.TryMount(player2, 1), probe.ref)
|
||||||
player2.GUID = PlanetSideGUID(2)
|
probe.receiveOne(Duration.create(100, "ms")) //discard
|
||||||
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
|
||||||
vehicle.GUID = PlanetSideGUID(3)
|
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
|
||||||
vehicle.Actor ! Mountable.TryMount(player1, 0)
|
|
||||||
receiveOne(Duration.create(100, "ms")) //discard
|
|
||||||
vehicle.Actor ! Mountable.TryMount(player2, 1)
|
|
||||||
receiveOne(Duration.create(100, "ms")) //discard
|
|
||||||
|
|
||||||
vehicle.Actor ! Mountable.TryDismount(player2, 1) //player2 requests dismount
|
vehicle.Actor.tell(Mountable.TryDismount(player2, 1), probe.ref) //player2 requests dismount
|
||||||
val reply1 = receiveOne(Duration.create(100, "ms"))
|
val reply1 = probe.receiveOne(Duration.create(100, "ms"))
|
||||||
assert(reply1.isInstanceOf[Mountable.MountMessages])
|
assert(reply1.isInstanceOf[Mountable.MountMessages])
|
||||||
assert(reply1.asInstanceOf[Mountable.MountMessages].response.isInstanceOf[Mountable.CanDismount]) //player2 dismounts
|
assert(reply1.asInstanceOf[Mountable.MountMessages].response.isInstanceOf[Mountable.CanDismount]) //player2 dismounts
|
||||||
vehicle.Actor ! Vehicle.PrepareForDeletion
|
|
||||||
|
|
||||||
vehicle.Actor ! Mountable.TryDismount(player1, 0) //player1 requests dismount
|
vehicle.Actor.tell(Vehicle.PrepareForDeletion(), probe.ref)
|
||||||
val reply2 = receiveOne(Duration.create(100, "ms"))
|
vehicle.Actor.tell(Mountable.TryDismount(player1, 0), probe.ref) //player1 requests dismount
|
||||||
|
val reply2 = probe.receiveOne(Duration.create(100, "ms"))
|
||||||
assert(reply2.isInstanceOf[Mountable.MountMessages])
|
assert(reply2.isInstanceOf[Mountable.MountMessages])
|
||||||
assert(reply2.asInstanceOf[Mountable.MountMessages].response.isInstanceOf[Mountable.CanDismount]) //player1 dismounts
|
assert(reply2.asInstanceOf[Mountable.MountMessages].response.isInstanceOf[Mountable.CanDismount]) //player1 dismounts
|
||||||
}
|
}
|
||||||
|
|
@ -391,8 +410,9 @@ class VehicleControlAlwaysDismountTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
class VehicleControlMountingBlockedExosuitTest extends ActorTest {
|
class VehicleControlMountingBlockedExosuitTest extends ActorTest {
|
||||||
|
val probe = new TestProbe(system)
|
||||||
def checkCanNotMount() : Unit = {
|
def checkCanNotMount() : Unit = {
|
||||||
val reply = receiveOne(Duration.create(100, "ms"))
|
val reply = probe.receiveOne(Duration.create(100, "ms"))
|
||||||
reply match {
|
reply match {
|
||||||
case msg : Mountable.MountMessages =>
|
case msg : Mountable.MountMessages =>
|
||||||
assert(msg.response.isInstanceOf[Mountable.CanNotMount])
|
assert(msg.response.isInstanceOf[Mountable.CanNotMount])
|
||||||
|
|
@ -402,7 +422,7 @@ class VehicleControlMountingBlockedExosuitTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkCanMount() : Unit = {
|
def checkCanMount() : Unit = {
|
||||||
val reply = receiveOne(Duration.create(100, "ms"))
|
val reply = probe.receiveOne(Duration.create(100, "ms"))
|
||||||
reply match {
|
reply match {
|
||||||
case msg : Mountable.MountMessages =>
|
case msg : Mountable.MountMessages =>
|
||||||
assert(msg.response.isInstanceOf[Mountable.CanMount])
|
assert(msg.response.isInstanceOf[Mountable.CanMount])
|
||||||
|
|
@ -410,49 +430,49 @@ class VehicleControlMountingBlockedExosuitTest extends ActorTest {
|
||||||
assert(false)
|
assert(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val vehicle = Vehicle(GlobalDefinitions.apc_tr)
|
||||||
|
vehicle.GUID = PlanetSideGUID(10)
|
||||||
|
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
|
|
||||||
|
val player1 = Player(VehicleTest.avatar1)
|
||||||
|
player1.ExoSuit = ExoSuitType.Reinforced
|
||||||
|
player1.GUID = PlanetSideGUID(1)
|
||||||
|
val player2 = Player(VehicleTest.avatar1)
|
||||||
|
player2.ExoSuit = ExoSuitType.MAX
|
||||||
|
player2.GUID = PlanetSideGUID(2)
|
||||||
|
val player3 = Player(VehicleTest.avatar1)
|
||||||
|
player3.ExoSuit = ExoSuitType.Agile
|
||||||
|
player3.GUID = PlanetSideGUID(3)
|
||||||
|
|
||||||
"Vehicle Control" should {
|
"Vehicle Control" should {
|
||||||
"block players from sitting if their exo-suit is not allowed by the seat" in {
|
"block players from sitting if their exo-suit is not allowed by the seat" in {
|
||||||
val vehicle = Vehicle(GlobalDefinitions.apc_tr)
|
|
||||||
vehicle.GUID = PlanetSideGUID(10)
|
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
|
||||||
|
|
||||||
val player1 = Player(VehicleTest.avatar1)
|
|
||||||
player1.ExoSuit = ExoSuitType.Reinforced
|
|
||||||
player1.GUID = PlanetSideGUID(1)
|
|
||||||
val player2 = Player(VehicleTest.avatar1)
|
|
||||||
player2.ExoSuit = ExoSuitType.MAX
|
|
||||||
player2.GUID = PlanetSideGUID(2)
|
|
||||||
val player3 = Player(VehicleTest.avatar1)
|
|
||||||
player3.ExoSuit = ExoSuitType.Agile
|
|
||||||
player3.GUID = PlanetSideGUID(3)
|
|
||||||
|
|
||||||
//disallow
|
//disallow
|
||||||
vehicle.Actor ! Mountable.TryMount(player1, 0) //Reinforced in non-MAX seat
|
vehicle.Actor.tell(Mountable.TryMount(player1, 0), probe.ref) //Reinforced in non-MAX seat
|
||||||
checkCanNotMount()
|
checkCanNotMount()
|
||||||
vehicle.Actor ! Mountable.TryMount(player2, 0) //MAX in non-Reinforced seat
|
vehicle.Actor.tell(Mountable.TryMount(player2, 0), probe.ref) //MAX in non-Reinforced seat
|
||||||
checkCanNotMount()
|
checkCanNotMount()
|
||||||
vehicle.Actor ! Mountable.TryMount(player2, 1) //MAX in non-MAX seat
|
vehicle.Actor.tell(Mountable.TryMount(player2, 1), probe.ref) //MAX in non-MAX seat
|
||||||
checkCanNotMount()
|
checkCanNotMount()
|
||||||
vehicle.Actor ! Mountable.TryMount(player1, 9) //Reinforced in MAX-only seat
|
vehicle.Actor.tell(Mountable.TryMount(player1, 9), probe.ref) //Reinforced in MAX-only seat
|
||||||
checkCanNotMount()
|
checkCanNotMount()
|
||||||
vehicle.Actor ! Mountable.TryMount(player3, 9) //Agile in MAX-only seat
|
vehicle.Actor.tell(Mountable.TryMount(player3, 9), probe.ref) //Agile in MAX-only seat
|
||||||
checkCanNotMount()
|
checkCanNotMount()
|
||||||
|
|
||||||
//allow
|
//allow
|
||||||
vehicle.Actor ! Mountable.TryMount(player1, 1)
|
vehicle.Actor.tell(Mountable.TryMount(player1, 1), probe.ref)
|
||||||
checkCanMount()
|
checkCanMount()
|
||||||
vehicle.Actor ! Mountable.TryMount(player2, 9)
|
vehicle.Actor.tell(Mountable.TryMount(player2, 9), probe.ref)
|
||||||
checkCanMount()
|
checkCanMount()
|
||||||
vehicle.Actor ! Mountable.TryMount(player3, 0)
|
vehicle.Actor.tell(Mountable.TryMount(player3, 0), probe.ref)
|
||||||
checkCanMount()
|
checkCanMount()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VehicleControlMountingBlockedSeatPermissionTest extends ActorTest {
|
class VehicleControlMountingBlockedSeatPermissionTest extends ActorTest {
|
||||||
|
val probe = new TestProbe(system)
|
||||||
def checkCanNotMount() : Unit = {
|
def checkCanNotMount() : Unit = {
|
||||||
val reply = receiveOne(Duration.create(100, "ms"))
|
val reply = probe.receiveOne(Duration.create(100, "ms"))
|
||||||
reply match {
|
reply match {
|
||||||
case msg : Mountable.MountMessages =>
|
case msg : Mountable.MountMessages =>
|
||||||
assert(msg.response.isInstanceOf[Mountable.CanNotMount])
|
assert(msg.response.isInstanceOf[Mountable.CanNotMount])
|
||||||
|
|
@ -462,7 +482,7 @@ class VehicleControlMountingBlockedSeatPermissionTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkCanMount() : Unit = {
|
def checkCanMount() : Unit = {
|
||||||
val reply = receiveOne(Duration.create(100, "ms"))
|
val reply = probe.receiveOne(Duration.create(100, "ms"))
|
||||||
reply match {
|
reply match {
|
||||||
case msg : Mountable.MountMessages =>
|
case msg : Mountable.MountMessages =>
|
||||||
assert(msg.response.isInstanceOf[Mountable.CanMount])
|
assert(msg.response.isInstanceOf[Mountable.CanMount])
|
||||||
|
|
@ -470,32 +490,33 @@ class VehicleControlMountingBlockedSeatPermissionTest extends ActorTest {
|
||||||
assert(false)
|
assert(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val vehicle = Vehicle(GlobalDefinitions.apc_tr)
|
||||||
|
vehicle.GUID = PlanetSideGUID(10)
|
||||||
|
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
|
|
||||||
|
val player1 = Player(VehicleTest.avatar1)
|
||||||
|
player1.GUID = PlanetSideGUID(1)
|
||||||
|
val player2 = Player(VehicleTest.avatar1)
|
||||||
|
player2.GUID = PlanetSideGUID(2)
|
||||||
|
|
||||||
"Vehicle Control" should {
|
"Vehicle Control" should {
|
||||||
//11 June 2018: Group is not supported yet so do not bother testing it
|
//11 June 2018: Group is not supported yet so do not bother testing it
|
||||||
"block players from sitting if the seat does not allow it" in {
|
"block players from sitting if the seat does not allow it" in {
|
||||||
val vehicle = Vehicle(GlobalDefinitions.apc_tr)
|
|
||||||
vehicle.GUID = PlanetSideGUID(10)
|
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
|
||||||
|
|
||||||
val player1 = Player(VehicleTest.avatar1)
|
|
||||||
player1.GUID = PlanetSideGUID(1)
|
|
||||||
val player2 = Player(VehicleTest.avatar1)
|
|
||||||
player2.GUID = PlanetSideGUID(2)
|
|
||||||
|
|
||||||
vehicle.PermissionGroup(2,3) //passenger group -> empire
|
vehicle.PermissionGroup(2,3) //passenger group -> empire
|
||||||
vehicle.Actor ! Mountable.TryMount(player1, 3) //passenger seat
|
vehicle.Actor.tell(Mountable.TryMount(player1, 3), probe.ref) //passenger seat
|
||||||
checkCanMount()
|
checkCanMount()
|
||||||
vehicle.PermissionGroup(2,0) //passenger group -> locked
|
vehicle.PermissionGroup(2,0) //passenger group -> locked
|
||||||
vehicle.Actor ! Mountable.TryMount(player2, 4) //passenger seat
|
vehicle.Actor.tell(Mountable.TryMount(player2, 4), probe.ref) //passenger seat
|
||||||
checkCanNotMount()
|
checkCanNotMount()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VehicleControlMountingDriverSeatTest extends ActorTest {
|
class VehicleControlMountingDriverSeatTest extends ActorTest {
|
||||||
|
val probe = new TestProbe(system)
|
||||||
def checkCanMount() : Unit = {
|
def checkCanMount() : Unit = {
|
||||||
val reply = receiveOne(Duration.create(100, "ms"))
|
val reply = probe.receiveOne(Duration.create(100, "ms"))
|
||||||
reply match {
|
reply match {
|
||||||
case msg : Mountable.MountMessages =>
|
case msg : Mountable.MountMessages =>
|
||||||
assert(msg.response.isInstanceOf[Mountable.CanMount])
|
assert(msg.response.isInstanceOf[Mountable.CanMount])
|
||||||
|
|
@ -503,19 +524,18 @@ class VehicleControlMountingDriverSeatTest extends ActorTest {
|
||||||
assert(false)
|
assert(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val vehicle = Vehicle(GlobalDefinitions.apc_tr)
|
||||||
|
vehicle.GUID = PlanetSideGUID(10)
|
||||||
|
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
|
val player1 = Player(VehicleTest.avatar1)
|
||||||
|
player1.GUID = PlanetSideGUID(1)
|
||||||
|
|
||||||
"Vehicle Control" should {
|
"Vehicle Control" should {
|
||||||
"allow players to sit in the driver seat, even if it is locked, if the vehicle is unowned" in {
|
"allow players to sit in the driver seat, even if it is locked, if the vehicle is unowned" in {
|
||||||
val vehicle = Vehicle(GlobalDefinitions.apc_tr)
|
|
||||||
vehicle.GUID = PlanetSideGUID(10)
|
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
|
||||||
val player1 = Player(VehicleTest.avatar1)
|
|
||||||
player1.GUID = PlanetSideGUID(1)
|
|
||||||
|
|
||||||
assert(vehicle.PermissionGroup(0).contains(VehicleLockState.Locked)) //driver group -> locked
|
assert(vehicle.PermissionGroup(0).contains(VehicleLockState.Locked)) //driver group -> locked
|
||||||
assert(vehicle.Seats(0).Occupant.isEmpty)
|
assert(vehicle.Seats(0).Occupant.isEmpty)
|
||||||
assert(vehicle.Owner.isEmpty)
|
assert(vehicle.Owner.isEmpty)
|
||||||
vehicle.Actor ! Mountable.TryMount(player1, 0)
|
vehicle.Actor.tell(Mountable.TryMount(player1, 0), probe.ref)
|
||||||
checkCanMount()
|
checkCanMount()
|
||||||
assert(vehicle.Seats(0).Occupant.nonEmpty)
|
assert(vehicle.Seats(0).Occupant.nonEmpty)
|
||||||
}
|
}
|
||||||
|
|
@ -523,8 +543,9 @@ class VehicleControlMountingDriverSeatTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
class VehicleControlMountingOwnedLockedDriverSeatTest extends ActorTest {
|
class VehicleControlMountingOwnedLockedDriverSeatTest extends ActorTest {
|
||||||
|
val probe = new TestProbe(system)
|
||||||
def checkCanNotMount() : Unit = {
|
def checkCanNotMount() : Unit = {
|
||||||
val reply = receiveOne(Duration.create(100, "ms"))
|
val reply = probe.receiveOne(Duration.create(100, "ms"))
|
||||||
reply match {
|
reply match {
|
||||||
case msg : Mountable.MountMessages =>
|
case msg : Mountable.MountMessages =>
|
||||||
assert(msg.response.isInstanceOf[Mountable.CanNotMount])
|
assert(msg.response.isInstanceOf[Mountable.CanNotMount])
|
||||||
|
|
@ -534,7 +555,7 @@ class VehicleControlMountingOwnedLockedDriverSeatTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkCanMount() : Unit = {
|
def checkCanMount() : Unit = {
|
||||||
val reply = receiveOne(Duration.create(100, "ms"))
|
val reply = probe.receiveOne(Duration.create(100, "ms"))
|
||||||
reply match {
|
reply match {
|
||||||
case msg : Mountable.MountMessages =>
|
case msg : Mountable.MountMessages =>
|
||||||
assert(msg.response.isInstanceOf[Mountable.CanMount])
|
assert(msg.response.isInstanceOf[Mountable.CanMount])
|
||||||
|
|
@ -542,30 +563,28 @@ class VehicleControlMountingOwnedLockedDriverSeatTest extends ActorTest {
|
||||||
assert(false)
|
assert(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val vehicle = Vehicle(GlobalDefinitions.apc_tr)
|
||||||
|
vehicle.GUID = PlanetSideGUID(10)
|
||||||
|
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
|
val player1 = Player(VehicleTest.avatar1)
|
||||||
|
player1.GUID = PlanetSideGUID(1)
|
||||||
|
val player2 = Player(VehicleTest.avatar1)
|
||||||
|
player2.GUID = PlanetSideGUID(2)
|
||||||
|
|
||||||
"Vehicle Control" should {
|
"Vehicle Control" should {
|
||||||
"block players that are not the current owner from sitting in the driver seat (locked)" in {
|
"block players that are not the current owner from sitting in the driver seat (locked)" in {
|
||||||
val vehicle = Vehicle(GlobalDefinitions.apc_tr)
|
|
||||||
vehicle.GUID = PlanetSideGUID(10)
|
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
|
||||||
|
|
||||||
val player1 = Player(VehicleTest.avatar1)
|
|
||||||
player1.GUID = PlanetSideGUID(1)
|
|
||||||
val player2 = Player(VehicleTest.avatar1)
|
|
||||||
player2.GUID = PlanetSideGUID(2)
|
|
||||||
|
|
||||||
assert(vehicle.PermissionGroup(0).contains(VehicleLockState.Locked)) //driver group -> locked
|
assert(vehicle.PermissionGroup(0).contains(VehicleLockState.Locked)) //driver group -> locked
|
||||||
assert(vehicle.Seats(0).Occupant.isEmpty)
|
assert(vehicle.Seats(0).Occupant.isEmpty)
|
||||||
vehicle.Owner = player1.GUID
|
vehicle.Owner = player1.GUID
|
||||||
|
|
||||||
vehicle.Actor ! Mountable.TryMount(player1, 0)
|
vehicle.Actor.tell(Mountable.TryMount(player1, 0), probe.ref)
|
||||||
checkCanMount()
|
checkCanMount()
|
||||||
assert(vehicle.Seats(0).Occupant.nonEmpty)
|
assert(vehicle.Seats(0).Occupant.nonEmpty)
|
||||||
vehicle.Actor ! Mountable.TryDismount(player1, 0)
|
vehicle.Actor.tell(Mountable.TryDismount(player1, 0), probe.ref)
|
||||||
receiveOne(Duration.create(100, "ms")) //discard
|
probe.receiveOne(Duration.create(100, "ms")) //discard
|
||||||
assert(vehicle.Seats(0).Occupant.isEmpty)
|
assert(vehicle.Seats(0).Occupant.isEmpty)
|
||||||
|
|
||||||
vehicle.Actor ! Mountable.TryMount(player2, 0)
|
vehicle.Actor.tell(Mountable.TryMount(player2, 0), probe.ref)
|
||||||
checkCanNotMount()
|
checkCanNotMount()
|
||||||
assert(vehicle.Seats(0).Occupant.isEmpty)
|
assert(vehicle.Seats(0).Occupant.isEmpty)
|
||||||
}
|
}
|
||||||
|
|
@ -573,8 +592,9 @@ class VehicleControlMountingOwnedLockedDriverSeatTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
class VehicleControlMountingOwnedUnlockedDriverSeatTest extends ActorTest {
|
class VehicleControlMountingOwnedUnlockedDriverSeatTest extends ActorTest {
|
||||||
|
val probe = new TestProbe(system)
|
||||||
def checkCanMount() : Unit = {
|
def checkCanMount() : Unit = {
|
||||||
val reply = receiveOne(Duration.create(100, "ms"))
|
val reply = probe.receiveOne(Duration.create(100, "ms"))
|
||||||
reply match {
|
reply match {
|
||||||
case msg : Mountable.MountMessages =>
|
case msg : Mountable.MountMessages =>
|
||||||
assert(msg.response.isInstanceOf[Mountable.CanMount])
|
assert(msg.response.isInstanceOf[Mountable.CanMount])
|
||||||
|
|
@ -582,31 +602,29 @@ class VehicleControlMountingOwnedUnlockedDriverSeatTest extends ActorTest {
|
||||||
assert(false)
|
assert(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val vehicle = Vehicle(GlobalDefinitions.apc_tr)
|
||||||
|
vehicle.GUID = PlanetSideGUID(10)
|
||||||
|
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
|
val player1 = Player(VehicleTest.avatar1)
|
||||||
|
player1.GUID = PlanetSideGUID(1)
|
||||||
|
val player2 = Player(VehicleTest.avatar1)
|
||||||
|
player2.GUID = PlanetSideGUID(2)
|
||||||
|
|
||||||
"Vehicle Control" should {
|
"Vehicle Control" should {
|
||||||
"allow players that are not the current owner to sit in the driver seat (empire)" in {
|
"allow players that are not the current owner to sit in the driver seat (empire)" in {
|
||||||
val vehicle = Vehicle(GlobalDefinitions.apc_tr)
|
|
||||||
vehicle.GUID = PlanetSideGUID(10)
|
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
|
||||||
|
|
||||||
val player1 = Player(VehicleTest.avatar1)
|
|
||||||
player1.GUID = PlanetSideGUID(1)
|
|
||||||
val player2 = Player(VehicleTest.avatar1)
|
|
||||||
player2.GUID = PlanetSideGUID(2)
|
|
||||||
|
|
||||||
vehicle.PermissionGroup(0,3) //passenger group -> empire
|
vehicle.PermissionGroup(0,3) //passenger group -> empire
|
||||||
assert(vehicle.PermissionGroup(0).contains(VehicleLockState.Empire)) //driver group -> empire
|
assert(vehicle.PermissionGroup(0).contains(VehicleLockState.Empire)) //driver group -> empire
|
||||||
assert(vehicle.Seats(0).Occupant.isEmpty)
|
assert(vehicle.Seats(0).Occupant.isEmpty)
|
||||||
vehicle.Owner = player1.GUID //owner set
|
vehicle.Owner = player1.GUID //owner set
|
||||||
|
|
||||||
vehicle.Actor ! Mountable.TryMount(player1, 0)
|
vehicle.Actor.tell(Mountable.TryMount(player1, 0), probe.ref)
|
||||||
checkCanMount()
|
checkCanMount()
|
||||||
assert(vehicle.Seats(0).Occupant.nonEmpty)
|
assert(vehicle.Seats(0).Occupant.nonEmpty)
|
||||||
vehicle.Actor ! Mountable.TryDismount(player1, 0)
|
vehicle.Actor.tell(Mountable.TryDismount(player1, 0), probe.ref)
|
||||||
receiveOne(Duration.create(100, "ms")) //discard
|
probe.receiveOne(Duration.create(100, "ms")) //discard
|
||||||
assert(vehicle.Seats(0).Occupant.isEmpty)
|
assert(vehicle.Seats(0).Occupant.isEmpty)
|
||||||
|
|
||||||
vehicle.Actor ! Mountable.TryMount(player2, 0)
|
vehicle.Actor.tell(Mountable.TryMount(player2, 0), probe.ref)
|
||||||
checkCanMount()
|
checkCanMount()
|
||||||
assert(vehicle.Seats(0).Occupant.nonEmpty)
|
assert(vehicle.Seats(0).Occupant.nonEmpty)
|
||||||
}
|
}
|
||||||
|
|
@ -614,26 +632,37 @@ class VehicleControlMountingOwnedUnlockedDriverSeatTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
class VehicleControlShieldsChargingTest extends ActorTest {
|
class VehicleControlShieldsChargingTest extends ActorTest {
|
||||||
|
val probe = new TestProbe(system)
|
||||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||||
vehicle.GUID = PlanetSideGUID(10)
|
vehicle.GUID = PlanetSideGUID(10)
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
|
vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
VehicleEvents = probe.ref
|
||||||
|
}
|
||||||
|
|
||||||
"charge vehicle shields" in {
|
"charge vehicle shields" in {
|
||||||
assert(vehicle.Shields == 0)
|
assert(vehicle.Shields == 0)
|
||||||
assert(!vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
assert(!vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
||||||
vehicle.Actor ! Vehicle.ChargeShields(15)
|
|
||||||
|
|
||||||
val msg = receiveOne(500 milliseconds)
|
vehicle.Actor ! Vehicle.ChargeShields(15)
|
||||||
assert(msg.isInstanceOf[Vehicle.UpdateShieldsCharge])
|
val msg = probe.receiveOne(500 milliseconds)
|
||||||
|
assert(msg match {
|
||||||
|
case VehicleServiceMessage(_, VehicleAction.PlanetsideAttribute(_, PlanetSideGUID(10), 68, 15)) => true
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
assert(vehicle.Shields == 15)
|
assert(vehicle.Shields == 15)
|
||||||
assert(vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
assert(vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VehicleControlShieldsNotChargingVehicleDeadTest extends ActorTest {
|
class VehicleControlShieldsNotChargingVehicleDeadTest extends ActorTest {
|
||||||
|
val probe = new TestProbe(system)
|
||||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||||
vehicle.GUID = PlanetSideGUID(10)
|
vehicle.GUID = PlanetSideGUID(10)
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
|
vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
VehicleEvents = probe.ref
|
||||||
|
}
|
||||||
|
|
||||||
"not charge vehicle shields if the vehicle is destroyed" in {
|
"not charge vehicle shields if the vehicle is destroyed" in {
|
||||||
assert(vehicle.Health > 0)
|
assert(vehicle.Health > 0)
|
||||||
|
|
@ -641,18 +670,22 @@ class VehicleControlShieldsNotChargingVehicleDeadTest extends ActorTest {
|
||||||
assert(vehicle.Health == 0)
|
assert(vehicle.Health == 0)
|
||||||
assert(vehicle.Shields == 0)
|
assert(vehicle.Shields == 0)
|
||||||
assert(!vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
assert(!vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
||||||
vehicle.Actor ! Vehicle.ChargeShields(15)
|
vehicle.Actor.tell(Vehicle.ChargeShields(15), probe.ref)
|
||||||
|
|
||||||
expectNoMsg(1 seconds)
|
probe.expectNoMsg(1 seconds)
|
||||||
assert(vehicle.Shields == 0)
|
assert(vehicle.Shields == 0)
|
||||||
assert(!vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
assert(!vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VehicleControlShieldsNotChargingVehicleShieldsFullTest extends ActorTest {
|
class VehicleControlShieldsNotChargingVehicleShieldsFullTest extends ActorTest {
|
||||||
|
val probe = new TestProbe(system)
|
||||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||||
vehicle.GUID = PlanetSideGUID(10)
|
vehicle.GUID = PlanetSideGUID(10)
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
|
vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
VehicleEvents = probe.ref
|
||||||
|
}
|
||||||
|
|
||||||
"not charge vehicle shields if the vehicle is destroyed" in {
|
"not charge vehicle shields if the vehicle is destroyed" in {
|
||||||
assert(vehicle.Shields == 0)
|
assert(vehicle.Shields == 0)
|
||||||
|
|
@ -661,54 +694,67 @@ class VehicleControlShieldsNotChargingVehicleShieldsFullTest extends ActorTest {
|
||||||
assert(!vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
assert(!vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
||||||
vehicle.Actor ! Vehicle.ChargeShields(15)
|
vehicle.Actor ! Vehicle.ChargeShields(15)
|
||||||
|
|
||||||
expectNoMsg(1 seconds)
|
probe.expectNoMsg(1 seconds)
|
||||||
assert(!vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
assert(!vehicle.History.exists({p => p.isInstanceOf[VehicleShieldCharge]}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VehicleControlShieldsNotChargingTooEarlyTest extends ActorTest {
|
class VehicleControlShieldsNotChargingTooEarlyTest extends ActorTest {
|
||||||
|
val probe = new TestProbe(system)
|
||||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||||
vehicle.GUID = PlanetSideGUID(10)
|
vehicle.GUID = PlanetSideGUID(10)
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
|
vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
VehicleEvents = probe.ref
|
||||||
|
}
|
||||||
|
|
||||||
"charge vehicle shields" in {
|
"charge vehicle shields" in {
|
||||||
assert(vehicle.Shields == 0)
|
assert(vehicle.Shields == 0)
|
||||||
vehicle.Actor ! Vehicle.ChargeShields(15)
|
|
||||||
|
|
||||||
val msg = receiveOne(200 milliseconds)
|
vehicle.Actor ! Vehicle.ChargeShields(15)
|
||||||
assert(msg.isInstanceOf[Vehicle.UpdateShieldsCharge])
|
val msg = probe.receiveOne(200 milliseconds)
|
||||||
|
//assert(msg.isInstanceOf[Vehicle.UpdateShieldsCharge])
|
||||||
|
assert(msg match {
|
||||||
|
case VehicleServiceMessage(_, VehicleAction.PlanetsideAttribute(_, PlanetSideGUID(10), 68, 15)) => true
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
assert(vehicle.Shields == 15)
|
assert(vehicle.Shields == 15)
|
||||||
vehicle.Actor ! Vehicle.ChargeShields(15)
|
|
||||||
|
|
||||||
expectNoMsg(200 milliseconds)
|
vehicle.Actor ! Vehicle.ChargeShields(15)
|
||||||
|
probe.expectNoMsg(200 milliseconds)
|
||||||
assert(vehicle.Shields == 15)
|
assert(vehicle.Shields == 15)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VehicleControlShieldsNotChargingDamagedTest extends ActorTest {
|
//TODO implement message protocol for zone startup completion
|
||||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
//class VehicleControlShieldsNotChargingDamagedTest extends ActorTest {
|
||||||
vehicle.GUID = PlanetSideGUID(10)
|
// val probe = new TestProbe(system)
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
// val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||||
//
|
// vehicle.GUID = PlanetSideGUID(10)
|
||||||
val beamer_wep = Tool(GlobalDefinitions.beamer)
|
// vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
val p_source = PlayerSource( Player(Avatar("TestTarget", PlanetSideEmpire.NC, CharacterGender.Female, 1, CharacterVoice.Mute)) )
|
// vehicle.Zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
val projectile = Projectile(beamer_wep.Projectile, GlobalDefinitions.beamer, beamer_wep.FireMode, p_source, GlobalDefinitions.beamer.ObjectId, Vector3.Zero, Vector3.Zero)
|
// VehicleEvents = probe.ref
|
||||||
val fury_dm = Vehicle(GlobalDefinitions.fury).DamageModel
|
// }
|
||||||
val obj = ResolvedProjectile(ProjectileResolution.Hit, projectile, p_source, fury_dm, Vector3(1.2f, 3.4f, 5.6f), System.nanoTime)
|
// //
|
||||||
|
// val beamer_wep = Tool(GlobalDefinitions.beamer)
|
||||||
"not charge vehicle shields if recently damaged" in {
|
// val p_source = PlayerSource( Player(Avatar("TestTarget", PlanetSideEmpire.NC, CharacterGender.Female, 1, CharacterVoice.Mute)) )
|
||||||
assert(vehicle.Shields == 0)
|
// val projectile = Projectile(beamer_wep.Projectile, GlobalDefinitions.beamer, beamer_wep.FireMode, p_source, GlobalDefinitions.beamer.ObjectId, Vector3.Zero, Vector3.Zero)
|
||||||
vehicle.Actor ! Vitality.Damage({case v : Vehicle => v.History(obj)})
|
// val fury_dm = Vehicle(GlobalDefinitions.fury).DamageModel
|
||||||
|
// val obj = ResolvedProjectile(ProjectileResolution.Hit, projectile, p_source, fury_dm, Vector3(1.2f, 3.4f, 5.6f), System.nanoTime)
|
||||||
val msg = receiveOne(200 milliseconds)
|
//
|
||||||
assert(msg.isInstanceOf[Vitality.DamageResolution])
|
// "not charge vehicle shields if recently damaged" in {
|
||||||
assert(vehicle.Shields == 0)
|
// assert(vehicle.Shields == 0)
|
||||||
vehicle.Actor ! Vehicle.ChargeShields(15)
|
// vehicle.Actor.tell(Vitality.Damage({case v : Vehicle => v.History(obj); obj }), probe.ref)
|
||||||
|
//
|
||||||
expectNoMsg(200 milliseconds)
|
// val msg = probe.receiveOne(200 milliseconds)
|
||||||
assert(vehicle.Shields == 0)
|
// assert(msg.isInstanceOf[Vitality.DamageResolution])
|
||||||
}
|
// assert(vehicle.Shields == 0)
|
||||||
}
|
// vehicle.Actor.tell(Vehicle.ChargeShields(15), probe.ref)
|
||||||
|
//
|
||||||
|
// probe.expectNoMsg(200 milliseconds)
|
||||||
|
// assert(vehicle.Shields == 0)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
object VehicleTest {
|
object VehicleTest {
|
||||||
import net.psforever.objects.Avatar
|
import net.psforever.objects.Avatar
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,9 @@ import services.support.SupportActor
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
class WorldSessionActor extends Actor with MDCContextAware {
|
class WorldSessionActor extends Actor
|
||||||
|
with MDCContextAware
|
||||||
|
with JammableBehavior {
|
||||||
import WorldSessionActor._
|
import WorldSessionActor._
|
||||||
|
|
||||||
private[this] val log = org.log4s.getLogger
|
private[this] val log = org.log4s.getLogger
|
||||||
|
|
@ -151,6 +153,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
|
|
||||||
var timeDL : Long = 0
|
var timeDL : Long = 0
|
||||||
var timeSurge : Long = 0
|
var timeSurge : Long = 0
|
||||||
|
var skipStaminaRegenForTurns : Int = 0
|
||||||
lazy val unsignedIntMaxValue : Long = Int.MaxValue.toLong * 2L + 1L
|
lazy val unsignedIntMaxValue : Long = Int.MaxValue.toLong * 2L + 1L
|
||||||
var serverTime : Long = 0
|
var serverTime : Long = 0
|
||||||
|
|
||||||
|
|
@ -174,12 +177,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
import scala.language.implicitConversions
|
import scala.language.implicitConversions
|
||||||
implicit def boolToInt(b : Boolean) : Int = if(b) 1 else 0
|
implicit def boolToInt(b : Boolean) : Int = if(b) 1 else 0
|
||||||
|
|
||||||
|
def JammableObject = player
|
||||||
|
|
||||||
override def postStop() : Unit = {
|
override def postStop() : Unit = {
|
||||||
//TODO normally, player avatar persists a minute or so after disconnect; we are subject to the SessionReaper
|
//TODO normally, player avatar persists a minute or so after disconnect; we are subject to the SessionReaper
|
||||||
clientKeepAlive.cancel
|
clientKeepAlive.cancel
|
||||||
reviveTimer.cancel
|
reviveTimer.cancel
|
||||||
respawnTimer.cancel
|
respawnTimer.cancel
|
||||||
PlayerActionsToCancel()
|
|
||||||
chatService ! Service.Leave()
|
chatService ! Service.Leave()
|
||||||
continent.AvatarEvents ! Service.Leave()
|
continent.AvatarEvents ! Service.Leave()
|
||||||
continent.LocalEvents ! Service.Leave()
|
continent.LocalEvents ! Service.Leave()
|
||||||
|
|
@ -187,6 +191,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
galaxyService ! Service.Leave()
|
galaxyService ! Service.Leave()
|
||||||
LivePlayerList.Remove(sessionId)
|
LivePlayerList.Remove(sessionId)
|
||||||
if(player != null && player.HasGUID) {
|
if(player != null && player.HasGUID) {
|
||||||
|
PlayerActionsToCancel()
|
||||||
squadService ! Service.Leave(Some(player.CharId.toString))
|
squadService ! Service.Leave(Some(player.CharId.toString))
|
||||||
val player_guid = player.GUID
|
val player_guid = player.GUID
|
||||||
//handle orphaned deployables
|
//handle orphaned deployables
|
||||||
|
|
@ -316,7 +321,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
context.stop(self)
|
context.stop(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
def Started : Receive = {
|
def Started : Receive = jammableBehavior.orElse {
|
||||||
case ServiceManager.LookupResult("chat", endpoint) =>
|
case ServiceManager.LookupResult("chat", endpoint) =>
|
||||||
chatService = endpoint
|
chatService = endpoint
|
||||||
log.info("ID: " + sessionId + " Got chat service " + endpoint)
|
log.info("ID: " + sessionId + " Got chat service " + endpoint)
|
||||||
|
|
@ -909,18 +914,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
continent.Deployables ! Zone.Deployable.Dismiss(obj)
|
continent.Deployables ! Zone.Deployable.Dismiss(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
case WorldSessionActor.FinalizeDeployable(obj : TurretDeployable, tool, index) =>
|
case WorldSessionActor.FinalizeDeployable(obj : SensorDeployable, tool, index) =>
|
||||||
//spitfires and deployable field turrets
|
//motion alarm sensor and sensor disruptor
|
||||||
StartBundlingPackets()
|
|
||||||
DeployableBuildActivity(obj)
|
|
||||||
CommonDestroyConstructionItem(tool, index)
|
|
||||||
FindReplacementConstructionItem(tool, index)
|
|
||||||
StopBundlingPackets()
|
|
||||||
|
|
||||||
case WorldSessionActor.FinalizeDeployable(obj : ComplexDeployable, tool, index) =>
|
|
||||||
//deployable_shield_generator
|
|
||||||
StartBundlingPackets()
|
StartBundlingPackets()
|
||||||
DeployableBuildActivity(obj)
|
DeployableBuildActivity(obj)
|
||||||
|
continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.TriggerEffectInfo(player.GUID, "on", obj.GUID, true, 1000))
|
||||||
CommonDestroyConstructionItem(tool, index)
|
CommonDestroyConstructionItem(tool, index)
|
||||||
FindReplacementConstructionItem(tool, index)
|
FindReplacementConstructionItem(tool, index)
|
||||||
StopBundlingPackets()
|
StopBundlingPackets()
|
||||||
|
|
@ -955,11 +953,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
FindReplacementConstructionItem(tool, index)
|
FindReplacementConstructionItem(tool, index)
|
||||||
StopBundlingPackets()
|
StopBundlingPackets()
|
||||||
|
|
||||||
case WorldSessionActor.FinalizeDeployable(obj : SensorDeployable, tool, index) =>
|
case WorldSessionActor.FinalizeDeployable(obj : ComplexDeployable, tool, index) =>
|
||||||
//motion alarm sensor and sensor disruptor
|
//spitfires and deployable field turrets and the deployable_shield_generator
|
||||||
StartBundlingPackets()
|
StartBundlingPackets()
|
||||||
DeployableBuildActivity(obj)
|
DeployableBuildActivity(obj)
|
||||||
continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.TriggerEffectInfo(player.GUID, "on", obj.GUID, true, 1000))
|
|
||||||
CommonDestroyConstructionItem(tool, index)
|
CommonDestroyConstructionItem(tool, index)
|
||||||
FindReplacementConstructionItem(tool, index)
|
FindReplacementConstructionItem(tool, index)
|
||||||
StopBundlingPackets()
|
StopBundlingPackets()
|
||||||
|
|
@ -1011,7 +1008,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
StartBundlingPackets()
|
StartBundlingPackets()
|
||||||
sendResponse(GenericObjectActionMessage(guid, 21)) //reset build cooldown
|
sendResponse(GenericObjectActionMessage(guid, 21)) //reset build cooldown
|
||||||
sendResponse(ObjectDeployedMessage.Failure(definition.Name))
|
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")
|
log.warn(s"FinalizeDeployable: deployable will be cleaned up, but may not get unregistered properly")
|
||||||
TryDropConstructionTool(tool, index, obj.Position)
|
TryDropConstructionTool(tool, index, obj.Position)
|
||||||
obj.Position = Vector3.Zero
|
obj.Position = Vector3.Zero
|
||||||
|
|
@ -1100,10 +1097,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case HackingProgress(progressType, tplayer, target, tool_guid, delta, completeAction, tickAction) =>
|
case HackingProgress(progressType, tplayer, target, tool_guid, delta, completeAction, tickAction) =>
|
||||||
HandleHackingProgress(progressType, tplayer, target, tool_guid, delta, completeAction, tickAction)
|
HandleHackingProgress(progressType, tplayer, target, tool_guid, delta, completeAction, tickAction)
|
||||||
|
|
||||||
case Vitality.DamageResolution(target : Vehicle) =>
|
case Vitality.DamageResolution(target : TrapDeployable, _) =>
|
||||||
HandleVehicleDamageResolution(target)
|
|
||||||
|
|
||||||
case Vitality.DamageResolution(target : TrapDeployable) =>
|
|
||||||
//tank_traps
|
//tank_traps
|
||||||
val guid = target.GUID
|
val guid = target.GUID
|
||||||
val health = target.Health
|
val health = target.Health
|
||||||
|
|
@ -1112,17 +1106,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
AnnounceDestroyDeployable(target, None)
|
AnnounceDestroyDeployable(target, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Vitality.DamageResolution(target : SensorDeployable) =>
|
case Vitality.DamageResolution(target : TelepadDeployable, _) =>
|
||||||
//sensors
|
//telepads
|
||||||
val guid = target.GUID
|
|
||||||
val health = target.Health
|
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(guid, 0, health))
|
|
||||||
if(health <= 0) {
|
|
||||||
AnnounceDestroyDeployable(target, Some(0 seconds))
|
|
||||||
}
|
|
||||||
|
|
||||||
case Vitality.DamageResolution(target : SimpleDeployable) =>
|
|
||||||
//boomers, mines
|
|
||||||
if(target.Health <= 0) {
|
if(target.Health <= 0) {
|
||||||
//update if destroyed
|
//update if destroyed
|
||||||
val guid = target.GUID
|
val guid = target.GUID
|
||||||
|
|
@ -1130,27 +1115,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
AnnounceDestroyDeployable(target, Some(0 seconds))
|
AnnounceDestroyDeployable(target, Some(0 seconds))
|
||||||
}
|
}
|
||||||
|
|
||||||
case Vitality.DamageResolution(target : TurretDeployable) =>
|
case Vitality.DamageResolution(target : PlanetSideGameObject, _) =>
|
||||||
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 : FacilityTurret) =>
|
|
||||||
HandleFacilityTurretDamageResolution(target)
|
|
||||||
|
|
||||||
case Vitality.DamageResolution(target : PlanetSideGameObject) =>
|
|
||||||
log.warn(s"Vital target ${target.Definition.Name} damage resolution not supported using this method")
|
log.warn(s"Vital target ${target.Definition.Name} damage resolution not supported using this method")
|
||||||
|
|
||||||
case Vehicle.UpdateShieldsCharge(vehicle) =>
|
|
||||||
continent.VehicleEvents ! VehicleServiceMessage(s"${vehicle.Actor}", VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), vehicle.GUID, 68, vehicle.Shields))
|
|
||||||
|
|
||||||
case ResponseToSelf(pkt) =>
|
case ResponseToSelf(pkt) =>
|
||||||
log.info(s"Received a direct message: $pkt")
|
log.info(s"Received a direct message: $pkt")
|
||||||
sendResponse(pkt)
|
sendResponse(pkt)
|
||||||
|
|
@ -1246,22 +1213,19 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
sendResponse(GenericObjectActionMessage(guid, 9))
|
sendResponse(GenericObjectActionMessage(guid, 9))
|
||||||
|
|
||||||
case AvatarResponse.EnvironmentalDamage(target, amount) =>
|
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
|
val originalHealth = player.Health
|
||||||
player.Health = player.Health - amount
|
player.Health = originalHealth - amount
|
||||||
sendResponse(PlanetsideAttributeMessage(target, 0, player.Health))
|
sendResponse(PlanetsideAttributeMessage(target, 0, player.Health))
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(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")
|
damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth/$armor/$capacitor, AFTER=${player.Health}/$armor/$capacitor, CHANGE=$amount/0/0")
|
||||||
if(amount != 0) {
|
if(player.Health == 0 && player.isAlive) {
|
||||||
val playerGUID = player.GUID
|
KillPlayer(player)
|
||||||
sendResponse(PlanetsideAttributeMessage(playerGUID, 0, player.Health))
|
}
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 0, player.Health))
|
else {
|
||||||
if(player.Health == 0 && player.isAlive) {
|
//todo: History?
|
||||||
KillPlayer(player)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//todo: History?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1270,26 +1234,24 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
val originalHealth = player.Health
|
val originalHealth = player.Health
|
||||||
val originalArmor = player.Armor
|
val originalArmor = player.Armor
|
||||||
val originalCapacitor = player.Capacitor.toInt
|
val originalCapacitor = player.Capacitor.toInt
|
||||||
resolution_function(target)
|
val cause = resolution_function(target)
|
||||||
val health = player.Health
|
val health = player.Health
|
||||||
val armor = player.Armor
|
val armor = player.Armor
|
||||||
val capacitor = player.Capacitor.toInt
|
val capacitor = player.Capacitor.toInt
|
||||||
val damageToHealth = originalHealth - health
|
val damageToHealth = originalHealth - health
|
||||||
val damageToArmor = originalArmor - armor
|
val damageToArmor = originalArmor - armor
|
||||||
val damageToCapacitor = originalCapacitor - capacitor
|
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) {
|
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
|
val playerGUID = player.GUID
|
||||||
if(damageToHealth > 0) {
|
if(damageToHealth > 0) {
|
||||||
sendResponse(PlanetsideAttributeMessage(playerGUID, 0, health))
|
sendResponse(PlanetsideAttributeMessage(playerGUID, 0, health))
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 0, health))
|
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 0, health))
|
||||||
}
|
}
|
||||||
|
|
||||||
if(damageToArmor > 0) {
|
if(damageToArmor > 0) {
|
||||||
sendResponse(PlanetsideAttributeMessage(playerGUID, 4, armor))
|
sendResponse(PlanetsideAttributeMessage(playerGUID, 4, armor))
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 4, armor))
|
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 4, armor))
|
||||||
}
|
}
|
||||||
|
|
||||||
if(damageToCapacitor > 0) {
|
if(damageToCapacitor > 0) {
|
||||||
sendResponse(PlanetsideAttributeMessage(playerGUID, 7, capacitor))
|
sendResponse(PlanetsideAttributeMessage(playerGUID, 7, capacitor))
|
||||||
}
|
}
|
||||||
|
|
@ -1301,10 +1263,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
KillPlayer(player)
|
KillPlayer(player)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//first damage entry -> most recent damage source -> killing blow
|
//damage cause -> recent damage source -> killing blow?
|
||||||
target.History.find(p => p.isInstanceOf[DamagingActivity]) match {
|
cause match {
|
||||||
case Some(data : DamageFromProjectile) =>
|
case data : ResolvedProjectile =>
|
||||||
val owner = data.data.projectile.owner
|
val owner = data.projectile.owner
|
||||||
owner match {
|
owner match {
|
||||||
case pSource : PlayerSource =>
|
case pSource : PlayerSource =>
|
||||||
continent.LivePlayers.find(_.Name == pSource.Name) match {
|
continent.LivePlayers.find(_.Name == pSource.Name) match {
|
||||||
|
|
@ -1316,11 +1278,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
sendResponse(DamageWithPositionMessage(damageToHealth + damageToArmor, vSource.Position))
|
sendResponse(DamageWithPositionMessage(damageToHealth + damageToArmor, vSource.Position))
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
continent.Activity ! Zone.HotSpot.Activity(owner, data.Target, target.Position)
|
continent.Activity ! Zone.HotSpot.Activity(owner, data.target, target.Position)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(target.isAlive && cause.projectile.profile.JammerProjectile) {
|
||||||
|
self ! JammableUnit.Jammered(cause)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case AvatarResponse.Destroy(victim, killer, weapon, pos) =>
|
case AvatarResponse.Destroy(victim, killer, weapon, pos) =>
|
||||||
|
|
@ -1459,13 +1424,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case AvatarResponse.ProjectileState(projectile_guid, shot_pos, shot_vel, shot_orient, seq, end, target_guid) =>
|
case AvatarResponse.ProjectileState(projectile_guid, shot_pos, shot_vel, shot_orient, seq, end, target_guid) =>
|
||||||
if(tplayer_guid != guid) {
|
if(tplayer_guid != guid) {
|
||||||
sendResponse(ProjectileStateMessage(projectile_guid, shot_pos, shot_vel, shot_orient, seq, end, target_guid))
|
sendResponse(ProjectileStateMessage(projectile_guid, shot_pos, shot_vel, shot_orient, seq, end, target_guid))
|
||||||
// continent.GUID(projectile_guid) match {
|
}
|
||||||
// case Some(obj) =>
|
|
||||||
// val definition = obj.Definition
|
|
||||||
// sendResponse(ObjectCreateMessage(definition.ObjectId, projectile_guid, definition.Packet.ConstructorData(obj).get))
|
|
||||||
// case _ => ;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
case AvatarResponse.PutDownFDU(target) =>
|
case AvatarResponse.PutDownFDU(target) =>
|
||||||
if(tplayer_guid != guid) {
|
if(tplayer_guid != guid) {
|
||||||
|
|
@ -1556,6 +1515,19 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
sendResponse(DeployableObjectsInfoMessage(behavior, deployInfo))
|
sendResponse(DeployableObjectsInfoMessage(behavior, deployInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case LocalResponse.Detonate(guid, obj : BoomerDeployable) =>
|
||||||
|
sendResponse(TriggerEffectMessage(guid, "detonate_boomer"))
|
||||||
|
sendResponse(PlanetsideAttributeMessage(guid, 29, 1))
|
||||||
|
sendResponse(ObjectDeleteMessage(guid, 0))
|
||||||
|
|
||||||
|
case LocalResponse.Detonate(guid, obj : ExplosiveDeployable) =>
|
||||||
|
sendResponse(GenericObjectActionMessage(guid, 19))
|
||||||
|
sendResponse(PlanetsideAttributeMessage(guid, 29, 1))
|
||||||
|
sendResponse(ObjectDeleteMessage(guid, 0))
|
||||||
|
|
||||||
|
case LocalResponse.Detonate(guid, obj) =>
|
||||||
|
log.warn(s"LocalResponse.Detonate: ${obj.Definition.Name} not configured to explode correctly")
|
||||||
|
|
||||||
case LocalResponse.DoorOpens(door_guid) =>
|
case LocalResponse.DoorOpens(door_guid) =>
|
||||||
if(tplayer_guid != guid) {
|
if(tplayer_guid != guid) {
|
||||||
sendResponse(GenericObjectStateMsg(door_guid, 16))
|
sendResponse(GenericObjectStateMsg(door_guid, 16))
|
||||||
|
|
@ -1572,6 +1544,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
DeconstructDeployable(obj, guid, pos, obj.Orientation, if(obj.MountPoints.isEmpty) 2 else 1)
|
DeconstructDeployable(obj, guid, pos, obj.Orientation, if(obj.MountPoints.isEmpty) 2 else 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case LocalResponse.EliminateDeployable(obj : ExplosiveDeployable, guid, pos) =>
|
||||||
|
if(obj.Exploded || obj.Jammed || obj.Health == 0) {
|
||||||
|
DeconstructDeployable(obj, guid, pos)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DeconstructDeployable(obj, guid, pos, obj.Orientation, 2)
|
||||||
|
}
|
||||||
|
|
||||||
case LocalResponse.EliminateDeployable(obj : ComplexDeployable, guid, pos) =>
|
case LocalResponse.EliminateDeployable(obj : ComplexDeployable, guid, pos) =>
|
||||||
if(obj.Health == 0) {
|
if(obj.Health == 0) {
|
||||||
DeconstructDeployable(obj, guid, pos)
|
DeconstructDeployable(obj, guid, pos)
|
||||||
|
|
@ -1580,14 +1560,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
DeconstructDeployable(obj, guid, pos, obj.Orientation, 1)
|
DeconstructDeployable(obj, guid, pos, obj.Orientation, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
case LocalResponse.EliminateDeployable(obj : ExplosiveDeployable, guid, pos) =>
|
|
||||||
if(obj.Exploded || obj.Health == 0) {
|
|
||||||
DeconstructDeployable(obj, guid, pos)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DeconstructDeployable(obj, guid, pos, obj.Orientation, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
case LocalResponse.EliminateDeployable(obj : TelepadDeployable, guid, pos) =>
|
case LocalResponse.EliminateDeployable(obj : TelepadDeployable, guid, pos) =>
|
||||||
//if active, deactivate
|
//if active, deactivate
|
||||||
if(obj.Active) {
|
if(obj.Active) {
|
||||||
|
|
@ -2458,7 +2430,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
|
|
||||||
case VehicleResponse.ConcealPlayer(player_guid) =>
|
case VehicleResponse.ConcealPlayer(player_guid) =>
|
||||||
sendResponse(GenericObjectActionMessage(player_guid, 9))
|
sendResponse(GenericObjectActionMessage(player_guid, 9))
|
||||||
//sendResponse(PlanetsideAttributeMessage(player_guid, 29, 1))
|
|
||||||
|
|
||||||
case VehicleResponse.DismountVehicle(bailType, wasKickedByDriver) =>
|
case VehicleResponse.DismountVehicle(bailType, wasKickedByDriver) =>
|
||||||
if(tplayer_guid != guid) {
|
if(tplayer_guid != guid) {
|
||||||
|
|
@ -2934,189 +2905,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
msgs
|
msgs
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* na
|
|
||||||
* @param target na
|
|
||||||
*/
|
|
||||||
def HandleVehicleDamageResolution(target : Vehicle) : Unit = {
|
|
||||||
val targetGUID = target.GUID
|
|
||||||
val playerGUID = player.GUID
|
|
||||||
val players = target.Seats.values.filter(seat => {
|
|
||||||
seat.isOccupied && seat.Occupant.get.isAlive
|
|
||||||
})
|
|
||||||
target.LastShot match { //TODO: collision damage from/in history
|
|
||||||
case Some(shot) =>
|
|
||||||
if(target.Health > 0) {
|
|
||||||
//activity on map
|
|
||||||
continent.Activity ! Zone.HotSpot.Activity(shot.target, shot.projectile.owner, shot.hit_pos)
|
|
||||||
//alert occupants to damage source
|
|
||||||
HandleVehicleDamageAwareness(target, playerGUID, shot)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//alert to vehicle death (hence, occupants' deaths)
|
|
||||||
HandleVehicleDestructionAwareness(target, shot)
|
|
||||||
}
|
|
||||||
continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health))
|
|
||||||
continent.VehicleEvents ! VehicleServiceMessage(s"${target.Actor}", VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 68, target.Shields))
|
|
||||||
case None => ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* na
|
|
||||||
* @param target na
|
|
||||||
* @param attribution na
|
|
||||||
* @param lastShot na
|
|
||||||
*/
|
|
||||||
def HandleVehicleDamageAwareness(target : Vehicle, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = {
|
|
||||||
//alert occupants to damage source
|
|
||||||
target.Seats.values.filter(seat => {
|
|
||||||
seat.isOccupied && seat.Occupant.get.isAlive
|
|
||||||
}).foreach(seat => {
|
|
||||||
val tplayer = seat.Occupant.get
|
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(attribution, tplayer.GUID))
|
|
||||||
})
|
|
||||||
//alert cargo occupants to damage source
|
|
||||||
target.CargoHolds.values.foreach(hold => {
|
|
||||||
hold.Occupant match {
|
|
||||||
case Some(cargo) =>
|
|
||||||
cargo.Health = 0
|
|
||||||
cargo.Shields = 0
|
|
||||||
cargo.History(lastShot)
|
|
||||||
HandleVehicleDamageAwareness(cargo, attribution, lastShot)
|
|
||||||
case None => ;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* na
|
|
||||||
* @param target na
|
|
||||||
* @param attribution na
|
|
||||||
* @param lastShot na
|
|
||||||
*/
|
|
||||||
def HandleVehicleDestructionAwareness(target : Vehicle, lastShot : ResolvedProjectile) : Unit = {
|
|
||||||
val playerGUID = player.GUID
|
|
||||||
val continentId = continent.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
|
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID))
|
|
||||||
continent.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
|
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID))
|
|
||||||
})
|
|
||||||
target.CargoHolds.values.foreach(hold => {
|
|
||||||
hold.Occupant match {
|
|
||||||
case Some(cargo) =>
|
|
||||||
cargo.Health = 0
|
|
||||||
cargo.Shields = 0
|
|
||||||
cargo.Position += Vector3.z(1)
|
|
||||||
cargo.History(lastShot) //necessary to kill cargo vehicle occupants //TODO: collision damage
|
|
||||||
HandleVehicleDestructionAwareness(cargo, lastShot) //might cause redundant packets
|
|
||||||
case None => ;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
target.Definition match {
|
|
||||||
case GlobalDefinitions.ams =>
|
|
||||||
target.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying)
|
|
||||||
case GlobalDefinitions.router =>
|
|
||||||
target.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying)
|
|
||||||
BeforeUnloadVehicle(target)
|
|
||||||
continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.ToggleTeleportSystem(PlanetSideGUID(0), target, None))
|
|
||||||
case _ => ;
|
|
||||||
}
|
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.Destroy(target.GUID, playerGUID, playerGUID, target.Position))
|
|
||||||
continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(target), continent))
|
|
||||||
continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(target, continent, Some(1 minute)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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))
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
* na
|
||||||
* @param tplayer na
|
* @param tplayer na
|
||||||
|
|
@ -3548,6 +3336,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
player.Slot(39).Equipment = SimpleItem(remote_electronics_kit)
|
player.Slot(39).Equipment = SimpleItem(remote_electronics_kit)
|
||||||
player.Locker.Inventory += 0 -> SimpleItem(remote_electronics_kit)
|
player.Locker.Inventory += 0 -> SimpleItem(remote_electronics_kit)
|
||||||
player.Inventory.Items.foreach { _.obj.Faction = faction }
|
player.Inventory.Items.foreach { _.obj.Faction = faction }
|
||||||
|
player.Actor = self
|
||||||
//TODO end temp player character auto-loading
|
//TODO end temp player character auto-loading
|
||||||
self ! ListAccountCharacters
|
self ! ListAccountCharacters
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
|
@ -3888,6 +3677,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
|
|
||||||
case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, yaw, pitch, yaw_upper, seq_time, unk3, is_crouching, is_jumping, jump_thrust, is_cloaking, unk5, unk6) =>
|
case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, yaw, pitch, yaw_upper, seq_time, unk3, is_crouching, is_jumping, jump_thrust, is_cloaking, unk5, unk6) =>
|
||||||
val isMoving = WorldEntity.isMoving(vel)
|
val isMoving = WorldEntity.isMoving(vel)
|
||||||
|
val isMovingPlus = isMoving || is_jumping || jump_thrust
|
||||||
//implants and stamina management start
|
//implants and stamina management start
|
||||||
val implantsAreActive = avatar.Implants(0).Active || avatar.Implants(1).Active
|
val implantsAreActive = avatar.Implants(0).Active || avatar.Implants(1).Active
|
||||||
val staminaBefore = player.Stamina
|
val staminaBefore = player.Stamina
|
||||||
|
|
@ -3919,14 +3709,23 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CapacitorTick(jump_thrust)
|
if(skipStaminaRegenForTurns > 0) {
|
||||||
//if the player lost all stamina this turn (had stamina at the start), do not renew 1 stamina
|
//do not renew stamina for a while
|
||||||
if(!isMoving && (if(player.Stamina > 0) player.Stamina < player.MaxStamina else !hadStaminaBefore)) {
|
skipStaminaRegenForTurns -= 1
|
||||||
player.Stamina = player.Stamina + 1
|
player.Stamina > 0
|
||||||
true
|
}
|
||||||
|
else if(player.Stamina == 0 && hadStaminaBefore) {
|
||||||
|
//if the player lost all stamina this turn (had stamina at the start), do not renew stamina for a while
|
||||||
|
skipStaminaRegenForTurns = 4
|
||||||
|
player.Stamina > 0
|
||||||
|
}
|
||||||
|
else if(isMovingPlus || player.Stamina == player.MaxStamina) {
|
||||||
|
//ineligible for stamina regen
|
||||||
|
player.Stamina > 0
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
player.Stamina > 0
|
player.Stamina = player.Stamina + 1
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -3938,18 +3737,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
sendResponse(PlanetsideAttributeMessage(player.GUID, 2, player.Stamina))
|
sendResponse(PlanetsideAttributeMessage(player.GUID, 2, player.Stamina))
|
||||||
}
|
}
|
||||||
if(implantsAreActive && !hasStaminaAfter) { //implants deactivated at 0 stamina
|
if(implantsAreActive && !hasStaminaAfter) { //implants deactivated at 0 stamina
|
||||||
if(avatar.Implants(0).Active) {
|
DeactivateImplants()
|
||||||
avatar.Implants(0).Active = false
|
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 28, avatar.Implant(0).id * 2))
|
|
||||||
sendResponse(AvatarImplantMessage(PlanetSideGUID(player.GUID.guid), ImplantAction.Activation, 0, 0))
|
|
||||||
timeDL = 0
|
|
||||||
}
|
|
||||||
if(avatar.Implants(1).Active) {
|
|
||||||
avatar.Implants(1).Active = false
|
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 28, avatar.Implant(1).id * 2))
|
|
||||||
sendResponse(AvatarImplantMessage(PlanetSideGUID(player.GUID.guid), ImplantAction.Activation, 1, 0))
|
|
||||||
timeSurge = 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//implants and stamina management finish
|
//implants and stamina management finish
|
||||||
player.Position = pos
|
player.Position = pos
|
||||||
|
|
@ -3959,8 +3747,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
player.Crouching = is_crouching
|
player.Crouching = is_crouching
|
||||||
player.Jumping = is_jumping
|
player.Jumping = is_jumping
|
||||||
player.Cloaked = player.ExoSuit == ExoSuitType.Infiltration && is_cloaking
|
player.Cloaked = player.ExoSuit == ExoSuitType.Infiltration && is_cloaking
|
||||||
|
CapacitorTick(jump_thrust)
|
||||||
|
|
||||||
if(isMoving && usingMedicalTerminal.isDefined) {
|
if(isMovingPlus && usingMedicalTerminal.isDefined) {
|
||||||
continent.GUID(usingMedicalTerminal) match {
|
continent.GUID(usingMedicalTerminal) match {
|
||||||
case Some(term : Terminal with ProximityUnit) =>
|
case Some(term : Terminal with ProximityUnit) =>
|
||||||
StopUsingProximityUnit(term)
|
StopUsingProximityUnit(term)
|
||||||
|
|
@ -3978,7 +3767,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
accessedContainer = None
|
accessedContainer = None
|
||||||
}
|
}
|
||||||
case Some(container) => //just in case
|
case Some(container) => //just in case
|
||||||
if(isMoving) {
|
if(isMovingPlus) {
|
||||||
val guid = player.GUID
|
val guid = player.GUID
|
||||||
// If the container is a corpse and gets removed just as this runs it can cause a client disconnect, so we'll check the container has a GUID first.
|
// If the container is a corpse and gets removed just as this runs it can cause a client disconnect, so we'll check the container has a GUID first.
|
||||||
if(container.HasGUID) {
|
if(container.HasGUID) {
|
||||||
|
|
@ -4404,15 +4193,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Start(playerGUID, item_guid))
|
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Start(playerGUID, item_guid))
|
||||||
continent.GUID(trigger.Companion) match {
|
continent.GUID(trigger.Companion) match {
|
||||||
case Some(boomer : BoomerDeployable) =>
|
case Some(boomer : BoomerDeployable) =>
|
||||||
val boomerGUID = boomer.GUID
|
|
||||||
boomer.Exploded = true
|
boomer.Exploded = true
|
||||||
sendResponse(TriggerEffectMessage(boomerGUID, "detonate_boomer"))
|
continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.Detonate(boomer.GUID, boomer))
|
||||||
sendResponse(PlanetsideAttributeMessage(boomerGUID, 29, 1))
|
Deployables.AnnounceDestroyDeployable(boomer, Some(500 milliseconds))
|
||||||
sendResponse(ObjectDeleteMessage(boomerGUID, 0))
|
|
||||||
continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.TriggerEffect(playerGUID, "detonate_boomer", boomerGUID))
|
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(boomerGUID, 29, 1))
|
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(playerGUID, boomerGUID))
|
|
||||||
continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(boomer, continent, Some(0 seconds)))
|
|
||||||
case Some(_) | None => ;
|
case Some(_) | None => ;
|
||||||
}
|
}
|
||||||
FindEquipmentToDelete(item_guid, trigger)
|
FindEquipmentToDelete(item_guid, trigger)
|
||||||
|
|
@ -4545,6 +4328,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case msg @ AvatarJumpMessage(state) =>
|
case msg @ AvatarJumpMessage(state) =>
|
||||||
//log.info("AvatarJump: " + msg)
|
//log.info("AvatarJump: " + msg)
|
||||||
player.Stamina = player.Stamina - 10
|
player.Stamina = player.Stamina - 10
|
||||||
|
skipStaminaRegenForTurns = 5
|
||||||
sendResponse(PlanetsideAttributeMessage(player.GUID, 2, player.Stamina))
|
sendResponse(PlanetsideAttributeMessage(player.GUID, 2, player.Stamina))
|
||||||
|
|
||||||
case msg @ ZipLineMessage(player_guid,origin_side,action,id,pos) =>
|
case msg @ ZipLineMessage(player_guid,origin_side,action,id,pos) =>
|
||||||
|
|
@ -4770,7 +4554,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) =>
|
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 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)
|
// TODO: Not all incoming UseItemMessage's respond with another UseItemMessage (i.e. doors only send out GenericObjectStateMsg)
|
||||||
continent.GUID(object_guid) match {
|
continent.GUID(object_guid) match {
|
||||||
|
|
@ -5495,6 +5279,15 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case msg @ WeaponJammedMessage(weapon_guid) =>
|
||||||
|
FindWeapon match {
|
||||||
|
case Some(tool : Tool) =>
|
||||||
|
log.info(s"WeaponJammed: ${tool.Definition.Name}@${weapon_guid.guid}")
|
||||||
|
//TODO
|
||||||
|
case _ =>
|
||||||
|
log.info(s"WeaponJammed: ${weapon_guid.guid}")
|
||||||
|
}
|
||||||
|
|
||||||
case msg @ WeaponFireMessage(seq_time, weapon_guid, projectile_guid, shot_origin, unk1, unk2, unk3, unk4, unk5, unk6, unk7) =>
|
case msg @ WeaponFireMessage(seq_time, weapon_guid, projectile_guid, shot_origin, unk1, unk2, unk3, unk4, unk5, unk6, unk7) =>
|
||||||
log.info(s"WeaponFire: $msg")
|
log.info(s"WeaponFire: $msg")
|
||||||
if(player.isShielded) {
|
if(player.isShielded) {
|
||||||
|
|
@ -5609,6 +5402,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case Some(projectile) =>
|
case Some(projectile) =>
|
||||||
projectile.Position = explosion_pos
|
projectile.Position = explosion_pos
|
||||||
projectile.Velocity = projectile_vel
|
projectile.Velocity = projectile_vel
|
||||||
|
//direct_victim_uid
|
||||||
continent.GUID(direct_victim_uid) match {
|
continent.GUID(direct_victim_uid) match {
|
||||||
case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) =>
|
case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) =>
|
||||||
ResolveProjectileEntry(projectile, ProjectileResolution.Splash, target, target.Position) match {
|
ResolveProjectileEntry(projectile, ProjectileResolution.Splash, target, target.Position) match {
|
||||||
|
|
@ -5618,6 +5412,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
//other victims
|
||||||
targets.foreach(elem => {
|
targets.foreach(elem => {
|
||||||
continent.GUID(elem.uid) match {
|
continent.GUID(elem.uid) match {
|
||||||
case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) =>
|
case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) =>
|
||||||
|
|
@ -7245,7 +7040,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
val orient : Vector3 = Vector3(0f, 0f, sourceOrientZ)
|
val orient : Vector3 = Vector3(0f, 0f, sourceOrientZ)
|
||||||
continent.Ground ! Zone.Ground.DropItem(item2, pos, orient)
|
continent.Ground ! Zone.Ground.DropItem(item2, pos, orient)
|
||||||
sendResponse(ObjectDetachMessage(destination_guid, item2_guid, pos, sourceOrientZ)) //ground
|
sendResponse(ObjectDetachMessage(destination_guid, item2_guid, pos, sourceOrientZ)) //ground
|
||||||
val objDef = item2.Definition
|
val objDef = item2.Definition
|
||||||
destination match {
|
destination match {
|
||||||
case obj : Vehicle =>
|
case obj : Vehicle =>
|
||||||
continent.VehicleEvents ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player_guid, item2_guid))
|
continent.VehicleEvents ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player_guid, item2_guid))
|
||||||
|
|
@ -7912,9 +7707,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
* This is not a complete list but, for the purpose of enforcement, some pointers will be documented here.
|
* This is not a complete list but, for the purpose of enforcement, some pointers will be documented here.
|
||||||
*/
|
*/
|
||||||
def PlayerActionsToCancel() : Unit = {
|
def PlayerActionsToCancel() : Unit = {
|
||||||
|
CancelJammeredSound(player)
|
||||||
|
CancelJammeredStatus(player)
|
||||||
progressBarUpdate.cancel
|
progressBarUpdate.cancel
|
||||||
progressBarValue = None
|
progressBarValue = None
|
||||||
lastTerminalOrderFulfillment = true
|
lastTerminalOrderFulfillment = true
|
||||||
|
skipStaminaRegenForTurns = 0
|
||||||
accessedContainer match {
|
accessedContainer match {
|
||||||
case Some(obj : Vehicle) =>
|
case Some(obj : Vehicle) =>
|
||||||
if(obj.AccessingTrunk.contains(player.GUID)) {
|
if(obj.AccessingTrunk.contains(player.GUID)) {
|
||||||
|
|
@ -8284,8 +8082,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
*/
|
*/
|
||||||
def FindProximityUnitTargetsInScope(terminal : Terminal with ProximityUnit) : Seq[PlanetSideGameObject] = {
|
def FindProximityUnitTargetsInScope(terminal : Terminal with ProximityUnit) : Seq[PlanetSideGameObject] = {
|
||||||
terminal.Definition.asInstanceOf[ProximityDefinition].TargetValidation.keySet collect {
|
terminal.Definition.asInstanceOf[ProximityDefinition].TargetValidation.keySet collect {
|
||||||
case ProximityTarget.Player => Some(player)
|
case EffectTarget.Category.Player => Some(player)
|
||||||
case ProximityTarget.Vehicle | ProximityTarget.Aircraft => continent.GUID(player.VehicleSeated)
|
case EffectTarget.Category.Vehicle | EffectTarget.Category.Aircraft => continent.GUID(player.VehicleSeated)
|
||||||
} collect {
|
} collect {
|
||||||
case Some(a) => a
|
case Some(a) => a
|
||||||
} toSeq
|
} toSeq
|
||||||
|
|
@ -8548,8 +8346,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
def ResolveProjectileEntry(projectile_guid : PlanetSideGUID, resolution : ProjectileResolution.Value, target : PlanetSideGameObject with FactionAffinity with Vitality, pos : Vector3) : Option[ResolvedProjectile] = {
|
def ResolveProjectileEntry(projectile_guid : PlanetSideGUID, resolution : ProjectileResolution.Value, target : PlanetSideGameObject with FactionAffinity with Vitality, pos : Vector3) : Option[ResolvedProjectile] = {
|
||||||
FindProjectileEntry(projectile_guid) match {
|
FindProjectileEntry(projectile_guid) match {
|
||||||
case Some(projectile) =>
|
case Some(projectile) =>
|
||||||
val index = projectile_guid.guid - Projectile.BaseUID
|
ResolveProjectileEntry(projectile, resolution, target, pos)
|
||||||
ResolveProjectileEntry(projectile, index, resolution, target, pos)
|
|
||||||
case None =>
|
case None =>
|
||||||
log.warn(s"ResolveProjectile: expected projectile, but ${projectile_guid.guid} not found")
|
log.warn(s"ResolveProjectile: expected projectile, but ${projectile_guid.guid} not found")
|
||||||
None
|
None
|
||||||
|
|
@ -8574,10 +8371,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a projectile with the given globally unique identifier and mark it as a resolved shot.
|
* na
|
||||||
* A `Resolved` shot has either encountered an obstacle or is being cleaned up for not finding an obstacle.
|
|
||||||
* The internal copy of the projectile is retained as merely `Resolved`
|
|
||||||
* while the observed projectile is promoted to the suggested resolution status.
|
|
||||||
* @param projectile the projectile object
|
* @param projectile the projectile object
|
||||||
* @param resolution the resolution status to promote the projectile
|
* @param resolution the resolution status to promote the projectile
|
||||||
* @return a copy of the projectile
|
* @return a copy of the projectile
|
||||||
|
|
@ -8637,15 +8431,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case obj : Player =>
|
case obj : Player =>
|
||||||
//damage is synchronized on the target player's `WSA` (results distributed from there)
|
//damage is synchronized on the target player's `WSA` (results distributed from there)
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(obj.Name, AvatarAction.Damage(player.GUID, obj, func))
|
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`)
|
case obj : Vehicle => obj.Actor ! Vitality.Damage(func)
|
||||||
obj.Actor ! Vitality.Damage(func)
|
case obj : FacilityTurret => obj.Actor ! Vitality.Damage(func)
|
||||||
case obj : Deployable =>
|
case obj : ComplexDeployable => obj.Actor ! Vitality.Damage(func)
|
||||||
|
|
||||||
|
case obj : SimpleDeployable =>
|
||||||
//damage is synchronized on `LSA` (results returned to and distributed from this `WSA`)
|
//damage is synchronized on `LSA` (results returned to and distributed from this `WSA`)
|
||||||
continent.LocalEvents ! Vitality.DamageOn(obj, func)
|
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 _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9803,7 +9596,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case GlobalDefinitions.ams if vehicle.Faction == player.Faction =>
|
case GlobalDefinitions.ams if vehicle.Faction == player.Faction =>
|
||||||
log.info("BeforeUnload: cleaning up after a mobile spawn vehicle ...")
|
log.info("BeforeUnload: cleaning up after a mobile spawn vehicle ...")
|
||||||
continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.UpdateAmsSpawnPoint(continent))
|
continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.UpdateAmsSpawnPoint(continent))
|
||||||
None
|
|
||||||
case GlobalDefinitions.router =>
|
case GlobalDefinitions.router =>
|
||||||
//this may repeat for multiple players on the same continent but that's okay(?)
|
//this may repeat for multiple players on the same continent but that's okay(?)
|
||||||
log.info("BeforeUnload: cleaning up after a router ...")
|
log.info("BeforeUnload: cleaning up after a router ...")
|
||||||
|
|
@ -10270,11 +10062,94 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
taskResolver ! UnregisterProjectile(projectile)
|
taskResolver ! UnregisterProjectile(projectile)
|
||||||
projectiles(local_index) match {
|
projectiles(local_index) match {
|
||||||
case Some(obj) if !obj.isResolved => obj.Miss
|
case Some(obj) if !obj.isResolved => obj.Miss
|
||||||
case None => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
projectilesToCleanUp(local_index) = false
|
projectilesToCleanUp(local_index) = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deactivate all active implants.
|
||||||
|
* This method is intended to support only the current Live server implants that are functional,
|
||||||
|
* the darklight vision implant and the surge implant.
|
||||||
|
*/
|
||||||
|
def DeactivateImplants() : Unit = {
|
||||||
|
DeactivateImplantDarkLight()
|
||||||
|
DeactivateImplantSurge()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deactivate the darklight vision implant.
|
||||||
|
* This method is intended to support only the current Live server implants.
|
||||||
|
*/
|
||||||
|
def DeactivateImplantDarkLight() : Unit = {
|
||||||
|
if(avatar.Implants(0).Active) {
|
||||||
|
avatar.Implants(0).Active = false
|
||||||
|
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 28, avatar.Implant(0).id * 2))
|
||||||
|
sendResponse(AvatarImplantMessage(PlanetSideGUID(player.GUID.guid), ImplantAction.Activation, 0, 0))
|
||||||
|
timeDL = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deactivate the surge implant.
|
||||||
|
* This method is intended to support only the current Live server implants.
|
||||||
|
*/
|
||||||
|
def DeactivateImplantSurge() : Unit = {
|
||||||
|
if(avatar.Implants(1).Active) {
|
||||||
|
avatar.Implants(1).Active = false
|
||||||
|
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 28, avatar.Implant(1).id * 2))
|
||||||
|
sendResponse(AvatarImplantMessage(PlanetSideGUID(player.GUID.guid), ImplantAction.Activation, 1, 0))
|
||||||
|
timeSurge = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the jammered buzzing.
|
||||||
|
* Although, as a rule, the jammering sound effect should last as long as the jammering status,
|
||||||
|
* Infantry seem to hear the sound for a bit longer than the effect.
|
||||||
|
* @see `JammableHevaior.StartJammeredSound`
|
||||||
|
* @param target an object that can be affected by the jammered status
|
||||||
|
* @param dur the duration of the timer, in milliseconds;
|
||||||
|
* by default, 30000
|
||||||
|
*/
|
||||||
|
override def StartJammeredSound(target : Any, dur : Int) : Unit = target match {
|
||||||
|
case obj : Player if !jammedSound =>
|
||||||
|
sendResponse(PlanetsideAttributeMessage(obj.GUID, 27, 1))
|
||||||
|
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(obj.GUID, 27, 1))
|
||||||
|
super.StartJammeredSound(obj, 3000)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a variety of tasks to indicate being jammered.
|
||||||
|
* Deactivate implants (should also uninitialize them),
|
||||||
|
* delay stamina regeneration for a certain number of turns,
|
||||||
|
* and set the jammered status on specific holstered equipment.
|
||||||
|
* @see `JammableHevaior.StartJammeredStatus`
|
||||||
|
* @param target an object that can be affected by the jammered status
|
||||||
|
* @param dur the duration of the timer, in milliseconds
|
||||||
|
*/
|
||||||
|
override def StartJammeredStatus(target : Any, dur : Int) : Unit = target match {
|
||||||
|
case obj : Player =>
|
||||||
|
DeactivateImplants()
|
||||||
|
skipStaminaRegenForTurns = 10
|
||||||
|
super.StartJammeredStatus(target, dur)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the jammered buzzing.
|
||||||
|
* @see `JammableHevaior.CancelJammeredSound`
|
||||||
|
* @param target an object that can be affected by the jammered status
|
||||||
|
*/
|
||||||
|
override def CancelJammeredSound(target : Any) : Unit = target match {
|
||||||
|
case obj : Player if jammedSound =>
|
||||||
|
sendResponse(PlanetsideAttributeMessage(obj.GUID, 27, 0))
|
||||||
|
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(obj.GUID, 27, 0))
|
||||||
|
super.CancelJammeredSound(obj)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
def failWithError(error : String) = {
|
def failWithError(error : String) = {
|
||||||
log.error(error)
|
log.error(error)
|
||||||
sendResponse(ConnectionClose())
|
sendResponse(ConnectionClose())
|
||||||
|
|
@ -10433,8 +10308,8 @@ object WorldSessionActor {
|
||||||
|
|
||||||
protected final case class SquadUIElement(name : String, index : Int, zone : Int, health : Int, armor : Int, position : Vector3)
|
protected final case class SquadUIElement(name : String, index : Int, zone : Int, health : Int, armor : Int, position : Vector3)
|
||||||
|
|
||||||
private final case class NtuCharging(tplayer: Player,
|
private final case class NtuCharging(tplayer: Player, vehicle: Vehicle)
|
||||||
vehicle: Vehicle)
|
|
||||||
private final case class NtuDischarging(tplayer: Player, vehicle: Vehicle, silo_guid: PlanetSideGUID)
|
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 FinalizeDeployable(obj : PlanetSideGameObject with Deployable, tool : ConstructionItem, index : Int)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import akka.actor.Props
|
||||||
import akka.routing.RandomPool
|
import akka.routing.RandomPool
|
||||||
import actor.base.ActorTest
|
import actor.base.ActorTest
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
|
import net.psforever.objects.ballistics.ResolvedProjectile
|
||||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||||
import net.psforever.objects.zones.{Zone, ZoneActor, ZoneMap}
|
import net.psforever.objects.zones.{Zone, ZoneActor, ZoneMap}
|
||||||
import net.psforever.packet.game.objectcreate.{DroppedItemData, ObjectClass, ObjectCreateMessageParent, PlacementData}
|
import net.psforever.packet.game.objectcreate.{DroppedItemData, ObjectClass, ObjectCreateMessageParent, PlacementData}
|
||||||
|
|
@ -370,8 +371,8 @@ class ChangeFireStateStopTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
class DamageTest extends ActorTest {
|
class DamageTest extends ActorTest {
|
||||||
val test_func_ref : (Any)=>Unit = {
|
val test_func_ref : Any=>ResolvedProjectile = {
|
||||||
def test_func(o : Any) : Unit = { }
|
def test_func(o : Any) : ResolvedProjectile = { null }
|
||||||
test_func
|
test_func
|
||||||
}
|
}
|
||||||
val player = Player(Avatar("TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1))
|
val player = Player(Avatar("TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue