mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-04-29 08:15:29 +00:00
powered amenity control agent; terminals, proximity terminals, spawn tubes, implant mechs, facility turrets, and painfields demonstrate this behavior
This commit is contained in:
parent
35b07f897d
commit
ef0d18d214
11 changed files with 392 additions and 174 deletions
|
|
@ -7,6 +7,7 @@ import akka.{actor => classic}
|
||||||
import net.psforever.actors.commands.NtuCommand
|
import net.psforever.actors.commands.NtuCommand
|
||||||
import net.psforever.objects.{CommonNtuContainer, NtuContainer}
|
import net.psforever.objects.{CommonNtuContainer, NtuContainer}
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
import net.psforever.objects.serverobject.generator.Generator
|
||||||
import net.psforever.objects.serverobject.structures.{Amenity, Building, StructureType, WarpGate}
|
import net.psforever.objects.serverobject.structures.{Amenity, Building, StructureType, WarpGate}
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.persistence
|
import net.psforever.persistence
|
||||||
|
|
@ -49,6 +50,10 @@ object BuildingActor {
|
||||||
final case class SuppliedWithNtu() extends Command
|
final case class SuppliedWithNtu() extends Command
|
||||||
|
|
||||||
final case class NtuDepleted() extends Command
|
final case class NtuDepleted() extends Command
|
||||||
|
|
||||||
|
final case class PowerOn() extends Command
|
||||||
|
|
||||||
|
final case class PowerOff() extends Command
|
||||||
}
|
}
|
||||||
|
|
||||||
class BuildingActor(
|
class BuildingActor(
|
||||||
|
|
@ -155,6 +160,14 @@ class BuildingActor(
|
||||||
galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage()))
|
galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage()))
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
|
|
||||||
|
case AmenityStateChange(obj: Generator) =>
|
||||||
|
//TODO when parameter object is finally immutable, perform analysis on it to determine specific actions
|
||||||
|
val msg = if(obj.Destroyed) BuildingActor.PowerOff() else BuildingActor.PowerOn()
|
||||||
|
building.Amenities.foreach { _.Actor ! msg }
|
||||||
|
//update the map
|
||||||
|
galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage()))
|
||||||
|
Behaviors.same
|
||||||
|
|
||||||
case AmenityStateChange(_) =>
|
case AmenityStateChange(_) =>
|
||||||
//TODO when parameter object is finally immutable, perform analysis on it to determine specific actions
|
//TODO when parameter object is finally immutable, perform analysis on it to determine specific actions
|
||||||
//for now, just update the map
|
//for now, just update the map
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ trait SpawnPoint {
|
||||||
*/
|
*/
|
||||||
def Definition: ObjectDefinition with SpawnPointDefinition
|
def Definition: ObjectDefinition with SpawnPointDefinition
|
||||||
|
|
||||||
def Offline: Boolean = psso.Destroyed
|
def isOffline: Boolean = psso.Destroyed
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine a specific position and orientation in which to spawn the target.
|
* Determine a specific position and orientation in which to spawn the target.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.implantmech
|
package net.psforever.objects.serverobject.implantmech
|
||||||
|
|
||||||
import akka.actor.Actor
|
|
||||||
import net.psforever.objects.ballistics.ResolvedProjectile
|
import net.psforever.objects.ballistics.ResolvedProjectile
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player, SimpleItem}
|
import net.psforever.objects.{GlobalDefinitions, Player, SimpleItem}
|
||||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||||
|
|
@ -11,14 +10,15 @@ import net.psforever.objects.serverobject.damage.Damageable.Target
|
||||||
import net.psforever.objects.serverobject.damage.{Damageable, DamageableEntity, DamageableMountable}
|
import net.psforever.objects.serverobject.damage.{Damageable, DamageableEntity, DamageableMountable}
|
||||||
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
|
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
|
||||||
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableEntity}
|
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableEntity}
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityControl}
|
||||||
|
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An `Actor` that handles messages being dispatched to a specific `ImplantTerminalMech`.
|
* An `Actor` that handles messages being dispatched to a specific `ImplantTerminalMech`.
|
||||||
* @param mech the "mech" object being governed
|
* @param mech the "mech" object being governed
|
||||||
*/
|
*/
|
||||||
class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
||||||
extends Actor
|
extends PoweredAmenityControl
|
||||||
with FactionAffinityBehavior.Check
|
with FactionAffinityBehavior.Check
|
||||||
with MountableBehavior.Mount
|
with MountableBehavior.Mount
|
||||||
with MountableBehavior.Dismount
|
with MountableBehavior.Dismount
|
||||||
|
|
@ -33,17 +33,19 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
||||||
def RepairableObject = mech
|
def RepairableObject = mech
|
||||||
def AutoRepairObject = mech
|
def AutoRepairObject = mech
|
||||||
|
|
||||||
def receive: Receive =
|
def commonBehavior: Receive =
|
||||||
checkBehavior
|
checkBehavior
|
||||||
.orElse(mountBehavior)
|
|
||||||
.orElse(dismountBehavior)
|
.orElse(dismountBehavior)
|
||||||
.orElse(hackableBehavior)
|
|
||||||
.orElse(takesDamage)
|
.orElse(takesDamage)
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
.orElse(autoRepairBehavior)
|
.orElse(autoRepairBehavior)
|
||||||
|
|
||||||
|
def poweredStateLogic : Receive =
|
||||||
|
commonBehavior
|
||||||
|
.orElse(mountBehavior)
|
||||||
.orElse {
|
.orElse {
|
||||||
case CommonMessages.Use(player, Some(item: SimpleItem))
|
case CommonMessages.Use(player, Some(item: SimpleItem))
|
||||||
if item.Definition == GlobalDefinitions.remote_electronics_kit =>
|
if item.Definition == GlobalDefinitions.remote_electronics_kit =>
|
||||||
//TODO setup certifications check
|
//TODO setup certifications check
|
||||||
mech.Owner match {
|
mech.Owner match {
|
||||||
case b: Building if (b.Faction != player.Faction || b.CaptureTerminalIsHacked) && mech.HackedBy.isEmpty =>
|
case b: Building if (b.Faction != player.Faction || b.CaptureTerminalIsHacked) && mech.HackedBy.isEmpty =>
|
||||||
|
|
@ -57,6 +59,12 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def unpoweredStateLogic: Receive =
|
||||||
|
commonBehavior
|
||||||
|
.orElse {
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
override protected def MountTest(
|
override protected def MountTest(
|
||||||
obj: PlanetSideServerObject with Mountable,
|
obj: PlanetSideServerObject with Mountable,
|
||||||
seatNumber: Int,
|
seatNumber: Int,
|
||||||
|
|
@ -98,4 +106,25 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
||||||
}
|
}
|
||||||
newHealth
|
newHealth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def powerTurnOffCallback(): Unit = {
|
||||||
|
//kick all occupants
|
||||||
|
val guid = mech.GUID
|
||||||
|
val zone = mech.Zone
|
||||||
|
val zoneId = zone.id
|
||||||
|
val events = zone.VehicleEvents
|
||||||
|
mech.Seats.values.foreach(seat =>
|
||||||
|
seat.Occupant match {
|
||||||
|
case Some(player) =>
|
||||||
|
seat.Occupant = None
|
||||||
|
player.VehicleSeated = None
|
||||||
|
if (player.HasGUID) {
|
||||||
|
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, false, guid))
|
||||||
|
}
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def powerTurnOnCallback(): Unit = { }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
package net.psforever.objects.serverobject.painbox
|
package net.psforever.objects.serverobject.painbox
|
||||||
|
|
||||||
import akka.actor.{Actor, Cancellable}
|
import akka.actor.Cancellable
|
||||||
|
import net.psforever.actors.zone.BuildingActor
|
||||||
import net.psforever.objects.serverobject.doors.Door
|
import net.psforever.objects.serverobject.doors.Door
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityControl}
|
||||||
import net.psforever.objects.{Default, GlobalDefinitions}
|
import net.psforever.objects.{Default, GlobalDefinitions}
|
||||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
|
@ -10,7 +11,7 @@ import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
class PainboxControl(painbox: Painbox) extends Actor {
|
class PainboxControl(painbox: Painbox) extends PoweredAmenityControl {
|
||||||
private[this] val log = org.log4s.getLogger(s"Painbox")
|
private[this] val log = org.log4s.getLogger(s"Painbox")
|
||||||
var painboxTick: Cancellable = Default.Cancellable
|
var painboxTick: Cancellable = Default.Cancellable
|
||||||
var nearestDoor: Option[Door] = None
|
var nearestDoor: Option[Door] = None
|
||||||
|
|
@ -20,149 +21,167 @@ class PainboxControl(painbox: Painbox) extends Actor {
|
||||||
|
|
||||||
var disabled = false // Temporary to disable cavern non-radius fields
|
var disabled = false // Temporary to disable cavern non-radius fields
|
||||||
|
|
||||||
def receive: Receive = {
|
val initialStartup: Unit = {
|
||||||
case "startup" =>
|
if (painbox.Definition.HasNearestDoorDependency) {
|
||||||
if (painbox.Definition.HasNearestDoorDependency) {
|
(painbox.Owner match {
|
||||||
(painbox.Owner match {
|
case obj : Building =>
|
||||||
case obj: Building =>
|
obj.Amenities
|
||||||
obj.Amenities
|
.collect { case door : Door => door }
|
||||||
.collect { case door: Door => door }
|
.sortBy(door => Vector3.DistanceSquared(painbox.Position, door.Position))
|
||||||
.sortBy(door => Vector3.DistanceSquared(painbox.Position, door.Position))
|
.headOption
|
||||||
.headOption
|
case _ =>
|
||||||
case _ =>
|
None
|
||||||
None
|
}) match {
|
||||||
}) match {
|
case door@Some(_) =>
|
||||||
case door @ Some(_) =>
|
nearestDoor = door
|
||||||
nearestDoor = door
|
case _ =>
|
||||||
case _ =>
|
log.error(
|
||||||
log.error(
|
s"Painbox ${painbox.GUID} on ${painbox.Owner.Continent} - ${painbox.Position} can not find a door that it is dependent on"
|
||||||
s"Painbox ${painbox.GUID} on ${painbox.Owner.Continent} - ${painbox.Position} can not find a door that it is dependent on"
|
)
|
||||||
)
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (painbox.Definition.Radius == 0f) {
|
||||||
|
if (painbox.Owner.Continent.matches("c[0-9]")) {
|
||||||
|
// todo: handle non-radius painboxes in caverns properly
|
||||||
|
log.warn(s"Skipping initialization of ${painbox.GUID} on ${painbox.Owner.Continent} - ${painbox.Position}")
|
||||||
|
disabled = true
|
||||||
}
|
}
|
||||||
} else {
|
else {
|
||||||
if (painbox.Definition.Radius == 0f) {
|
painbox.Owner match {
|
||||||
if (painbox.Owner.Continent.matches("c[0-9]")) {
|
case obj : Building =>
|
||||||
// todo: handle non-radius painboxes in caverns properly
|
val planarRange = 16.5f
|
||||||
log.warn(s"Skipping initialization of ${painbox.GUID} on ${painbox.Owner.Continent} - ${painbox.Position}")
|
val aboveRange = 5
|
||||||
disabled = true
|
val belowRange = 5
|
||||||
} else {
|
// Find amenities within the specified range
|
||||||
painbox.Owner match {
|
val nearbyAmenities = obj.Amenities
|
||||||
case obj: Building =>
|
.filter(amenity =>
|
||||||
val planarRange = 16.5f
|
amenity.Position != Vector3.Zero
|
||||||
val aboveRange = 5
|
&& (amenity.Definition == GlobalDefinitions.mb_locker
|
||||||
val belowRange = 5
|
|| amenity.Definition == GlobalDefinitions.respawn_tube
|
||||||
|
|| amenity.Definition == GlobalDefinitions.spawn_terminal
|
||||||
|
|| amenity.Definition == GlobalDefinitions.order_terminal
|
||||||
|
|| amenity.Definition == GlobalDefinitions.door)
|
||||||
|
&& amenity.Position.x > painbox.Position.x - planarRange && amenity.Position.x < painbox.Position.x + planarRange
|
||||||
|
&& amenity.Position.y > painbox.Position.y - planarRange && amenity.Position.y < painbox.Position.y + planarRange
|
||||||
|
&& amenity.Position.z > painbox.Position.z - belowRange && amenity.Position.z < painbox.Position.z + aboveRange
|
||||||
|
)
|
||||||
|
|
||||||
// Find amenities within the specified range
|
// Calculate bounding box of amenities
|
||||||
val nearbyAmenities = obj.Amenities
|
bBoxMinCorner = Vector3(
|
||||||
.filter(amenity =>
|
nearbyAmenities.minBy(amenity => amenity.Position.x).Position.x,
|
||||||
amenity.Position != Vector3.Zero
|
nearbyAmenities.minBy(amenity => amenity.Position.y).Position.y,
|
||||||
&& (amenity.Definition == GlobalDefinitions.mb_locker
|
nearbyAmenities.minBy(x => x.Position.z).Position.z
|
||||||
|| amenity.Definition == GlobalDefinitions.respawn_tube
|
)
|
||||||
|| amenity.Definition == GlobalDefinitions.spawn_terminal
|
bBoxMaxCorner = Vector3(
|
||||||
|| amenity.Definition == GlobalDefinitions.order_terminal
|
nearbyAmenities.maxBy(amenity => amenity.Position.x).Position.x,
|
||||||
|| amenity.Definition == GlobalDefinitions.door)
|
nearbyAmenities.maxBy(amenity => amenity.Position.y).Position.y,
|
||||||
&& amenity.Position.x > painbox.Position.x - planarRange && amenity.Position.x < painbox.Position.x + planarRange
|
painbox.Position.z
|
||||||
&& amenity.Position.y > painbox.Position.y - planarRange && amenity.Position.y < painbox.Position.y + planarRange
|
)
|
||||||
&& amenity.Position.z > painbox.Position.z - belowRange && amenity.Position.z < painbox.Position.z + aboveRange
|
bBoxMidPoint = Vector3(
|
||||||
)
|
(bBoxMinCorner.x + bBoxMaxCorner.x) / 2,
|
||||||
|
(bBoxMinCorner.y + bBoxMaxCorner.y) / 2,
|
||||||
// Calculate bounding box of amenities
|
(bBoxMinCorner.z + bBoxMaxCorner.z) / 2
|
||||||
bBoxMinCorner = Vector3(
|
)
|
||||||
nearbyAmenities.minBy(amenity => amenity.Position.x).Position.x,
|
case _ => None
|
||||||
nearbyAmenities.minBy(amenity => amenity.Position.y).Position.y,
|
|
||||||
nearbyAmenities.minBy(x => x.Position.z).Position.z
|
|
||||||
)
|
|
||||||
bBoxMaxCorner = Vector3(
|
|
||||||
nearbyAmenities.maxBy(amenity => amenity.Position.x).Position.x,
|
|
||||||
nearbyAmenities.maxBy(amenity => amenity.Position.y).Position.y,
|
|
||||||
painbox.Position.z
|
|
||||||
)
|
|
||||||
bBoxMidPoint = Vector3(
|
|
||||||
(bBoxMinCorner.x + bBoxMaxCorner.x) / 2,
|
|
||||||
(bBoxMinCorner.y + bBoxMaxCorner.y) / 2,
|
|
||||||
(bBoxMinCorner.z + bBoxMaxCorner.z) / 2
|
|
||||||
)
|
|
||||||
case _ => None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!disabled) {
|
if (!disabled) {
|
||||||
context.become(Stopped)
|
self ! BuildingActor.PowerOff()
|
||||||
}
|
}
|
||||||
|
|
||||||
case _ => ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def Running: Receive = {
|
var commonBehavior: Receive = {
|
||||||
|
case "startup" =>
|
||||||
|
if (bBoxMidPoint == Vector3.Zero) {
|
||||||
|
initialStartup()
|
||||||
|
}
|
||||||
|
|
||||||
case Painbox.Stop() =>
|
case Painbox.Stop() =>
|
||||||
context.become(Stopped)
|
|
||||||
painboxTick.cancel()
|
painboxTick.cancel()
|
||||||
painboxTick = Default.Cancellable
|
painboxTick = Default.Cancellable
|
||||||
|
}
|
||||||
|
|
||||||
case Painbox.Tick() =>
|
def poweredStateLogic: Receive =
|
||||||
//todo: Account for overlapping pain fields
|
commonBehavior
|
||||||
//todo: Pain module
|
.orElse {
|
||||||
//todo: REK boosting
|
case Painbox.Start() if isPowered =>
|
||||||
val guid = painbox.GUID
|
painboxTick.cancel()
|
||||||
val owner = painbox.Owner.asInstanceOf[Building]
|
painboxTick = context.system.scheduler.scheduleWithFixedDelay(0 seconds, 1 second, self, Painbox.Tick())
|
||||||
val faction = owner.Faction
|
|
||||||
if (
|
|
||||||
faction != PlanetSideEmpire.NEUTRAL && (nearestDoor match {
|
|
||||||
case Some(door) => door.Open.nonEmpty;
|
|
||||||
case _ => true
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
val events = painbox.Zone.AvatarEvents
|
|
||||||
val damage = painbox.Definition.Damage
|
|
||||||
val radius = painbox.Definition.Radius * painbox.Definition.Radius
|
|
||||||
val position = painbox.Position
|
|
||||||
|
|
||||||
if (painbox.Definition.Radius != 0f) {
|
case Painbox.Tick() =>
|
||||||
// Spherical pain field
|
//todo: Account for overlapping pain fields
|
||||||
owner.PlayersInSOI
|
//todo: Pain module
|
||||||
.collect {
|
//todo: REK boosting
|
||||||
case p
|
val guid = painbox.GUID
|
||||||
if p.Faction != faction
|
val owner = painbox.Owner.asInstanceOf[Building]
|
||||||
&& p.Health > 0
|
val faction = owner.Faction
|
||||||
&& Vector3.DistanceSquared(p.Position, position) < radius =>
|
if (
|
||||||
events ! AvatarServiceMessage(p.Name, AvatarAction.EnvironmentalDamage(p.GUID, guid, damage))
|
isPowered && faction != PlanetSideEmpire.NEUTRAL && (nearestDoor match {
|
||||||
}
|
case Some(door) => door.Open.nonEmpty;
|
||||||
} else {
|
case _ => true
|
||||||
// Bounding box pain field
|
})
|
||||||
owner.PlayersInSOI
|
) {
|
||||||
.collect {
|
val events = painbox.Zone.AvatarEvents
|
||||||
case p
|
val damage = painbox.Definition.Damage
|
||||||
if p.Faction != faction
|
val radius = painbox.Definition.Radius * painbox.Definition.Radius
|
||||||
&& p.Health > 0 =>
|
val position = painbox.Position
|
||||||
/*
|
|
||||||
This may be cpu intensive with a large number of players in SOI. Further performance tweaking may be required
|
if (painbox.Definition.Radius != 0f) {
|
||||||
The bounding box is calculated aligned to the world XY axis, instead of rotating the painbox corners to match the base rotation
|
// Spherical pain field
|
||||||
we instead rotate the player's current coordinates to match the base rotation, which allows for much simplified checking of if the player is
|
owner.PlayersInSOI
|
||||||
within the bounding box
|
.collect {
|
||||||
*/
|
case p
|
||||||
val playerRot =
|
if p.Faction != faction
|
||||||
Vector3.PlanarRotateAroundPoint(p.Position, bBoxMidPoint, painbox.Owner.Orientation.z.toRadians)
|
&& p.Health > 0
|
||||||
if (
|
&& Vector3.DistanceSquared(p.Position, position) < radius =>
|
||||||
bBoxMinCorner.x <= playerRot.x && playerRot.x <= bBoxMaxCorner.x && bBoxMinCorner.y <= playerRot.y && playerRot.y <= bBoxMaxCorner.y
|
events ! AvatarServiceMessage(p.Name, AvatarAction.EnvironmentalDamage(p.GUID, guid, damage))
|
||||||
&& playerRot.z >= bBoxMinCorner.z && playerRot.z <= bBoxMaxCorner.z
|
}
|
||||||
) {
|
} else {
|
||||||
events ! AvatarServiceMessage(p.Name, AvatarAction.EnvironmentalDamage(p.GUID, guid, damage))
|
// Bounding box pain field
|
||||||
|
owner.PlayersInSOI
|
||||||
|
.collect {
|
||||||
|
case p
|
||||||
|
if p.Faction != faction
|
||||||
|
&& p.Health > 0 =>
|
||||||
|
/*
|
||||||
|
This may be cpu intensive with a large number of players in SOI. Further performance tweaking may be required
|
||||||
|
The bounding box is calculated aligned to the world XY axis, instead of rotating the painbox corners to match the base rotation
|
||||||
|
we instead rotate the player's current coordinates to match the base rotation, which allows for much simplified checking of if the player is
|
||||||
|
within the bounding box
|
||||||
|
*/
|
||||||
|
val playerRot =
|
||||||
|
Vector3.PlanarRotateAroundPoint(p.Position, bBoxMidPoint, painbox.Owner.Orientation.z.toRadians)
|
||||||
|
if (
|
||||||
|
bBoxMinCorner.x <= playerRot.x && playerRot.x <= bBoxMaxCorner.x && bBoxMinCorner.y <= playerRot.y && playerRot.y <= bBoxMaxCorner.y
|
||||||
|
&& playerRot.z >= bBoxMinCorner.z && playerRot.z <= bBoxMaxCorner.z
|
||||||
|
) {
|
||||||
|
events ! AvatarServiceMessage(p.Name, AvatarAction.EnvironmentalDamage(p.GUID, guid, damage))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
case _ => ;
|
def unpoweredStateLogic: Receive =
|
||||||
|
commonBehavior
|
||||||
|
.orElse {
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
def powerTurnOffCallback(): Unit = {
|
||||||
|
self ! Painbox.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
def Stopped: Receive = {
|
def powerTurnOnCallback(): Unit = {
|
||||||
case Painbox.Start() =>
|
painbox.Owner match {
|
||||||
context.become(Running)
|
case b: Building if b.PlayersInSOI.nonEmpty =>
|
||||||
painboxTick.cancel()
|
self ! Painbox.Start()
|
||||||
painboxTick = context.system.scheduler.scheduleWithFixedDelay(0 seconds, 1 second, self, Painbox.Tick())
|
case _ => ;
|
||||||
|
}
|
||||||
case _ => ;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
// Copyright (c) 2020 PSForever
|
||||||
|
package net.psforever.objects.serverobject.structures
|
||||||
|
|
||||||
|
import akka.actor.Actor
|
||||||
|
import net.psforever.actors.zone.BuildingActor
|
||||||
|
|
||||||
|
trait PoweredAmenityControl extends Actor {
|
||||||
|
private var powered: Boolean = true
|
||||||
|
|
||||||
|
final def receive: Receive = powerOnCondition
|
||||||
|
|
||||||
|
final def powerOnCondition: Receive = {
|
||||||
|
case BuildingActor.PowerOff() =>
|
||||||
|
powered = false
|
||||||
|
context.become(powerOffCondition)
|
||||||
|
powerTurnOffCallback()
|
||||||
|
case msg =>
|
||||||
|
poweredStateLogic.apply(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
final def powerOffCondition: Receive = {
|
||||||
|
case BuildingActor.PowerOn() =>
|
||||||
|
powered = true
|
||||||
|
context.become(powerOnCondition)
|
||||||
|
powerTurnOnCallback()
|
||||||
|
case msg =>
|
||||||
|
unpoweredStateLogic.apply(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
def isPowered: Boolean = powered
|
||||||
|
|
||||||
|
def poweredStateLogic: Receive
|
||||||
|
|
||||||
|
def unpoweredStateLogic: Receive
|
||||||
|
|
||||||
|
def powerTurnOnCallback(): Unit
|
||||||
|
|
||||||
|
def powerTurnOffCallback(): Unit
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.terminals
|
package net.psforever.objects.serverobject.terminals
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorRef, Cancellable}
|
import akka.actor.{ActorRef, Cancellable}
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
import net.psforever.objects.serverobject.CommonMessages
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
||||||
import net.psforever.objects.serverobject.damage.DamageableAmenity
|
import net.psforever.objects.serverobject.damage.DamageableAmenity
|
||||||
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
|
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
|
||||||
import net.psforever.objects.serverobject.repair.RepairableAmenity
|
import net.psforever.objects.serverobject.repair.RepairableAmenity
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityControl}
|
||||||
|
import net.psforever.services.Service
|
||||||
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
@ -20,7 +22,7 @@ import scala.concurrent.duration._
|
||||||
* @param term the proximity unit (terminal)
|
* @param term the proximity unit (terminal)
|
||||||
*/
|
*/
|
||||||
class ProximityTerminalControl(term: Terminal with ProximityUnit)
|
class ProximityTerminalControl(term: Terminal with ProximityUnit)
|
||||||
extends Actor
|
extends PoweredAmenityControl
|
||||||
with FactionAffinityBehavior.Check
|
with FactionAffinityBehavior.Check
|
||||||
with HackableBehavior.GenericHackable
|
with HackableBehavior.GenericHackable
|
||||||
with DamageableAmenity
|
with DamageableAmenity
|
||||||
|
|
@ -35,11 +37,20 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit)
|
||||||
val callbacks: mutable.ListBuffer[ActorRef] = new mutable.ListBuffer[ActorRef]()
|
val callbacks: mutable.ListBuffer[ActorRef] = new mutable.ListBuffer[ActorRef]()
|
||||||
val log = org.log4s.getLogger
|
val log = org.log4s.getLogger
|
||||||
|
|
||||||
def receive: Receive =
|
val commonBehavior: Receive = checkBehavior
|
||||||
checkBehavior
|
.orElse(takesDamage)
|
||||||
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
|
.orElse {
|
||||||
|
case CommonMessages.Unuse(_, Some(target: PlanetSideGameObject)) =>
|
||||||
|
Unuse(target, term.Continent)
|
||||||
|
|
||||||
|
case CommonMessages.Unuse(_, _) =>
|
||||||
|
log.warn(s"unexpected format for CommonMessages.Unuse in this context")
|
||||||
|
}
|
||||||
|
|
||||||
|
def poweredStateLogic: Receive =
|
||||||
|
commonBehavior
|
||||||
.orElse(hackableBehavior)
|
.orElse(hackableBehavior)
|
||||||
.orElse(takesDamage)
|
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
|
||||||
.orElse {
|
.orElse {
|
||||||
case CommonMessages.Use(player, Some(item: SimpleItem))
|
case CommonMessages.Use(player, Some(item: SimpleItem))
|
||||||
if item.Definition == GlobalDefinitions.remote_electronics_kit =>
|
if item.Definition == GlobalDefinitions.remote_electronics_kit =>
|
||||||
|
|
@ -66,12 +77,6 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit)
|
||||||
case CommonMessages.Use(_, _) =>
|
case CommonMessages.Use(_, _) =>
|
||||||
log.warn(s"unexpected format for CommonMessages.Use in this context")
|
log.warn(s"unexpected format for CommonMessages.Use in this context")
|
||||||
|
|
||||||
case CommonMessages.Unuse(_, Some(target: PlanetSideGameObject)) =>
|
|
||||||
Unuse(target, term.Continent)
|
|
||||||
|
|
||||||
case CommonMessages.Unuse(_, _) =>
|
|
||||||
log.warn(s"unexpected format for CommonMessages.Unuse in this context")
|
|
||||||
|
|
||||||
case ProximityTerminalControl.TerminalAction() =>
|
case ProximityTerminalControl.TerminalAction() =>
|
||||||
val proxDef = term.Definition.asInstanceOf[ProximityDefinition]
|
val proxDef = term.Definition.asInstanceOf[ProximityDefinition]
|
||||||
val validateFunc: PlanetSideGameObject => Boolean =
|
val validateFunc: PlanetSideGameObject => Boolean =
|
||||||
|
|
@ -99,6 +104,19 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit)
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def unpoweredStateLogic : Receive = commonBehavior
|
||||||
|
.orElse {
|
||||||
|
case CommonMessages.Use(_, _) =>
|
||||||
|
log.warn(s"unexpected format for CommonMessages.Use in this context")
|
||||||
|
|
||||||
|
case CommonMessages.Unuse(_, Some(target: PlanetSideGameObject)) =>
|
||||||
|
Unuse(target, term.Continent)
|
||||||
|
|
||||||
|
case CommonMessages.Unuse(_, _) =>
|
||||||
|
log.warn(s"unexpected format for CommonMessages.Unuse in this context")
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
def Use(target: PlanetSideGameObject, zone: String, callback: ActorRef): Unit = {
|
def Use(target: PlanetSideGameObject, zone: String, callback: ActorRef): Unit = {
|
||||||
val hadNoUsers = term.NumberUsers == 0
|
val hadNoUsers = term.NumberUsers == 0
|
||||||
if (term.AddUser(target)) {
|
if (term.AddUser(target)) {
|
||||||
|
|
@ -145,6 +163,22 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def powerTurnOffCallback() : Unit = {
|
||||||
|
//clear effect callbacks
|
||||||
|
terminalAction.cancel()
|
||||||
|
if (callbacks.nonEmpty) {
|
||||||
|
callbacks.clear()
|
||||||
|
TerminalObject.Zone.LocalEvents ! Terminal.StopProximityEffect(term)
|
||||||
|
}
|
||||||
|
//clear hack state
|
||||||
|
if (term.HackedBy.nonEmpty) {
|
||||||
|
val zone = term.Zone
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.ClearTemporaryHack(Service.defaultPlayerGUID, term))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def powerTurnOnCallback() : Unit = { }
|
||||||
|
|
||||||
override def toString: String = term.Definition.Name
|
override def toString: String = term.Definition.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.terminals
|
package net.psforever.objects.serverobject.terminals
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorRef}
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.ballistics.ResolvedProjectile
|
import net.psforever.objects.ballistics.ResolvedProjectile
|
||||||
import net.psforever.objects.{GlobalDefinitions, SimpleItem}
|
import net.psforever.objects.{GlobalDefinitions, SimpleItem}
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
import net.psforever.objects.serverobject.CommonMessages
|
||||||
|
|
@ -10,14 +10,16 @@ import net.psforever.objects.serverobject.damage.Damageable.Target
|
||||||
import net.psforever.objects.serverobject.damage.{Damageable, DamageableAmenity}
|
import net.psforever.objects.serverobject.damage.{Damageable, DamageableAmenity}
|
||||||
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
|
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
|
||||||
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableAmenity}
|
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableAmenity}
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityControl}
|
||||||
|
import net.psforever.services.Service
|
||||||
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An `Actor` that handles messages being dispatched to a specific `Terminal`.
|
* An `Actor` that handles messages being dispatched to a specific `Terminal`.
|
||||||
* @param term the `Terminal` object being governed
|
* @param term the `Terminal` object being governed
|
||||||
*/
|
*/
|
||||||
class TerminalControl(term: Terminal)
|
class TerminalControl(term: Terminal)
|
||||||
extends Actor
|
extends PoweredAmenityControl
|
||||||
with FactionAffinityBehavior.Check
|
with FactionAffinityBehavior.Check
|
||||||
with HackableBehavior.GenericHackable
|
with HackableBehavior.GenericHackable
|
||||||
with DamageableAmenity
|
with DamageableAmenity
|
||||||
|
|
@ -29,18 +31,20 @@ class TerminalControl(term: Terminal)
|
||||||
def RepairableObject = term
|
def RepairableObject = term
|
||||||
def AutoRepairObject = term
|
def AutoRepairObject = term
|
||||||
|
|
||||||
def receive: Receive =
|
val commonBehavior: Receive = checkBehavior
|
||||||
checkBehavior
|
.orElse(takesDamage)
|
||||||
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
|
.orElse(autoRepairBehavior)
|
||||||
|
|
||||||
|
def poweredStateLogic : Receive =
|
||||||
|
commonBehavior
|
||||||
.orElse(hackableBehavior)
|
.orElse(hackableBehavior)
|
||||||
.orElse(takesDamage)
|
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
|
||||||
.orElse(autoRepairBehavior)
|
|
||||||
.orElse {
|
.orElse {
|
||||||
case Terminal.Request(player, msg) =>
|
case Terminal.Request(player, msg) =>
|
||||||
TerminalControl.Dispatch(sender(), term, Terminal.TerminalMessage(player, msg, term.Request(player, msg)))
|
TerminalControl.Dispatch(sender(), term, Terminal.TerminalMessage(player, msg, term.Request(player, msg)))
|
||||||
|
|
||||||
case CommonMessages.Use(player, Some(item: SimpleItem))
|
case CommonMessages.Use(player, Some(item: SimpleItem))
|
||||||
if item.Definition == GlobalDefinitions.remote_electronics_kit =>
|
if item.Definition == GlobalDefinitions.remote_electronics_kit =>
|
||||||
//TODO setup certifications check
|
//TODO setup certifications check
|
||||||
term.Owner match {
|
term.Owner match {
|
||||||
case b: Building if (b.Faction != player.Faction || b.CaptureTerminalIsHacked) && term.HackedBy.isEmpty =>
|
case b: Building if (b.Faction != player.Faction || b.CaptureTerminalIsHacked) && term.HackedBy.isEmpty =>
|
||||||
|
|
@ -55,6 +59,14 @@ class TerminalControl(term: Terminal)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def unpoweredStateLogic : Receive = commonBehavior
|
||||||
|
.orElse {
|
||||||
|
case Terminal.Request(player, msg) =>
|
||||||
|
sender() ! Terminal.TerminalMessage(player, msg, Terminal.NoDeal())
|
||||||
|
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
override protected def DamageAwareness(target : Target, cause : ResolvedProjectile, amount : Any) : Unit = {
|
override protected def DamageAwareness(target : Target, cause : ResolvedProjectile, amount : Any) : Unit = {
|
||||||
tryAutoRepair()
|
tryAutoRepair()
|
||||||
super.DamageAwareness(target, cause, amount)
|
super.DamageAwareness(target, cause, amount)
|
||||||
|
|
@ -62,6 +74,10 @@ class TerminalControl(term: Terminal)
|
||||||
|
|
||||||
override protected def DestructionAwareness(target: Damageable.Target, cause: ResolvedProjectile) : Unit = {
|
override protected def DestructionAwareness(target: Damageable.Target, cause: ResolvedProjectile) : Unit = {
|
||||||
tryAutoRepair()
|
tryAutoRepair()
|
||||||
|
if (term.HackedBy.nonEmpty) {
|
||||||
|
val zone = term.Zone
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.ClearTemporaryHack(Service.defaultPlayerGUID, term))
|
||||||
|
}
|
||||||
super.DestructionAwareness(target, cause)
|
super.DestructionAwareness(target, cause)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,6 +89,16 @@ class TerminalControl(term: Terminal)
|
||||||
newHealth
|
newHealth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def powerTurnOffCallback() : Unit = {
|
||||||
|
//clear hack state
|
||||||
|
if (term.HackedBy.nonEmpty) {
|
||||||
|
val zone = term.Zone
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.ClearTemporaryHack(Service.defaultPlayerGUID, term))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def powerTurnOnCallback() : Unit = { }
|
||||||
|
|
||||||
override def toString: String = term.Definition.Name
|
override def toString: String = term.Definition.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,10 @@ import net.psforever.objects.serverobject.structures.Amenity
|
||||||
* @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
|
||||||
*/
|
*/
|
||||||
class SpawnTube(tDef: SpawnTubeDefinition) extends Amenity with SpawnPoint {
|
class SpawnTube(tDef: SpawnTubeDefinition) extends Amenity with SpawnPoint {
|
||||||
|
var offline: Boolean = false
|
||||||
|
|
||||||
|
override def isOffline: Boolean = offline || super.isOffline
|
||||||
|
|
||||||
def Definition: SpawnTubeDefinition = tDef
|
def Definition: SpawnTubeDefinition = tDef
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,20 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.tube
|
package net.psforever.objects.serverobject.tube
|
||||||
|
|
||||||
import akka.actor.Actor
|
|
||||||
import net.psforever.actors.zone.BuildingActor
|
import net.psforever.actors.zone.BuildingActor
|
||||||
import net.psforever.objects.ballistics.ResolvedProjectile
|
import net.psforever.objects.ballistics.ResolvedProjectile
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
||||||
import net.psforever.objects.serverobject.damage.Damageable.Target
|
import net.psforever.objects.serverobject.damage.Damageable.Target
|
||||||
import net.psforever.objects.serverobject.damage.DamageableAmenity
|
import net.psforever.objects.serverobject.damage.DamageableAmenity
|
||||||
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, Repairable, RepairableAmenity}
|
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, Repairable, RepairableAmenity}
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityControl}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An `Actor` that handles messages being dispatched to a specific `SpawnTube`.
|
* An `Actor` that handles messages being dispatched to a specific `SpawnTube`.
|
||||||
* @param tube the `SpawnTube` object being governed
|
* @param tube the `SpawnTube` object being governed
|
||||||
*/
|
*/
|
||||||
class SpawnTubeControl(tube: SpawnTube)
|
class SpawnTubeControl(tube: SpawnTube)
|
||||||
extends Actor
|
extends PoweredAmenityControl
|
||||||
with FactionAffinityBehavior.Check
|
with FactionAffinityBehavior.Check
|
||||||
with DamageableAmenity
|
with DamageableAmenity
|
||||||
with RepairableAmenity
|
with RepairableAmenity
|
||||||
|
|
@ -25,11 +24,19 @@ class SpawnTubeControl(tube: SpawnTube)
|
||||||
def RepairableObject = tube
|
def RepairableObject = tube
|
||||||
def AutoRepairObject = tube
|
def AutoRepairObject = tube
|
||||||
|
|
||||||
def receive: Receive =
|
val commonBehavior: Receive = checkBehavior
|
||||||
checkBehavior
|
.orElse(takesDamage)
|
||||||
.orElse(takesDamage)
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
.orElse(autoRepairBehavior)
|
||||||
.orElse(autoRepairBehavior)
|
|
||||||
|
def poweredStateLogic: Receive =
|
||||||
|
commonBehavior
|
||||||
|
.orElse {
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
def unpoweredStateLogic: Receive =
|
||||||
|
commonBehavior
|
||||||
.orElse {
|
.orElse {
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
@ -64,5 +71,21 @@ class SpawnTubeControl(tube: SpawnTube)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def powerTurnOffCallback(): Unit = {
|
||||||
|
tube.offline = false
|
||||||
|
tube.Owner match {
|
||||||
|
case b: Building => b.Actor ! BuildingActor.AmenityStateChange(tube)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def powerTurnOnCallback(): Unit = {
|
||||||
|
tube.offline = true
|
||||||
|
tube.Owner match {
|
||||||
|
case b: Building => b.Actor ! BuildingActor.AmenityStateChange(tube)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override def toString: String = tube.Definition.Name
|
override def toString: String = tube.Definition.Name
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.turret
|
package net.psforever.objects.serverobject.turret
|
||||||
|
|
||||||
import akka.actor.Actor
|
|
||||||
import net.psforever.objects.ballistics.ResolvedProjectile
|
import net.psforever.objects.ballistics.ResolvedProjectile
|
||||||
import net.psforever.objects.{Default, GlobalDefinitions, Player, Tool}
|
import net.psforever.objects.{Default, GlobalDefinitions, Player, Tool}
|
||||||
import net.psforever.objects.equipment.{Ammo, JammableMountedWeapons}
|
import net.psforever.objects.equipment.{Ammo, JammableMountedWeapons}
|
||||||
|
|
@ -11,8 +10,10 @@ import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
||||||
import net.psforever.objects.serverobject.damage.{Damageable, DamageableWeaponTurret}
|
import net.psforever.objects.serverobject.damage.{Damageable, DamageableWeaponTurret}
|
||||||
import net.psforever.objects.serverobject.hackable.GenericHackables
|
import net.psforever.objects.serverobject.hackable.GenericHackables
|
||||||
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableWeaponTurret}
|
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableWeaponTurret}
|
||||||
|
import net.psforever.objects.serverobject.structures.PoweredAmenityControl
|
||||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
@ -27,7 +28,7 @@ import scala.concurrent.duration._
|
||||||
* @param turret the `MannedTurret` object being governed
|
* @param turret the `MannedTurret` object being governed
|
||||||
*/
|
*/
|
||||||
class FacilityTurretControl(turret: FacilityTurret)
|
class FacilityTurretControl(turret: FacilityTurret)
|
||||||
extends Actor
|
extends PoweredAmenityControl
|
||||||
with FactionAffinityBehavior.Check
|
with FactionAffinityBehavior.Check
|
||||||
with MountableBehavior.TurretMount
|
with MountableBehavior.TurretMount
|
||||||
with MountableBehavior.Dismount
|
with MountableBehavior.Dismount
|
||||||
|
|
@ -51,14 +52,17 @@ class FacilityTurretControl(turret: FacilityTurret)
|
||||||
stopAutoRepair()
|
stopAutoRepair()
|
||||||
}
|
}
|
||||||
|
|
||||||
def receive: Receive =
|
def commonBehavior: Receive =
|
||||||
checkBehavior
|
checkBehavior
|
||||||
.orElse(jammableBehavior)
|
.orElse(jammableBehavior)
|
||||||
.orElse(mountBehavior)
|
|
||||||
.orElse(dismountBehavior)
|
.orElse(dismountBehavior)
|
||||||
.orElse(takesDamage)
|
.orElse(takesDamage)
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
.orElse(autoRepairBehavior)
|
.orElse(autoRepairBehavior)
|
||||||
|
|
||||||
|
def poweredStateLogic: Receive =
|
||||||
|
commonBehavior
|
||||||
|
.orElse(mountBehavior)
|
||||||
.orElse {
|
.orElse {
|
||||||
case CommonMessages.Use(player, Some((item: Tool, upgradeValue: Int)))
|
case CommonMessages.Use(player, Some((item: Tool, upgradeValue: Int)))
|
||||||
if player.Faction == turret.Faction &&
|
if player.Faction == turret.Faction &&
|
||||||
|
|
@ -113,6 +117,12 @@ class FacilityTurretControl(turret: FacilityTurret)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def unpoweredStateLogic: Receive =
|
||||||
|
commonBehavior
|
||||||
|
.orElse {
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
override protected def DamageAwareness(target : Damageable.Target, cause : ResolvedProjectile, amount : Any) : Unit = {
|
override protected def DamageAwareness(target : Damageable.Target, cause : ResolvedProjectile, amount : Any) : Unit = {
|
||||||
tryAutoRepair()
|
tryAutoRepair()
|
||||||
super.DamageAwareness(target, cause, amount)
|
super.DamageAwareness(target, cause, amount)
|
||||||
|
|
@ -146,4 +156,25 @@ class FacilityTurretControl(turret: FacilityTurret)
|
||||||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 50, 0))
|
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 50, 0))
|
||||||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 51, 0))
|
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 51, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def powerTurnOffCallback(): Unit = {
|
||||||
|
//kick all occupants
|
||||||
|
val guid = turret.GUID
|
||||||
|
val zone = turret.Zone
|
||||||
|
val zoneId = zone.id
|
||||||
|
val events = zone.VehicleEvents
|
||||||
|
turret.Seats.values.foreach(seat =>
|
||||||
|
seat.Occupant match {
|
||||||
|
case Some(player) =>
|
||||||
|
seat.Occupant = None
|
||||||
|
player.VehicleSeated = None
|
||||||
|
if (player.HasGUID) {
|
||||||
|
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, false, guid))
|
||||||
|
}
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def powerTurnOnCallback(): Unit = { }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -354,8 +354,8 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
|
||||||
.filter {
|
.filter {
|
||||||
case (building, spawns) =>
|
case (building, spawns) =>
|
||||||
spawns.nonEmpty &&
|
spawns.nonEmpty &&
|
||||||
spawns.exists(_.Offline == false) &&
|
spawns.exists(_.isOffline == false) &&
|
||||||
structures.contains(building.BuildingType)
|
structures.contains(building.BuildingType)
|
||||||
}
|
}
|
||||||
.filter {
|
.filter {
|
||||||
case (building, _) =>
|
case (building, _) =>
|
||||||
|
|
@ -368,7 +368,7 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
|
||||||
}
|
}
|
||||||
.map {
|
.map {
|
||||||
case (building, spawns: List[SpawnPoint]) =>
|
case (building, spawns: List[SpawnPoint]) =>
|
||||||
(building, spawns.filter(!_.Offline))
|
(building, spawns.filter(!_.isOffline))
|
||||||
}
|
}
|
||||||
.concat(
|
.concat(
|
||||||
(if (ams) Vehicles else List())
|
(if (ams) Vehicles else List())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue