mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-13 15:34:42 +00:00
Amenity Auto-Repair (#594)
* working proof of concept for ntu request/flow * ntu is now measured in Float rather than Int; adjusted the type declarations in ChatActor, as it was complaining * added auto repair information for amenities; modified terminal working example to include periodic repair timer * crude power state acknowledgement exchange between ntu silo and building, following by building and amenities; better management and control over auto-repair * separated auto-repair from terminal control; resource silo publishes an appropriate power state message upon formal start-up * various Damageble objects have been granted auto-repair; doors no longer report no event for intercepting unhandled messages * documentation and comments; unit tests and integration tests for AmneityAutoRepair, ResourceSilo, and BuildingActor * merge plus some fixes * addition checks for auto-repairing cavern equipment and for auto-repairing un-owned equipment
This commit is contained in:
parent
e4664d1727
commit
e58f1d5987
29 changed files with 1138 additions and 154 deletions
|
|
@ -11,19 +11,19 @@ object NtuCommand {
|
||||||
*
|
*
|
||||||
* @param source the nanite container recognized as the sender
|
* @param source the nanite container recognized as the sender
|
||||||
*/
|
*/
|
||||||
final case class Offer(source: NtuContainer) extends Command
|
final case class Offer(source: NtuContainer, replyTo: ActorRef[Request]) extends Command
|
||||||
|
|
||||||
/** Message for asking for nanites from the recipient.
|
/** Message for asking for nanites from the recipient.
|
||||||
*
|
*
|
||||||
* @param amount the amount of nanites requested
|
* @param amount the amount of nanites requested
|
||||||
*/
|
*/
|
||||||
final case class Request(amount: Int, replyTo: ActorRef[Grant]) extends Command
|
final case class Request(amount: Float, replyTo: ActorRef[Grant]) extends Command
|
||||||
|
|
||||||
/** Response for transferring nanites to a recipient.
|
/** Response for transferring nanites to a recipient.
|
||||||
*
|
*
|
||||||
* @param source the nanite container recognized as the sender
|
* @param source the nanite container recognized as the sender
|
||||||
* @param amount the nanites transferred in this package
|
* @param amount the nanites transferred in this package
|
||||||
*/
|
*/
|
||||||
final case class Grant(source: NtuContainer, amount: Int)
|
final case class Grant(source: NtuContainer, amount: Float) extends Command
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import net.psforever.objects.avatar.{BattleRank, Certification, CommandRank, Cos
|
||||||
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
||||||
import net.psforever.objects.{Default, GlobalDefinitions, Player, Session}
|
import net.psforever.objects.{Default, GlobalDefinitions, Player, Session}
|
||||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
||||||
|
import net.psforever.objects.serverobject.structures.Building
|
||||||
import net.psforever.objects.serverobject.turret.{FacilityTurret, TurretUpgrade, WeaponTurrets}
|
import net.psforever.objects.serverobject.turret.{FacilityTurret, TurretUpgrade, WeaponTurrets}
|
||||||
import net.psforever.objects.zones.Zoning
|
import net.psforever.objects.zones.Zoning
|
||||||
import net.psforever.packet.game.{ChatMsg, DeadState, RequestDestroyMessage, ZonePopulationUpdateMessage}
|
import net.psforever.packet.game.{ChatMsg, DeadState, RequestDestroyMessage, ZonePopulationUpdateMessage}
|
||||||
|
|
@ -346,9 +347,9 @@ class ChatActor(
|
||||||
building.Amenities.foreach(amenity =>
|
building.Amenities.foreach(amenity =>
|
||||||
amenity.Definition match {
|
amenity.Definition match {
|
||||||
case GlobalDefinitions.resource_silo =>
|
case GlobalDefinitions.resource_silo =>
|
||||||
val r = new scala.util.Random
|
val r = new scala.util.Random
|
||||||
val silo = amenity.asInstanceOf[ResourceSilo]
|
val silo = amenity.asInstanceOf[ResourceSilo]
|
||||||
val ntu: Int = 900 + r.nextInt(100) - silo.NtuCapacitor
|
val ntu = 900f + r.nextFloat() * 100f - silo.NtuCapacitor
|
||||||
silo.Actor ! ResourceSilo.UpdateChargeLevel(ntu)
|
silo.Actor ! ResourceSilo.UpdateChargeLevel(ntu)
|
||||||
|
|
||||||
case _ => ()
|
case _ => ()
|
||||||
|
|
@ -363,8 +364,8 @@ class ChatActor(
|
||||||
case (CMT_CAPTUREBASE, _, contents) if gmCommandAllowed =>
|
case (CMT_CAPTUREBASE, _, contents) if gmCommandAllowed =>
|
||||||
val args = contents.split(" ").filter(_ != "")
|
val args = contents.split(" ").filter(_ != "")
|
||||||
|
|
||||||
val (faction, factionPos) = args.zipWithIndex
|
val (faction, factionPos): (PlanetSideEmpire.Value, Option[Int]) = args.zipWithIndex
|
||||||
.map { case (faction, pos) => (faction.toLowerCase, pos) }
|
.map { case (factionName, pos) => (factionName.toLowerCase, pos) }
|
||||||
.flatMap {
|
.flatMap {
|
||||||
case ("tr", pos) => Some(PlanetSideEmpire.TR, pos)
|
case ("tr", pos) => Some(PlanetSideEmpire.TR, pos)
|
||||||
case ("nc", pos) => Some(PlanetSideEmpire.NC, pos)
|
case ("nc", pos) => Some(PlanetSideEmpire.NC, pos)
|
||||||
|
|
@ -373,11 +374,11 @@ class ChatActor(
|
||||||
case _ => None
|
case _ => None
|
||||||
}
|
}
|
||||||
.headOption match {
|
.headOption match {
|
||||||
case Some((faction, pos)) => (faction, Some(pos))
|
case Some((isFaction, pos)) => (isFaction, Some(pos))
|
||||||
case None => (session.player.Faction, None)
|
case None => (session.player.Faction, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
val (buildingsOption, buildingPos) = args.zipWithIndex.flatMap {
|
val (buildingsOption, buildingPos): (Option[Seq[Building]], Option[Int]) = args.zipWithIndex.flatMap {
|
||||||
case (_, pos) if factionPos.isDefined && factionPos.get == pos => None
|
case (_, pos) if factionPos.isDefined && factionPos.get == pos => None
|
||||||
case ("all", pos) =>
|
case ("all", pos) =>
|
||||||
Some(
|
Some(
|
||||||
|
|
@ -391,7 +392,7 @@ class ChatActor(
|
||||||
),
|
),
|
||||||
Some(pos)
|
Some(pos)
|
||||||
)
|
)
|
||||||
case (name, pos) =>
|
case (name: String, pos) =>
|
||||||
session.zone.Buildings.find {
|
session.zone.Buildings.find {
|
||||||
case (_, building) => name.equalsIgnoreCase(building.Name) && building.CaptureTerminal.isDefined
|
case (_, building) => name.equalsIgnoreCase(building.Name) && building.CaptureTerminal.isDefined
|
||||||
} match {
|
} match {
|
||||||
|
|
@ -411,11 +412,11 @@ class ChatActor(
|
||||||
case None => (None, None)
|
case None => (None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
val (timerOption, timerPos) = args.zipWithIndex.flatMap {
|
val (timerOption, timerPos): (Option[Int], Option[Int]) = args.zipWithIndex.flatMap {
|
||||||
case (_, pos)
|
case (_, pos)
|
||||||
if factionPos.isDefined && factionPos.get == pos || buildingPos.isDefined && buildingPos.get == pos =>
|
if factionPos.isDefined && factionPos.get == pos || buildingPos.isDefined && buildingPos.get == pos =>
|
||||||
None
|
None
|
||||||
case (timer, pos) =>
|
case (timer: String, pos) =>
|
||||||
try {
|
try {
|
||||||
val t = timer.toInt // TODO what is the timer format supposed to be?
|
val t = timer.toInt // TODO what is the timer format supposed to be?
|
||||||
Some(Some(t), Some(pos))
|
Some(Some(t), Some(pos))
|
||||||
|
|
@ -436,15 +437,15 @@ class ChatActor(
|
||||||
(None | Some(1), Some(0), None, Some(_), None) | (Some(1), Some(0), Some(2), Some(_), Some(_)) |
|
(None | Some(1), Some(0), None, Some(_), None) | (Some(1), Some(0), Some(2), Some(_), Some(_)) |
|
||||||
// [all [<empire>|none]]
|
// [all [<empire>|none]]
|
||||||
(Some(1) | None, Some(0), None, Some(_), None) =>
|
(Some(1) | None, Some(0), None, Some(_), None) =>
|
||||||
val buildings = buildingsOption.getOrElse(
|
val buildings: Seq[Building] = buildingsOption.getOrElse(
|
||||||
session.zone.Buildings
|
session.zone.Buildings
|
||||||
.filter {
|
.values
|
||||||
case (_, building) =>
|
.filter { building =>
|
||||||
building.PlayersInSOI.exists { soiPlayer =>
|
building.PlayersInSOI.exists { soiPlayer =>
|
||||||
session.player.CharId == soiPlayer.CharId
|
session.player.CharId == soiPlayer.CharId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map { case (_, building) => building }
|
.toSeq
|
||||||
)
|
)
|
||||||
buildings foreach { building =>
|
buildings foreach { building =>
|
||||||
// TODO implement timer
|
// TODO implement timer
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
|
||||||
import akka.pattern.ask
|
import akka.pattern.ask
|
||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import MDCContextAware.Implicits._
|
|
||||||
import net.psforever.actors.net.MiddlewareActor
|
import net.psforever.actors.net.MiddlewareActor
|
||||||
import net.psforever.services.ServiceManager.Lookup
|
import net.psforever.services.ServiceManager.Lookup
|
||||||
import net.psforever.objects.locker.LockerContainer
|
import net.psforever.objects.locker.LockerContainer
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ import akka.actor.typed.scaladsl.{ActorContext, Behaviors, StashBuffer}
|
||||||
import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy}
|
import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy}
|
||||||
import akka.{actor => classic}
|
import akka.{actor => classic}
|
||||||
import net.psforever.actors.commands.NtuCommand
|
import net.psforever.actors.commands.NtuCommand
|
||||||
import net.psforever.objects.serverobject.structures.{Building, WarpGate}
|
import net.psforever.objects.{CommonNtuContainer, NtuContainer}
|
||||||
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
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
|
||||||
import net.psforever.types.PlanetSideEmpire
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
|
@ -40,7 +42,13 @@ object BuildingActor {
|
||||||
// Once they do, we won't need this anymore
|
// Once they do, we won't need this anymore
|
||||||
final case class MapUpdate() extends Command
|
final case class MapUpdate() extends Command
|
||||||
|
|
||||||
|
final case class AmenityStateChange(obj: Amenity) extends Command
|
||||||
|
|
||||||
final case class Ntu(command: NtuCommand.Command) extends Command
|
final case class Ntu(command: NtuCommand.Command) extends Command
|
||||||
|
|
||||||
|
final case class SuppliedWithNtu() extends Command
|
||||||
|
|
||||||
|
final case class NtuDepleted() extends Command
|
||||||
}
|
}
|
||||||
|
|
||||||
class BuildingActor(
|
class BuildingActor(
|
||||||
|
|
@ -147,6 +155,26 @@ class BuildingActor(
|
||||||
galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage()))
|
galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage()))
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
|
|
||||||
|
case AmenityStateChange(_) =>
|
||||||
|
//TODO when parameter object is finally immutable, perform analysis on it to determine specific actions
|
||||||
|
//for now, just update the map
|
||||||
|
galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage()))
|
||||||
|
Behaviors.same
|
||||||
|
|
||||||
|
case msg @ NtuDepleted() =>
|
||||||
|
log.trace(s"${building.Definition.Name} ${building.Name} ntu has been depleted")
|
||||||
|
building.Amenities.foreach { amenity =>
|
||||||
|
amenity.Actor ! msg
|
||||||
|
}
|
||||||
|
Behaviors.same
|
||||||
|
|
||||||
|
case msg @ SuppliedWithNtu() =>
|
||||||
|
log.trace(s"ntu supply has been restored to ${building.Definition.Name} ${building.Name}")
|
||||||
|
building.Amenities.foreach { amenity =>
|
||||||
|
amenity.Actor ! msg
|
||||||
|
}
|
||||||
|
Behaviors.same
|
||||||
|
|
||||||
case Ntu(msg) =>
|
case Ntu(msg) =>
|
||||||
ntu(msg)
|
ntu(msg)
|
||||||
}
|
}
|
||||||
|
|
@ -154,22 +182,41 @@ class BuildingActor(
|
||||||
|
|
||||||
def ntu(msg: NtuCommand.Command): Behavior[Command] = {
|
def ntu(msg: NtuCommand.Command): Behavior[Command] = {
|
||||||
import NtuCommand._
|
import NtuCommand._
|
||||||
val ntuBuilding = building match {
|
|
||||||
case b: WarpGate => b
|
|
||||||
case _ => return Behaviors.unhandled
|
|
||||||
}
|
|
||||||
|
|
||||||
msg match {
|
msg match {
|
||||||
case Offer(source) =>
|
case Offer(_, _) =>
|
||||||
|
Behaviors.same
|
||||||
case Request(amount, replyTo) =>
|
case Request(amount, replyTo) =>
|
||||||
ntuBuilding match {
|
building match {
|
||||||
case warpGate: WarpGate => replyTo ! Grant(warpGate, if (warpGate.Active) amount else 0)
|
case b: WarpGate =>
|
||||||
case _ => return Behaviors.unhandled
|
//warp gates are an infiite source of nanites
|
||||||
|
replyTo ! Grant(b, if (b.Active) amount else 0)
|
||||||
|
Behaviors.same
|
||||||
|
case _ if building.BuildingType == StructureType.Tower || building.Zone.map.cavern =>
|
||||||
|
//towers and cavern stuff get free repairs
|
||||||
|
replyTo ! NtuCommand.Grant(new FakeNtuSource(building), amount)
|
||||||
|
Behaviors.same
|
||||||
|
case _ =>
|
||||||
|
//all other facilities require a storage silo for ntu
|
||||||
|
building.Amenities.find(_.isInstanceOf[NtuContainer]) match {
|
||||||
|
case Some(ntuContainer) =>
|
||||||
|
ntuContainer.Actor ! msg //needs to redirect
|
||||||
|
Behaviors.same
|
||||||
|
case None =>
|
||||||
|
replyTo ! NtuCommand.Grant(null, 0)
|
||||||
|
Behaviors.unhandled
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
case _ =>
|
||||||
|
Behaviors.same
|
||||||
}
|
}
|
||||||
|
|
||||||
Behaviors.same
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeNtuSource(private val building: Building)
|
||||||
|
extends PlanetSideServerObject
|
||||||
|
with CommonNtuContainer {
|
||||||
|
override def NtuCapacitor = Float.MaxValue
|
||||||
|
override def Faction = building.Faction
|
||||||
|
override def Zone = building.Zone
|
||||||
|
override def Definition = null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import net.psforever.objects.serverobject.painbox.PainboxDefinition
|
||||||
import net.psforever.objects.serverobject.terminals._
|
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.{BuildingDefinition, WarpGateDefinition}
|
import net.psforever.objects.serverobject.structures.{AutoRepairStats, BuildingDefinition, WarpGateDefinition}
|
||||||
import net.psforever.objects.serverobject.turret.{FacilityTurretDefinition, TurretUpgrade}
|
import net.psforever.objects.serverobject.turret.{FacilityTurretDefinition, TurretUpgrade}
|
||||||
import net.psforever.objects.vehicles.{DestroyedVehicle, InternalTelepadDefinition, SeatArmorRestriction, UtilityType}
|
import net.psforever.objects.vehicles.{DestroyedVehicle, InternalTelepadDefinition, SeatArmorRestriction, UtilityType}
|
||||||
import net.psforever.objects.vital.damage.{DamageCalculations, DamageModifiers}
|
import net.psforever.objects.vital.damage.{DamageCalculations, DamageModifiers}
|
||||||
|
|
@ -6747,6 +6747,7 @@ object GlobalDefinitions {
|
||||||
spawn_terminal.Name = "spawn_terminal"
|
spawn_terminal.Name = "spawn_terminal"
|
||||||
spawn_terminal.Damageable = false
|
spawn_terminal.Damageable = false
|
||||||
spawn_terminal.Repairable = false
|
spawn_terminal.Repairable = false
|
||||||
|
spawn_terminal.autoRepair = AutoRepairStats(1, 5000, 200, 1) //TODO amount and drain are default? undefined?
|
||||||
|
|
||||||
order_terminal.Name = "order_terminal"
|
order_terminal.Name = "order_terminal"
|
||||||
order_terminal.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(
|
order_terminal.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(
|
||||||
|
|
@ -6765,6 +6766,7 @@ object GlobalDefinitions {
|
||||||
order_terminal.MaxHealth = 500
|
order_terminal.MaxHealth = 500
|
||||||
order_terminal.Damageable = true
|
order_terminal.Damageable = true
|
||||||
order_terminal.Repairable = true
|
order_terminal.Repairable = true
|
||||||
|
order_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||||
order_terminal.RepairIfDestroyed = true
|
order_terminal.RepairIfDestroyed = true
|
||||||
order_terminal.Subtract.Damage1 = 8
|
order_terminal.Subtract.Damage1 = 8
|
||||||
|
|
||||||
|
|
@ -6828,6 +6830,7 @@ object GlobalDefinitions {
|
||||||
cert_terminal.MaxHealth = 500
|
cert_terminal.MaxHealth = 500
|
||||||
cert_terminal.Damageable = true
|
cert_terminal.Damageable = true
|
||||||
cert_terminal.Repairable = true
|
cert_terminal.Repairable = true
|
||||||
|
cert_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||||
cert_terminal.RepairIfDestroyed = true
|
cert_terminal.RepairIfDestroyed = true
|
||||||
cert_terminal.Subtract.Damage1 = 8
|
cert_terminal.Subtract.Damage1 = 8
|
||||||
|
|
||||||
|
|
@ -6835,6 +6838,7 @@ object GlobalDefinitions {
|
||||||
implant_terminal_mech.MaxHealth = 1500 //TODO 1000; right now, 1000 (mech) + 500 (interface)
|
implant_terminal_mech.MaxHealth = 1500 //TODO 1000; right now, 1000 (mech) + 500 (interface)
|
||||||
implant_terminal_mech.Damageable = true
|
implant_terminal_mech.Damageable = true
|
||||||
implant_terminal_mech.Repairable = true
|
implant_terminal_mech.Repairable = true
|
||||||
|
implant_terminal_mech.autoRepair = AutoRepairStats(1, 5000, 2400, 0.5f)
|
||||||
implant_terminal_mech.RepairIfDestroyed = true
|
implant_terminal_mech.RepairIfDestroyed = true
|
||||||
|
|
||||||
implant_terminal_interface.Name = "implant_terminal_interface"
|
implant_terminal_interface.Name = "implant_terminal_interface"
|
||||||
|
|
@ -6842,6 +6846,7 @@ object GlobalDefinitions {
|
||||||
implant_terminal_interface.MaxHealth = 500
|
implant_terminal_interface.MaxHealth = 500
|
||||||
implant_terminal_interface.Damageable = false //TODO true
|
implant_terminal_interface.Damageable = false //TODO true
|
||||||
implant_terminal_interface.Repairable = true
|
implant_terminal_interface.Repairable = true
|
||||||
|
implant_terminal_interface.autoRepair = AutoRepairStats(1, 5000, 200, 1) //TODO amount and drain are default? undefined?
|
||||||
implant_terminal_interface.RepairIfDestroyed = true
|
implant_terminal_interface.RepairIfDestroyed = true
|
||||||
|
|
||||||
ground_vehicle_terminal.Name = "ground_vehicle_terminal"
|
ground_vehicle_terminal.Name = "ground_vehicle_terminal"
|
||||||
|
|
@ -6853,6 +6858,7 @@ object GlobalDefinitions {
|
||||||
ground_vehicle_terminal.MaxHealth = 500
|
ground_vehicle_terminal.MaxHealth = 500
|
||||||
ground_vehicle_terminal.Damageable = true
|
ground_vehicle_terminal.Damageable = true
|
||||||
ground_vehicle_terminal.Repairable = true
|
ground_vehicle_terminal.Repairable = true
|
||||||
|
ground_vehicle_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||||
ground_vehicle_terminal.RepairIfDestroyed = true
|
ground_vehicle_terminal.RepairIfDestroyed = true
|
||||||
ground_vehicle_terminal.Subtract.Damage1 = 8
|
ground_vehicle_terminal.Subtract.Damage1 = 8
|
||||||
|
|
||||||
|
|
@ -6865,6 +6871,7 @@ object GlobalDefinitions {
|
||||||
air_vehicle_terminal.MaxHealth = 500
|
air_vehicle_terminal.MaxHealth = 500
|
||||||
air_vehicle_terminal.Damageable = true
|
air_vehicle_terminal.Damageable = true
|
||||||
air_vehicle_terminal.Repairable = true
|
air_vehicle_terminal.Repairable = true
|
||||||
|
air_vehicle_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||||
air_vehicle_terminal.RepairIfDestroyed = true
|
air_vehicle_terminal.RepairIfDestroyed = true
|
||||||
air_vehicle_terminal.Subtract.Damage1 = 8
|
air_vehicle_terminal.Subtract.Damage1 = 8
|
||||||
|
|
||||||
|
|
@ -6877,6 +6884,7 @@ object GlobalDefinitions {
|
||||||
dropship_vehicle_terminal.MaxHealth = 500
|
dropship_vehicle_terminal.MaxHealth = 500
|
||||||
dropship_vehicle_terminal.Damageable = true
|
dropship_vehicle_terminal.Damageable = true
|
||||||
dropship_vehicle_terminal.Repairable = true
|
dropship_vehicle_terminal.Repairable = true
|
||||||
|
dropship_vehicle_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||||
dropship_vehicle_terminal.RepairIfDestroyed = true
|
dropship_vehicle_terminal.RepairIfDestroyed = true
|
||||||
dropship_vehicle_terminal.Subtract.Damage1 = 8
|
dropship_vehicle_terminal.Subtract.Damage1 = 8
|
||||||
|
|
||||||
|
|
@ -6889,6 +6897,7 @@ object GlobalDefinitions {
|
||||||
vehicle_terminal_combined.MaxHealth = 500
|
vehicle_terminal_combined.MaxHealth = 500
|
||||||
vehicle_terminal_combined.Damageable = true
|
vehicle_terminal_combined.Damageable = true
|
||||||
vehicle_terminal_combined.Repairable = true
|
vehicle_terminal_combined.Repairable = true
|
||||||
|
vehicle_terminal_combined.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||||
vehicle_terminal_combined.RepairIfDestroyed = true
|
vehicle_terminal_combined.RepairIfDestroyed = true
|
||||||
vehicle_terminal_combined.Subtract.Damage1 = 8
|
vehicle_terminal_combined.Subtract.Damage1 = 8
|
||||||
|
|
||||||
|
|
@ -6901,6 +6910,7 @@ object GlobalDefinitions {
|
||||||
vanu_air_vehicle_term.MaxHealth = 500
|
vanu_air_vehicle_term.MaxHealth = 500
|
||||||
vanu_air_vehicle_term.Damageable = true
|
vanu_air_vehicle_term.Damageable = true
|
||||||
vanu_air_vehicle_term.Repairable = true
|
vanu_air_vehicle_term.Repairable = true
|
||||||
|
vanu_air_vehicle_term.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||||
vanu_air_vehicle_term.RepairIfDestroyed = true
|
vanu_air_vehicle_term.RepairIfDestroyed = true
|
||||||
vanu_air_vehicle_term.Subtract.Damage1 = 8
|
vanu_air_vehicle_term.Subtract.Damage1 = 8
|
||||||
|
|
||||||
|
|
@ -6913,6 +6923,7 @@ object GlobalDefinitions {
|
||||||
vanu_vehicle_term.MaxHealth = 500
|
vanu_vehicle_term.MaxHealth = 500
|
||||||
vanu_vehicle_term.Damageable = true
|
vanu_vehicle_term.Damageable = true
|
||||||
vanu_vehicle_term.Repairable = true
|
vanu_vehicle_term.Repairable = true
|
||||||
|
vanu_vehicle_term.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||||
vanu_vehicle_term.RepairIfDestroyed = true
|
vanu_vehicle_term.RepairIfDestroyed = true
|
||||||
vanu_vehicle_term.Subtract.Damage1 = 8
|
vanu_vehicle_term.Subtract.Damage1 = 8
|
||||||
|
|
||||||
|
|
@ -6925,6 +6936,7 @@ object GlobalDefinitions {
|
||||||
bfr_terminal.MaxHealth = 500
|
bfr_terminal.MaxHealth = 500
|
||||||
bfr_terminal.Damageable = true
|
bfr_terminal.Damageable = true
|
||||||
bfr_terminal.Repairable = true
|
bfr_terminal.Repairable = true
|
||||||
|
bfr_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||||
bfr_terminal.RepairIfDestroyed = true
|
bfr_terminal.RepairIfDestroyed = true
|
||||||
bfr_terminal.Subtract.Damage1 = 8
|
bfr_terminal.Subtract.Damage1 = 8
|
||||||
|
|
||||||
|
|
@ -6935,6 +6947,7 @@ object GlobalDefinitions {
|
||||||
respawn_tube.Damageable = true
|
respawn_tube.Damageable = true
|
||||||
respawn_tube.DamageableByFriendlyFire = false
|
respawn_tube.DamageableByFriendlyFire = false
|
||||||
respawn_tube.Repairable = true
|
respawn_tube.Repairable = true
|
||||||
|
respawn_tube.autoRepair = AutoRepairStats(1, 10000, 2400, 1)
|
||||||
respawn_tube.RepairIfDestroyed = true
|
respawn_tube.RepairIfDestroyed = true
|
||||||
respawn_tube.Subtract.Damage1 = 8
|
respawn_tube.Subtract.Damage1 = 8
|
||||||
|
|
||||||
|
|
@ -6944,6 +6957,7 @@ object GlobalDefinitions {
|
||||||
respawn_tube_sanctuary.Damageable = false //true?
|
respawn_tube_sanctuary.Damageable = false //true?
|
||||||
respawn_tube_sanctuary.DamageableByFriendlyFire = false
|
respawn_tube_sanctuary.DamageableByFriendlyFire = false
|
||||||
respawn_tube_sanctuary.Repairable = true
|
respawn_tube_sanctuary.Repairable = true
|
||||||
|
respawn_tube_sanctuary.autoRepair = AutoRepairStats(1, 10000, 2400, 1)
|
||||||
|
|
||||||
respawn_tube_tower.Name = "respawn_tube_tower"
|
respawn_tube_tower.Name = "respawn_tube_tower"
|
||||||
respawn_tube_tower.Delay = 10
|
respawn_tube_tower.Delay = 10
|
||||||
|
|
@ -6952,6 +6966,7 @@ object GlobalDefinitions {
|
||||||
respawn_tube_tower.Damageable = true
|
respawn_tube_tower.Damageable = true
|
||||||
respawn_tube_tower.DamageableByFriendlyFire = false
|
respawn_tube_tower.DamageableByFriendlyFire = false
|
||||||
respawn_tube_tower.Repairable = true
|
respawn_tube_tower.Repairable = true
|
||||||
|
respawn_tube_tower.autoRepair = AutoRepairStats(1, 10000, 2400, 1)
|
||||||
respawn_tube_tower.RepairIfDestroyed = true
|
respawn_tube_tower.RepairIfDestroyed = true
|
||||||
respawn_tube_tower.Subtract.Damage1 = 8
|
respawn_tube_tower.Subtract.Damage1 = 8
|
||||||
|
|
||||||
|
|
@ -6969,6 +6984,7 @@ object GlobalDefinitions {
|
||||||
medical_terminal.MaxHealth = 500
|
medical_terminal.MaxHealth = 500
|
||||||
medical_terminal.Damageable = true
|
medical_terminal.Damageable = true
|
||||||
medical_terminal.Repairable = true
|
medical_terminal.Repairable = true
|
||||||
|
medical_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||||
medical_terminal.RepairIfDestroyed = true
|
medical_terminal.RepairIfDestroyed = true
|
||||||
|
|
||||||
adv_med_terminal.Name = "adv_med_terminal"
|
adv_med_terminal.Name = "adv_med_terminal"
|
||||||
|
|
@ -6980,6 +6996,7 @@ object GlobalDefinitions {
|
||||||
adv_med_terminal.MaxHealth = 750
|
adv_med_terminal.MaxHealth = 750
|
||||||
adv_med_terminal.Damageable = true
|
adv_med_terminal.Damageable = true
|
||||||
adv_med_terminal.Repairable = true
|
adv_med_terminal.Repairable = true
|
||||||
|
adv_med_terminal.autoRepair = AutoRepairStats(1, 5000, 2400, 0.5f)
|
||||||
adv_med_terminal.RepairIfDestroyed = true
|
adv_med_terminal.RepairIfDestroyed = true
|
||||||
|
|
||||||
crystals_health_a.Name = "crystals_health_a"
|
crystals_health_a.Name = "crystals_health_a"
|
||||||
|
|
@ -7007,6 +7024,7 @@ object GlobalDefinitions {
|
||||||
portable_med_terminal.MaxHealth = 500
|
portable_med_terminal.MaxHealth = 500
|
||||||
portable_med_terminal.Damageable = false //TODO actually true
|
portable_med_terminal.Damageable = false //TODO actually true
|
||||||
portable_med_terminal.Repairable = false
|
portable_med_terminal.Repairable = false
|
||||||
|
portable_med_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||||
|
|
||||||
pad_landing_frame.Name = "pad_landing_frame"
|
pad_landing_frame.Name = "pad_landing_frame"
|
||||||
pad_landing_frame.Interval = 1000
|
pad_landing_frame.Interval = 1000
|
||||||
|
|
@ -7120,6 +7138,7 @@ object GlobalDefinitions {
|
||||||
manned_turret.Damageable = true
|
manned_turret.Damageable = true
|
||||||
manned_turret.DamageDisablesAt = 0
|
manned_turret.DamageDisablesAt = 0
|
||||||
manned_turret.Repairable = true
|
manned_turret.Repairable = true
|
||||||
|
manned_turret.autoRepair = AutoRepairStats(1, 10000, 1600, 0.5f)
|
||||||
manned_turret.RepairIfDestroyed = true
|
manned_turret.RepairIfDestroyed = true
|
||||||
manned_turret.Weapons += 1 -> new mutable.HashMap()
|
manned_turret.Weapons += 1 -> new mutable.HashMap()
|
||||||
manned_turret.Weapons(1) += TurretUpgrade.None -> phalanx_sgl_hevgatcan
|
manned_turret.Weapons(1) += TurretUpgrade.None -> phalanx_sgl_hevgatcan
|
||||||
|
|
@ -7134,6 +7153,7 @@ object GlobalDefinitions {
|
||||||
vanu_sentry_turret.Damageable = true
|
vanu_sentry_turret.Damageable = true
|
||||||
vanu_sentry_turret.DamageDisablesAt = 0
|
vanu_sentry_turret.DamageDisablesAt = 0
|
||||||
vanu_sentry_turret.Repairable = true
|
vanu_sentry_turret.Repairable = true
|
||||||
|
vanu_sentry_turret.autoRepair = AutoRepairStats(3, 10000, 1000, 0.5f)
|
||||||
vanu_sentry_turret.RepairIfDestroyed = true
|
vanu_sentry_turret.RepairIfDestroyed = true
|
||||||
vanu_sentry_turret.Weapons += 1 -> new mutable.HashMap()
|
vanu_sentry_turret.Weapons += 1 -> new mutable.HashMap()
|
||||||
vanu_sentry_turret.Weapons(1) += TurretUpgrade.None -> vanu_sentry_turret_weapon
|
vanu_sentry_turret.Weapons(1) += TurretUpgrade.None -> vanu_sentry_turret_weapon
|
||||||
|
|
@ -7175,9 +7195,9 @@ object GlobalDefinitions {
|
||||||
generator.Damageable = true
|
generator.Damageable = true
|
||||||
generator.DamageableByFriendlyFire = false
|
generator.DamageableByFriendlyFire = false
|
||||||
generator.Repairable = true
|
generator.Repairable = true
|
||||||
|
generator.autoRepair = AutoRepairStats(1, 5000, 875, 1)
|
||||||
generator.RepairDistance = 13.5f
|
generator.RepairDistance = 13.5f
|
||||||
generator.RepairIfDestroyed = true
|
generator.RepairIfDestroyed = true
|
||||||
generator.Subtract.Damage1 = 9
|
generator.Subtract.Damage1 = 9
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ object Ntu {
|
||||||
* @param max the amount of nanites required to not make further requests;
|
* @param max the amount of nanites required to not make further requests;
|
||||||
* if 0, the `sender` is full and the message is for clean up operations
|
* if 0, the `sender` is full and the message is for clean up operations
|
||||||
*/
|
*/
|
||||||
final case class Request(min: Int, max: Int)
|
final case class Request(min: Float, max: Float)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message for transferring nanites to a recipient.
|
* Message for transferring nanites to a recipient.
|
||||||
|
|
@ -31,23 +31,23 @@ object Ntu {
|
||||||
* @param src the nanite container recognized as the sender
|
* @param src the nanite container recognized as the sender
|
||||||
* @param amount the nanites transferred in this package
|
* @param amount the nanites transferred in this package
|
||||||
*/
|
*/
|
||||||
final case class Grant(src: NtuContainer, amount: Int)
|
final case class Grant(src: NtuContainer, amount: Float)
|
||||||
}
|
}
|
||||||
|
|
||||||
trait NtuContainer extends TransferContainer {
|
trait NtuContainer extends TransferContainer {
|
||||||
def NtuCapacitor: Int
|
def NtuCapacitor: Float
|
||||||
|
|
||||||
def NtuCapacitor_=(value: Int): Int
|
def NtuCapacitor_=(value: Float): Float
|
||||||
|
|
||||||
def Definition: NtuContainerDefinition
|
def Definition: NtuContainerDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
trait CommonNtuContainer extends NtuContainer {
|
trait CommonNtuContainer extends NtuContainer {
|
||||||
private var ntuCapacitor: Int = 0
|
private var ntuCapacitor: Float = 0
|
||||||
|
|
||||||
def NtuCapacitor: Int = ntuCapacitor
|
def NtuCapacitor: Float = ntuCapacitor
|
||||||
|
|
||||||
def NtuCapacitor_=(value: Int): Int = {
|
def NtuCapacitor_=(value: Float): Float = {
|
||||||
ntuCapacitor = scala.math.max(0, scala.math.min(value, Definition.MaxNtuCapacitor))
|
ntuCapacitor = scala.math.max(0, scala.math.min(value, Definition.MaxNtuCapacitor))
|
||||||
NtuCapacitor
|
NtuCapacitor
|
||||||
}
|
}
|
||||||
|
|
@ -56,11 +56,11 @@ trait CommonNtuContainer extends NtuContainer {
|
||||||
}
|
}
|
||||||
|
|
||||||
trait NtuContainerDefinition {
|
trait NtuContainerDefinition {
|
||||||
private var maxNtuCapacitor: Int = 0
|
private var maxNtuCapacitor: Float = 0
|
||||||
|
|
||||||
def MaxNtuCapacitor: Int = maxNtuCapacitor
|
def MaxNtuCapacitor: Float = maxNtuCapacitor
|
||||||
|
|
||||||
def MaxNtuCapacitor_=(max: Int): Int = {
|
def MaxNtuCapacitor_=(max: Float): Float = {
|
||||||
maxNtuCapacitor = max
|
maxNtuCapacitor = max
|
||||||
MaxNtuCapacitor
|
MaxNtuCapacitor
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +76,12 @@ trait NtuStorageBehavior extends Actor {
|
||||||
|
|
||||||
case Ntu.Request(min, max) => HandleNtuRequest(sender(), min, max)
|
case Ntu.Request(min, max) => HandleNtuRequest(sender(), min, max)
|
||||||
|
|
||||||
|
case NtuCommand.Request(amount, replyTo) =>
|
||||||
|
import akka.actor.typed.scaladsl.adapter.TypedActorRefOps
|
||||||
|
HandleNtuRequest(new TypedActorRefOps(replyTo).toClassic, amount, amount+1)
|
||||||
|
|
||||||
case Ntu.Grant(src, amount) => HandleNtuGrant(sender(), src, amount)
|
case Ntu.Grant(src, amount) => HandleNtuGrant(sender(), src, amount)
|
||||||
|
|
||||||
case NtuCommand.Grant(src, amount) => HandleNtuGrant(sender(), src, amount)
|
case NtuCommand.Grant(src, amount) => HandleNtuGrant(sender(), src, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,7 +89,7 @@ trait NtuStorageBehavior extends Actor {
|
||||||
|
|
||||||
def StopNtuBehavior(sender: ActorRef): Unit
|
def StopNtuBehavior(sender: ActorRef): Unit
|
||||||
|
|
||||||
def HandleNtuRequest(sender: ActorRef, min: Int, max: Int): Unit
|
def HandleNtuRequest(sender: ActorRef, min: Float, max: Float): Unit
|
||||||
|
|
||||||
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Int): Unit
|
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Float): Unit
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -231,9 +231,9 @@ object Vehicles {
|
||||||
// Forcefully dismount any cargo
|
// Forcefully dismount any cargo
|
||||||
target.CargoHolds.values.foreach(cargoHold => {
|
target.CargoHolds.values.foreach(cargoHold => {
|
||||||
cargoHold.Occupant match {
|
cargoHold.Occupant match {
|
||||||
case Some(cargo: Vehicle) => {
|
case Some(cargo: Vehicle) =>
|
||||||
cargo.Seats(0).Occupant match {
|
cargo.Seats(0).Occupant match {
|
||||||
case Some(cargoDriver: Player) =>
|
case Some(_: Player) =>
|
||||||
CargoBehavior.HandleVehicleCargoDismount(
|
CargoBehavior.HandleVehicleCargoDismount(
|
||||||
target.Zone,
|
target.Zone,
|
||||||
cargo.GUID,
|
cargo.GUID,
|
||||||
|
|
@ -243,8 +243,7 @@ object Vehicles {
|
||||||
)
|
)
|
||||||
case None =>
|
case None =>
|
||||||
log.error("FinishHackingVehicle: vehicle in cargo hold missing driver")
|
log.error("FinishHackingVehicle: vehicle in cargo hold missing driver")
|
||||||
CargoBehavior.HandleVehicleCargoDismount(cargo.GUID, cargo, target.GUID, target, false, false, true)
|
CargoBehavior.HandleVehicleCargoDismount(cargo.GUID, cargo, target.GUID, target, bailed = false, requestedByPassenger = false, kicked = true)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case None => ;
|
case None => ;
|
||||||
}
|
}
|
||||||
|
|
@ -326,7 +325,7 @@ object Vehicles {
|
||||||
Vector3.DistanceSquared(obj.Position.xy, target.Position.xy) < soiRadius * soiRadius
|
Vector3.DistanceSquared(obj.Position.xy, target.Position.xy) < soiRadius * soiRadius
|
||||||
} =>
|
} =>
|
||||||
Some(target.asInstanceOf[NtuContainer])
|
Some(target.asInstanceOf[NtuContainer])
|
||||||
case None =>
|
case _ =>
|
||||||
None
|
None
|
||||||
}).orElse {
|
}).orElse {
|
||||||
val position = obj.Position.xy
|
val position = obj.Position.xy
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ class DoorControl(door: Door) extends Actor with FactionAffinityBehavior.Check {
|
||||||
case Door.Use(player, msg) =>
|
case Door.Use(player, msg) =>
|
||||||
sender() ! Door.DoorMessage(player, msg, door.Use(player, msg))
|
sender() ! Door.DoorMessage(player, msg, door.Use(player, msg))
|
||||||
|
|
||||||
case _ =>
|
case _ => ;
|
||||||
sender() ! Door.NoEvent()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,13 @@
|
||||||
package net.psforever.objects.serverobject.generator
|
package net.psforever.objects.serverobject.generator
|
||||||
|
|
||||||
import akka.actor.Actor
|
import akka.actor.Actor
|
||||||
|
import net.psforever.actors.zone.BuildingActor
|
||||||
import net.psforever.objects.{Player, Tool}
|
import net.psforever.objects.{Player, Tool}
|
||||||
import net.psforever.objects.ballistics._
|
import net.psforever.objects.ballistics._
|
||||||
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.DamageableEntity
|
import net.psforever.objects.serverobject.damage.DamageableEntity
|
||||||
import net.psforever.objects.serverobject.repair.{Repairable, RepairableEntity}
|
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, Repairable, RepairableEntity}
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.Building
|
||||||
import net.psforever.objects.vital.DamageFromExplosion
|
import net.psforever.objects.vital.DamageFromExplosion
|
||||||
import net.psforever.packet.game.TriggerEffectMessage
|
import net.psforever.packet.game.TriggerEffectMessage
|
||||||
|
|
@ -27,10 +28,12 @@ class GeneratorControl(gen: Generator)
|
||||||
extends Actor
|
extends Actor
|
||||||
with FactionAffinityBehavior.Check
|
with FactionAffinityBehavior.Check
|
||||||
with DamageableEntity
|
with DamageableEntity
|
||||||
with RepairableEntity {
|
with RepairableEntity
|
||||||
def FactionObject = gen
|
with AmenityAutoRepair {
|
||||||
def DamageableObject = gen
|
def FactionObject = gen
|
||||||
def RepairableObject = gen
|
def DamageableObject = gen
|
||||||
|
def RepairableObject = gen
|
||||||
|
def AutoRepairObject = gen
|
||||||
var imminentExplosion: Boolean = false
|
var imminentExplosion: Boolean = false
|
||||||
var alarmCooldownPeriod: Boolean = false
|
var alarmCooldownPeriod: Boolean = false
|
||||||
|
|
||||||
|
|
@ -38,6 +41,7 @@ class GeneratorControl(gen: Generator)
|
||||||
checkBehavior
|
checkBehavior
|
||||||
.orElse(takesDamage)
|
.orElse(takesDamage)
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
|
.orElse(autoRepairBehavior)
|
||||||
.orElse {
|
.orElse {
|
||||||
case GeneratorControl.GeneratorExplodes() => //TODO this only works with projectiles right now!
|
case GeneratorControl.GeneratorExplodes() => //TODO this only works with projectiles right now!
|
||||||
val zone = gen.Zone
|
val zone = gen.Zone
|
||||||
|
|
@ -89,6 +93,7 @@ class GeneratorControl(gen: Generator)
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected def DamageAwareness(target: Target, cause: ResolvedProjectile, amount: Any): Unit = {
|
override protected def DamageAwareness(target: Target, cause: ResolvedProjectile, amount: Any): Unit = {
|
||||||
|
tryAutoRepair()
|
||||||
super.DamageAwareness(target, cause, amount)
|
super.DamageAwareness(target, cause, amount)
|
||||||
val damageTo = amount match {
|
val damageTo = amount match {
|
||||||
case a: Int => a
|
case a: Int => a
|
||||||
|
|
@ -98,6 +103,7 @@ class GeneratorControl(gen: Generator)
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected def DestructionAwareness(target: Target, cause: ResolvedProjectile): Unit = {
|
override protected def DestructionAwareness(target: Target, cause: ResolvedProjectile): Unit = {
|
||||||
|
tryAutoRepair()
|
||||||
if (!target.Destroyed) {
|
if (!target.Destroyed) {
|
||||||
target.Health = 1 //temporary
|
target.Health = 1 //temporary
|
||||||
imminentExplosion = true
|
imminentExplosion = true
|
||||||
|
|
@ -106,6 +112,14 @@ class GeneratorControl(gen: Generator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def PerformRepairs(target : Target, amount : Int) : Int = {
|
||||||
|
val newHealth = super.PerformRepairs(target, amount)
|
||||||
|
if(newHealth == target.Definition.MaxHealth) {
|
||||||
|
stopAutoRepair()
|
||||||
|
}
|
||||||
|
newHealth
|
||||||
|
}
|
||||||
|
|
||||||
override def Restoration(obj: Repairable.Target): Unit = {
|
override def Restoration(obj: Repairable.Target): Unit = {
|
||||||
super.Restoration(obj)
|
super.Restoration(obj)
|
||||||
gen.Condition = PlanetSideGeneratorState.Normal
|
gen.Condition = PlanetSideGeneratorState.Normal
|
||||||
|
|
@ -137,7 +151,7 @@ object GeneratorControl {
|
||||||
*/
|
*/
|
||||||
private def UpdateOwner(obj: Generator): Unit = {
|
private def UpdateOwner(obj: Generator): Unit = {
|
||||||
obj.Owner match {
|
obj.Owner match {
|
||||||
case b: Building => b.Actor ! Building.AmenityStateChange(obj)
|
case b: Building => b.Actor ! BuildingActor.AmenityStateChange(obj)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ 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.{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.RepairableEntity
|
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableEntity}
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.Building
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -24,12 +24,14 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
||||||
with MountableBehavior.Dismount
|
with MountableBehavior.Dismount
|
||||||
with HackableBehavior.GenericHackable
|
with HackableBehavior.GenericHackable
|
||||||
with DamageableEntity
|
with DamageableEntity
|
||||||
with RepairableEntity {
|
with RepairableEntity
|
||||||
|
with AmenityAutoRepair {
|
||||||
def MountableObject = mech
|
def MountableObject = mech
|
||||||
def HackableObject = mech
|
def HackableObject = mech
|
||||||
def FactionObject = mech
|
def FactionObject = mech
|
||||||
def DamageableObject = mech
|
def DamageableObject = mech
|
||||||
def RepairableObject = mech
|
def RepairableObject = mech
|
||||||
|
def AutoRepairObject = mech
|
||||||
|
|
||||||
def receive: Receive =
|
def receive: Receive =
|
||||||
checkBehavior
|
checkBehavior
|
||||||
|
|
@ -38,6 +40,7 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
||||||
.orElse(hackableBehavior)
|
.orElse(hackableBehavior)
|
||||||
.orElse(takesDamage)
|
.orElse(takesDamage)
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
|
.orElse(autoRepairBehavior)
|
||||||
.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 =>
|
||||||
|
|
@ -73,6 +76,7 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected def DamageAwareness(target: Target, cause: ResolvedProjectile, amount: Any): Unit = {
|
override protected def DamageAwareness(target: Target, cause: ResolvedProjectile, amount: Any): Unit = {
|
||||||
|
tryAutoRepair()
|
||||||
super.DamageAwareness(target, cause, amount)
|
super.DamageAwareness(target, cause, amount)
|
||||||
val damageTo = amount match {
|
val damageTo = amount match {
|
||||||
case a: Int => a
|
case a: Int => a
|
||||||
|
|
@ -86,4 +90,12 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
||||||
DamageableMountable.DestructionAwareness(DamageableObject, cause)
|
DamageableMountable.DestructionAwareness(DamageableObject, cause)
|
||||||
target.ClearHistory()
|
target.ClearHistory()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def PerformRepairs(target : Damageable.Target, amount : Int) : Int = {
|
||||||
|
val newHealth = super.PerformRepairs(target, amount)
|
||||||
|
if(newHealth == target.Definition.MaxHealth) {
|
||||||
|
stopAutoRepair()
|
||||||
|
}
|
||||||
|
newHealth
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,197 @@
|
||||||
|
//Copyright (c) 2020 PSForever
|
||||||
|
package net.psforever.objects.serverobject.repair
|
||||||
|
|
||||||
|
import akka.actor.{Actor, ActorRef, Cancellable}
|
||||||
|
import akka.actor.typed.{ActorRef => TypedActorRef}
|
||||||
|
import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps
|
||||||
|
import net.psforever.actors.commands.NtuCommand
|
||||||
|
import net.psforever.actors.zone.BuildingActor
|
||||||
|
import net.psforever.objects.{Default, NtuContainer, NtuStorageBehavior}
|
||||||
|
import net.psforever.objects.serverobject.damage.Damageable
|
||||||
|
import net.psforever.objects.serverobject.structures.{Amenity, AutoRepairStats, Building}
|
||||||
|
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mixin for handling the automatic repair functionality of facility amenities.
|
||||||
|
* Auto-repair is facilitated primarily as a function of nanite transfer unit (NTU) provisions
|
||||||
|
* and is prompted by the amenity itself sustaining damage
|
||||||
|
* and being, at some level, capable of being repaired.
|
||||||
|
* In major facilities - technology plants, bio labs, etc. -
|
||||||
|
* this NTU is obtained from that facility's nanite resource silo.
|
||||||
|
* The amenity that wishes to be repaired asks the facility for nanite.
|
||||||
|
* The reply comes from the NTU source, or from the facility again.
|
||||||
|
* In exchange for the automatic repair, the silo looses some of its NTU stockpile
|
||||||
|
* and that entails all of the consequences of losing all of the NTU for the base.
|
||||||
|
* In smaller field tower bases, the lack of resource silo should not hinder operations
|
||||||
|
* as auto-repair is still carried out nonetheless.
|
||||||
|
* The consequences of losing NTU do not apply in this case;
|
||||||
|
* the field tower is considered to have unlimited, unshared NTU.
|
||||||
|
*/
|
||||||
|
trait AmenityAutoRepair
|
||||||
|
extends NtuStorageBehavior {
|
||||||
|
_: Damageable with RepairableEntity with Actor =>
|
||||||
|
/** a dedicated reference to self that facilitates in receiving `NtuCommand.Grant` messages for auto-repair operation */
|
||||||
|
private lazy val ntuGrantActorRef: TypedActorRef[NtuCommand.Grant] =
|
||||||
|
new ClassicActorRefOps(self).toTyped[NtuCommand.Grant]
|
||||||
|
/** the function that initializes auto-repair operations, if those operations have not yet started */
|
||||||
|
private var autoRepairStartFunc: ()=>Unit = startAutoRepairIfStopped
|
||||||
|
/** the timer for requests for auto-repair-actionable resource deposits (NTU) */
|
||||||
|
private var autoRepairTimer: Cancellable = Default.Cancellable
|
||||||
|
|
||||||
|
def AutoRepairObject: Amenity
|
||||||
|
|
||||||
|
final val autoRepairBehavior: Receive = storageBehavior.orElse {
|
||||||
|
case BuildingActor.SuppliedWithNtu() =>
|
||||||
|
withNtuSupplyCallback()
|
||||||
|
|
||||||
|
case BuildingActor.NtuDepleted() =>
|
||||||
|
noNtuSupplyCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
//nothing special
|
||||||
|
def HandleNtuOffer(sender: ActorRef, src: NtuContainer): Unit = { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the auto-repair timer.
|
||||||
|
*/
|
||||||
|
def StopNtuBehavior(sender : ActorRef) : Unit = {
|
||||||
|
autoRepairTimer.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
//nothing special
|
||||||
|
def HandleNtuRequest(sender: ActorRef, min: Float, max: Float): Unit = { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When reports of an NTU provision is returned to the requesting amenity,
|
||||||
|
* the amount of repair that can be performed is obtained
|
||||||
|
* and, if the amenity still requires those repairs,
|
||||||
|
* auto-repair executes a single tick.
|
||||||
|
* @see `RepairableAmenity`
|
||||||
|
*/
|
||||||
|
def HandleNtuGrant(sender : ActorRef, src : NtuContainer, amount : Float) : Unit = {
|
||||||
|
val obj = AutoRepairObject
|
||||||
|
obj.Definition.autoRepair match {
|
||||||
|
case Some(repair : AutoRepairStats) if obj.Health < obj.Definition.MaxHealth =>
|
||||||
|
PerformRepairs(obj, repair.amount)
|
||||||
|
case _ =>
|
||||||
|
StopNtuBehavior(sender)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm that a provision of NTU to the potential requesting amenity is possible.
|
||||||
|
* Attempt to start auto-repair operations.
|
||||||
|
*/
|
||||||
|
def withNtuSupplyCallback(): Unit = {
|
||||||
|
startAutoRepairFunctionality()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No (further) provisions of NTU to the potential requesting amenity will be forthcoming.
|
||||||
|
* Cancel any attempts at auto-repair.
|
||||||
|
*/
|
||||||
|
def noNtuSupplyCallback(): Unit = {
|
||||||
|
stopAutoRepairFunctionality()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to start auto-repair operation if possible,
|
||||||
|
* restarting an existing timed operation if necessary.
|
||||||
|
* Set a function that will attempt auto-repair operations under specific trigger-able conditions (damage).
|
||||||
|
*/
|
||||||
|
private def startAutoRepairFunctionality(): Unit = {
|
||||||
|
retimeAutoRepair()
|
||||||
|
autoRepairStartFunc = startAutoRepairIfStopped
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel any attempts at auto-repair
|
||||||
|
* by stopping any currently processing repair timer
|
||||||
|
* and ensuring that otherwise trigger-able conditions (damages) do not instigate auto-repair operations.
|
||||||
|
* @see `stopAutoRepair`
|
||||||
|
*/
|
||||||
|
private def stopAutoRepairFunctionality(): Unit = {
|
||||||
|
autoRepairTimer.cancel()
|
||||||
|
autoRepairStartFunc = ()=>{}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to start auto-repair operation
|
||||||
|
* only if no operation is currently being processed.
|
||||||
|
*/
|
||||||
|
private def startAutoRepairIfStopped(): Unit = {
|
||||||
|
if(autoRepairTimer.isCancelled) {
|
||||||
|
retimeAutoRepair()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to start auto-repair operation
|
||||||
|
* only if no operation is currently being processed.
|
||||||
|
* @return `true`, if the auto-repair process started specifically due to this call;
|
||||||
|
* `false`, if it was already started, or did not start
|
||||||
|
*/
|
||||||
|
final def tryAutoRepair(): Boolean = {
|
||||||
|
val before = autoRepairTimer.isCancelled
|
||||||
|
autoRepairStartFunc()
|
||||||
|
!(before || autoRepairTimer.isCancelled)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel any attempts at auto-repair
|
||||||
|
* by stopping any currently processing repair timer
|
||||||
|
* The operation can be resumed.
|
||||||
|
* @see `stopAutoRepairFunctionality`
|
||||||
|
*/
|
||||||
|
final def stopAutoRepair(): Unit = {
|
||||||
|
autoRepairTimer.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* As long as setup information regarding the auto-repair process can be discovered in the amenity's definition
|
||||||
|
* and the amenity actually requires to be performed,
|
||||||
|
* perform the setup for the auto-repair operation.
|
||||||
|
*/
|
||||||
|
private def retimeAutoRepair(): Unit = {
|
||||||
|
val obj = AutoRepairObject
|
||||||
|
obj.Definition.autoRepair match {
|
||||||
|
case Some(AutoRepairStats(_, start, interval, drain)) if obj.Health < obj.Definition.MaxHealth =>
|
||||||
|
retimeAutoRepair(start, interval, drain)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* As long as setup information regarding the auto-repair process can be provided,
|
||||||
|
* perform the setup for the auto-repair operation.
|
||||||
|
* @see `BuildingActor.Ntu`
|
||||||
|
* @see `NtuCommand.Request`
|
||||||
|
* @see `scheduleWithFixedDelay`
|
||||||
|
* @param initialDelay the delay before the first message
|
||||||
|
* @param delay the delay between subsequent messages, after the first
|
||||||
|
* @param drain the amount of NTU being levied as a cost for auto-repair operation
|
||||||
|
* (the responding entity determines how to satisfy the cost)
|
||||||
|
*/
|
||||||
|
private def retimeAutoRepair(initialDelay: Long, delay: Long, drain: Float): Unit = {
|
||||||
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
autoRepairTimer.cancel()
|
||||||
|
autoRepairTimer = if(AutoRepairObject.Owner == Building.NoBuilding) {
|
||||||
|
//without an owner, auto-repair freely
|
||||||
|
context.system.scheduler.scheduleWithFixedDelay(
|
||||||
|
initialDelay milliseconds,
|
||||||
|
delay milliseconds,
|
||||||
|
self,
|
||||||
|
NtuCommand.Grant(null, drain)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
//ask
|
||||||
|
context.system.scheduler.scheduleWithFixedDelay(
|
||||||
|
initialDelay milliseconds,
|
||||||
|
delay milliseconds,
|
||||||
|
AutoRepairObject.Owner.Actor,
|
||||||
|
BuildingActor.Ntu(NtuCommand.Request(drain, ntuGrantActorRef))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -78,32 +78,21 @@ trait RepairableEntity extends Repairable {
|
||||||
*/
|
*/
|
||||||
protected def PerformRepairs(target: Repairable.Target, player: Player, item: Tool): Unit = {
|
protected def PerformRepairs(target: Repairable.Target, player: Player, item: Tool): Unit = {
|
||||||
val definition = target.Definition
|
val definition = target.Definition
|
||||||
val zone = target.Zone
|
val events = target.Zone.AvatarEvents
|
||||||
val events = zone.AvatarEvents
|
|
||||||
val name = player.Name
|
val name = player.Name
|
||||||
val tguid = target.GUID
|
|
||||||
val originalHealth = target.Health
|
val originalHealth = target.Health
|
||||||
val updatedHealth =
|
val updatedHealth =
|
||||||
if (!(player.isMoving(1f) || target.isMoving(1f))) { //only allow stationary repairs within margin of error
|
if (!(player.isMoving(1f) || target.isMoving(1f))) { //only allow stationary repairs within margin of error
|
||||||
val newHealth = target.Health = originalHealth + Repairable.Quality + RepairValue(item) + definition.RepairMod
|
val repairValue = Repairable.Quality + RepairValue(item) + target.Definition.RepairMod
|
||||||
val zoneId = zone.id
|
|
||||||
val magazine = item.Discharge()
|
val magazine = item.Discharge()
|
||||||
events ! AvatarServiceMessage(
|
events ! AvatarServiceMessage(
|
||||||
name,
|
player.Name,
|
||||||
AvatarAction.SendResponse(
|
AvatarAction.SendResponse(
|
||||||
Service.defaultPlayerGUID,
|
Service.defaultPlayerGUID,
|
||||||
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong)
|
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if (target.Destroyed) {
|
PerformRepairs(target, repairValue)
|
||||||
if (newHealth >= definition.RepairRestoresAt) {
|
|
||||||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 0, newHealth))
|
|
||||||
Restoration(target)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 0, newHealth))
|
|
||||||
}
|
|
||||||
newHealth
|
|
||||||
} else {
|
} else {
|
||||||
originalHealth
|
originalHealth
|
||||||
}
|
}
|
||||||
|
|
@ -112,11 +101,28 @@ trait RepairableEntity extends Repairable {
|
||||||
name,
|
name,
|
||||||
AvatarAction.SendResponse(
|
AvatarAction.SendResponse(
|
||||||
Service.defaultPlayerGUID,
|
Service.defaultPlayerGUID,
|
||||||
RepairMessage(tguid, updatedHealth * 100 / definition.MaxHealth)
|
RepairMessage(target.GUID, updatedHealth * 100 / definition.MaxHealth)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected def PerformRepairs(target: Repairable.Target, amount: Int): Int = {
|
||||||
|
val zone = target.Zone
|
||||||
|
val zoneId = zone.id
|
||||||
|
val events = zone.AvatarEvents
|
||||||
|
val tguid = target.GUID
|
||||||
|
val newHealth = target.Health = target.Health + amount
|
||||||
|
if (target.Destroyed) {
|
||||||
|
if (newHealth >= target.Definition.RepairRestoresAt) {
|
||||||
|
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 0, newHealth))
|
||||||
|
Restoration(target)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 0, newHealth))
|
||||||
|
}
|
||||||
|
newHealth
|
||||||
|
}
|
||||||
|
|
||||||
/* random object repair modifier */
|
/* random object repair modifier */
|
||||||
override def RepairValue(item: Tool): Int = item.FireMode.Add.Damage1
|
override def RepairValue(item: Tool): Int = item.FireMode.Add.Damage1
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ class ResourceSilo extends Amenity with CommonNtuContainer {
|
||||||
// For the NTU display bar
|
// For the NTU display bar
|
||||||
private var capacitorDisplay: Long = 0
|
private var capacitorDisplay: Long = 0
|
||||||
|
|
||||||
def MaxNtuCapacitor : Int = Definition.MaxNtuCapacitor
|
def MaxNtuCapacitor : Float = Definition.MaxNtuCapacitor
|
||||||
|
|
||||||
def LowNtuWarningOn: Boolean = lowNtuWarningOn
|
def LowNtuWarningOn: Boolean = lowNtuWarningOn
|
||||||
def LowNtuWarningOn_=(enabled: Boolean): Boolean = {
|
def LowNtuWarningOn_=(enabled: Boolean): Boolean = {
|
||||||
|
|
@ -24,7 +24,7 @@ class ResourceSilo extends Amenity with CommonNtuContainer {
|
||||||
LowNtuWarningOn
|
LowNtuWarningOn
|
||||||
}
|
}
|
||||||
|
|
||||||
def CapacitorDisplay : Long = scala.math.ceil((NtuCapacitor.toFloat / MaxNtuCapacitor.toFloat) * 10).toInt
|
def CapacitorDisplay : Long = scala.math.ceil((NtuCapacitor / MaxNtuCapacitor) * 10).toInt
|
||||||
|
|
||||||
def Definition: ResourceSiloDefinition = GlobalDefinitions.resource_silo
|
def Definition: ResourceSiloDefinition = GlobalDefinitions.resource_silo
|
||||||
|
|
||||||
|
|
@ -34,7 +34,7 @@ class ResourceSilo extends Amenity with CommonNtuContainer {
|
||||||
}
|
}
|
||||||
|
|
||||||
object ResourceSilo {
|
object ResourceSilo {
|
||||||
final case class UpdateChargeLevel(amount: Int)
|
final case class UpdateChargeLevel(amount: Float)
|
||||||
final case class LowNtuWarning(enabled: Boolean)
|
final case class LowNtuWarning(enabled: Boolean)
|
||||||
sealed trait Exchange
|
sealed trait Exchange
|
||||||
final case class ChargeEvent() extends Exchange
|
final case class ChargeEvent() extends Exchange
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects.serverobject.resourcesilo
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorRef}
|
import akka.actor.{Actor, ActorRef}
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
import net.psforever.objects.serverobject.CommonMessages
|
||||||
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
|
import net.psforever.actors.zone.BuildingActor
|
||||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||||
import net.psforever.objects.serverobject.transfer.TransferBehavior
|
import net.psforever.objects.serverobject.transfer.TransferBehavior
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.Building
|
||||||
|
|
@ -28,12 +28,19 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
||||||
def FactionObject: FactionAffinity = resourceSilo
|
def FactionObject: FactionAffinity = resourceSilo
|
||||||
|
|
||||||
private[this] val log = org.log4s.getLogger
|
private[this] val log = org.log4s.getLogger
|
||||||
var panelAnimationFunc: Int => Unit = PanelAnimation
|
var panelAnimationFunc: Float => Unit = PanelAnimation
|
||||||
|
|
||||||
def receive: Receive = {
|
def receive: Receive = {
|
||||||
case "startup" =>
|
case "startup" =>
|
||||||
// todo: This is just a temporary solution to drain NTU over time. When base object destruction is properly implemented NTU should be deducted when base objects repair themselves
|
resourceSilo.Owner match {
|
||||||
// context.system.scheduler.schedule(5 second, 5 second, self, ResourceSilo.UpdateChargeLevel(-1))
|
case building: Building =>
|
||||||
|
building.Actor ! (if (resourceSilo.NtuCapacitor <= 0f ) {
|
||||||
|
BuildingActor.NtuDepleted()
|
||||||
|
} else {
|
||||||
|
BuildingActor.SuppliedWithNtu()
|
||||||
|
})
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
context.become(Processing)
|
context.become(Processing)
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
|
|
@ -59,7 +66,7 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
||||||
case ResourceSilo.LowNtuWarning(enabled: Boolean) =>
|
case ResourceSilo.LowNtuWarning(enabled: Boolean) =>
|
||||||
LowNtuWarning(enabled)
|
LowNtuWarning(enabled)
|
||||||
|
|
||||||
case ResourceSilo.UpdateChargeLevel(amount: Int) =>
|
case ResourceSilo.UpdateChargeLevel(amount: Float) =>
|
||||||
UpdateChargeLevel(amount)
|
UpdateChargeLevel(amount)
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
|
|
@ -76,7 +83,7 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def UpdateChargeLevel(amount: Int): Unit = {
|
def UpdateChargeLevel(amount: Float): Unit = {
|
||||||
val siloChargeBeforeChange = resourceSilo.NtuCapacitor
|
val siloChargeBeforeChange = resourceSilo.NtuCapacitor
|
||||||
val siloDisplayBeforeChange = resourceSilo.CapacitorDisplay
|
val siloDisplayBeforeChange = resourceSilo.CapacitorDisplay
|
||||||
val building = resourceSilo.Owner.asInstanceOf[Building]
|
val building = resourceSilo.Owner.asInstanceOf[Building]
|
||||||
|
|
@ -93,14 +100,13 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
||||||
log.trace(
|
log.trace(
|
||||||
s"Silo ${resourceSilo.GUID} NTU bar level has changed from $siloDisplayBeforeChange to ${resourceSilo.CapacitorDisplay}"
|
s"Silo ${resourceSilo.GUID} NTU bar level has changed from $siloDisplayBeforeChange to ${resourceSilo.CapacitorDisplay}"
|
||||||
)
|
)
|
||||||
resourceSilo.Owner.Actor ! BuildingActor.MapUpdate()
|
|
||||||
zone.AvatarEvents ! AvatarServiceMessage(
|
zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
zone.id,
|
zone.id,
|
||||||
AvatarAction.PlanetsideAttribute(resourceSilo.GUID, 45, resourceSilo.CapacitorDisplay)
|
AvatarAction.PlanetsideAttribute(resourceSilo.GUID, 45, resourceSilo.CapacitorDisplay)
|
||||||
)
|
)
|
||||||
building.Actor ! BuildingActor.MapUpdate()
|
building.Actor ! BuildingActor.MapUpdate()
|
||||||
}
|
}
|
||||||
val ntuIsLow = resourceSilo.NtuCapacitor.toFloat / resourceSilo.Definition.MaxNtuCapacitor.toFloat < 0.2f
|
val ntuIsLow = resourceSilo.NtuCapacitor / resourceSilo.Definition.MaxNtuCapacitor < 0.2f
|
||||||
if (resourceSilo.LowNtuWarningOn && !ntuIsLow) {
|
if (resourceSilo.LowNtuWarningOn && !ntuIsLow) {
|
||||||
LowNtuWarning(enabled = false)
|
LowNtuWarning(enabled = false)
|
||||||
} else if (!resourceSilo.LowNtuWarningOn && ntuIsLow) {
|
} else if (!resourceSilo.LowNtuWarningOn && ntuIsLow) {
|
||||||
|
|
@ -109,6 +115,8 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
||||||
if (resourceSilo.NtuCapacitor == 0 && siloChargeBeforeChange > 0) {
|
if (resourceSilo.NtuCapacitor == 0 && siloChargeBeforeChange > 0) {
|
||||||
// Oops, someone let the base run out of power. Shut it all down.
|
// Oops, someone let the base run out of power. Shut it all down.
|
||||||
zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.PlanetsideAttribute(building.GUID, 48, 1))
|
zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.PlanetsideAttribute(building.GUID, 48, 1))
|
||||||
|
building.Actor ! BuildingActor.NtuDepleted()
|
||||||
|
building.Actor ! BuildingActor.AmenityStateChange(resourceSilo)
|
||||||
building.Actor ! BuildingActor.SetFaction(PlanetSideEmpire.NEUTRAL)
|
building.Actor ! BuildingActor.SetFaction(PlanetSideEmpire.NEUTRAL)
|
||||||
} else if (siloChargeBeforeChange == 0 && resourceSilo.NtuCapacitor > 0) {
|
} else if (siloChargeBeforeChange == 0 && resourceSilo.NtuCapacitor > 0) {
|
||||||
// Power restored. Reactor Online. Sensors Online. Weapons Online. All systems nominal.
|
// Power restored. Reactor Online. Sensors Online. Weapons Online. All systems nominal.
|
||||||
|
|
@ -117,7 +125,8 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
||||||
zone.id,
|
zone.id,
|
||||||
AvatarAction.PlanetsideAttribute(building.GUID, 48, 0)
|
AvatarAction.PlanetsideAttribute(building.GUID, 48, 0)
|
||||||
)
|
)
|
||||||
building.Zone.actor ! ZoneActor.ZoneMapUpdate()
|
building.Actor ! BuildingActor.SuppliedWithNtu()
|
||||||
|
building.Actor ! BuildingActor.AmenityStateChange(resourceSilo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,7 +157,7 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
||||||
* @param min a minimum amount of nanites requested;
|
* @param min a minimum amount of nanites requested;
|
||||||
* @param max the amount of nanites required to not make further requests;
|
* @param max the amount of nanites required to not make further requests;
|
||||||
*/
|
*/
|
||||||
def HandleNtuRequest(sender: ActorRef, min: Int, max: Int): Unit = {
|
def HandleNtuRequest(sender: ActorRef, min: Float, max: Float): Unit = {
|
||||||
val originalAmount = resourceSilo.NtuCapacitor
|
val originalAmount = resourceSilo.NtuCapacitor
|
||||||
UpdateChargeLevel(-min)
|
UpdateChargeLevel(-min)
|
||||||
sender ! Ntu.Grant(resourceSilo, originalAmount - resourceSilo.NtuCapacitor)
|
sender ! Ntu.Grant(resourceSilo, originalAmount - resourceSilo.NtuCapacitor)
|
||||||
|
|
@ -157,7 +166,7 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
||||||
/**
|
/**
|
||||||
* Accept nanites into the silo capacitor and set the animation state.
|
* Accept nanites into the silo capacitor and set the animation state.
|
||||||
*/
|
*/
|
||||||
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Int): Unit = {
|
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Float): Unit = {
|
||||||
if (amount != 0) {
|
if (amount != 0) {
|
||||||
val originalAmount = resourceSilo.NtuCapacitor
|
val originalAmount = resourceSilo.NtuCapacitor
|
||||||
UpdateChargeLevel(amount)
|
UpdateChargeLevel(amount)
|
||||||
|
|
@ -174,7 +183,7 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
||||||
* @param trigger if positive, activate the animation;
|
* @param trigger if positive, activate the animation;
|
||||||
* if negative or zero, disable the animation
|
* if negative or zero, disable the animation
|
||||||
*/
|
*/
|
||||||
def PanelAnimation(trigger: Int): Unit = {
|
def PanelAnimation(trigger: Float): Unit = {
|
||||||
val zone = resourceSilo.Zone
|
val zone = resourceSilo.Zone
|
||||||
zone.VehicleEvents ! VehicleServiceMessage(
|
zone.VehicleEvents ! VehicleServiceMessage(
|
||||||
zone.id,
|
zone.id,
|
||||||
|
|
@ -185,5 +194,5 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
||||||
/**
|
/**
|
||||||
* Do nothing this turn.
|
* Do nothing this turn.
|
||||||
*/
|
*/
|
||||||
def SkipPanelAnimation(trigger: Int): Unit = {}
|
def SkipPanelAnimation(trigger: Float): Unit = {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import net.psforever.objects.vital.damage.DamageCalculations
|
||||||
import net.psforever.objects.vital.{DamageResistanceModel, StandardAmenityResistance, StandardResolutions, VitalityDefinition}
|
import net.psforever.objects.vital.{DamageResistanceModel, StandardAmenityResistance, StandardResolutions, VitalityDefinition}
|
||||||
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
||||||
|
|
||||||
|
final case class AutoRepairStats(amount: Int, start: Long, repeat: Long, drain: Float)
|
||||||
|
|
||||||
abstract class AmenityDefinition(objectId: Int)
|
abstract class AmenityDefinition(objectId: Int)
|
||||||
extends ObjectDefinition(objectId)
|
extends ObjectDefinition(objectId)
|
||||||
with ResistanceProfileMutators
|
with ResistanceProfileMutators
|
||||||
|
|
@ -15,4 +17,13 @@ abstract class AmenityDefinition(objectId: Int)
|
||||||
DamageUsing = DamageCalculations.AgainstVehicle
|
DamageUsing = DamageCalculations.AgainstVehicle
|
||||||
ResistUsing = StandardAmenityResistance
|
ResistUsing = StandardAmenityResistance
|
||||||
Model = StandardResolutions.Amenities
|
Model = StandardResolutions.Amenities
|
||||||
|
|
||||||
|
var autoRepair: Option[AutoRepairStats] = None
|
||||||
|
|
||||||
|
def autoRepair_=(auto: AutoRepairStats): Option[AutoRepairStats] = {
|
||||||
|
autoRepair = Some(auto)
|
||||||
|
autoRepair
|
||||||
|
}
|
||||||
|
|
||||||
|
def hasAutoRepair: Boolean = autoRepair.nonEmpty
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -330,9 +330,7 @@ object Building {
|
||||||
)(name: String, guid: Int, id: Int, zone: Zone, context: ActorContext): Building = {
|
)(name: String, guid: Int, id: Int, zone: Zone, context: ActorContext): Building = {
|
||||||
val obj = new Building(name, guid, id, zone, buildingType, buildingDefinition)
|
val obj = new Building(name, guid, id, zone, buildingType, buildingDefinition)
|
||||||
obj.Position = location
|
obj.Position = location
|
||||||
context.spawn(BuildingActor(zone, obj), s"$id-$buildingType-building").toClassic
|
obj.Actor = context.spawn(BuildingActor(zone, obj), s"$id-$buildingType-building").toClassic
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class AmenityStateChange(obj: Amenity)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -150,9 +150,9 @@ class WarpGate(name: String, building_guid: Int, map_id: Int, zone: Zone, buildi
|
||||||
|
|
||||||
def Owner: PlanetSideServerObject = this
|
def Owner: PlanetSideServerObject = this
|
||||||
|
|
||||||
def NtuCapacitor: Int = Definition.MaxNtuCapacitor
|
def NtuCapacitor: Float = Definition.MaxNtuCapacitor
|
||||||
|
|
||||||
def NtuCapacitor_=(value: Int): Int = NtuCapacitor
|
def NtuCapacitor_=(value: Float): Float = NtuCapacitor
|
||||||
|
|
||||||
override def Definition: WarpGateDefinition = buildingDefinition
|
override def Definition: WarpGateDefinition = buildingDefinition
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,8 +96,7 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit)
|
||||||
case ProximityUnit.Action(_, _) =>
|
case ProximityUnit.Action(_, _) =>
|
||||||
//reserved
|
//reserved
|
||||||
|
|
||||||
case msg =>
|
case _ =>
|
||||||
log.warn(s"unexpected message $msg")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def Use(target: PlanetSideGameObject, zone: String, callback: ActorRef): Unit = {
|
def Use(target: PlanetSideGameObject, zone: String, callback: ActorRef): Unit = {
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,14 @@
|
||||||
package net.psforever.objects.serverobject.terminals
|
package net.psforever.objects.serverobject.terminals
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorRef}
|
import akka.actor.{Actor, ActorRef}
|
||||||
|
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
|
||||||
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.Damageable.Target
|
||||||
|
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.RepairableAmenity
|
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableAmenity}
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.Building
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -19,17 +21,20 @@ class TerminalControl(term: Terminal)
|
||||||
with FactionAffinityBehavior.Check
|
with FactionAffinityBehavior.Check
|
||||||
with HackableBehavior.GenericHackable
|
with HackableBehavior.GenericHackable
|
||||||
with DamageableAmenity
|
with DamageableAmenity
|
||||||
with RepairableAmenity {
|
with RepairableAmenity
|
||||||
|
with AmenityAutoRepair {
|
||||||
def FactionObject = term
|
def FactionObject = term
|
||||||
def HackableObject = term
|
def HackableObject = term
|
||||||
def DamageableObject = term
|
def DamageableObject = term
|
||||||
def RepairableObject = term
|
def RepairableObject = term
|
||||||
|
def AutoRepairObject = term
|
||||||
|
|
||||||
def receive: Receive =
|
def receive: Receive =
|
||||||
checkBehavior
|
checkBehavior
|
||||||
.orElse(hackableBehavior)
|
.orElse(hackableBehavior)
|
||||||
.orElse(takesDamage)
|
.orElse(takesDamage)
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
.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)))
|
||||||
|
|
@ -46,9 +51,28 @@ class TerminalControl(term: Terminal)
|
||||||
)
|
)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override protected def DamageAwareness(target : Target, cause : ResolvedProjectile, amount : Any) : Unit = {
|
||||||
|
tryAutoRepair()
|
||||||
|
super.DamageAwareness(target, cause, amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected def DestructionAwareness(target: Damageable.Target, cause: ResolvedProjectile) : Unit = {
|
||||||
|
tryAutoRepair()
|
||||||
|
super.DestructionAwareness(target, cause)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def PerformRepairs(target : Target, amount : Int) : Int = {
|
||||||
|
val newHealth = super.PerformRepairs(target, amount)
|
||||||
|
if(newHealth == target.Definition.MaxHealth) {
|
||||||
|
stopAutoRepair()
|
||||||
|
}
|
||||||
|
newHealth
|
||||||
|
}
|
||||||
|
|
||||||
override def toString: String = term.Definition.Name
|
override def toString: String = term.Definition.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,12 @@
|
||||||
package net.psforever.objects.serverobject.tube
|
package net.psforever.objects.serverobject.tube
|
||||||
|
|
||||||
import akka.actor.Actor
|
import akka.actor.Actor
|
||||||
|
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.{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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -17,31 +18,48 @@ class SpawnTubeControl(tube: SpawnTube)
|
||||||
extends Actor
|
extends Actor
|
||||||
with FactionAffinityBehavior.Check
|
with FactionAffinityBehavior.Check
|
||||||
with DamageableAmenity
|
with DamageableAmenity
|
||||||
with RepairableAmenity {
|
with RepairableAmenity
|
||||||
|
with AmenityAutoRepair {
|
||||||
def FactionObject = tube
|
def FactionObject = tube
|
||||||
def DamageableObject = tube
|
def DamageableObject = tube
|
||||||
def RepairableObject = tube
|
def RepairableObject = tube
|
||||||
|
def AutoRepairObject = tube
|
||||||
|
|
||||||
def receive: Receive =
|
def receive: Receive =
|
||||||
checkBehavior
|
checkBehavior
|
||||||
.orElse(takesDamage)
|
.orElse(takesDamage)
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
|
.orElse(autoRepairBehavior)
|
||||||
.orElse {
|
.orElse {
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override protected def DamageAwareness(target : Target, cause : ResolvedProjectile, amount : Any) : Unit = {
|
||||||
|
tryAutoRepair()
|
||||||
|
super.DamageAwareness(target, cause, amount)
|
||||||
|
}
|
||||||
|
|
||||||
override protected def DestructionAwareness(target: Target, cause: ResolvedProjectile): Unit = {
|
override protected def DestructionAwareness(target: Target, cause: ResolvedProjectile): Unit = {
|
||||||
|
tryAutoRepair()
|
||||||
super.DestructionAwareness(target, cause)
|
super.DestructionAwareness(target, cause)
|
||||||
tube.Owner match {
|
tube.Owner match {
|
||||||
case b: Building => b.Actor ! Building.AmenityStateChange(tube)
|
case b: Building => b.Actor ! BuildingActor.AmenityStateChange(tube)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def PerformRepairs(target : Target, amount : Int) : Int = {
|
||||||
|
val newHealth = super.PerformRepairs(target, amount)
|
||||||
|
if(newHealth == target.Definition.MaxHealth) {
|
||||||
|
stopAutoRepair()
|
||||||
|
}
|
||||||
|
newHealth
|
||||||
|
}
|
||||||
|
|
||||||
override def Restoration(obj: Repairable.Target): Unit = {
|
override def Restoration(obj: Repairable.Target): Unit = {
|
||||||
super.Restoration(obj)
|
super.Restoration(obj)
|
||||||
tube.Owner match {
|
tube.Owner match {
|
||||||
case b: Building => b.Actor ! Building.AmenityStateChange(tube)
|
case b: Building => b.Actor ! BuildingActor.AmenityStateChange(tube)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,9 @@ import net.psforever.objects.equipment.{Ammo, JammableMountedWeapons}
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
import net.psforever.objects.serverobject.CommonMessages
|
||||||
import net.psforever.objects.serverobject.mount.MountableBehavior
|
import net.psforever.objects.serverobject.mount.MountableBehavior
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
||||||
import net.psforever.objects.serverobject.damage.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.Repairable.Target
|
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableWeaponTurret}
|
||||||
import net.psforever.objects.serverobject.repair.RepairableWeaponTurret
|
|
||||||
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}
|
||||||
|
|
||||||
|
|
@ -34,12 +33,14 @@ class FacilityTurretControl(turret: FacilityTurret)
|
||||||
with MountableBehavior.Dismount
|
with MountableBehavior.Dismount
|
||||||
with DamageableWeaponTurret
|
with DamageableWeaponTurret
|
||||||
with RepairableWeaponTurret
|
with RepairableWeaponTurret
|
||||||
|
with AmenityAutoRepair
|
||||||
with JammableMountedWeapons {
|
with JammableMountedWeapons {
|
||||||
def FactionObject = turret
|
def FactionObject = turret
|
||||||
def MountableObject = turret
|
def MountableObject = turret
|
||||||
def JammableObject = turret
|
def JammableObject = turret
|
||||||
def DamageableObject = turret
|
def DamageableObject = turret
|
||||||
def RepairableObject = turret
|
def RepairableObject = turret
|
||||||
|
def AutoRepairObject = turret
|
||||||
|
|
||||||
// Used for timing ammo recharge for vanu turrets in caves
|
// Used for timing ammo recharge for vanu turrets in caves
|
||||||
var weaponAmmoRechargeTimer = Default.Cancellable
|
var weaponAmmoRechargeTimer = Default.Cancellable
|
||||||
|
|
@ -47,6 +48,7 @@ class FacilityTurretControl(turret: FacilityTurret)
|
||||||
override def postStop(): Unit = {
|
override def postStop(): Unit = {
|
||||||
super.postStop()
|
super.postStop()
|
||||||
damageableWeaponTurretPostStop()
|
damageableWeaponTurretPostStop()
|
||||||
|
stopAutoRepair()
|
||||||
}
|
}
|
||||||
|
|
||||||
def receive: Receive =
|
def receive: Receive =
|
||||||
|
|
@ -56,6 +58,7 @@ class FacilityTurretControl(turret: FacilityTurret)
|
||||||
.orElse(dismountBehavior)
|
.orElse(dismountBehavior)
|
||||||
.orElse(takesDamage)
|
.orElse(takesDamage)
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
|
.orElse(autoRepairBehavior)
|
||||||
.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 &&
|
||||||
|
|
@ -110,7 +113,13 @@ class FacilityTurretControl(turret: FacilityTurret)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected def DestructionAwareness(target: Target, cause: ResolvedProjectile): Unit = {
|
override protected def DamageAwareness(target : Damageable.Target, cause : ResolvedProjectile, amount : Any) : Unit = {
|
||||||
|
tryAutoRepair()
|
||||||
|
super.DamageAwareness(target, cause, amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected def DestructionAwareness(target: Damageable.Target, cause: ResolvedProjectile): Unit = {
|
||||||
|
tryAutoRepair()
|
||||||
super.DestructionAwareness(target, cause)
|
super.DestructionAwareness(target, cause)
|
||||||
val zone = target.Zone
|
val zone = target.Zone
|
||||||
val zoneId = zone.id
|
val zoneId = zone.id
|
||||||
|
|
@ -120,7 +129,15 @@ class FacilityTurretControl(turret: FacilityTurret)
|
||||||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 51, 1))
|
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 51, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
override def Restoration(obj: Target): Unit = {
|
override def PerformRepairs(target : Damageable.Target, amount : Int) : Int = {
|
||||||
|
val newHealth = super.PerformRepairs(target, amount)
|
||||||
|
if(newHealth == target.Definition.MaxHealth) {
|
||||||
|
stopAutoRepair()
|
||||||
|
}
|
||||||
|
newHealth
|
||||||
|
}
|
||||||
|
|
||||||
|
override def Restoration(obj: Damageable.Target): Unit = {
|
||||||
super.Restoration(obj)
|
super.Restoration(obj)
|
||||||
val zone = turret.Zone
|
val zone = turret.Zone
|
||||||
val zoneId = zone.id
|
val zoneId = zone.id
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
||||||
//ANTs would charge from 0-100% in roughly 75s on live (https://www.youtube.com/watch?v=veOWToR2nSk&feature=youtu.be&t=1194)
|
//ANTs would charge from 0-100% in roughly 75s on live (https://www.youtube.com/watch?v=veOWToR2nSk&feature=youtu.be&t=1194)
|
||||||
val max = obj.Definition.MaxNtuCapacitor - obj.NtuCapacitor
|
val max = obj.Definition.MaxNtuCapacitor - obj.NtuCapacitor
|
||||||
target.Actor ! BuildingActor.Ntu(
|
target.Actor ! BuildingActor.Ntu(
|
||||||
NtuCommand.Request(scala.math.min(obj.Definition.MaxNtuCapacitor / 75, max), context.self)
|
NtuCommand.Request(scala.math.min(obj.Definition.MaxNtuCapacitor / 75f, max), context.self)
|
||||||
)
|
)
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
|
|
@ -86,7 +86,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def ReceiveAndDepositUntilFull(vehicle: Vehicle, amount: Int): Boolean = {
|
def ReceiveAndDepositUntilFull(vehicle: Vehicle, amount: Float): Boolean = {
|
||||||
val isNotFull = (vehicle.NtuCapacitor += amount) < vehicle.Definition.MaxNtuCapacitor
|
val isNotFull = (vehicle.NtuCapacitor += amount) < vehicle.Definition.MaxNtuCapacitor
|
||||||
UpdateNtuUI(vehicle)
|
UpdateNtuUI(vehicle)
|
||||||
isNotFull
|
isNotFull
|
||||||
|
|
@ -128,7 +128,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
||||||
ActivatePanelsForChargingEvent(ChargeTransferObject)
|
ActivatePanelsForChargingEvent(ChargeTransferObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
def WithdrawAndTransmit(vehicle: Vehicle, maxRequested: Int): Any = {
|
def WithdrawAndTransmit(vehicle: Vehicle, maxRequested: Float): Any = {
|
||||||
val chargeable = ChargeTransferObject
|
val chargeable = ChargeTransferObject
|
||||||
var chargeToDeposit = Math.min(Math.min(chargeable.NtuCapacitor, 100), maxRequested)
|
var chargeToDeposit = Math.min(Math.min(chargeable.NtuCapacitor, 100), maxRequested)
|
||||||
chargeable.NtuCapacitor -= chargeToDeposit
|
chargeable.NtuCapacitor -= chargeToDeposit
|
||||||
|
|
@ -176,7 +176,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
||||||
|
|
||||||
def HandleNtuOffer(sender: ActorRef, src: NtuContainer): Unit = {}
|
def HandleNtuOffer(sender: ActorRef, src: NtuContainer): Unit = {}
|
||||||
|
|
||||||
def HandleNtuRequest(sender: ActorRef, min: Int, max: Int): Unit = {
|
def HandleNtuRequest(sender: ActorRef, min: Float, max: Float): Unit = {
|
||||||
if (transferEvent == TransferBehavior.Event.Discharging) {
|
if (transferEvent == TransferBehavior.Event.Discharging) {
|
||||||
val chargeable = ChargeTransferObject
|
val chargeable = ChargeTransferObject
|
||||||
val chargeToDeposit = if (min == 0) {
|
val chargeToDeposit = if (min == 0) {
|
||||||
|
|
@ -197,7 +197,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Int): Unit = {
|
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Float): Unit = {
|
||||||
if (transferEvent == TransferBehavior.Event.Charging) {
|
if (transferEvent == TransferBehavior.Event.Charging) {
|
||||||
val obj = ChargeTransferObject
|
val obj = ChargeTransferObject
|
||||||
if (ReceiveAndDepositUntilFull(obj, amount)) {
|
if (ReceiveAndDepositUntilFull(obj, amount)) {
|
||||||
|
|
|
||||||
164
src/test/scala/objects/AutoRepairIntegrationTest.scala
Normal file
164
src/test/scala/objects/AutoRepairIntegrationTest.scala
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
// Copyright (c) 2020 PSForever
|
||||||
|
package objects
|
||||||
|
|
||||||
|
import akka.actor.Props
|
||||||
|
import akka.testkit.TestProbe
|
||||||
|
import base.FreedContextActorTest
|
||||||
|
import net.psforever.objects.avatar.Avatar
|
||||||
|
import net.psforever.objects.ballistics.{Projectile, ProjectileResolution, ResolvedProjectile, SourceEntry}
|
||||||
|
import net.psforever.objects.guid.NumberPoolHub
|
||||||
|
import net.psforever.objects.guid.source.MaxNumberSource
|
||||||
|
import net.psforever.objects.serverobject.resourcesilo.{ResourceSilo, ResourceSiloControl}
|
||||||
|
import net.psforever.objects.serverobject.structures.{AutoRepairStats, Building, StructureType}
|
||||||
|
import net.psforever.objects.serverobject.terminals.{OrderTerminalDefinition, Terminal, TerminalControl}
|
||||||
|
import net.psforever.objects.vital.Vitality
|
||||||
|
import net.psforever.objects.vital.damage.DamageProfile
|
||||||
|
import net.psforever.objects.zones.{Zone, ZoneMap}
|
||||||
|
import net.psforever.objects.{GlobalDefinitions, Player, Tool}
|
||||||
|
import net.psforever.services.galaxy.GalaxyService
|
||||||
|
import net.psforever.services.{InterstellarClusterService, ServiceManager}
|
||||||
|
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, Vector3}
|
||||||
|
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
class AutoRepairFacilityIntegrationTest extends FreedContextActorTest {
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id)
|
||||||
|
ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService](), "galaxy")
|
||||||
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
|
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||||
|
player.Spawn()
|
||||||
|
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||||
|
val terminal = new Terminal(AutoRepairIntegrationTest.terminal_definition)
|
||||||
|
val silo = new ResourceSilo()
|
||||||
|
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||||
|
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
override def SetupNumberPools() = {}
|
||||||
|
GUID(guid)
|
||||||
|
}
|
||||||
|
val avatarProbe = new TestProbe(system)
|
||||||
|
zone.AvatarEvents = avatarProbe.ref
|
||||||
|
|
||||||
|
guid.register(player, number = 1)
|
||||||
|
guid.register(weapon, number = 2)
|
||||||
|
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||||
|
guid.register(terminal, number = 4)
|
||||||
|
guid.register(silo, number = 5)
|
||||||
|
|
||||||
|
val building = Building.Structure(StructureType.Facility)(name = "test-building", guid = 6, map_id = 0, zone, context)
|
||||||
|
building.Invalidate()
|
||||||
|
guid.register(building, number = 6)
|
||||||
|
building.Amenities = silo
|
||||||
|
building.Amenities = terminal
|
||||||
|
|
||||||
|
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||||
|
|
||||||
|
silo.NtuCapacitor = 1000
|
||||||
|
silo.Actor = system.actorOf(Props(classOf[ResourceSiloControl], silo), "test-silo")
|
||||||
|
silo.Actor ! "startup"
|
||||||
|
|
||||||
|
val wep_fmode = weapon.FireMode
|
||||||
|
val wep_prof = wep_fmode.Add
|
||||||
|
val proj = weapon.Projectile
|
||||||
|
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||||
|
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||||
|
val resolved = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
projectile,
|
||||||
|
SourceEntry(terminal),
|
||||||
|
terminal.DamageModel,
|
||||||
|
Vector3(1, 0, 0)
|
||||||
|
)
|
||||||
|
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||||
|
|
||||||
|
"AutoRepair" should {
|
||||||
|
"should activate on damage and trade NTU from the facility's resource silo for repairs" in {
|
||||||
|
assert(silo.NtuCapacitor == silo.MaxNtuCapacitor)
|
||||||
|
assert(terminal.Health == terminal.MaxHealth)
|
||||||
|
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||||
|
|
||||||
|
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||||
|
assert(terminal.Health < terminal.MaxHealth)
|
||||||
|
var i = 0 //safety counter
|
||||||
|
while(terminal.Health < terminal.MaxHealth && i < 100) {
|
||||||
|
i += 1
|
||||||
|
avatarProbe.receiveOne(max = 1000 milliseconds) //health update event
|
||||||
|
}
|
||||||
|
assert(silo.NtuCapacitor < silo.MaxNtuCapacitor)
|
||||||
|
assert(terminal.Health == terminal.MaxHealth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AutoRepairTowerIntegrationTest extends FreedContextActorTest {
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id)
|
||||||
|
ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService](), "galaxy")
|
||||||
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
|
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||||
|
player.Spawn()
|
||||||
|
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||||
|
val terminal = new Terminal(AutoRepairIntegrationTest.terminal_definition)
|
||||||
|
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||||
|
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
override def SetupNumberPools() = {}
|
||||||
|
GUID(guid)
|
||||||
|
}
|
||||||
|
val avatarProbe = new TestProbe(system)
|
||||||
|
zone.AvatarEvents = avatarProbe.ref
|
||||||
|
|
||||||
|
guid.register(player, number = 1)
|
||||||
|
guid.register(weapon, number = 2)
|
||||||
|
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||||
|
guid.register(terminal, number = 4)
|
||||||
|
|
||||||
|
val building = Building.Structure(StructureType.Tower)(name = "test-building", guid = 6, map_id = 0, zone, context)
|
||||||
|
building.Invalidate()
|
||||||
|
guid.register(building, number = 6)
|
||||||
|
building.Amenities = terminal
|
||||||
|
|
||||||
|
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||||
|
|
||||||
|
val wep_fmode = weapon.FireMode
|
||||||
|
val wep_prof = wep_fmode.Add
|
||||||
|
val proj = weapon.Projectile
|
||||||
|
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||||
|
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||||
|
val resolved = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
projectile,
|
||||||
|
SourceEntry(terminal),
|
||||||
|
terminal.DamageModel,
|
||||||
|
Vector3(1, 0, 0)
|
||||||
|
)
|
||||||
|
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||||
|
|
||||||
|
"AutoRepair" should {
|
||||||
|
"should activate on damage and trade NTU from the tower for repairs" in {
|
||||||
|
assert(terminal.Health == terminal.MaxHealth)
|
||||||
|
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||||
|
|
||||||
|
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||||
|
assert(terminal.Health < terminal.MaxHealth)
|
||||||
|
var i = 0 //safety counter
|
||||||
|
while(terminal.Health < terminal.MaxHealth && i < 100) {
|
||||||
|
i += 1
|
||||||
|
avatarProbe.receiveOne(max = 1000 milliseconds) //health update event
|
||||||
|
}
|
||||||
|
assert(terminal.Health == terminal.MaxHealth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object AutoRepairIntegrationTest {
|
||||||
|
val terminal_definition = new OrderTerminalDefinition(objId = 612) {
|
||||||
|
Name = "order_terminal"
|
||||||
|
MaxHealth = 500
|
||||||
|
Damageable = true
|
||||||
|
Repairable = true
|
||||||
|
autoRepair = AutoRepairStats(1, 500, 500, 1)
|
||||||
|
RepairIfDestroyed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
390
src/test/scala/objects/AutoRepairTest.scala
Normal file
390
src/test/scala/objects/AutoRepairTest.scala
Normal file
|
|
@ -0,0 +1,390 @@
|
||||||
|
// Copyright (c) 2020 PSForever
|
||||||
|
package objects
|
||||||
|
|
||||||
|
import akka.actor.Props
|
||||||
|
import akka.testkit.TestProbe
|
||||||
|
import base.FreedContextActorTest
|
||||||
|
import net.psforever.actors.commands.NtuCommand
|
||||||
|
import net.psforever.actors.zone.BuildingActor
|
||||||
|
import net.psforever.objects.avatar.Avatar
|
||||||
|
import net.psforever.objects.ballistics.{Projectile, ProjectileResolution, ResolvedProjectile, SourceEntry}
|
||||||
|
import net.psforever.objects.guid.NumberPoolHub
|
||||||
|
import net.psforever.objects.guid.source.MaxNumberSource
|
||||||
|
import net.psforever.objects.serverobject.structures.{AutoRepairStats, Building, StructureType}
|
||||||
|
import net.psforever.objects.serverobject.terminals.{OrderTerminalDefinition, Terminal, TerminalControl}
|
||||||
|
import net.psforever.objects.vital.Vitality
|
||||||
|
import net.psforever.objects.vital.damage.DamageProfile
|
||||||
|
import net.psforever.objects.zones.{Zone, ZoneMap}
|
||||||
|
import net.psforever.objects.{GlobalDefinitions, Player, Tool}
|
||||||
|
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, Vector3}
|
||||||
|
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
class AutoRepairRequestNtuTest extends FreedContextActorTest {
|
||||||
|
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||||
|
player.Spawn()
|
||||||
|
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||||
|
val terminal = new Terminal(AutoRepairTest.terminal_definition)
|
||||||
|
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||||
|
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
override def SetupNumberPools() = {}
|
||||||
|
GUID(guid)
|
||||||
|
}
|
||||||
|
val avatarProbe = new TestProbe(system)
|
||||||
|
zone.AvatarEvents = avatarProbe.ref
|
||||||
|
|
||||||
|
guid.register(player, number = 1)
|
||||||
|
guid.register(weapon, number = 2)
|
||||||
|
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||||
|
guid.register(terminal, number = 4)
|
||||||
|
|
||||||
|
val building = Building("test-building", 1, 1, zone, StructureType.Facility)
|
||||||
|
building.Invalidate()
|
||||||
|
guid.register(building, number = 6)
|
||||||
|
val buildingProbe = new TestProbe(system)
|
||||||
|
building.Actor = buildingProbe.ref
|
||||||
|
building.Zone = zone
|
||||||
|
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||||
|
terminal.Owner = building
|
||||||
|
|
||||||
|
val wep_fmode = weapon.FireMode
|
||||||
|
val wep_prof = wep_fmode.Add
|
||||||
|
val proj = weapon.Projectile
|
||||||
|
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||||
|
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||||
|
val resolved = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
projectile,
|
||||||
|
SourceEntry(terminal),
|
||||||
|
terminal.DamageModel,
|
||||||
|
Vector3(1, 0, 0)
|
||||||
|
)
|
||||||
|
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||||
|
|
||||||
|
"AutoRepair" should {
|
||||||
|
"asks owning building for NTU after damage" in {
|
||||||
|
assert(terminal.Health == terminal.MaxHealth)
|
||||||
|
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||||
|
|
||||||
|
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||||
|
assert(terminal.Health < terminal.MaxHealth)
|
||||||
|
val buildingMsg = buildingProbe.receiveOne(max = 600 milliseconds)
|
||||||
|
assert(buildingMsg match {
|
||||||
|
case BuildingActor.Ntu(NtuCommand.Request(drain, _)) =>
|
||||||
|
drain == terminal.Definition.autoRepair.get.drain
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AutoRepairRequestNtuRepeatTest extends FreedContextActorTest {
|
||||||
|
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||||
|
player.Spawn()
|
||||||
|
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||||
|
val terminal = new Terminal(AutoRepairTest.terminal_definition)
|
||||||
|
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||||
|
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
override def SetupNumberPools() = {}
|
||||||
|
GUID(guid)
|
||||||
|
}
|
||||||
|
val avatarProbe = new TestProbe(system)
|
||||||
|
zone.AvatarEvents = avatarProbe.ref
|
||||||
|
|
||||||
|
guid.register(player, number = 1)
|
||||||
|
guid.register(weapon, number = 2)
|
||||||
|
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||||
|
guid.register(terminal, number = 4)
|
||||||
|
|
||||||
|
val building = Building("test-building", 1, 1, zone, StructureType.Facility)
|
||||||
|
building.Invalidate()
|
||||||
|
guid.register(building, number = 6)
|
||||||
|
val buildingProbe = new TestProbe(system)
|
||||||
|
building.Actor = buildingProbe.ref
|
||||||
|
building.Zone = zone
|
||||||
|
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||||
|
terminal.Owner = building
|
||||||
|
|
||||||
|
val wep_fmode = weapon.FireMode
|
||||||
|
val wep_prof = wep_fmode.Add
|
||||||
|
val proj = weapon.Projectile
|
||||||
|
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||||
|
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||||
|
val resolved = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
projectile,
|
||||||
|
SourceEntry(terminal),
|
||||||
|
terminal.DamageModel,
|
||||||
|
Vector3(1, 0, 0)
|
||||||
|
)
|
||||||
|
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||||
|
|
||||||
|
"AutoRepair" should {
|
||||||
|
"repeatedly asks owning building for NTU after damage" in {
|
||||||
|
assert(terminal.Health == terminal.MaxHealth)
|
||||||
|
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||||
|
|
||||||
|
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||||
|
assert(terminal.Health < terminal.MaxHealth)
|
||||||
|
(0 to 3).foreach { _ =>
|
||||||
|
val buildingMsg = buildingProbe.receiveOne(max = 1000 milliseconds)
|
||||||
|
assert(buildingMsg match {
|
||||||
|
case BuildingActor.Ntu(NtuCommand.Request(drain, _)) =>
|
||||||
|
drain == terminal.Definition.autoRepair.get.drain
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AutoRepairNoRequestNtuTest extends FreedContextActorTest {
|
||||||
|
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||||
|
player.Spawn()
|
||||||
|
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||||
|
val terminal = new Terminal(AutoRepairTest.terminal_definition)
|
||||||
|
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||||
|
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
override def SetupNumberPools() = {}
|
||||||
|
GUID(guid)
|
||||||
|
}
|
||||||
|
val avatarProbe = new TestProbe(system)
|
||||||
|
zone.AvatarEvents = avatarProbe.ref
|
||||||
|
|
||||||
|
guid.register(player, number = 1)
|
||||||
|
guid.register(weapon, number = 2)
|
||||||
|
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||||
|
guid.register(terminal, number = 4)
|
||||||
|
|
||||||
|
val building = Building("test-building", 1, 1, zone, StructureType.Facility)
|
||||||
|
building.Invalidate()
|
||||||
|
guid.register(building, number = 6)
|
||||||
|
val buildingProbe = new TestProbe(system)
|
||||||
|
building.Actor = buildingProbe.ref
|
||||||
|
building.Zone = zone
|
||||||
|
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||||
|
terminal.Owner = building
|
||||||
|
|
||||||
|
val wep_fmode = weapon.FireMode
|
||||||
|
val wep_prof = wep_fmode.Add
|
||||||
|
val proj = weapon.Projectile
|
||||||
|
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||||
|
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||||
|
val resolved = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
projectile,
|
||||||
|
SourceEntry(terminal),
|
||||||
|
terminal.DamageModel,
|
||||||
|
Vector3(1, 0, 0)
|
||||||
|
)
|
||||||
|
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||||
|
|
||||||
|
"AutoRepair" should {
|
||||||
|
"not ask for NTU after damage if it expects no NTU" in {
|
||||||
|
assert(terminal.Health == terminal.MaxHealth)
|
||||||
|
terminal.Actor ! BuildingActor.NtuDepleted()
|
||||||
|
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||||
|
|
||||||
|
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||||
|
assert(terminal.Health < terminal.MaxHealth)
|
||||||
|
buildingProbe.expectNoMessage(max = 2000 milliseconds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AutoRepairRestoreRequestNtuTest extends FreedContextActorTest {
|
||||||
|
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||||
|
player.Spawn()
|
||||||
|
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||||
|
val terminal = new Terminal(AutoRepairTest.terminal_definition)
|
||||||
|
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||||
|
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
override def SetupNumberPools() = {}
|
||||||
|
GUID(guid)
|
||||||
|
}
|
||||||
|
val avatarProbe = new TestProbe(system)
|
||||||
|
zone.AvatarEvents = avatarProbe.ref
|
||||||
|
|
||||||
|
guid.register(player, number = 1)
|
||||||
|
guid.register(weapon, number = 2)
|
||||||
|
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||||
|
guid.register(terminal, number = 4)
|
||||||
|
|
||||||
|
val building = Building("test-building", 1, 1, zone, StructureType.Facility)
|
||||||
|
building.Invalidate()
|
||||||
|
guid.register(building, number = 6)
|
||||||
|
val buildingProbe = new TestProbe(system)
|
||||||
|
building.Actor = buildingProbe.ref
|
||||||
|
building.Zone = zone
|
||||||
|
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||||
|
terminal.Owner = building
|
||||||
|
|
||||||
|
val wep_fmode = weapon.FireMode
|
||||||
|
val wep_prof = wep_fmode.Add
|
||||||
|
val proj = weapon.Projectile
|
||||||
|
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||||
|
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||||
|
val resolved = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
projectile,
|
||||||
|
SourceEntry(terminal),
|
||||||
|
terminal.DamageModel,
|
||||||
|
Vector3(1, 0, 0)
|
||||||
|
)
|
||||||
|
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||||
|
|
||||||
|
"AutoRepair" should {
|
||||||
|
"ask for NTU after damage if its expectation of NTU is restored" in {
|
||||||
|
assert(terminal.Health == terminal.MaxHealth)
|
||||||
|
terminal.Actor ! BuildingActor.NtuDepleted()
|
||||||
|
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||||
|
|
||||||
|
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||||
|
assert(terminal.Health < terminal.MaxHealth)
|
||||||
|
buildingProbe.expectNoMessage(max = 2000 milliseconds)
|
||||||
|
|
||||||
|
terminal.Actor ! BuildingActor.SuppliedWithNtu()
|
||||||
|
val buildingMsg = buildingProbe.receiveOne(max = 600 milliseconds)
|
||||||
|
assert(buildingMsg match {
|
||||||
|
case BuildingActor.Ntu(NtuCommand.Request(drain, _)) =>
|
||||||
|
drain == terminal.Definition.autoRepair.get.drain
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AutoRepairRepairWithNtuTest extends FreedContextActorTest {
|
||||||
|
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||||
|
player.Spawn()
|
||||||
|
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||||
|
val terminal = new Terminal(AutoRepairTest.terminal_definition)
|
||||||
|
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||||
|
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
override def SetupNumberPools() = {}
|
||||||
|
GUID(guid)
|
||||||
|
}
|
||||||
|
val avatarProbe = new TestProbe(system)
|
||||||
|
zone.AvatarEvents = avatarProbe.ref
|
||||||
|
|
||||||
|
guid.register(player, number = 1)
|
||||||
|
guid.register(weapon, number = 2)
|
||||||
|
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||||
|
guid.register(terminal, number = 4)
|
||||||
|
|
||||||
|
val building = Building("test-building", 1, 1, zone, StructureType.Facility)
|
||||||
|
building.Invalidate()
|
||||||
|
guid.register(building, number = 6)
|
||||||
|
val buildingProbe = new TestProbe(system)
|
||||||
|
building.Actor = buildingProbe.ref
|
||||||
|
building.Zone = zone
|
||||||
|
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||||
|
terminal.Owner = building
|
||||||
|
|
||||||
|
val wep_fmode = weapon.FireMode
|
||||||
|
val wep_prof = wep_fmode.Add
|
||||||
|
val proj = weapon.Projectile
|
||||||
|
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||||
|
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||||
|
val resolved = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
projectile,
|
||||||
|
SourceEntry(terminal),
|
||||||
|
terminal.DamageModel,
|
||||||
|
Vector3(1, 0, 0)
|
||||||
|
)
|
||||||
|
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||||
|
|
||||||
|
"AutoRepair" should {
|
||||||
|
"repair some of the damage when it receives NTU" in {
|
||||||
|
assert(terminal.Health == terminal.MaxHealth)
|
||||||
|
terminal.Actor ! BuildingActor.NtuDepleted() //don't worry about requests
|
||||||
|
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||||
|
|
||||||
|
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||||
|
assert(terminal.Health < terminal.MaxHealth)
|
||||||
|
val reducedHealth = terminal.Health
|
||||||
|
buildingProbe.expectNoMessage(max = 2000 milliseconds)
|
||||||
|
terminal.Actor ! NtuCommand.Grant(null, 1)
|
||||||
|
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||||
|
assert(terminal.Health > reducedHealth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AutoRepairRepairWithNtuUntilDoneTest extends FreedContextActorTest {
|
||||||
|
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||||
|
player.Spawn()
|
||||||
|
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||||
|
val terminal = new Terminal(AutoRepairTest.terminal_definition)
|
||||||
|
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||||
|
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
|
override def SetupNumberPools() = {}
|
||||||
|
GUID(guid)
|
||||||
|
}
|
||||||
|
val avatarProbe = new TestProbe(system)
|
||||||
|
zone.AvatarEvents = avatarProbe.ref
|
||||||
|
|
||||||
|
guid.register(player, number = 1)
|
||||||
|
guid.register(weapon, number = 2)
|
||||||
|
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||||
|
guid.register(terminal, number = 4)
|
||||||
|
|
||||||
|
val building = Building("test-building", 1, 1, zone, StructureType.Facility)
|
||||||
|
building.Invalidate()
|
||||||
|
guid.register(building, number = 6)
|
||||||
|
val buildingProbe = new TestProbe(system)
|
||||||
|
building.Actor = buildingProbe.ref
|
||||||
|
building.Zone = zone
|
||||||
|
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||||
|
terminal.Owner = building
|
||||||
|
|
||||||
|
val wep_fmode = weapon.FireMode
|
||||||
|
val wep_prof = wep_fmode.Add
|
||||||
|
val proj = weapon.Projectile
|
||||||
|
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||||
|
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||||
|
val resolved = ResolvedProjectile(
|
||||||
|
ProjectileResolution.Hit,
|
||||||
|
projectile,
|
||||||
|
SourceEntry(terminal),
|
||||||
|
terminal.DamageModel,
|
||||||
|
Vector3(1, 0, 0)
|
||||||
|
)
|
||||||
|
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||||
|
|
||||||
|
"AutoRepair" should {
|
||||||
|
"ask for NTU after damage and repair some of the damage when it receives NTU, until fully-repaired" in {
|
||||||
|
assert(terminal.Health == terminal.MaxHealth)
|
||||||
|
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||||
|
|
||||||
|
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||||
|
assert(terminal.Health < terminal.MaxHealth)
|
||||||
|
var i = 0
|
||||||
|
while(terminal.Health < terminal.MaxHealth && i < 100) {
|
||||||
|
i += 1 //safety counter
|
||||||
|
val buildingMsg = buildingProbe.receiveOne(max = 1000 milliseconds)
|
||||||
|
buildingMsg match {
|
||||||
|
case BuildingActor.Ntu(NtuCommand.Request(_, _)) =>
|
||||||
|
terminal.Actor ! NtuCommand.Grant(null, 1)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(terminal.Health == terminal.MaxHealth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object AutoRepairTest {
|
||||||
|
val terminal_definition = new OrderTerminalDefinition(objId = 612) {
|
||||||
|
Name = "order_terminal"
|
||||||
|
MaxHealth = 500
|
||||||
|
Damageable = true
|
||||||
|
Repairable = true
|
||||||
|
autoRepair = AutoRepairStats(1, 500, 500, 1)
|
||||||
|
RepairIfDestroyed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,22 +25,22 @@ class DoorTest extends Specification {
|
||||||
|
|
||||||
"starts as closed (false)" in {
|
"starts as closed (false)" in {
|
||||||
val door = Door(GlobalDefinitions.door)
|
val door = Door(GlobalDefinitions.door)
|
||||||
door.Open mustEqual None
|
door.Open.isEmpty mustEqual true
|
||||||
door.isOpen mustEqual false
|
door.isOpen mustEqual false
|
||||||
}
|
}
|
||||||
|
|
||||||
"be opened and closed (1; manual)" in {
|
"be opened and closed (1; manual)" in {
|
||||||
val door = Door(GlobalDefinitions.door)
|
val door = Door(GlobalDefinitions.door)
|
||||||
door.isOpen mustEqual false
|
door.isOpen mustEqual false
|
||||||
door.Open mustEqual None
|
door.Open.isEmpty mustEqual true
|
||||||
|
|
||||||
door.Open = Some(player)
|
door.Open = Some(player)
|
||||||
door.isOpen mustEqual true
|
door.isOpen mustEqual true
|
||||||
door.Open mustEqual Some(player)
|
door.Open.contains(player) mustEqual true
|
||||||
|
|
||||||
door.Open = None
|
door.Open = None
|
||||||
door.isOpen mustEqual false
|
door.isOpen mustEqual false
|
||||||
door.Open mustEqual None
|
door.Open.isEmpty mustEqual true
|
||||||
}
|
}
|
||||||
|
|
||||||
"be opened and closed (2; toggle)" in {
|
"be opened and closed (2; toggle)" in {
|
||||||
|
|
@ -58,11 +58,11 @@ class DoorTest extends Specification {
|
||||||
364
|
364
|
||||||
)
|
)
|
||||||
val door = Door(GlobalDefinitions.door)
|
val door = Door(GlobalDefinitions.door)
|
||||||
door.Open mustEqual None
|
door.Open.isEmpty mustEqual true
|
||||||
door.Use(player, msg)
|
door.Use(player, msg)
|
||||||
door.Open mustEqual Some(player)
|
door.Open.contains(player) mustEqual true
|
||||||
door.Use(player, msg)
|
door.Use(player, msg)
|
||||||
door.Open mustEqual None
|
door.Open.isEmpty mustEqual true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -115,8 +115,7 @@ class DoorControl3Test extends ActorTest {
|
||||||
assert(door.Open.isEmpty)
|
assert(door.Open.isEmpty)
|
||||||
|
|
||||||
door.Actor ! "trash"
|
door.Actor ! "trash"
|
||||||
val reply = receiveOne(Duration.create(500, "ms"))
|
expectNoMessage(Duration.create(500, "ms"))
|
||||||
assert(reply.isInstanceOf[Door.NoEvent])
|
|
||||||
assert(door.Open.isEmpty)
|
assert(door.Open.isEmpty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package objects
|
||||||
import akka.actor.{ActorRef, Props}
|
import akka.actor.{ActorRef, Props}
|
||||||
import akka.testkit.TestProbe
|
import akka.testkit.TestProbe
|
||||||
import base.ActorTest
|
import base.ActorTest
|
||||||
|
import net.psforever.actors.zone.BuildingActor
|
||||||
import net.psforever.objects.avatar.Avatar
|
import net.psforever.objects.avatar.Avatar
|
||||||
import net.psforever.objects.ballistics._
|
import net.psforever.objects.ballistics._
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player, Tool}
|
import net.psforever.objects.{GlobalDefinitions, Player, Tool}
|
||||||
|
|
@ -206,7 +207,7 @@ class GeneratorControlCriticalTest extends ActorTest {
|
||||||
)
|
)
|
||||||
assert(
|
assert(
|
||||||
msg_building match {
|
msg_building match {
|
||||||
case Building.AmenityStateChange(o) => o eq gen
|
case BuildingActor.AmenityStateChange(o) => o eq gen
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -268,6 +269,7 @@ class GeneratorControlDestroyedTest extends ActorTest {
|
||||||
Vector3(1, 0, 0)
|
Vector3(1, 0, 0)
|
||||||
)
|
)
|
||||||
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||||
|
gen.Actor ! BuildingActor.NtuDepleted() //no auto-repair
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
//we're not testing that the math is correct
|
//we're not testing that the math is correct
|
||||||
|
|
||||||
|
|
@ -293,12 +295,11 @@ class GeneratorControlDestroyedTest extends ActorTest {
|
||||||
assert(gen.Condition == PlanetSideGeneratorState.Normal)
|
assert(gen.Condition == PlanetSideGeneratorState.Normal)
|
||||||
|
|
||||||
avatarProbe.expectNoMessage(9 seconds)
|
avatarProbe.expectNoMessage(9 seconds)
|
||||||
buildingProbe.expectNoMessage(50 milliseconds) //no prior messages
|
|
||||||
val msg_avatar2 = avatarProbe.receiveN(3, 1000 milliseconds) //see DamageableEntity test file
|
val msg_avatar2 = avatarProbe.receiveN(3, 1000 milliseconds) //see DamageableEntity test file
|
||||||
val msg_building = buildingProbe.receiveOne(200 milliseconds)
|
val msg_building = buildingProbe.receiveOne(200 milliseconds)
|
||||||
assert(
|
assert(
|
||||||
msg_building match {
|
msg_building match {
|
||||||
case Building.AmenityStateChange(o) => o eq gen
|
case BuildingActor.AmenityStateChange(o) => o eq gen
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -399,6 +400,7 @@ class GeneratorControlKillsTest extends ActorTest {
|
||||||
Vector3(1, 0, 0)
|
Vector3(1, 0, 0)
|
||||||
)
|
)
|
||||||
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||||
|
gen.Actor ! BuildingActor.NtuDepleted() //no auto-repair
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
//we're not testing that the math is correct
|
//we're not testing that the math is correct
|
||||||
|
|
||||||
|
|
@ -438,7 +440,7 @@ class GeneratorControlKillsTest extends ActorTest {
|
||||||
player2Probe.expectNoMessage(200 milliseconds)
|
player2Probe.expectNoMessage(200 milliseconds)
|
||||||
assert(
|
assert(
|
||||||
msg_building match {
|
msg_building match {
|
||||||
case Building.AmenityStateChange(o) => o eq gen
|
case BuildingActor.AmenityStateChange(o) => o eq gen
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -840,7 +842,7 @@ class GeneratorControlRepairPastRestorePoint extends ActorTest {
|
||||||
)
|
)
|
||||||
assert(
|
assert(
|
||||||
msg_building match {
|
msg_building match {
|
||||||
case Building.AmenityStateChange(o) => o eq gen
|
case BuildingActor.AmenityStateChange(o) => o eq gen
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -87,12 +87,63 @@ class ResourceSiloControlStartupTest extends ActorTest {
|
||||||
"Resource silo" should {
|
"Resource silo" should {
|
||||||
"startup properly" in {
|
"startup properly" in {
|
||||||
expectNoMessage(500 milliseconds)
|
expectNoMessage(500 milliseconds)
|
||||||
system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo") ! "startup"
|
||||||
expectNoMessage(1 seconds)
|
expectNoMessage(1 seconds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ResourceSiloControlStartupMessageNoneTest extends ActorTest {
|
||||||
|
val obj = ResourceSilo()
|
||||||
|
obj.GUID = PlanetSideGUID(1)
|
||||||
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
|
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||||
|
val buildingEvents = TestProbe("test-building-events")
|
||||||
|
obj.Owner =
|
||||||
|
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
|
||||||
|
Actor = buildingEvents.ref
|
||||||
|
}
|
||||||
|
obj.Owner.GUID = PlanetSideGUID(6)
|
||||||
|
|
||||||
|
"Resource silo" should {
|
||||||
|
"report if it has no NTU on startup" in {
|
||||||
|
assert(obj.NtuCapacitor == 0)
|
||||||
|
obj.Actor ! "startup"
|
||||||
|
val ownerMsg = buildingEvents.receiveOne(200 milliseconds)
|
||||||
|
assert(ownerMsg match {
|
||||||
|
case BuildingActor.NtuDepleted() => true
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ResourceSiloControlStartupMessageSomeTest extends ActorTest {
|
||||||
|
val obj = ResourceSilo()
|
||||||
|
obj.GUID = PlanetSideGUID(1)
|
||||||
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
|
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||||
|
val buildingEvents = TestProbe("test-building-events")
|
||||||
|
obj.Owner =
|
||||||
|
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
|
||||||
|
Actor = buildingEvents.ref
|
||||||
|
}
|
||||||
|
obj.Owner.GUID = PlanetSideGUID(6)
|
||||||
|
|
||||||
|
"Resource silo" should {
|
||||||
|
"report if it has any NTU on startup" in {
|
||||||
|
obj.NtuCapacitor = 1
|
||||||
|
assert(obj.NtuCapacitor == 1)
|
||||||
|
obj.Actor ! "startup"
|
||||||
|
val ownerMsg = buildingEvents.receiveOne(200 milliseconds)
|
||||||
|
assert(ownerMsg match {
|
||||||
|
case BuildingActor.SuppliedWithNtu() => true
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ResourceSiloControlUseTest extends ActorTest {
|
class ResourceSiloControlUseTest extends ActorTest {
|
||||||
val guid = new NumberPoolHub(new MaxNumberSource(10))
|
val guid = new NumberPoolHub(new MaxNumberSource(10))
|
||||||
val map = new ZoneMap("test")
|
val map = new ZoneMap("test")
|
||||||
|
|
@ -109,6 +160,7 @@ class ResourceSiloControlUseTest extends ActorTest {
|
||||||
StructureType.Building,
|
StructureType.Building,
|
||||||
GlobalDefinitions.building
|
GlobalDefinitions.building
|
||||||
) //guid=1
|
) //guid=1
|
||||||
|
building.Actor = TestProbe("building-actor").ref
|
||||||
|
|
||||||
val obj = ResourceSilo() //guid=2
|
val obj = ResourceSilo() //guid=2
|
||||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
|
|
@ -151,21 +203,23 @@ class ResourceSiloControlNtuWarningTest extends ActorTest {
|
||||||
val obj = ResourceSilo()
|
val obj = ResourceSilo()
|
||||||
obj.GUID = PlanetSideGUID(1)
|
obj.GUID = PlanetSideGUID(1)
|
||||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
obj.Actor ! "startup"
|
|
||||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||||
obj.Owner =
|
obj.Owner =
|
||||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
|
||||||
|
Actor = TestProbe("building-events").ref
|
||||||
|
}
|
||||||
obj.Owner.GUID = PlanetSideGUID(6)
|
obj.Owner.GUID = PlanetSideGUID(6)
|
||||||
|
|
||||||
val zoneEvents = TestProbe("zone-events")
|
val zoneEvents = TestProbe("zone-events")
|
||||||
|
zone.AvatarEvents = zoneEvents.ref
|
||||||
|
obj.Actor ! "startup"
|
||||||
|
|
||||||
"Resource silo" should {
|
"Resource silo" should {
|
||||||
"announce high ntu" in {
|
"announce high ntu" in {
|
||||||
zone.AvatarEvents = zoneEvents.ref
|
|
||||||
assert(obj.LowNtuWarningOn)
|
assert(obj.LowNtuWarningOn)
|
||||||
obj.Actor ! ResourceSilo.LowNtuWarning(false)
|
obj.Actor ! ResourceSilo.LowNtuWarning(false)
|
||||||
|
|
||||||
val reply = zoneEvents.receiveOne(500 milliseconds)
|
val reply = zoneEvents.receiveOne(5000 milliseconds)
|
||||||
assert(!obj.LowNtuWarningOn)
|
|
||||||
assert(reply.isInstanceOf[AvatarServiceMessage])
|
assert(reply.isInstanceOf[AvatarServiceMessage])
|
||||||
assert(reply.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere")
|
assert(reply.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere")
|
||||||
assert(reply.asInstanceOf[AvatarServiceMessage].actionMessage.isInstanceOf[AvatarAction.PlanetsideAttribute])
|
assert(reply.asInstanceOf[AvatarServiceMessage].actionMessage.isInstanceOf[AvatarAction.PlanetsideAttribute])
|
||||||
|
|
@ -190,6 +244,7 @@ class ResourceSiloControlNtuWarningTest extends ActorTest {
|
||||||
.asInstanceOf[AvatarAction.PlanetsideAttribute]
|
.asInstanceOf[AvatarAction.PlanetsideAttribute]
|
||||||
.attribute_value == 0
|
.attribute_value == 0
|
||||||
)
|
)
|
||||||
|
assert(!obj.LowNtuWarningOn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -198,7 +253,6 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
|
||||||
val obj = ResourceSilo()
|
val obj = ResourceSilo()
|
||||||
obj.GUID = PlanetSideGUID(1)
|
obj.GUID = PlanetSideGUID(1)
|
||||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
obj.Actor ! "startup"
|
|
||||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||||
val bldg =
|
val bldg =
|
||||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
||||||
|
|
@ -206,12 +260,13 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
|
||||||
obj.Owner = bldg
|
obj.Owner = bldg
|
||||||
val zoneEvents = TestProbe("zone-events")
|
val zoneEvents = TestProbe("zone-events")
|
||||||
val buildingEvents = TestProbe("building-events")
|
val buildingEvents = TestProbe("building-events")
|
||||||
|
zone.AvatarEvents = zoneEvents.ref
|
||||||
|
bldg.Actor = buildingEvents.ref
|
||||||
|
obj.Actor ! "startup"
|
||||||
|
|
||||||
"Resource silo" should {
|
"Resource silo" should {
|
||||||
"update the charge level and capacitor display (report high ntu, power restored)" in {
|
"update the charge level and capacitor display (report high ntu, power restored)" in {
|
||||||
zone.AvatarEvents = zoneEvents.ref
|
buildingEvents.receiveOne(500 milliseconds) //message caused by "startup"
|
||||||
bldg.Actor = buildingEvents.ref
|
|
||||||
|
|
||||||
assert(obj.NtuCapacitor == 0)
|
assert(obj.NtuCapacitor == 0)
|
||||||
assert(obj.CapacitorDisplay == 0)
|
assert(obj.CapacitorDisplay == 0)
|
||||||
assert(obj.LowNtuWarningOn)
|
assert(obj.LowNtuWarningOn)
|
||||||
|
|
@ -247,7 +302,6 @@ class ResourceSiloControlUpdate2Test extends ActorTest {
|
||||||
val obj = ResourceSilo()
|
val obj = ResourceSilo()
|
||||||
obj.GUID = PlanetSideGUID(1)
|
obj.GUID = PlanetSideGUID(1)
|
||||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
obj.Actor ! "startup"
|
|
||||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||||
val bldg =
|
val bldg =
|
||||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
||||||
|
|
@ -255,12 +309,13 @@ class ResourceSiloControlUpdate2Test extends ActorTest {
|
||||||
obj.Owner = bldg
|
obj.Owner = bldg
|
||||||
val zoneEvents = TestProbe("zone-events")
|
val zoneEvents = TestProbe("zone-events")
|
||||||
val buildingEvents = TestProbe("building-events")
|
val buildingEvents = TestProbe("building-events")
|
||||||
|
zone.AvatarEvents = zoneEvents.ref
|
||||||
|
bldg.Actor = buildingEvents.ref
|
||||||
|
obj.Actor ! "startup"
|
||||||
|
|
||||||
"Resource silo" should {
|
"Resource silo" should {
|
||||||
"update the charge level and capacitor display (report good ntu)" in {
|
"update the charge level and capacitor display (report good ntu)" in {
|
||||||
zone.AvatarEvents = zoneEvents.ref
|
buildingEvents.receiveOne(500 milliseconds) //message caused by "startup"
|
||||||
bldg.Actor = buildingEvents.ref
|
|
||||||
|
|
||||||
obj.NtuCapacitor = 100
|
obj.NtuCapacitor = 100
|
||||||
obj.LowNtuWarningOn = true
|
obj.LowNtuWarningOn = true
|
||||||
assert(obj.NtuCapacitor == 100)
|
assert(obj.NtuCapacitor == 100)
|
||||||
|
|
@ -333,7 +388,6 @@ class ResourceSiloControlNoUpdateTest extends ActorTest {
|
||||||
val obj = ResourceSilo()
|
val obj = ResourceSilo()
|
||||||
obj.GUID = PlanetSideGUID(1)
|
obj.GUID = PlanetSideGUID(1)
|
||||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
obj.Actor ! "startup"
|
|
||||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||||
val bldg =
|
val bldg =
|
||||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
||||||
|
|
@ -341,12 +395,13 @@ class ResourceSiloControlNoUpdateTest extends ActorTest {
|
||||||
obj.Owner = bldg
|
obj.Owner = bldg
|
||||||
val zoneEvents = TestProbe("zone-events")
|
val zoneEvents = TestProbe("zone-events")
|
||||||
val buildingEvents = TestProbe("building-events")
|
val buildingEvents = TestProbe("building-events")
|
||||||
|
zone.AvatarEvents = zoneEvents.ref
|
||||||
|
bldg.Actor = buildingEvents.ref
|
||||||
|
obj.Actor ! "startup"
|
||||||
|
|
||||||
"Resource silo" should {
|
"Resource silo" should {
|
||||||
"update, but not sufficiently to change the capacitor display" in {
|
"update, but not sufficiently to change the capacitor display" in {
|
||||||
zone.AvatarEvents = zoneEvents.ref
|
buildingEvents.receiveOne(500 milliseconds) //message caused by "startup"
|
||||||
bldg.Actor = buildingEvents.ref
|
|
||||||
|
|
||||||
obj.NtuCapacitor = 250
|
obj.NtuCapacitor = 250
|
||||||
obj.LowNtuWarningOn = false
|
obj.LowNtuWarningOn = false
|
||||||
assert(obj.NtuCapacitor == 250)
|
assert(obj.NtuCapacitor == 250)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import scodec.Attempt.{Failure, Successful}
|
||||||
import scodec.bits._
|
import scodec.bits._
|
||||||
|
|
||||||
import scala.concurrent.duration.{DurationInt, FiniteDuration}
|
import scala.concurrent.duration.{DurationInt, FiniteDuration}
|
||||||
import scala.util.control.Breaks._
|
|
||||||
|
|
||||||
object Client {
|
object Client {
|
||||||
Security.addProvider(new BouncyCastleProvider)
|
Security.addProvider(new BouncyCastleProvider)
|
||||||
|
|
@ -153,6 +152,7 @@ class Client(username: String, password: String) {
|
||||||
socket.send(new DatagramPacket(payload, payload.length, host))
|
socket.send(new DatagramPacket(payload, payload.length, host))
|
||||||
case (None, Some(ref)) =>
|
case (None, Some(ref)) =>
|
||||||
// ref ! Udp.Received(ByteString(payload), new InetSocketAddress(socket.getInetAddress, socket.getPort))
|
// ref ! Udp.Received(ByteString(payload), new InetSocketAddress(socket.getInetAddress, socket.getPort))
|
||||||
|
case _ => ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ import scala.collection.parallel.CollectionConverters._
|
||||||
import scala.io.{Codec, Source}
|
import scala.io.{Codec, Source}
|
||||||
import scala.sys.process._
|
import scala.sys.process._
|
||||||
import scala.util.Using
|
import scala.util.Using
|
||||||
import scala.util.control.Breaks._
|
|
||||||
|
|
||||||
case class Config(
|
case class Config(
|
||||||
outDir: String = System.getProperty("user.dir"),
|
outDir: String = System.getProperty("user.dir"),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue