correcting the inheritance of turrets (FacilityTurret and TurretDeployable) by untangling their definition structures; damage and jammering code for ComplexDeployable objects moved onto that object's control actor; setting up SimpleDeployable objects for jammering status; correcting an oversight with FacilityTurret jammering

This commit is contained in:
FateJH 2019-12-21 09:08:06 -05:00
parent a568e52590
commit fee001596f
22 changed files with 378 additions and 177 deletions

View file

@ -1,9 +1,9 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects
import net.psforever.objects.definition.DeployableDefinition
import net.psforever.objects.definition.SimpleDeployableDefinition
class BoomerDeployable(cdef : DeployableDefinition) extends ExplosiveDeployable(cdef) {
class BoomerDeployable(cdef : SimpleDeployableDefinition) extends ExplosiveDeployable(cdef) {
private var trigger : Option[BoomerTrigger] = None
def Trigger : Option[BoomerTrigger] = trigger

View file

@ -2,9 +2,11 @@
package net.psforever.objects
import net.psforever.objects.ce.SimpleDeployable
import net.psforever.objects.definition.DeployableDefinition
import net.psforever.objects.definition.SimpleDeployableDefinition
import net.psforever.objects.equipment.JammableUnit
class ExplosiveDeployable(cdef : DeployableDefinition) extends SimpleDeployable(cdef) {
class ExplosiveDeployable(cdef : SimpleDeployableDefinition) extends SimpleDeployable(cdef)
with JammableUnit {
private var exploded : Boolean = false
def Exploded : Boolean = exploded

View file

@ -17,7 +17,7 @@ import net.psforever.objects.serverobject.terminals._
import net.psforever.objects.serverobject.tube.SpawnTubeDefinition
import net.psforever.objects.serverobject.resourcesilo.ResourceSiloDefinition
import net.psforever.objects.serverobject.structures.SphereOfInfluence
import net.psforever.objects.serverobject.turret.{TurretDefinition, TurretUpgrade}
import net.psforever.objects.serverobject.turret.{FacilityTurretDefinition, TurretUpgrade}
import net.psforever.objects.vehicles.{DestroyedVehicle, SeatArmorRestriction, UtilityType}
import net.psforever.objects.vital.{DamageType, StandardMaxDamage, StandardResolutions}
import net.psforever.types.{CertificationType, ExoSuitType, PlanetSideEmpire, Vector3}
@ -870,11 +870,11 @@ object GlobalDefinitions {
/*
combat engineering deployables
*/
val boomer = DeployableDefinition(DeployedItem.boomer)
val boomer = SimpleDeployableDefinition(DeployedItem.boomer)
val he_mine = DeployableDefinition(DeployedItem.he_mine)
val he_mine = SimpleDeployableDefinition(DeployedItem.he_mine)
val jammer_mine = DeployableDefinition(DeployedItem.jammer_mine)
val jammer_mine = SimpleDeployableDefinition(DeployedItem.jammer_mine)
val spitfire_turret = TurretDeployableDefinition(DeployedItem.spitfire_turret)
@ -882,11 +882,11 @@ object GlobalDefinitions {
val spitfire_aa = TurretDeployableDefinition(DeployedItem.spitfire_aa)
val motionalarmsensor = DeployableDefinition(DeployedItem.motionalarmsensor)
val motionalarmsensor = SimpleDeployableDefinition(DeployedItem.motionalarmsensor)
val sensor_shield = DeployableDefinition(DeployedItem.sensor_shield)
val sensor_shield = SimpleDeployableDefinition(DeployedItem.sensor_shield)
val tank_traps = DeployableDefinition(DeployedItem.tank_traps)
val tank_traps = SimpleDeployableDefinition(DeployedItem.tank_traps)
val portable_manned_turret = TurretDeployableDefinition(DeployedItem.portable_manned_turret)
@ -898,10 +898,10 @@ object GlobalDefinitions {
val deployable_shield_generator = new ShieldGeneratorDefinition
val router_telepad_deployable = DeployableDefinition(DeployedItem.router_telepad_deployable)
val router_telepad_deployable = SimpleDeployableDefinition(DeployedItem.router_telepad_deployable)
//this is only treated like a deployable
val internal_router_telepad_deployable = DeployableDefinition(DeployedItem.router_telepad_deployable)
val internal_router_telepad_deployable = SimpleDeployableDefinition(DeployedItem.router_telepad_deployable)
init_deployables()
/*
@ -989,7 +989,7 @@ object GlobalDefinitions {
val ground_rearm_terminal = new OrderTerminalDefinition(384)
val manned_turret = new TurretDefinition(480)
val manned_turret = new FacilityTurretDefinition(480)
val painbox = new PainboxDefinition(622)
val painbox_continuous = new PainboxDefinition(623)

View file

@ -2,8 +2,10 @@
package net.psforever.objects
import net.psforever.objects.ce.SimpleDeployable
import net.psforever.objects.definition.DeployableDefinition
import net.psforever.objects.definition.SimpleDeployableDefinition
import net.psforever.objects.equipment.JammableUnit
import net.psforever.objects.serverobject.hackable.Hackable
class SensorDeployable(cdef : DeployableDefinition) extends SimpleDeployable(cdef)
class SensorDeployable(cdef : SimpleDeployableDefinition) extends SimpleDeployable(cdef)
with Hackable
with JammableUnit

View file

@ -1,15 +1,139 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects
import net.psforever.objects.ce.{ComplexDeployable, DeployableCategory}
import net.psforever.objects.definition.DeployableDefinition
import akka.actor.{Actor, ActorContext, Props}
import net.psforever.objects.ballistics.ResolvedProjectile
import net.psforever.objects.ce.{ComplexDeployable, Deployable, DeployableCategory}
import net.psforever.objects.definition.{ComplexDeployableDefinition, SimpleDeployableDefinition}
import net.psforever.objects.definition.converter.ShieldGeneratorConverter
import net.psforever.objects.equipment.{JammableBehavior, JammableUnit}
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.vital.Vitality
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{DeployableInfo, DeploymentAction, PlanetSideGUID}
import services.avatar.{AvatarAction, AvatarServiceMessage}
import services.local.{LocalAction, LocalServiceMessage}
import services.{RemoverActor, Service}
import services.vehicle.{VehicleAction, VehicleServiceMessage}
import scala.concurrent.duration.FiniteDuration
class ShieldGeneratorDeployable(cdef : ShieldGeneratorDefinition) extends ComplexDeployable(cdef)
with Hackable
with JammableUnit
class ShieldGeneratorDefinition extends DeployableDefinition(240) {
class ShieldGeneratorDefinition extends ComplexDeployableDefinition(240) {
Packet = new ShieldGeneratorConverter
DeployCategory = DeployableCategory.ShieldGenerators
override def Initialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = {
obj.Actor = context.actorOf(Props(classOf[ShieldGeneratorControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}")
}
override def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = {
SimpleDeployableDefinition.SimpleUninitialize(obj, context)
}
}
class ShieldGeneratorControl(gen : ShieldGeneratorDeployable) extends Actor
with JammableBehavior {
def JammableObject = gen
def receive : Receive = jammableBehavior
.orElse {
case Vitality.Damage(damage_func) => //note: damage status is reported as vehicle events, not local events
if(gen.Health > 0) {
val originalHealth = gen.Health
val cause = damage_func(gen)
val health = gen.Health
val damageToHealth = originalHealth - health
ShieldGeneratorControl.HandleDamageResolution(gen, cause, damageToHealth)
if(damageToHealth > 0) {
val name = gen.Actor.toString
val slashPoint = name.lastIndexOf("/")
org.log4s.getLogger("DamageResolution").info(s"${name.substring(slashPoint + 1, name.length - 1)}: BEFORE=$originalHealth, AFTER=$health, CHANGE=$damageToHealth")
}
}
case _ => ;
}
override def StartJammeredSound(target : Any, dur : Int) : Unit = { }
override def StartJammeredStatus(target : Any, dur : Int) : Unit = target match {
case obj : PlanetSideServerObject =>
obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 1))
super.StartJammeredStatus(obj, dur)
case _ => ;
}
override def CancelJammeredSound(target : Any) : Unit = { }
override def CancelJammeredStatus(target : Any) : Unit = target match {
case obj : PlanetSideServerObject =>
obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 0))
super.CancelJammeredStatus(obj)
case _ => ;
}
}
object ShieldGeneratorControl {
/**
* na
* @param target na
*/
def HandleDamageResolution(target : ShieldGeneratorDeployable, cause : ResolvedProjectile, damage : Int) : Unit = {
val zone = target.Zone
val targetGUID = target.GUID
val playerGUID = zone.LivePlayers.find { p => cause.projectile.owner.Name.equals(p.Name) } match {
case Some(player) => player.GUID
case _ => PlanetSideGUID(0)
}
if(target.Health > 0) {
//activity on map
if(damage > 0) {
zone.Activity ! Zone.HotSpot.Activity(cause.target, cause.projectile.owner, cause.hit_pos)
}
if(cause.projectile.profile.JammerProjectile) {
target.Actor ! JammableUnit.Jammered(cause)
}
}
else {
HandleDestructionAwareness(target, playerGUID, cause)
}
zone.VehicleEvents ! VehicleServiceMessage(zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health))
}
/**
* na
* @param target na
* @param attribution na
* @param lastShot na
*/
def HandleDestructionAwareness(target : ShieldGeneratorDeployable, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = {
target.Actor ! JammableUnit.ClearJammeredSound()
target.Actor ! JammableUnit.ClearJammeredStatus()
val zone = target.Zone
AnnounceDestroyDeployable(target, None)
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.Destroy(target.GUID, attribution, attribution, target.Position))
}
def AnnounceDestroyDeployable(target : PlanetSideServerObject with Deployable, time : Option[FiniteDuration]) : Unit = {
val zone = target.Zone
target.OwnerName match {
case Some(owner) =>
target.OwnerName = None
zone.LocalEvents ! LocalServiceMessage(owner, LocalAction.AlertDestroyDeployable(PlanetSideGUID(0), target))
case None => ;
}
zone.LocalEvents ! LocalServiceMessage(s"${target.Faction}", LocalAction.DeployableMapIcon(
PlanetSideGUID(0),
DeploymentAction.Dismiss,
DeployableInfo(target.GUID, Deployable.Icon(target.Definition.Item), target.Position, PlanetSideGUID(0)))
)
zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(target), zone))
zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(target, zone, time))
}
}

View file

@ -2,7 +2,7 @@
package net.psforever.objects
import net.psforever.objects.ce.{SimpleDeployable, TelepadLike}
import net.psforever.objects.definition.DeployableDefinition
import net.psforever.objects.definition.SimpleDeployableDefinition
class TelepadDeployable(ddef : DeployableDefinition) extends SimpleDeployable(ddef)
class TelepadDeployable(ddef : SimpleDeployableDefinition) extends SimpleDeployable(ddef)
with TelepadLike

View file

@ -2,6 +2,6 @@
package net.psforever.objects
import net.psforever.objects.ce.SimpleDeployable
import net.psforever.objects.definition.DeployableDefinition
import net.psforever.objects.definition.SimpleDeployableDefinition
class TrapDeployable(cdef : DeployableDefinition) extends SimpleDeployable(cdef)
class TrapDeployable(cdef : SimpleDeployableDefinition) extends SimpleDeployable(cdef)

View file

@ -2,65 +2,59 @@
package net.psforever.objects
import akka.actor.{Actor, ActorContext, Props}
import net.psforever.objects.ce.{Deployable, DeployedItem}
import net.psforever.objects.definition.{BaseDeployableDefinition, DeployableDefinition}
import net.psforever.objects.ballistics.ResolvedProjectile
import net.psforever.objects.ce.{ComplexDeployable, Deployable, DeployedItem}
import net.psforever.objects.definition.{ComplexDeployableDefinition, SimpleDeployableDefinition}
import net.psforever.objects.definition.converter.SmallTurretConverter
import net.psforever.objects.equipment.{JammableMountedWeapons, JammableUnit}
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.mount.MountableBehavior
import net.psforever.objects.serverobject.turret.{TurretDefinition, WeaponTurret}
import net.psforever.objects.vital.{StandardResolutions, StandardVehicleDamage, StandardVehicleResistance, Vitality}
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{DeployableInfo, DeploymentAction, PlanetSideGUID}
import services.{RemoverActor, Service}
import services.avatar.{AvatarAction, AvatarServiceMessage}
import services.local.{LocalAction, LocalServiceMessage}
import services.vehicle.{VehicleAction, VehicleServiceMessage}
class TurretDeployable(tdef : TurretDeployableDefinition) extends PlanetSideServerObject
with Deployable
class TurretDeployable(tdef : TurretDeployableDefinition) extends ComplexDeployable(tdef)
with WeaponTurret
with JammableUnit
with Hackable {
private var shields : Int = 0
WeaponTurret.LoadDefinition(this) //calls the equivalent of Health = Definition.MaxHealth
def MaxHealth : Int = Definition.MaxHealth
def Shields : Int = shields
def Shields_=(toShields : Int) : Int = {
shields = math.min(math.max(0, toShields), MaxShields)
Shields
}
def MaxShields : Int = {
0//Definition.MaxShields
}
def MountPoints : Map[Int, Int] = Definition.MountPoints.toMap
//override to clarify inheritance conflict
override def Health : Int = super[Deployable].Health
override def Health : Int = super[ComplexDeployable].Health
//override to clarify inheritance conflict
override def Health_=(toHealth : Int) : Int = super[Deployable].Health_=(toHealth)
override def Health_=(toHealth : Int) : Int = super[ComplexDeployable].Health_=(toHealth)
override def Definition = tdef
}
class TurretDeployableDefinition(private val objectId : Int) extends TurretDefinition(objectId)
with BaseDeployableDefinition {
private val item = DeployedItem(objectId) //let throw NoSuchElementException
class TurretDeployableDefinition(private val objectId : Int) extends ComplexDeployableDefinition(objectId)
with TurretDefinition {
Name = "turret_deployable"
Packet = new SmallTurretConverter
def Item : DeployedItem.Value = item
Damage = StandardVehicleDamage
Resistance = StandardVehicleResistance
Model = StandardResolutions.FacilityTurrets
//override to clarify inheritance conflict
override def MaxHealth : Int = super[BaseDeployableDefinition].MaxHealth
override def MaxHealth : Int = super[ComplexDeployableDefinition].MaxHealth
//override to clarify inheritance conflict
override def MaxHealth_=(max : Int) : Int = super[BaseDeployableDefinition].MaxHealth_=(max)
override def MaxHealth_=(max : Int) : Int = super[ComplexDeployableDefinition].MaxHealth_=(max)
override def Initialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = {
obj.Actor = context.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}")
}
override def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = {
DeployableDefinition.SimpleUninitialize(obj, context)
SimpleDeployableDefinition.SimpleUninitialize(obj, context)
}
}
@ -74,16 +68,134 @@ object TurretDeployableDefinition {
class TurretControl(turret : TurretDeployable) extends Actor
with FactionAffinityBehavior.Check
with JammableMountedWeapons //note: jammable status is reported as vehicle events, not local events
with MountableBehavior.Mount
with MountableBehavior.Dismount {
def MountableObject = turret //do not add type!
def JammableObject = turret
def FactionObject : FactionAffinity = turret
def receive : Receive = checkBehavior
.orElse(jammableBehavior)
.orElse(dismountBehavior)
.orElse(turretMountBehavior)
.orElse {
case Vitality.Damage(damage_func) => //note: damage status is reported as vehicle events, not local events
if(turret.Health > 0) {
val originalHealth = turret.Health
val cause = damage_func(turret)
val health = turret.Health
val damageToHealth = originalHealth - health
TurretControl.HandleDamageResolution(turret, cause, damageToHealth)
if(damageToHealth > 0) {
val name = turret.Actor.toString
val slashPoint = name.lastIndexOf("/")
org.log4s.getLogger("DamageResolution").info(s"${name.substring(slashPoint + 1, name.length - 1)}: BEFORE=$originalHealth, AFTER=$health, CHANGE=$damageToHealth")
}
}
case _ => ;
}
}
object TurretControl {
import scala.concurrent.duration._
/**
* na
* @param target na
*/
def HandleDamageResolution(target : TurretDeployable, cause : ResolvedProjectile, damage : Int) : Unit = {
val zone = target.Zone
val targetGUID = target.GUID
val playerGUID = zone.LivePlayers.find { p => cause.projectile.owner.Name.equals(p.Name) } match {
case Some(player) => player.GUID
case _ => PlanetSideGUID(0)
}
if(target.Health > 0) {
//activity on map
if(damage > 0) {
zone.Activity ! Zone.HotSpot.Activity(cause.target, cause.projectile.owner, cause.hit_pos)
//alert occupants to damage source
HandleDamageAwareness(target, playerGUID, cause)
}
if(cause.projectile.profile.JammerProjectile) {
target.Actor ! JammableUnit.Jammered(cause)
}
}
else {
//alert to turret death (hence, occupants' deaths)
HandleDestructionAwareness(target, playerGUID, cause)
}
zone.VehicleEvents ! VehicleServiceMessage(zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health))
}
/**
* na
* @param target na
* @param attribution na
* @param lastShot na
*/
def HandleDamageAwareness(target : TurretDeployable, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = {
val zone = target.Zone
//alert occupants to damage source
target.Seats.values.filter(seat => {
seat.isOccupied && seat.Occupant.get.isAlive
}).foreach(seat => {
val tplayer = seat.Occupant.get
zone.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(attribution, tplayer.GUID))
})
}
/**
* na
* @param target na
* @param attribution na
* @param lastShot na
*/
def HandleDestructionAwareness(target : TurretDeployable, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = {
target.Actor ! JammableUnit.ClearJammeredSound()
target.Actor ! JammableUnit.ClearJammeredStatus()
val zone = target.Zone
val continentId = zone.Id
//alert to vehicle death (hence, occupants' deaths)
target.Seats.values.filter(seat => {
seat.isOccupied && seat.Occupant.get.isAlive
}).foreach(seat => {
val tplayer = seat.Occupant.get
val tplayerGUID = tplayer.GUID
zone.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID))
zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self
})
//vehicle wreckage has no weapons
target.Weapons.values
.filter {
_.Equipment.nonEmpty
}
.foreach(slot => {
val wep = slot.Equipment.get
zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID))
})
AnnounceDestroyDeployable(target, None)
zone.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.Destroy(target.GUID, attribution, attribution, target.Position))
}
def AnnounceDestroyDeployable(target : PlanetSideServerObject with Deployable, time : Option[FiniteDuration]) : Unit = {
val zone = target.Zone
target.OwnerName match {
case Some(owner) =>
target.OwnerName = None
zone.LocalEvents ! LocalServiceMessage(owner, LocalAction.AlertDestroyDeployable(PlanetSideGUID(0), target))
case None => ;
}
zone.LocalEvents ! LocalServiceMessage(s"${target.Faction}", LocalAction.DeployableMapIcon(
PlanetSideGUID(0),
DeploymentAction.Dismiss,
DeployableInfo(target.GUID, Deployable.Icon(target.Definition.Item), target.Position, PlanetSideGUID(0)))
)
zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(target), zone))
zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(target, zone, time))
}
}

View file

@ -3,7 +3,7 @@ package net.psforever.objects.ballistics
import net.psforever.objects.ce.{ComplexDeployable, SimpleDeployable}
import net.psforever.objects.definition.ObjectDefinition
import net.psforever.objects.{PlanetSideGameObject, Player, TurretDeployable, Vehicle}
import net.psforever.objects.{PlanetSideGameObject, Player, Vehicle}
import net.psforever.objects.entity.WorldEntity
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.vital.resistance.ResistanceProfile
@ -34,7 +34,6 @@ object SourceEntry {
case obj : Player => PlayerSource(obj)
case obj : Vehicle => VehicleSource(obj)
case obj : ComplexDeployable => ComplexDeployableSource(obj)
case obj : TurretDeployable => ComplexDeployableSource(obj)
case obj : SimpleDeployable => DeployableSource(obj)
case _ => ObjectSource(target)
}

View file

@ -1,10 +1,10 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.ce
import net.psforever.objects.definition.DeployableDefinition
import net.psforever.objects.definition.ComplexDeployableDefinition
import net.psforever.objects.serverobject.PlanetSideServerObject
abstract class ComplexDeployable(cdef : DeployableDefinition) extends PlanetSideServerObject
abstract class ComplexDeployable(cdef : ComplexDeployableDefinition) extends PlanetSideServerObject
with Deployable {
Health = Definition.MaxHealth

View file

@ -5,12 +5,14 @@ import net.psforever.objects._
import net.psforever.objects.definition.{BaseDeployableDefinition, ObjectDefinition}
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.vital.{DamageResistanceModel, Vitality}
import net.psforever.packet.game.{DeployableIcon, PlanetSideGUID}
import net.psforever.objects.zones.ZoneAware
import net.psforever.packet.game.DeployableIcon
import net.psforever.types.PlanetSideEmpire
trait Deployable extends FactionAffinity
with Vitality
with OwnableByPlayer {
with OwnableByPlayer
with ZoneAware {
this : PlanetSideGameObject =>
private var health : Int = 1
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL

View file

@ -2,9 +2,9 @@
package net.psforever.objects.ce
import net.psforever.objects.PlanetSideGameObject
import net.psforever.objects.definition.DeployableDefinition
import net.psforever.objects.definition.SimpleDeployableDefinition
abstract class SimpleDeployable(cdef : DeployableDefinition) extends PlanetSideGameObject
abstract class SimpleDeployable(cdef : SimpleDeployableDefinition) extends PlanetSideGameObject
with Deployable {
Health = Definition.MaxHealth

View file

@ -7,7 +7,7 @@ import net.psforever.objects.ce.{Deployable, DeployableCategory, DeployedItem}
import net.psforever.objects.definition.converter.SmallDeployableConverter
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
import net.psforever.objects.vital.{DamageResistanceModel, NoResistanceSelection, StandardDeployableDamage, StandardResistanceProfile}
import net.psforever.objects.vital.{DamageResistanceModel, NoResistanceSelection, StandardDeployableDamage}
import scala.concurrent.duration._
@ -53,7 +53,7 @@ trait BaseDeployableDefinition extends DamageResistanceModel
def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) : Unit = { }
}
class DeployableDefinition(private val objectId : Int) extends ObjectDefinition(objectId)
class SimpleDeployableDefinition(private val objectId : Int) extends ObjectDefinition(objectId)
with BaseDeployableDefinition {
private val item = DeployedItem(objectId) //let throw NoSuchElementException
Packet = new SmallDeployableConverter
@ -61,9 +61,16 @@ class DeployableDefinition(private val objectId : Int) extends ObjectDefinition(
def Item : DeployedItem.Value = item
}
object DeployableDefinition {
def apply(item : DeployedItem.Value) : DeployableDefinition =
new DeployableDefinition(item.id)
abstract class ComplexDeployableDefinition(private val objectId : Int) extends ObjectDefinition(objectId)
with BaseDeployableDefinition {
private val item = DeployedItem(objectId) //let throw NoSuchElementException
def Item : DeployedItem.Value = item
}
object SimpleDeployableDefinition {
def apply(item : DeployedItem.Value) : SimpleDeployableDefinition =
new SimpleDeployableDefinition(item.id)
def SimpleUninitialize(obj : PlanetSideGameObject, context : ActorContext) : Unit = { }

View file

@ -65,7 +65,17 @@ trait JammableBehavior {
def JammableObject : PlanetSideServerObject with JammableUnit with ZoneAware
def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit
def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit = target match {
case obj : PlanetSideServerObject =>
val radius = cause.projectile.profile.DamageRadius
JammingUnit.FindJammerDuration(cause.projectile.profile, obj) match {
case Some(dur) if Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius =>
StartJammeredSound(obj)
StartJammeredStatus(obj, dur)
case _ => ;
}
case _ => ;
}
def StartJammeredSound(target : Any, dur : Int = 30000) : Unit = {
import scala.concurrent.ExecutionContext.Implicits.global
@ -89,7 +99,7 @@ trait JammableBehavior {
jammeredStatusTimer.cancel
}
def jammableBehavior : Receive = {
val jammableBehavior : Receive = {
case JammableUnit.Jammered(cause) =>
TryJammerEffectActivate(JammableObject, cause)
@ -101,21 +111,9 @@ trait JammableBehavior {
}
}
trait JammableMountedWeapons extends Actor with JammableBehavior {
trait JammableMountedWeapons extends JammableBehavior {
_ : Actor =>
def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit = target match {
case obj : PlanetSideServerObject with MountedWeapons =>
val radius = cause.projectile.profile.DamageRadius
JammingUnit.FindJammerDuration(cause.projectile.profile, obj) match {
case Some(dur) if Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius =>
StartJammeredSound(obj)
StartJammeredStatus(obj, dur)
case _ => ;
}
case _ => ;
}
override def StartJammeredSound(target : Any, dur : Int) : Unit = target match {
case obj : PlanetSideServerObject with MountedWeapons =>
obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 1))

View file

@ -6,7 +6,7 @@ import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.types.Vector3
import net.psforever.objects.vital.{DamageResistanceModel, StandardResistanceProfile, Vitality}
class FacilityTurret(tDef : TurretDefinition) extends Amenity
class FacilityTurret(tDef : FacilityTurretDefinition) extends Amenity
with WeaponTurret
with JammableUnit
with Vitality
@ -55,7 +55,7 @@ class FacilityTurret(tDef : TurretDefinition) extends Amenity
def DamageModel = Definition.asInstanceOf[DamageResistanceModel]
def Definition : TurretDefinition = tDef
def Definition : FacilityTurretDefinition = tDef
}
object FacilityTurret {
@ -64,7 +64,7 @@ object FacilityTurret {
* @param tDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
* @return a `FacilityTurret` object
*/
def apply(tDef : TurretDefinition) : FacilityTurret = {
def apply(tDef : FacilityTurretDefinition) : FacilityTurret = {
new FacilityTurret(tDef)
}
@ -75,14 +75,14 @@ object FacilityTurret {
* @param context a context to allow the object to properly set up `ActorSystem` functionality
* @return the `MannedTurret` object
*/
def Constructor(tdef : TurretDefinition)(id : Int, context : ActorContext) : FacilityTurret = {
def Constructor(tdef : FacilityTurretDefinition)(id : Int, context : ActorContext) : FacilityTurret = {
import akka.actor.Props
val obj = FacilityTurret(tdef)
obj.Actor = context.actorOf(Props(classOf[FacilityTurretControl], obj), s"${tdef.Name}_$id")
obj
}
def Constructor(pos: Vector3, tdef : TurretDefinition)(id : Int, context : ActorContext) : FacilityTurret = {
def Constructor(pos: Vector3, tdef : FacilityTurretDefinition)(id : Int, context : ActorContext) : FacilityTurret = {
import akka.actor.Props
val obj = FacilityTurret(tdef)
obj.Position = pos

View file

@ -34,6 +34,7 @@ class FacilityTurretControl(turret : FacilityTurret) extends Actor
def FactionObject : FactionAffinity = turret
def receive : Receive = checkBehavior
.orElse(jammableBehavior)
.orElse(dismountBehavior)
.orElse {
case Mountable.TryMount(user, seat_num) =>

View file

@ -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
}

View file

@ -3,19 +3,18 @@ package net.psforever.objects.serverobject.turret
import net.psforever.objects.definition.{ObjectDefinition, ToolDefinition}
import net.psforever.objects.vehicles.Turrets
import net.psforever.objects.vital.{DamageResistanceModel, StandardResolutions, StandardVehicleDamage, StandardVehicleResistance}
import net.psforever.objects.vital.DamageResistanceModel
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
import scala.collection.mutable
/**
* The definition for any `MannedTurret`.
* @param objectId the object's identifier number
*/
class TurretDefinition(private val objectId : Int) extends ObjectDefinition(objectId)
with ResistanceProfileMutators
trait TurretDefinition extends ResistanceProfileMutators
with DamageResistanceModel {
Turrets(objectId) //let throw NoSuchElementException
odef : ObjectDefinition =>
Turrets(odef.ObjectId) //let throw NoSuchElementException
private var maxHealth : Int = 100
/* key - entry point index, value - seat index */
@ -29,9 +28,6 @@ class TurretDefinition(private val objectId : Int) extends ObjectDefinition(obje
/** creates internal ammunition reserves that can not become depleted
* see `MannedTurret.TurretAmmoBox` for details */
private var hasReserveAmmunition : Boolean = false
Damage = StandardVehicleDamage
Resistance = StandardVehicleResistance
Model = StandardResolutions.FacilityTurrets
def MaxHealth : Int = maxHealth

View file

@ -2,7 +2,7 @@
package net.psforever.objects.vehicles
import akka.actor.ActorContext
import net.psforever.objects.definition.DeployableDefinition
import net.psforever.objects.definition.SimpleDeployableDefinition
import net.psforever.objects._
import net.psforever.objects.ce.TelepadLike
import net.psforever.objects.serverobject.structures.Amenity
@ -193,7 +193,7 @@ object Utility {
* and allows it to serve as one of the terminal points of a Router-telepad teleportation system.
* @param ddef na
*/
class InternalTelepad(ddef : DeployableDefinition) extends Amenity
class InternalTelepad(ddef : SimpleDeployableDefinition) extends Amenity
with TelepadLike {
/** a link to the telepad that serves as the other endpoint of this teleportation system */
private var activeTelepad : Option[PlanetSideGUID] = None

View file

@ -25,6 +25,7 @@ class ZoneDeployableActor(zone : Zone, deployableList : ListBuffer[PlanetSideGam
case _ =>
obj.Definition.Initialize(obj, context)
}
obj.Zone = zone
sender ! Zone.Deployable.DeployableIsBuilt(obj, tool)
}

View file

@ -19,7 +19,7 @@ import scala.concurrent.duration._
class FacilityTurretTest extends Specification {
"FacilityTurretTest" should {
"define" in {
val obj = new TurretDefinition(480)
val obj = new FacilityTurretDefinition(480)
obj.Weapons mustEqual mutable.HashMap.empty[TurretUpgrade.Value, ToolDefinition]
obj.ReserveAmmunition mustEqual false
obj.FactionLocked mustEqual true
@ -152,7 +152,7 @@ class FacilityTurretControl3Test extends ActorTest {
class FacilityTurretControl4Test extends ActorTest {
val player = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val objDef = new TurretDefinition(480)
val objDef = new FacilityTurretDefinition(480)
objDef.FactionLocked = false
val obj = FacilityTurret(objDef)
obj.GUID = PlanetSideGUID(1)

View file

@ -915,16 +915,8 @@ class WorldSessionActor extends Actor
continent.Deployables ! Zone.Deployable.Dismiss(obj)
}
case WorldSessionActor.FinalizeDeployable(obj : TurretDeployable, tool, index) =>
//spitfires and deployable field turrets
StartBundlingPackets()
DeployableBuildActivity(obj)
CommonDestroyConstructionItem(tool, index)
FindReplacementConstructionItem(tool, index)
StopBundlingPackets()
case WorldSessionActor.FinalizeDeployable(obj : ComplexDeployable, tool, index) =>
//deployable_shield_generator
//spitfires and deployable field turrets and the deployable_shield_generator
StartBundlingPackets()
DeployableBuildActivity(obj)
CommonDestroyConstructionItem(tool, index)
@ -1017,7 +1009,7 @@ class WorldSessionActor extends Actor
StartBundlingPackets()
sendResponse(GenericObjectActionMessage(guid, 21)) //reset build cooldown
sendResponse(ObjectDeployedMessage.Failure(definition.Name))
log.warn(s"FinalizeDeployable: deployable ${definition.asInstanceOf[DeployableDefinition].Item}@$guid not handled by specific case")
log.warn(s"FinalizeDeployable: deployable ${definition.asInstanceOf[SimpleDeployableDefinition].Item}@$guid not handled by specific case")
log.warn(s"FinalizeDeployable: deployable will be cleaned up, but may not get unregistered properly")
TryDropConstructionTool(tool, index, obj.Position)
obj.Position = Vector3.Zero
@ -1133,18 +1125,6 @@ class WorldSessionActor extends Actor
AnnounceDestroyDeployable(target, Some(0 seconds))
}
case Vitality.DamageResolution(target : TurretDeployable, _) =>
HandleTurretDeployableDamageResolution(target)
case Vitality.DamageResolution(target : ComplexDeployable, _) =>
//shield_generators
val health = target.Health
val guid = target.GUID
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(guid, 0, health))
if(health <= 0) {
AnnounceDestroyDeployable(target, None)
}
case Vitality.DamageResolution(target : PlanetSideGameObject, _) =>
log.warn(s"Vital target ${target.Definition.Name} damage resolution not supported using this method")
@ -1243,22 +1223,19 @@ class WorldSessionActor extends Actor
sendResponse(GenericObjectActionMessage(guid, 9))
case AvatarResponse.EnvironmentalDamage(target, amount) =>
if(player.isAlive) {
if(player.isAlive && amount != 0) {
val armor = player.Armor
val capacitor = player.Capacitor
val originalHealth = player.Health
player.Health = player.Health - amount
player.Health = originalHealth - amount
sendResponse(PlanetsideAttributeMessage(target, 0, player.Health))
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(target, 0, player.Health))
damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth, AFTER=${player.Health}, CHANGE=$amount")
if(amount != 0) {
val playerGUID = player.GUID
sendResponse(PlanetsideAttributeMessage(playerGUID, 0, player.Health))
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 0, player.Health))
if(player.Health == 0 && player.isAlive) {
KillPlayer(player)
}
else {
//todo: History?
}
damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth/$armor/$capacitor, AFTER=${player.Health}/$armor/$capacitor, CHANGE=$amount/0/0")
if(player.Health == 0 && player.isAlive) {
KillPlayer(player)
}
else {
//todo: History?
}
}
@ -1274,19 +1251,17 @@ class WorldSessionActor extends Actor
val damageToHealth = originalHealth - health
val damageToArmor = originalArmor - armor
val damageToCapacitor = originalCapacitor - capacitor
damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth/$originalArmor/$originalCapacitor, AFTER=$health/$armor/$capacitor, CHANGE=$damageToHealth/$damageToArmor/$damageToCapacitor")
if(damageToHealth != 0 || damageToArmor != 0 || damageToCapacitor != 0) {
damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth/$originalArmor/$originalCapacitor, AFTER=$health/$armor/$capacitor, CHANGE=$damageToHealth/$damageToArmor/$damageToCapacitor")
val playerGUID = player.GUID
if(damageToHealth > 0) {
sendResponse(PlanetsideAttributeMessage(playerGUID, 0, health))
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 0, health))
}
if(damageToArmor > 0) {
sendResponse(PlanetsideAttributeMessage(playerGUID, 4, armor))
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 4, armor))
}
if(damageToCapacitor > 0) {
sendResponse(PlanetsideAttributeMessage(playerGUID, 7, capacitor))
}
@ -2933,40 +2908,6 @@ class WorldSessionActor extends Actor
msgs
}
/**
* na
* @param target na
*/
def HandleTurretDeployableDamageResolution(target : TurretDeployable) : Unit = {
//spitfires and field turrets
val health = target.Health
val guid = target.GUID
val continentId = continent.Id
if(health <= 0) {
//if occupants, kill them
target.Seats.values
.filter(seat => {
seat.isOccupied && seat.Occupant.get.isAlive
})
.foreach(seat => {
val tplayer = seat.Occupant.get
val tplayerGUID = tplayer.GUID
continent.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID))
continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self
})
//destroy weapons
target.Weapons.values
.map(slot => slot.Equipment)
.collect { case Some(weapon) =>
val wguid = weapon.GUID
sendResponse(ObjectDeleteMessage(wguid, 0))
continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(player.GUID, wguid))
}
AnnounceDestroyDeployable(target, None)
}
continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.PlanetsideAttribute(guid, 0, health))
}
/**
* na
* @param tplayer na
@ -8499,13 +8440,12 @@ class WorldSessionActor extends Actor
case obj : Player =>
//damage is synchronized on the target player's `WSA` (results distributed from there)
continent.AvatarEvents ! AvatarServiceMessage(obj.Name, AvatarAction.Damage(player.GUID, obj, func))
case obj : Vehicle =>
//damage is synchronized on the vehicle actor
obj.Actor ! Vitality.Damage(func)
case obj : FacilityTurret =>
//damage is synchronized on the turret actor
obj.Actor ! Vitality.Damage(func)
case obj : Deployable =>
case obj : Vehicle => obj.Actor ! Vitality.Damage(func)
case obj : FacilityTurret => obj.Actor ! Vitality.Damage(func)
case obj : ComplexDeployable => obj.Actor ! Vitality.Damage(func)
case obj : SimpleDeployable =>
//damage is synchronized on `LSA` (results returned to and distributed from this `WSA`)
continent.LocalEvents ! Vitality.DamageOn(obj, func)
case _ => ;
@ -10216,7 +10156,7 @@ class WorldSessionActor extends Actor
}
}
def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit = target match {
override def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit = target match {
case obj : Player =>
val radius = cause.projectile.profile.DamageRadius
JammingUnit.FindJammerDuration(cause.projectile.profile, obj) match {