mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-20 02:54:46 +00:00
introduced definition properties to configure auto fire; interspersed properties into relevant files; non-squared velocity check for isMoving
This commit is contained in:
parent
2e84b33a47
commit
18c3162dfe
|
|
@ -24,7 +24,7 @@ import net.psforever.objects.serverobject.resourcesilo.ResourceSiloDefinition
|
|||
import net.psforever.objects.serverobject.structures.{AmenityDefinition, AutoRepairStats, BuildingDefinition, WarpGateDefinition}
|
||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalDefinition
|
||||
import net.psforever.objects.serverobject.terminals.implant.{ImplantTerminalDefinition, ImplantTerminalMechDefinition}
|
||||
import net.psforever.objects.serverobject.turret.{FacilityTurretDefinition, TurretUpgrade}
|
||||
import net.psforever.objects.serverobject.turret.{Automation, FacilityTurretDefinition, TurretUpgrade}
|
||||
import net.psforever.objects.vehicles.{DestroyedVehicle, InternalTelepadDefinition, UtilityType, VehicleSubsystemEntry}
|
||||
import net.psforever.objects.vital.base.DamageType
|
||||
import net.psforever.objects.vital.damage._
|
||||
|
|
@ -1913,6 +1913,20 @@ object GlobalDefinitions {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the definition for a `Vehicle` determine whether it is an all-terrain vehicle type.
|
||||
* @param vdef the `VehicleDefinition` of the vehicle
|
||||
* @return `true`, if it is; `false`, otherwise
|
||||
*/
|
||||
def isAtvVehicle(vdef: VehicleDefinition): Boolean = {
|
||||
vdef match {
|
||||
case `quadassault` | `fury` | `quadstealth` =>
|
||||
true
|
||||
case _ =>
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the definition for a `Vehicle` determine whether it can fly.
|
||||
* Does not count the flying battleframe robotics vehicles.
|
||||
|
|
@ -9059,6 +9073,11 @@ object GlobalDefinitions {
|
|||
spitfire_turret.DeployTime = Duration.create(5000, "ms")
|
||||
spitfire_turret.Model = ComplexDeployableResolutions.calculate
|
||||
spitfire_turret.deployAnimation = DeployAnimation.Standard
|
||||
spitfire_turret.AutoFire = Automation(
|
||||
targetingRange = 40f,
|
||||
targetValidation = List(EffectTarget.Validation.ObviousPlayer, EffectTarget.Validation.Vehicle),
|
||||
retaliatoryDuration = 8000L
|
||||
)
|
||||
spitfire_turret.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 200
|
||||
|
|
@ -9085,6 +9104,11 @@ object GlobalDefinitions {
|
|||
spitfire_cloaked.DeployTime = Duration.create(5000, "ms")
|
||||
spitfire_cloaked.deployAnimation = DeployAnimation.Standard
|
||||
spitfire_cloaked.Model = ComplexDeployableResolutions.calculate
|
||||
spitfire_cloaked.AutoFire = Automation(
|
||||
targetingRange = 40f,
|
||||
targetValidation = List(EffectTarget.Validation.ObviousPlayer, EffectTarget.Validation.Vehicle),
|
||||
retaliatoryDuration = 8000L
|
||||
)
|
||||
spitfire_cloaked.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 50
|
||||
|
|
@ -9111,6 +9135,11 @@ object GlobalDefinitions {
|
|||
spitfire_aa.DeployTime = Duration.create(5000, "ms")
|
||||
spitfire_aa.deployAnimation = DeployAnimation.Standard
|
||||
spitfire_aa.Model = ComplexDeployableResolutions.calculate
|
||||
spitfire_aa.AutoFire = Automation(
|
||||
targetingRange = 80f,
|
||||
targetValidation = List(EffectTarget.Validation.Aircraft),
|
||||
retaliatoryDuration = 8000L
|
||||
)
|
||||
spitfire_aa.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 200
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class Player(var avatar: Avatar)
|
|||
with MountableEntity {
|
||||
interaction(new InteractWithEnvironment())
|
||||
interaction(new InteractWithMinesUnlessSpectating(obj = this, range = 10))
|
||||
interaction(new InteractWithTurrets(range = 25f))
|
||||
interaction(new InteractWithTurrets(range = 100f))
|
||||
interaction(new InteractWithRadiationClouds(range = 10f, Some(this)))
|
||||
|
||||
private var backpack: Boolean = false
|
||||
|
|
|
|||
|
|
@ -108,9 +108,9 @@ class TurretControl(turret: TurretDeployable)
|
|||
override def TryJammerEffectActivate(target: Any, cause: DamageResult): Unit = {
|
||||
val startsUnjammed = !JammableObject.Jammed
|
||||
super.TryJammerEffectActivate(target, cause)
|
||||
if (startsUnjammed && JammableObject.Jammed) {
|
||||
if (startsUnjammed && JammableObject.Jammed && AutomatedTurretObject.Definition.AutoFire.exists(_.retaliatoryDuration > 0)) {
|
||||
AutomaticOperation = false
|
||||
//look in direction of source of jamming
|
||||
//look in direction of cause of jamming
|
||||
val zone = JammableObject.Zone
|
||||
TurretControl.getAttackerFromCause(zone, cause).foreach {
|
||||
attacker =>
|
||||
|
|
@ -129,10 +129,10 @@ class TurretControl(turret: TurretDeployable)
|
|||
}
|
||||
|
||||
override protected def DamageAwareness(target: Target, cause: DamageResult, amount: Any): Unit = {
|
||||
//turret retribution
|
||||
if (AutomaticOperation) {
|
||||
TurretControl.getAttackerFromCause(target.Zone, cause).foreach {
|
||||
attacker =>
|
||||
if (AutomaticOperation && AutomatedTurretObject.Definition.AutoFire.exists(_.retaliatoryDuration > 0)) {
|
||||
//turret retribution
|
||||
TurretControl.getAttackerFromCause(target.Zone, cause).collect {
|
||||
case attacker if attacker.Faction != target.Faction =>
|
||||
engageNewDetectedTarget(attacker)
|
||||
}
|
||||
}
|
||||
|
|
@ -153,7 +153,7 @@ class TurretControl(turret: TurretDeployable)
|
|||
val seats = turret.Seats.values
|
||||
//either we have no seats or no one gets to sit
|
||||
val retime = if (seats.count(_.isOccupied) > 0) {
|
||||
//unlike with vehicles, it's possible to request deconstruction of one's own field turret while seated in it
|
||||
//it's possible to request deconstruction of one's own field turret while seated in it
|
||||
val wasKickedByDriver = false
|
||||
seats.foreach { seat =>
|
||||
seat.occupant match {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class InteractWithTurrets(val range: Float)
|
|||
case clarifiedTarget: AutomatedTurret.Target =>
|
||||
val posxy = clarifiedTarget.Position.xy
|
||||
val unique = SourceEntry(clarifiedTarget).unique
|
||||
val targets = getTurretTargets(sector, posxy).filter { turret => turret.Detected(unique).isEmpty }
|
||||
val targets = getTurretTargets(sector, posxy).filter { turret => turret.Definition.AutoFire.nonEmpty && turret.Detected(unique).isEmpty }
|
||||
targets.foreach { t => t.Actor ! AutomatedTurretBehavior.Alert(clarifiedTarget) }
|
||||
case _ => ()
|
||||
}
|
||||
|
|
@ -32,10 +32,16 @@ trait WorldEntity {
|
|||
def isMoving(test: Vector3): Boolean = WorldEntity.isMoving(Velocity, test)
|
||||
|
||||
/**
|
||||
* This object is not considered moving unless it is moving at least as fast as a certain velocity.
|
||||
* @param test the (squared) velocity to test against
|
||||
* @return `true`, if we are moving; `false`, otherwise
|
||||
*/
|
||||
* This object is not considered moving unless it is moving at least as fast as a certain velocity.
|
||||
* @param test the velocity to test against
|
||||
* @return `true`, if we are moving; `false`, otherwise
|
||||
*/
|
||||
def isMoving(test: Double): Boolean = WorldEntity.isMoving(Velocity, (test * test).toFloat)
|
||||
/**
|
||||
* This object is not considered moving unless it is moving at least as fast as a certain velocity.
|
||||
* @param test the (squared) velocity to test against
|
||||
* @return `true`, if we are moving; `false`, otherwise
|
||||
*/
|
||||
def isMoving(test: Float): Boolean = WorldEntity.isMoving(Velocity, test)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import net.psforever.objects._
|
|||
import net.psforever.objects.ce.DeployableCategory
|
||||
import net.psforever.objects.serverobject.turret.FacilityTurret
|
||||
import net.psforever.objects.vital.DamagingActivity
|
||||
import net.psforever.types.{ExoSuitType, ImplantType}
|
||||
|
||||
final case class TargetValidation(category: EffectTarget.Category.Value, test: EffectTarget.Validation.Value)
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ object EffectTarget {
|
|||
object Validation {
|
||||
type Value = PlanetSideGameObject => Boolean
|
||||
|
||||
//noinspection ScalaUnusedSymbol
|
||||
def Invalid(target: PlanetSideGameObject): Boolean = false
|
||||
|
||||
def Medical(target: PlanetSideGameObject): Boolean =
|
||||
|
|
@ -185,5 +187,36 @@ object EffectTarget {
|
|||
case _ =>
|
||||
false
|
||||
}
|
||||
|
||||
def ObviousPlayer(target: PlanetSideGameObject): Boolean =
|
||||
!target.Destroyed && (target match {
|
||||
case p: Player =>
|
||||
//TODO attacking breaks stealth
|
||||
p.LastDamage.map(_.interaction.hitTime).exists(System.currentTimeMillis() - _ < 3000L) ||
|
||||
p.avatar.implants.flatten.find(a => a.definition.implantType == ImplantType.SilentRun).exists(_.active) ||
|
||||
(p.isMoving(test = 17d) && !p.Crouching) ||
|
||||
p.Jumping
|
||||
case _ =>
|
||||
false
|
||||
})
|
||||
|
||||
def ObviousMax(target: PlanetSideGameObject): Boolean =
|
||||
!target.Destroyed && (target match {
|
||||
case p: Player =>
|
||||
p.ExoSuit == ExoSuitType.MAX && p.isMoving(test = 17d)
|
||||
case _ =>
|
||||
false
|
||||
})
|
||||
|
||||
def VehiclesOnRadar(target: PlanetSideGameObject): Boolean =
|
||||
!target.Destroyed && (target match {
|
||||
case v: Vehicle =>
|
||||
val vdef = v.Definition
|
||||
!(GlobalDefinitions.isAtvVehicle(vdef) ||
|
||||
vdef == GlobalDefinitions.two_man_assault_buggy ||
|
||||
vdef == GlobalDefinitions.skyguard)
|
||||
case _ =>
|
||||
false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ object GenericHackables {
|
|||
HackState.Start
|
||||
} else if (progress >= 100L) {
|
||||
HackState.Finished
|
||||
} else if (target.isMoving(1f)) {
|
||||
} else if (target.isMoving(test = 1f)) {
|
||||
// If the object is moving (more than slightly to account for things like magriders rotating, or the last velocity reported being the magrider dipping down on dismount) then cancel the hack
|
||||
HackState.Cancelled
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ trait MountableBehavior {
|
|||
): Boolean = {
|
||||
obj.PassengerInSeat(user).contains(seatNumber) &&
|
||||
(obj.Seats.get(seatNumber) match {
|
||||
case Some(seat) => seat.bailable || !obj.isMoving(test = 1)
|
||||
case Some(seat) => seat.bailable || !obj.isMoving(test = 1f)
|
||||
case _ => false
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,19 +2,20 @@
|
|||
package net.psforever.objects.serverobject.turret
|
||||
|
||||
import akka.actor.{Actor, Cancellable}
|
||||
import net.psforever.objects.ce.TurretInteraction
|
||||
import net.psforever.objects.definition.ObjectDefinition
|
||||
import net.psforever.objects.{Default, Player}
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.serverobject.damage.DamageableEntity
|
||||
import net.psforever.objects.sourcing.{SourceEntry, SourceUniqueness}
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.objects.zones.{InteractsWithZone, Zone}
|
||||
import net.psforever.packet.game.{ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ObjectDetectedMessage}
|
||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||
import net.psforever.types.{PlanetSideGUID, Vector3}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
trait AutomatedTurret
|
||||
extends PlanetSideServerObject
|
||||
|
|
@ -84,9 +85,11 @@ trait AutomatedTurretBehavior {
|
|||
|
||||
private var periodicValidationTest: Cancellable = Default.Cancellable
|
||||
|
||||
private lazy val autoStats: Option[Automation] = AutomatedTurretObject.Definition.AutoFire
|
||||
|
||||
def AutomatedTurretObject: AutomatedTurret
|
||||
|
||||
val automatedTurretBehavior: Actor.Receive = {
|
||||
val automatedTurretBehavior: Actor.Receive = if (autoStats.isDefined) {
|
||||
case AutomatedTurretBehavior.Alert(target) =>
|
||||
bringAttentionToTarget(target)
|
||||
|
||||
|
|
@ -101,19 +104,27 @@ trait AutomatedTurretBehavior {
|
|||
|
||||
case AutomatedTurretBehavior.PeriodicCheck =>
|
||||
performPeriodicTargetValidation()
|
||||
} else {
|
||||
Actor.emptyBehavior
|
||||
}
|
||||
|
||||
def AutomaticOperation: Boolean = automaticOperation
|
||||
|
||||
def AutomaticOperation_=(state: Boolean): Boolean = {
|
||||
val previousState = automaticOperation
|
||||
automaticOperation = state
|
||||
if (!previousState && state) {
|
||||
trySelectNewTarget()
|
||||
} else if (previousState && !state) {
|
||||
currentTarget.foreach { noLongerEngageDetectedTarget }
|
||||
if (autoStats.isDefined) {
|
||||
automaticOperation = state
|
||||
if (!previousState && state) {
|
||||
trySelectNewTarget()
|
||||
} else if (previousState && !state) {
|
||||
currentTarget.foreach {
|
||||
noLongerEngageDetectedTarget
|
||||
}
|
||||
}
|
||||
state
|
||||
} else {
|
||||
false
|
||||
}
|
||||
state
|
||||
}
|
||||
|
||||
private def bringAttentionToTarget(target: Target): Unit = {
|
||||
|
|
@ -129,10 +140,12 @@ trait AutomatedTurretBehavior {
|
|||
|
||||
private def confirmShot(target: Target): Unit = {
|
||||
val now = System.currentTimeMillis()
|
||||
if (currentTargetToken.isEmpty || now - currentTargetLastShotReported > 1500L) {
|
||||
if (currentTargetToken.isEmpty || now - currentTargetLastShotReported > autoStats.map { _.targetSelectCooldown }.get) {
|
||||
currentTargetLastShotReported = now
|
||||
engageNewDetectedTarget(target)
|
||||
} else if (currentTargetToken.contains(SourceEntry(target).unique) && now - currentTargetLastShotReported < 3000L) {
|
||||
} else if (
|
||||
currentTargetToken.contains(SourceEntry(target).unique) &&
|
||||
now - currentTargetLastShotReported < autoStats.map { _.missedShotCooldown }.get) {
|
||||
currentTargetLastShotReported = now
|
||||
}
|
||||
}
|
||||
|
|
@ -196,17 +209,22 @@ trait AutomatedTurretBehavior {
|
|||
private def trySelectNewTarget(): Option[Target] = {
|
||||
currentTarget.orElse {
|
||||
val turretPosition = AutomatedTurretObject.Position
|
||||
AutomatedTurretObject.Targets
|
||||
.filter { target =>
|
||||
!target.Destroyed && (target match {
|
||||
case p: Player => validTargetCheck(p)
|
||||
case _ => false
|
||||
})
|
||||
val radiusSquared = autoStats.get.targetingRange * autoStats.get.targetingRange
|
||||
val validation = autoStats.get.targetValidation
|
||||
val faction = AutomatedTurretObject.Faction
|
||||
AutomatedTurretObject
|
||||
.Targets
|
||||
.map { target =>
|
||||
(target, Vector3.DistanceSquared(target.Position, turretPosition))
|
||||
}
|
||||
.sortBy {
|
||||
target => Vector3.DistanceSquared(target.Position, turretPosition)
|
||||
.collect { case out @ (target, distance)
|
||||
if /*target.Faction != faction &&*/
|
||||
distance < radiusSquared &&
|
||||
validation.exists(func => func(target)) =>
|
||||
out
|
||||
}
|
||||
.flatMap { case target: Player =>
|
||||
.sortBy(_._2)
|
||||
.flatMap { case (target: Player, _) =>
|
||||
testNewDetectedTarget(target, target.Name)
|
||||
Some(target)
|
||||
}
|
||||
|
|
@ -214,16 +232,6 @@ trait AutomatedTurretBehavior {
|
|||
}
|
||||
}
|
||||
|
||||
private def validTargetCheck(target: Target): Boolean = {
|
||||
!target.Destroyed && (target match {
|
||||
case p: Player =>
|
||||
if (p.Cloaked) false
|
||||
else if (p.Crouching) false
|
||||
else p.isMoving(test = 3f)
|
||||
case _ => false
|
||||
})
|
||||
}
|
||||
|
||||
private def performPeriodicTargetValidation(): List[Target] = {
|
||||
val size = AutomatedTurretObject.Targets.size
|
||||
val list = performDistanceCheck()
|
||||
|
|
@ -237,39 +245,71 @@ trait AutomatedTurretBehavior {
|
|||
val pos = AutomatedTurretObject.Position
|
||||
val removedTargets = AutomatedTurretObject.Targets
|
||||
.collect {
|
||||
case t if t.Destroyed || Vector3.DistanceSquared(t.Position, pos) > 625 =>
|
||||
case t: InteractsWithZone
|
||||
if t.Destroyed || {
|
||||
val range = t.interaction().find(_.Type == TurretInteraction).map(_.range).getOrElse(100f)
|
||||
Vector3.DistanceSquared(t.Position, pos) > range * range
|
||||
} =>
|
||||
AutomatedTurretObject.RemoveTarget(t)
|
||||
t
|
||||
}
|
||||
removedTargets
|
||||
}
|
||||
|
||||
private def performCurrentTargetDecayCheck(): Unit = {
|
||||
val now = System.currentTimeMillis()
|
||||
val delay = autoStats.map(_.missedShotCooldown).getOrElse(3000L)
|
||||
currentTarget
|
||||
.collect { target =>
|
||||
if (target.Destroyed) {
|
||||
//if the target died while we were shooting at it, immediately switch to the next target
|
||||
noLongerEngageDetectedTarget(target)
|
||||
currentTargetLastShotReported = now - delay
|
||||
None
|
||||
} else if (System.currentTimeMillis() - currentTargetLastShotReported >= delay) {
|
||||
//if the target goes mia, evaluate a possible cooldown phase before selecting next target
|
||||
noLongerEngageDetectedTarget(target)
|
||||
None
|
||||
} else {
|
||||
//continue shooting
|
||||
Some(target)
|
||||
}
|
||||
}
|
||||
.orElse {
|
||||
//no target; unless we are deactivated or have any unfinished delays, search for new target
|
||||
if (automaticOperation && now - currentTargetLastShotReported >= delay) {
|
||||
trySelectNewTarget()
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
private def testTargetListQualifications(beforeSize: Int): Boolean = {
|
||||
beforeSize > 0 && AutomatedTurretObject.Targets.isEmpty && periodicValidationTest.cancel()
|
||||
}
|
||||
|
||||
private def retimePeriodicTargetChecks(beforeSize: Int): Boolean = {
|
||||
if (beforeSize == 0 && AutomatedTurretObject.Targets.nonEmpty) {
|
||||
periodicValidationTest = context.system.scheduler.scheduleWithFixedDelay(
|
||||
Duration.Zero,
|
||||
1.second,
|
||||
self,
|
||||
AutomatedTurretBehavior.PeriodicCheck
|
||||
)
|
||||
if (beforeSize == 0 && AutomatedTurretObject.Targets.nonEmpty && autoStats.isDefined) {
|
||||
val (initial, repeated) = autoStats
|
||||
.map {
|
||||
ta => (ta.initialDetectionSpeed, ta.detectionSpeed)
|
||||
}
|
||||
.get
|
||||
retimePeriodicTargetChecks(initial, repeated)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private def performCurrentTargetDecayCheck(): Unit = {
|
||||
//complete culling and/or check the current selected target
|
||||
if (System.currentTimeMillis() - currentTargetLastShotReported > 3000L) {
|
||||
currentTarget.foreach { noLongerEngageDetectedTarget }
|
||||
if (automaticOperation) {
|
||||
//trySelectNewTarget()
|
||||
}
|
||||
}
|
||||
private def retimePeriodicTargetChecks(initial: FiniteDuration, repeated: FiniteDuration): Unit = {
|
||||
periodicValidationTest.cancel()
|
||||
periodicValidationTest = context.system.scheduler.scheduleWithFixedDelay(
|
||||
initial,
|
||||
repeated,
|
||||
self,
|
||||
AutomatedTurretBehavior.PeriodicCheck
|
||||
)
|
||||
}
|
||||
|
||||
def automaticTurretPostStop(): Unit = {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,28 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.turret
|
||||
|
||||
import net.psforever.objects.PlanetSideGameObject
|
||||
import net.psforever.objects.definition.{ObjectDefinition, ToolDefinition, WithShields}
|
||||
import net.psforever.objects.vehicles.{MountableWeaponsDefinition, Turrets}
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
||||
import net.psforever.objects.vital.resolution.DamageResistanceModel
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.duration._
|
||||
|
||||
final case class Automation(
|
||||
targetingRange: Float,
|
||||
targetValidation: List[PlanetSideGameObject => Boolean],
|
||||
retaliatoryDuration: Long = 0,
|
||||
initialDetectionSpeed: FiniteDuration = Duration.Zero,
|
||||
detectionSpeed: FiniteDuration = 1.seconds,
|
||||
targetSelectCooldown: Long = 1500L, //ms
|
||||
missedShotCooldown: Long = 3000L, //ms
|
||||
targetEliminationCooldown: Long = 0L //ms
|
||||
)
|
||||
|
||||
/**
|
||||
* The definition for any `MannedTurret`.
|
||||
* The definition for any `WeaponTurret`.
|
||||
*/
|
||||
trait TurretDefinition
|
||||
extends MountableWeaponsDefinition
|
||||
|
|
@ -25,11 +38,12 @@ trait TurretDefinition
|
|||
/** can only be mounted by owning faction when `true` */
|
||||
private var factionLocked: Boolean = true
|
||||
|
||||
/** creates internal ammunition reserves that can not become depleted
|
||||
* see `MannedTurret.TurretAmmoBox` for details
|
||||
*/
|
||||
/** creates internal ammunition reserves that can not become depleted */
|
||||
private var hasReserveAmmunition: Boolean = false
|
||||
|
||||
/** */
|
||||
private var turretAutomation: Option[Automation] = None
|
||||
|
||||
def WeaponPaths: mutable.HashMap[Int, mutable.HashMap[TurretUpgrade.Value, ToolDefinition]] = weaponPaths
|
||||
|
||||
def FactionLocked: Boolean = factionLocked
|
||||
|
|
@ -45,4 +59,15 @@ trait TurretDefinition
|
|||
hasReserveAmmunition = reserved
|
||||
ReserveAmmunition
|
||||
}
|
||||
|
||||
def AutoFire: Option[Automation] = turretAutomation
|
||||
|
||||
def AutoFire_=(auto: Automation): Option[Automation] = {
|
||||
AutoFire_=(Some(auto))
|
||||
}
|
||||
|
||||
def AutoFire_=(auto: Option[Automation]): Option[Automation] = {
|
||||
turretAutomation = auto
|
||||
turretAutomation
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue