mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-15 00:14:40 +00:00
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:
parent
a568e52590
commit
fee001596f
22 changed files with 378 additions and 177 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects
|
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
|
private var trigger : Option[BoomerTrigger] = None
|
||||||
|
|
||||||
def Trigger : Option[BoomerTrigger] = trigger
|
def Trigger : Option[BoomerTrigger] = trigger
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@
|
||||||
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
|
||||||
|
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
|
private var exploded : Boolean = false
|
||||||
|
|
||||||
def Exploded : Boolean = exploded
|
def Exploded : Boolean = exploded
|
||||||
|
|
|
||||||
|
|
@ -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 = 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)
|
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 = 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)
|
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)
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@
|
||||||
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
|
||||||
|
import net.psforever.objects.equipment.JammableUnit
|
||||||
import net.psforever.objects.serverobject.hackable.Hackable
|
import net.psforever.objects.serverobject.hackable.Hackable
|
||||||
|
|
||||||
class SensorDeployable(cdef : DeployableDefinition) extends SimpleDeployable(cdef)
|
class SensorDeployable(cdef : SimpleDeployableDefinition) extends SimpleDeployable(cdef)
|
||||||
with Hackable
|
with Hackable
|
||||||
|
with JammableUnit
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,139 @@
|
||||||
// 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.{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)
|
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 _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,59 @@
|
||||||
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.{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
|
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 +68,134 @@ 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 {
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 = { }
|
||||||
|
|
||||||
|
|
@ -65,7 +65,17 @@ trait JammableBehavior {
|
||||||
|
|
||||||
def JammableObject : PlanetSideServerObject with JammableUnit with ZoneAware
|
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 = {
|
def StartJammeredSound(target : Any, dur : Int = 30000) : Unit = {
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
|
@ -89,7 +99,7 @@ trait JammableBehavior {
|
||||||
jammeredStatusTimer.cancel
|
jammeredStatusTimer.cancel
|
||||||
}
|
}
|
||||||
|
|
||||||
def jammableBehavior : Receive = {
|
val jammableBehavior : Receive = {
|
||||||
case JammableUnit.Jammered(cause) =>
|
case JammableUnit.Jammered(cause) =>
|
||||||
TryJammerEffectActivate(JammableObject, cause)
|
TryJammerEffectActivate(JammableObject, cause)
|
||||||
|
|
||||||
|
|
@ -101,21 +111,9 @@ trait JammableBehavior {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait JammableMountedWeapons extends Actor with JammableBehavior {
|
trait JammableMountedWeapons extends JammableBehavior {
|
||||||
_ : Actor =>
|
_ : 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 {
|
override def StartJammeredSound(target : Any, dur : Int) : Unit = target match {
|
||||||
case obj : PlanetSideServerObject with MountedWeapons =>
|
case obj : PlanetSideServerObject with MountedWeapons =>
|
||||||
obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 1))
|
obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 1))
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ 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 JammableUnit
|
||||||
with Vitality
|
with Vitality
|
||||||
|
|
@ -55,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 {
|
||||||
|
|
@ -64,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,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
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ class FacilityTurretControl(turret : FacilityTurret) extends Actor
|
||||||
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) =>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -915,16 +915,8 @@ class WorldSessionActor extends Actor
|
||||||
continent.Deployables ! Zone.Deployable.Dismiss(obj)
|
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) =>
|
case WorldSessionActor.FinalizeDeployable(obj : ComplexDeployable, tool, index) =>
|
||||||
//deployable_shield_generator
|
//spitfires and deployable field turrets and the deployable_shield_generator
|
||||||
StartBundlingPackets()
|
StartBundlingPackets()
|
||||||
DeployableBuildActivity(obj)
|
DeployableBuildActivity(obj)
|
||||||
CommonDestroyConstructionItem(tool, index)
|
CommonDestroyConstructionItem(tool, index)
|
||||||
|
|
@ -1017,7 +1009,7 @@ class WorldSessionActor extends Actor
|
||||||
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
|
||||||
|
|
@ -1133,18 +1125,6 @@ class WorldSessionActor extends Actor
|
||||||
AnnounceDestroyDeployable(target, Some(0 seconds))
|
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, _) =>
|
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")
|
||||||
|
|
||||||
|
|
@ -1243,22 +1223,19 @@ class WorldSessionActor extends Actor
|
||||||
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?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1274,19 +1251,17 @@ class WorldSessionActor extends Actor
|
||||||
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))
|
||||||
}
|
}
|
||||||
|
|
@ -2933,40 +2908,6 @@ class WorldSessionActor extends Actor
|
||||||
msgs
|
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
|
* na
|
||||||
* @param tplayer na
|
* @param tplayer na
|
||||||
|
|
@ -8499,13 +8440,12 @@ class WorldSessionActor extends Actor
|
||||||
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
|
case obj : Vehicle => obj.Actor ! Vitality.Damage(func)
|
||||||
obj.Actor ! Vitality.Damage(func)
|
case obj : FacilityTurret => obj.Actor ! Vitality.Damage(func)
|
||||||
case obj : FacilityTurret =>
|
case obj : ComplexDeployable => obj.Actor ! Vitality.Damage(func)
|
||||||
//damage is synchronized on the turret actor
|
|
||||||
obj.Actor ! Vitality.Damage(func)
|
case obj : SimpleDeployable =>
|
||||||
case obj : Deployable =>
|
|
||||||
//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 _ => ;
|
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 =>
|
case obj : Player =>
|
||||||
val radius = cause.projectile.profile.DamageRadius
|
val radius = cause.projectile.profile.DamageRadius
|
||||||
JammingUnit.FindJammerDuration(cause.projectile.profile, obj) match {
|
JammingUnit.FindJammerDuration(cause.projectile.profile, obj) match {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue