mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
Entity Interference (#1191)
* basic interference fields; setting up operations for ce deployables * applying corrected properties to object definitions and applying them to interference tests for deployable ce and for deploying vehicles; made two otherwise useles object definitions to store property data (if we ever need ziplines or teleport pads ...) * sent deployment requests to a centralized pipeline for interference testing; swapped out math.pow(a,2) for a * a * temporary interference for vehicles that are going to transition to deployed eventually and block other deploying vehicles * reversed the origin of the interference tests * exception for non-interference resolves to wrong conclusion * ramshackle merge conflict resolution; fixing interference for non-interference deploying vehicles
This commit is contained in:
parent
426ab84f0a
commit
a3eb3a8a95
|
|
@ -533,7 +533,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
|
|||
case _ =>
|
||||
GUIDTask.registerObject(continent.GUID, dObj)
|
||||
}
|
||||
TaskWorkflow.execute(CallBackForTask(tasking, continent.Deployables, Zone.Deployable.BuildByOwner(dObj, player, obj)))
|
||||
TaskWorkflow.execute(CallBackForTask(tasking, continent.Deployables, Zone.Deployable.BuildByOwner(dObj, player, obj), context.self))
|
||||
case Some(obj) =>
|
||||
log.warn(s"DeployObject: what is $obj, ${player.Name}? It's not a construction tool!")
|
||||
case None =>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package net.psforever.actors.session.normal
|
|||
import akka.actor.Actor.Receive
|
||||
import akka.actor.ActorRef
|
||||
import net.psforever.actors.session.support.{ChatFunctions, GeneralFunctions, LocalHandlerFunctions, MountHandlerFunctions, SquadHandlerFunctions, TerminalHandlerFunctions, VehicleFunctions, VehicleHandlerFunctions, WeaponAndProjectileFunctions}
|
||||
import net.psforever.objects.Players
|
||||
import net.psforever.packet.game.UplinkRequest
|
||||
import net.psforever.services.chat.ChatService
|
||||
//
|
||||
|
|
@ -248,9 +249,11 @@ class NormalModeLogic(data: SessionData) extends ModeLogic {
|
|||
case _: Zone.Vehicle.HasDespawned => ;
|
||||
|
||||
case Zone.Deployable.IsDismissed(obj: TurretDeployable) => //only if target deployable was never fully introduced
|
||||
Players.buildCooldownReset(data.continent, data.player.Name, obj)
|
||||
TaskWorkflow.execute(GUIDTask.unregisterDeployableTurret(data.continent.GUID, obj))
|
||||
|
||||
case Zone.Deployable.IsDismissed(obj) => //only if target deployable was never fully introduced
|
||||
Players.buildCooldownReset(data.continent, data.player.Name, obj)
|
||||
TaskWorkflow.execute(GUIDTask.unregisterObject(data.continent.GUID, obj))
|
||||
|
||||
case msg: Containable.ItemPutInSlot =>
|
||||
|
|
|
|||
|
|
@ -272,24 +272,29 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
|
|||
|
||||
def handleDeployRequest(pkt: DeployRequestMessage): Unit = {
|
||||
val DeployRequestMessage(_, vehicle_guid, deploy_state, _, _, _) = pkt
|
||||
val vehicle = player.avatar.vehicle
|
||||
if (vehicle.contains(vehicle_guid)) {
|
||||
if (vehicle == player.VehicleSeated) {
|
||||
continent.GUID(vehicle_guid) match {
|
||||
case Some(obj: Vehicle) =>
|
||||
continent.GUID(vehicle_guid)
|
||||
.collect {
|
||||
case obj: Vehicle =>
|
||||
val vehicle = player.avatar.vehicle
|
||||
if (!vehicle.contains(vehicle_guid)) {
|
||||
log.warn(s"DeployRequest: ${player.Name} does not own the would-be-deploying ${obj.Definition.Name}")
|
||||
} else if (vehicle != player.VehicleSeated) {
|
||||
log.warn(s"${player.Name} must be mounted as the driver to request a deployment change")
|
||||
} else {
|
||||
log.info(s"${player.Name} is requesting a deployment change for ${obj.Definition.Name} - $deploy_state")
|
||||
obj.Actor ! Deployment.TryDeploymentChange(deploy_state)
|
||||
|
||||
case _ =>
|
||||
log.error(s"DeployRequest: ${player.Name} can not find vehicle $vehicle_guid")
|
||||
avatarActor ! AvatarActor.SetVehicle(None)
|
||||
}
|
||||
} else {
|
||||
log.warn(s"${player.Name} must be mounted to request a deployment change")
|
||||
continent.Transport ! Zone.Vehicle.TryDeploymentChange(obj, deploy_state)
|
||||
}
|
||||
obj
|
||||
case obj =>
|
||||
log.error(s"DeployRequest: ${player.Name} expected a vehicle, but found a ${obj.Definition.Name} instead")
|
||||
obj
|
||||
}
|
||||
.orElse {
|
||||
log.error(s"DeployRequest: ${player.Name} can not find entity $vehicle_guid")
|
||||
avatarActor ! AvatarActor.SetVehicle(None) //todo is this safe
|
||||
None
|
||||
}
|
||||
} else {
|
||||
log.warn(s"DeployRequest: ${player.Name} does not own the deploying $vehicle_guid object")
|
||||
}
|
||||
}
|
||||
|
||||
/* messages */
|
||||
|
|
|
|||
|
|
@ -1080,4 +1080,22 @@ object WorldSession {
|
|||
task
|
||||
)
|
||||
}
|
||||
|
||||
def CallBackForTask(task: TaskBundle, sendTo: ActorRef, pass: Any, replyTo: ActorRef): TaskBundle = {
|
||||
TaskBundle(
|
||||
new StraightforwardTask() {
|
||||
private val localDesc = task.description()
|
||||
private val destination = sendTo
|
||||
private val passMsg = pass
|
||||
|
||||
override def description(): String = s"callback for tasking $localDesc"
|
||||
|
||||
def action() : Future[Any] = {
|
||||
destination.tell(passMsg, replyTo)
|
||||
Future(this)
|
||||
}
|
||||
},
|
||||
task
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import net.psforever.objects.vital._
|
|||
import net.psforever.types.{ExoSuitType, ImplantType, PlanetSideEmpire, Vector3}
|
||||
import net.psforever.types._
|
||||
import net.psforever.objects.serverobject.llu.{CaptureFlagDefinition, CaptureFlagSocketDefinition}
|
||||
import net.psforever.objects.serverobject.zipline.GenericTeleportationDefinition
|
||||
|
||||
import scala.annotation.switch
|
||||
|
||||
|
|
@ -1277,6 +1278,10 @@ object GlobalDefinitions {
|
|||
|
||||
val targeting_laser_dispenser = new OrderTerminalDefinition(851)
|
||||
|
||||
val stationaryteleportpad = new GenericTeleportationDefinition(836)
|
||||
|
||||
val zipline = new GenericTeleportationDefinition(1047)
|
||||
|
||||
/*
|
||||
Buildings
|
||||
*/
|
||||
|
|
@ -1294,29 +1299,28 @@ object GlobalDefinitions {
|
|||
|
||||
val vanu_core = new BuildingDefinition(932)
|
||||
|
||||
//the following group borrows the object id from entity mainbase1
|
||||
val ground_bldg_a = new BuildingDefinition(474)
|
||||
val ground_bldg_b = new BuildingDefinition(474)
|
||||
val ground_bldg_c = new BuildingDefinition(474)
|
||||
val ground_bldg_d = new BuildingDefinition(474)
|
||||
val ground_bldg_e = new BuildingDefinition(474)
|
||||
val ground_bldg_f = new BuildingDefinition(474)
|
||||
val ground_bldg_g = new BuildingDefinition(474)
|
||||
val ground_bldg_h = new BuildingDefinition(474)
|
||||
val ground_bldg_i = new BuildingDefinition(474)
|
||||
val ground_bldg_j = new BuildingDefinition(474)
|
||||
val ground_bldg_z = new BuildingDefinition(474)
|
||||
val ceiling_bldg_a = new BuildingDefinition(474)
|
||||
val ceiling_bldg_b = new BuildingDefinition(474)
|
||||
val ceiling_bldg_c = new BuildingDefinition(474)
|
||||
val ceiling_bldg_d = new BuildingDefinition(474)
|
||||
val ceiling_bldg_e = new BuildingDefinition(474)
|
||||
val ceiling_bldg_f = new BuildingDefinition(474)
|
||||
val ceiling_bldg_g = new BuildingDefinition(474)
|
||||
val ceiling_bldg_h = new BuildingDefinition(474)
|
||||
val ceiling_bldg_i = new BuildingDefinition(474)
|
||||
val ceiling_bldg_j = new BuildingDefinition(474)
|
||||
val ceiling_bldg_z = new BuildingDefinition(474)
|
||||
val ground_bldg_a = new BuildingDefinition(373)
|
||||
val ground_bldg_b = new BuildingDefinition(374)
|
||||
val ground_bldg_c = new BuildingDefinition(375)
|
||||
val ground_bldg_d = new BuildingDefinition(376)
|
||||
val ground_bldg_e = new BuildingDefinition(377)
|
||||
val ground_bldg_f = new BuildingDefinition(378)
|
||||
val ground_bldg_g = new BuildingDefinition(379)
|
||||
val ground_bldg_h = new BuildingDefinition(380)
|
||||
val ground_bldg_i = new BuildingDefinition(381)
|
||||
val ground_bldg_j = new BuildingDefinition(382)
|
||||
val ground_bldg_z = new BuildingDefinition(383)
|
||||
val ceiling_bldg_a = new BuildingDefinition(159)
|
||||
val ceiling_bldg_b = new BuildingDefinition(160)
|
||||
val ceiling_bldg_c = new BuildingDefinition(161)
|
||||
val ceiling_bldg_d = new BuildingDefinition(162)
|
||||
val ceiling_bldg_e = new BuildingDefinition(163)
|
||||
val ceiling_bldg_f = new BuildingDefinition(164)
|
||||
val ceiling_bldg_g = new BuildingDefinition(165)
|
||||
val ceiling_bldg_h = new BuildingDefinition(166)
|
||||
val ceiling_bldg_i = new BuildingDefinition(167)
|
||||
val ceiling_bldg_j = new BuildingDefinition(168)
|
||||
val ceiling_bldg_z = new BuildingDefinition(169)
|
||||
|
||||
val mainbase1 = new BuildingDefinition(474)
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class DeployableToolbox {
|
|||
* keys: categories, values: quantity storage object
|
||||
*/
|
||||
private val categoryCounts =
|
||||
DeployableCategory.values.toSeq.map(value => { value -> new DeployableToolbox.Bin }).toMap
|
||||
DeployableCategory.values.map(value => { value -> new DeployableToolbox.Bin }).toMap
|
||||
|
||||
/**
|
||||
* a map of bins for keeping track of the quantities of individual deployables
|
||||
|
|
@ -46,7 +46,7 @@ class DeployableToolbox {
|
|||
* keys: categories, values: deployable objects
|
||||
*/
|
||||
private val deployableLists =
|
||||
DeployableCategory.values.toSeq
|
||||
DeployableCategory.values
|
||||
.map(value => { value -> mutable.ListBuffer[DeployableToolbox.AcceptableDeployable]() })
|
||||
.toMap
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ class DeployableToolbox {
|
|||
}
|
||||
}
|
||||
|
||||
def UpdateMaxCounts(certifications: Set[Certification]) = {
|
||||
def UpdateMaxCounts(certifications: Set[Certification]): Unit = {
|
||||
DeployableToolbox.UpdateMaxCounts(deployableCounts, categoryCounts, certifications)
|
||||
}
|
||||
|
||||
|
|
@ -247,7 +247,7 @@ class DeployableToolbox {
|
|||
* @param category the target category
|
||||
* @return any deployable that is found
|
||||
*/
|
||||
def DisplaceFirst(category: DeployableCategory.Value): Option[DeployableToolbox.AcceptableDeployable] = {
|
||||
def DisplaceFirst(category: DeployableCategory): Option[DeployableToolbox.AcceptableDeployable] = {
|
||||
val categoryList = deployableLists(category)
|
||||
if (categoryList.nonEmpty) {
|
||||
val found = categoryList.remove(0)
|
||||
|
|
@ -294,7 +294,7 @@ class DeployableToolbox {
|
|||
* @param filter the type of deployable
|
||||
* @return a list of globally unique identifiers that should be valid for the current zone
|
||||
*/
|
||||
def Category(filter: DeployableCategory.Value): List[PlanetSideGUID] = {
|
||||
def Category(filter: DeployableCategory): List[PlanetSideGUID] = {
|
||||
deployableLists(filter).map(_.GUID).toList
|
||||
}
|
||||
|
||||
|
|
@ -478,7 +478,7 @@ object DeployableToolbox {
|
|||
*/
|
||||
private def UpdateMaxCounts(
|
||||
counts: Map[DeployedItem.Value, DeployableToolbox.Bin],
|
||||
categories: Map[DeployableCategory.Value, DeployableToolbox.Bin],
|
||||
categories: Map[DeployableCategory, DeployableToolbox.Bin],
|
||||
certifications: Set[Certification]
|
||||
): Unit = {
|
||||
import Certification._
|
||||
|
|
|
|||
|
|
@ -77,18 +77,18 @@ object Deployable {
|
|||
}
|
||||
|
||||
object Category {
|
||||
def Of(item: DeployedItem.Value): DeployableCategory.Value = deployablesToCategories(item)
|
||||
def Of(item: DeployedItem.Value): DeployableCategory = deployablesToCategories(item)
|
||||
|
||||
def Includes(category: DeployableCategory.Value): List[DeployedItem.Value] = {
|
||||
def Includes(category: DeployableCategory): List[DeployedItem.Value] = {
|
||||
(for {
|
||||
(ce: DeployedItem.Value, cat: DeployableCategory.Value) <- deployablesToCategories
|
||||
(ce: DeployedItem.Value, cat: DeployableCategory) <- deployablesToCategories
|
||||
if cat == category
|
||||
} yield ce) toList
|
||||
}
|
||||
|
||||
def OfAll(): Map[DeployedItem.Value, DeployableCategory.Value] = deployablesToCategories
|
||||
def OfAll(): Map[DeployedItem.Value, DeployableCategory] = deployablesToCategories
|
||||
|
||||
private val deployablesToCategories: Map[DeployedItem.Value, DeployableCategory.Value] = Map(
|
||||
private val deployablesToCategories: Map[DeployedItem.Value, DeployableCategory] = Map(
|
||||
DeployedItem.boomer -> DeployableCategory.Boomers,
|
||||
DeployedItem.he_mine -> DeployableCategory.Mines,
|
||||
DeployedItem.jammer_mine -> DeployableCategory.Mines,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,26 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.ce
|
||||
|
||||
object DeployableCategory extends Enumeration {
|
||||
type Type = Value
|
||||
abstract class DeployableCategory(val name: String)
|
||||
|
||||
val Boomers, Mines, SmallTurrets, Sensors, TankTraps, FieldTurrets, ShieldGenerators, Telepads = Value
|
||||
object DeployableCategory {
|
||||
case object None extends DeployableCategory(name = "None")
|
||||
|
||||
case object Boomers extends DeployableCategory(name = "Boomers")
|
||||
|
||||
case object Mines extends DeployableCategory(name = "Mines")
|
||||
|
||||
case object SmallTurrets extends DeployableCategory(name = "SmallTurrets")
|
||||
|
||||
case object Sensors extends DeployableCategory(name = "Sensors")
|
||||
|
||||
case object TankTraps extends DeployableCategory(name = "TankTraps")
|
||||
|
||||
case object FieldTurrets extends DeployableCategory(name = "FieldTurrets")
|
||||
|
||||
case object ShieldGenerators extends DeployableCategory(name = "ShieldGenerators")
|
||||
|
||||
case object Telepads extends DeployableCategory(name = "Telepads")
|
||||
|
||||
val values: Seq[DeployableCategory] = Seq(None, Boomers, Mines, SmallTurrets, Sensors, TankTraps, FieldTurrets, ShieldGenerators, Telepads)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,15 +19,15 @@ object DeployAnimation extends Enumeration {
|
|||
}
|
||||
|
||||
trait BaseDeployableDefinition {
|
||||
private var category: DeployableCategory.Value = DeployableCategory.Boomers
|
||||
private var category: DeployableCategory = DeployableCategory.None
|
||||
private var deployTime: Long = (1 second).toMillis //ms
|
||||
var deployAnimation: DeployAnimation.Value = DeployAnimation.None
|
||||
|
||||
def Item: DeployedItem.Value
|
||||
|
||||
def DeployCategory: DeployableCategory.Value = category
|
||||
def DeployCategory: DeployableCategory = category
|
||||
|
||||
def DeployCategory_=(cat: DeployableCategory.Value): DeployableCategory.Value = {
|
||||
def DeployCategory_=(cat: DeployableCategory): DeployableCategory = {
|
||||
category = cat
|
||||
DeployCategory
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import net.psforever.objects.PlanetSideGameObject
|
|||
import net.psforever.objects.definition.converter.{ObjectCreateConverter, PacketConverter}
|
||||
import net.psforever.objects.geometry.GeometryForm
|
||||
import net.psforever.objects.geometry.d3.VolumetricGeometry
|
||||
import net.psforever.objects.serverobject.deploy.{Interference, InterferenceRange}
|
||||
import net.psforever.types.OxygenState
|
||||
|
||||
/**
|
||||
|
|
@ -121,5 +122,10 @@ abstract class ObjectDefinition(private val objectId: Int)
|
|||
*/
|
||||
var maxForwardSpeed: Float = 0f
|
||||
|
||||
/**
|
||||
* na
|
||||
*/
|
||||
var interference: InterferenceRange = Interference.AllowAll
|
||||
|
||||
def ObjectId: Int = objectId
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import net.psforever.objects.definition.converter.{FieldTurretConverter, Interna
|
|||
import net.psforever.objects.equipment.{EffectTarget, TargetValidation}
|
||||
import net.psforever.objects.geometry.GeometryForm
|
||||
import net.psforever.objects.geometry.d3.VolumetricGeometry
|
||||
import net.psforever.objects.serverobject.deploy.InterferenceRange
|
||||
import net.psforever.objects.serverobject.mount.{MountInfo, SeatDefinition}
|
||||
import net.psforever.objects.serverobject.turret.{AutoChecks, AutoCooldowns, AutoRanges, Automation, TurretUpgrade}
|
||||
import net.psforever.objects.vital.{CollisionXYData, CollisionZData, ComplexDeployableResolutions, SimpleResolutions}
|
||||
|
|
@ -40,6 +41,7 @@ object GlobalDefinitionsDeployable {
|
|||
boomer.DeployCategory = DeployableCategory.Boomers
|
||||
boomer.DeployTime = Duration.create(1000, "ms")
|
||||
boomer.deployAnimation = DeployAnimation.Standard
|
||||
boomer.interference = InterferenceRange(main = 0.2f)
|
||||
boomer.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.Splash
|
||||
SympatheticExplosion = true
|
||||
|
|
@ -62,6 +64,7 @@ object GlobalDefinitionsDeployable {
|
|||
he_mine.Repairable = false
|
||||
he_mine.DeployTime = Duration.create(1000, "ms")
|
||||
he_mine.deployAnimation = DeployAnimation.Standard
|
||||
he_mine.interference = InterferenceRange(main = 7f, sharedGroupId = 1, shared = 7f, deployables = 0.1f)
|
||||
he_mine.triggerRadius = 3f
|
||||
he_mine.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.Splash
|
||||
|
|
@ -85,6 +88,7 @@ object GlobalDefinitionsDeployable {
|
|||
jammer_mine.Repairable = false
|
||||
jammer_mine.DeployTime = Duration.create(1000, "ms")
|
||||
jammer_mine.deployAnimation = DeployAnimation.Standard
|
||||
jammer_mine.interference = InterferenceRange(main = 7f, sharedGroupId = 1, shared = 7f, deployables = 0.1f)
|
||||
jammer_mine.DetonateOnJamming = false
|
||||
jammer_mine.triggerRadius = 3f
|
||||
jammer_mine.innateDamage = new DamageWithPosition {
|
||||
|
|
@ -133,6 +137,7 @@ object GlobalDefinitionsDeployable {
|
|||
spitfire_turret.DeployTime = Duration.create(5000, "ms")
|
||||
spitfire_turret.Model = ComplexDeployableResolutions.calculate
|
||||
spitfire_turret.deployAnimation = DeployAnimation.Standard
|
||||
spitfire_turret.interference = InterferenceRange(main = 25f, sharedGroupId = 2, shared = 25f, deployables = 0.1f)
|
||||
spitfire_turret.AutoFire = Automation(
|
||||
AutoRanges(
|
||||
detection = 75f,
|
||||
|
|
@ -176,6 +181,7 @@ object GlobalDefinitionsDeployable {
|
|||
spitfire_cloaked.DeployCategory = DeployableCategory.SmallTurrets
|
||||
spitfire_cloaked.DeployTime = Duration.create(5000, "ms")
|
||||
spitfire_cloaked.deployAnimation = DeployAnimation.Standard
|
||||
spitfire_cloaked.interference = InterferenceRange(main = 25f, sharedGroupId = 2, shared = 25f, deployables = 0.1f)
|
||||
spitfire_cloaked.Model = ComplexDeployableResolutions.calculate
|
||||
spitfire_cloaked.AutoFire = Automation(
|
||||
AutoRanges(
|
||||
|
|
@ -226,6 +232,7 @@ object GlobalDefinitionsDeployable {
|
|||
spitfire_aa.DeployCategory = DeployableCategory.SmallTurrets
|
||||
spitfire_aa.DeployTime = Duration.create(5000, "ms")
|
||||
spitfire_aa.deployAnimation = DeployAnimation.Standard
|
||||
spitfire_aa.interference = InterferenceRange(main = 25f, sharedGroupId = 2, shared = 25f, deployables = 0.1f)
|
||||
spitfire_aa.Model = ComplexDeployableResolutions.calculate
|
||||
spitfire_aa.AutoFire = Automation(
|
||||
AutoRanges(
|
||||
|
|
@ -263,6 +270,7 @@ object GlobalDefinitionsDeployable {
|
|||
motionalarmsensor.RepairIfDestroyed = false
|
||||
motionalarmsensor.DeployTime = Duration.create(1000, "ms")
|
||||
motionalarmsensor.deployAnimation = DeployAnimation.Standard
|
||||
motionalarmsensor.interference = InterferenceRange(main = 25f, deployables = 0.1f)
|
||||
motionalarmsensor.Geometry = sensor
|
||||
|
||||
sensor_shield.Name = "sensor_shield"
|
||||
|
|
@ -273,6 +281,7 @@ object GlobalDefinitionsDeployable {
|
|||
sensor_shield.RepairIfDestroyed = false
|
||||
sensor_shield.DeployTime = Duration.create(5000, "ms")
|
||||
sensor_shield.deployAnimation = DeployAnimation.Standard
|
||||
sensor_shield.interference = InterferenceRange(main = 20f, deployables = 0.1f)
|
||||
sensor_shield.Geometry = sensor
|
||||
|
||||
tank_traps.Name = "tank_traps"
|
||||
|
|
@ -284,6 +293,8 @@ object GlobalDefinitionsDeployable {
|
|||
tank_traps.DeployCategory = DeployableCategory.TankTraps
|
||||
tank_traps.DeployTime = Duration.create(6000, "ms")
|
||||
tank_traps.deployAnimation = DeployAnimation.Fdu
|
||||
tank_traps.interference = InterferenceRange(main = 3.5f, sharedGroupId = 3, shared = 60f, deployables = 3f)
|
||||
//todo what is tank_traps interference2 60
|
||||
//tank_traps do not explode
|
||||
tank_traps.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
|
|
@ -318,6 +329,7 @@ object GlobalDefinitionsDeployable {
|
|||
portable_manned_turret.DeployCategory = DeployableCategory.FieldTurrets
|
||||
portable_manned_turret.DeployTime = Duration.create(6000, "ms")
|
||||
portable_manned_turret.deployAnimation = DeployAnimation.Fdu
|
||||
portable_manned_turret.interference = InterferenceRange(main = 60f, sharedGroupId = 3, shared = 40f, deployables = 2.5f)
|
||||
portable_manned_turret.Model = ComplexDeployableResolutions.calculate
|
||||
portable_manned_turret.RadiationShielding = 0.5f
|
||||
portable_manned_turret.innateDamage = new DamageWithPosition {
|
||||
|
|
@ -351,6 +363,7 @@ object GlobalDefinitionsDeployable {
|
|||
portable_manned_turret_nc.DeployCategory = DeployableCategory.FieldTurrets
|
||||
portable_manned_turret_nc.DeployTime = Duration.create(6000, "ms")
|
||||
portable_manned_turret_nc.deployAnimation = DeployAnimation.Fdu
|
||||
portable_manned_turret_nc.interference = InterferenceRange(main = 60f, sharedGroupId = 3, shared = 40f, deployables = 2.5f)
|
||||
portable_manned_turret_nc.Model = ComplexDeployableResolutions.calculate
|
||||
portable_manned_turret_nc.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
|
|
@ -383,6 +396,7 @@ object GlobalDefinitionsDeployable {
|
|||
portable_manned_turret_tr.DeployCategory = DeployableCategory.FieldTurrets
|
||||
portable_manned_turret_tr.DeployTime = Duration.create(6000, "ms")
|
||||
portable_manned_turret_tr.deployAnimation = DeployAnimation.Fdu
|
||||
portable_manned_turret_tr.interference = InterferenceRange(main = 60f, sharedGroupId = 3, shared = 40f, deployables = 2.5f)
|
||||
portable_manned_turret_tr.Model = ComplexDeployableResolutions.calculate
|
||||
portable_manned_turret_tr.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
|
|
@ -415,6 +429,7 @@ object GlobalDefinitionsDeployable {
|
|||
portable_manned_turret_vs.DeployCategory = DeployableCategory.FieldTurrets
|
||||
portable_manned_turret_vs.DeployTime = Duration.create(6000, "ms")
|
||||
portable_manned_turret_vs.deployAnimation = DeployAnimation.Fdu
|
||||
portable_manned_turret_vs.interference = InterferenceRange(main = 60f, sharedGroupId = 3, shared = 40f, deployables = 2.5f)
|
||||
portable_manned_turret_vs.Model = ComplexDeployableResolutions.calculate
|
||||
portable_manned_turret_vs.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
|
|
@ -437,6 +452,7 @@ object GlobalDefinitionsDeployable {
|
|||
deployable_shield_generator.RepairIfDestroyed = false
|
||||
deployable_shield_generator.DeployTime = Duration.create(6000, "ms")
|
||||
deployable_shield_generator.deployAnimation = DeployAnimation.Fdu
|
||||
deployable_shield_generator.interference = InterferenceRange(main = 125f, sharedGroupId = 3, shared = 60f, deployables = 2f)
|
||||
deployable_shield_generator.Model = ComplexDeployableResolutions.calculate
|
||||
deployable_shield_generator.Geometry = GeometryForm.representByCylinder(radius = 0.6562f, height = 2.17188f)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import net.psforever.objects.avatar.Certification
|
|||
import net.psforever.objects.equipment.EffectTarget
|
||||
import net.psforever.objects.geometry.GeometryForm
|
||||
import net.psforever.objects.geometry.d3.VolumetricGeometry
|
||||
import net.psforever.objects.serverobject.deploy.InterferenceRange
|
||||
import net.psforever.objects.serverobject.doors.InteriorDoorField
|
||||
import net.psforever.objects.serverobject.mount.{MountInfo, SeatDefinition}
|
||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPadDefinition
|
||||
|
|
@ -934,5 +935,11 @@ object GlobalDefinitionsMiscellaneous {
|
|||
obbasemesh.Descriptor = "orbital_shuttle_pad"
|
||||
obbasemesh.Damageable = false
|
||||
obbasemesh.Repairable = false
|
||||
|
||||
stationaryteleportpad.Name = "stationaryteleportpad"
|
||||
stationaryteleportpad.interference = InterferenceRange(deployables = 5.5f)
|
||||
|
||||
zipline.Name = "zipline"
|
||||
zipline.interference = InterferenceRange(deployables = 5.5f)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import net.psforever.objects.definition.converter._
|
|||
import net.psforever.objects.geometry.GeometryForm
|
||||
import net.psforever.objects.inventory.InventoryTile
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
import net.psforever.objects.serverobject.deploy.InterferenceRange
|
||||
import net.psforever.objects.serverobject.mount._
|
||||
import net.psforever.objects.vehicles.{DestroyedVehicle, UtilityType, VehicleSubsystemEntry}
|
||||
import net.psforever.objects.vital.base.DamageType
|
||||
|
|
@ -969,6 +970,7 @@ object GlobalDefinitionsVehicle {
|
|||
ams.Deployment = true
|
||||
ams.DeployTime = 2000
|
||||
ams.UndeployTime = 2000
|
||||
ams.interference = InterferenceRange(main = 125f, sharedGroupId = 3, shared = 30f)
|
||||
ams.DeconstructionTime = Some(20 minutes)
|
||||
ams.AutoPilotSpeeds = (18, 6)
|
||||
ams.Packet = utilityConverter
|
||||
|
|
|
|||
|
|
@ -0,0 +1,128 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.serverobject.deploy
|
||||
|
||||
import net.psforever.objects.PlanetSideGameObject
|
||||
import net.psforever.objects.definition.{DeployableDefinition, ObjectDefinition}
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.types.{DriveState, Vector3}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/**
|
||||
* Block the deployment of certain entities within a certain distance.
|
||||
* Deployable vehicles and combat engineer entities both have a deployment condition that can be influenced by these ranges.
|
||||
* Vehicles of an object type block other vehicles of that object type.
|
||||
* Combat engineering entities block combat engineering entities of the same category.
|
||||
* @param main distance between which this kind of entity blocks itself (m)
|
||||
* @param sharedGroupId identifier for the similar entity group
|
||||
* @param shared distance between entities that belong to the similar group block one another (m)
|
||||
* @param deployables distance between which this entity may block deployment of combat engineering entities (m);
|
||||
* defaults to 0
|
||||
*/
|
||||
final case class InterferenceRange(main: Float = 0f, sharedGroupId: Int = 0, shared: Float = 0f, deployables: Float = 0f) {
|
||||
assert(
|
||||
main > -1f && deployables > -1f,
|
||||
"if set, interference range must be positive non-zero float value"
|
||||
)
|
||||
assert(
|
||||
sharedGroupId == 0 || shared > 0f,
|
||||
"if set, a shared group of a non-zero id should have a positive non-zero float value"
|
||||
)
|
||||
}
|
||||
|
||||
object Interference {
|
||||
final val AllowAll: InterferenceRange = InterferenceRange()
|
||||
|
||||
final val MaxRange: Float = 125f
|
||||
|
||||
/**
|
||||
* When two entities connected by similarity or distance exert influence on one another
|
||||
* that stops the later-acting entity from manifesting
|
||||
* or disables certain behaviors from the later-acting entity.
|
||||
* Only dynamic entities are examined.
|
||||
* Static entities like facility amenities or zone-specific elements that exert interference
|
||||
* must manage their interactions through other methods.
|
||||
* @param zone game world in which this test will be conducted;
|
||||
* entity should be `ZoneAware`, but it may not be set correctly during this part of its internal process
|
||||
* @param obj entity that may be interfered with
|
||||
* @return a different entity that causes the test entity to suffer interference
|
||||
*/
|
||||
def Test(zone: Zone, obj: PlanetSideGameObject with FactionAffinity): Option[PlanetSideGameObject with FactionAffinity] = {
|
||||
val (data, filterFunc) = SetupForTest(zone, obj)
|
||||
data.find(filterFunc)
|
||||
}
|
||||
|
||||
/**
|
||||
* When two entities connected by similarity or distance exert influence on one another
|
||||
* that stops the later-acting entity from manifesting
|
||||
* or disables certain behaviors from the later-acting entity.
|
||||
* @param zone game world in which this test will be conducted;
|
||||
* entity should be `ZoneAware`, but it may not be set correctly during this part of its internal process
|
||||
* @param obj entity that may be interfered with
|
||||
* @return list of entities to run an interference test on, and
|
||||
* predicate to determine which entities pass the test
|
||||
*/
|
||||
def SetupForTest(
|
||||
zone: Zone,
|
||||
obj: PlanetSideGameObject with FactionAffinity
|
||||
): (List[PlanetSideGameObject with FactionAffinity], PlanetSideGameObject => Boolean) = {
|
||||
val objectDefinition = obj.Definition
|
||||
if (objectDefinition.interference eq Interference.AllowAll) {
|
||||
(List(), interferenceTestNoResults) //no targets can block, and test will never pass
|
||||
} else {
|
||||
val position = obj.Position
|
||||
val faction = obj.Faction
|
||||
val sharedGroupId = objectDefinition.interference.sharedGroupId
|
||||
val sector = zone.blockMap.sector(position, Interference.MaxRange)
|
||||
val targets = (sector.deployableList ++ sector.vehicleList.filter(_.DeploymentState >= DriveState.Deploying))
|
||||
.collect { case target: PlanetSideGameObject with FactionAffinity
|
||||
if target.Faction != faction &&
|
||||
(target.Definition.asInstanceOf[ObjectDefinition].interference ne Interference.AllowAll) =>
|
||||
target
|
||||
}
|
||||
if (sharedGroupId != 0) {
|
||||
(targets, interferenceTestWithSharedGroup(position, objectDefinition, sharedGroupId))
|
||||
} else {
|
||||
(targets, interferenceTestNoSharedGroup(position, objectDefinition))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def interferenceTestNoResults(@unused p: PlanetSideGameObject): Boolean = false
|
||||
|
||||
private def interferenceTestNoSharedGroup(
|
||||
position: Vector3,
|
||||
objectDefinition: ObjectDefinition
|
||||
): PlanetSideGameObject => Boolean = { p =>
|
||||
val pDefinition = p.Definition
|
||||
val objectInterference = objectDefinition.interference
|
||||
lazy val distanceSq = Vector3.DistanceSquared(position, p.Position)
|
||||
if (pDefinition == objectDefinition) {
|
||||
distanceSq < objectInterference.main * objectInterference.main
|
||||
} else if (pDefinition.isInstanceOf[DeployableDefinition]) {
|
||||
distanceSq < objectInterference.deployables * objectInterference.deployables
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private def interferenceTestWithSharedGroup(
|
||||
position: Vector3,
|
||||
objectDefinition: ObjectDefinition,
|
||||
sharedGroupId: Int
|
||||
): PlanetSideGameObject => Boolean = { p =>
|
||||
val pDefinition = p.Definition
|
||||
val objectInterference = objectDefinition.interference
|
||||
lazy val distanceSq = Vector3.DistanceSquared(position, p.Position)
|
||||
if (pDefinition == objectDefinition) {
|
||||
distanceSq < objectInterference.main * objectInterference.main
|
||||
} else if (sharedGroupId == pDefinition.interference.sharedGroupId) {
|
||||
distanceSq < objectInterference.shared * objectInterference.shared
|
||||
} else if (pDefinition.isInstanceOf[DeployableDefinition]) {
|
||||
distanceSq < objectInterference.deployables * objectInterference.deployables
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.serverobject.zipline
|
||||
|
||||
import net.psforever.objects.definition.ObjectDefinition
|
||||
|
||||
/**
|
||||
* The definition for any generic teleportation entity.
|
||||
* Two entities are described by this object definition - zip lines and the teleportation rings, both in the caverns.
|
||||
* Entities of these objects are environmental, like facilities, do not get constructed by the user.
|
||||
* The said entities also do not require being configured at login or zone load.
|
||||
*/
|
||||
class GenericTeleportationDefinition(private val objectId: Int) extends ObjectDefinition(objectId)
|
||||
|
|
@ -1317,6 +1317,10 @@ object Zone {
|
|||
final case class CanNotSpawn(zone: Zone, vehicle: Vehicle, reason: String)
|
||||
|
||||
final case class CanNotDespawn(zone: Zone, vehicle: Vehicle, reason: String)
|
||||
|
||||
final case class TryDeploymentChange(vehicle: Vehicle, toDeployState: DriveState.Value)
|
||||
|
||||
final case class CanNotDeploy(zone: Zone, vehicle: Vehicle, toDeployState: DriveState.Value, reason: String)
|
||||
}
|
||||
|
||||
object HotSpot {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import akka.actor.Actor
|
|||
import net.psforever.objects.Player
|
||||
import net.psforever.actors.zone.ZoneActor
|
||||
import net.psforever.objects.ce.Deployable
|
||||
import net.psforever.objects.serverobject.deploy.Interference
|
||||
import net.psforever.objects.sourcing.ObjectSource
|
||||
import net.psforever.objects.vehicles.MountedWeapons
|
||||
import net.psforever.objects.vital.SpawningActivity
|
||||
|
|
@ -28,7 +29,7 @@ class ZoneDeployableActor(
|
|||
|
||||
def receive: Receive = {
|
||||
case Zone.Deployable.Build(obj) =>
|
||||
if (DeployableBuild(obj, deployableList)) {
|
||||
if (DeployableBuild(zone, obj, deployableList)) {
|
||||
obj.Zone = zone
|
||||
obj match {
|
||||
case mounting: MountedWeapons =>
|
||||
|
|
@ -40,11 +41,10 @@ class ZoneDeployableActor(
|
|||
.foreach { guid =>
|
||||
turretToMount.put(guid, dguid)
|
||||
}
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
obj.Definition.Initialize(obj, context)
|
||||
zone.actor ! ZoneActor.AddToBlockMap(obj, obj.Position)
|
||||
//obj.History(EntitySpawn(SourceEntry(obj), obj.Zone))
|
||||
obj.LogActivity(SpawningActivity(ObjectSource(obj), zone.Number, None))
|
||||
obj.Actor ! Zone.Deployable.Setup()
|
||||
} else {
|
||||
log.warn(s"failed to build a ${obj.Definition.Name}")
|
||||
|
|
@ -52,7 +52,7 @@ class ZoneDeployableActor(
|
|||
}
|
||||
|
||||
case Zone.Deployable.BuildByOwner(obj, owner, tool) =>
|
||||
if (DeployableBuild(obj, deployableList)) {
|
||||
if (DeployableBuild(zone, obj, deployableList)) {
|
||||
obj.Zone = zone
|
||||
obj match {
|
||||
case mounting: MountedWeapons =>
|
||||
|
|
@ -64,10 +64,9 @@ class ZoneDeployableActor(
|
|||
.foreach { guid =>
|
||||
turretToMount.put(guid, dguid)
|
||||
}
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
obj.Definition.Initialize(obj, context)
|
||||
zone.actor ! ZoneActor.AddToBlockMap(obj, obj.Position)
|
||||
obj.LogActivity(SpawningActivity(ObjectSource(obj), zone.Number, None))
|
||||
owner.Actor ! Player.BuildDeployable(obj, tool)
|
||||
} else {
|
||||
|
|
@ -76,50 +75,54 @@ class ZoneDeployableActor(
|
|||
}
|
||||
|
||||
case Zone.Deployable.Dismiss(obj) =>
|
||||
if (DeployableDismiss(obj, deployableList)) {
|
||||
if (DeployableDismiss(zone, obj, deployableList)) {
|
||||
obj match {
|
||||
case _: MountedWeapons =>
|
||||
val dguid = obj.GUID.guid
|
||||
turretToMount.filterInPlace { case (_, guid) => guid != dguid }
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
obj.Actor ! Zone.Deployable.IsDismissed(obj)
|
||||
obj.Definition.Uninitialize(obj, context)
|
||||
obj.ClearHistory()
|
||||
zone.actor ! ZoneActor.RemoveFromBlockMap(obj)
|
||||
}
|
||||
|
||||
case Zone.Deployable.IsBuilt(_) => ;
|
||||
case Zone.Deployable.IsBuilt(_) => ()
|
||||
|
||||
case Zone.Deployable.IsDismissed(_) => ;
|
||||
case Zone.Deployable.IsDismissed(_) => ()
|
||||
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
||||
object ZoneDeployableActor {
|
||||
def DeployableBuild(
|
||||
obj: Deployable,
|
||||
deployableList: ListBuffer[Deployable]
|
||||
): Boolean = {
|
||||
deployableList.find(d => d == obj) match {
|
||||
case Some(_) =>
|
||||
false
|
||||
case None =>
|
||||
zone: Zone,
|
||||
obj: Deployable,
|
||||
deployableList: ListBuffer[Deployable]
|
||||
): Boolean = {
|
||||
val position = obj.Position
|
||||
deployableList.find(_ eq obj) match {
|
||||
case None if Interference.Test(zone, obj).isEmpty =>
|
||||
deployableList += obj
|
||||
zone.actor ! ZoneActor.AddToBlockMap(obj, position)
|
||||
true
|
||||
case _ =>
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
def DeployableDismiss(
|
||||
obj: Deployable,
|
||||
deployableList: ListBuffer[Deployable]
|
||||
): Boolean = {
|
||||
zone: Zone,
|
||||
obj: Deployable,
|
||||
deployableList: ListBuffer[Deployable]
|
||||
): Boolean = {
|
||||
recursiveFindDeployable(deployableList.iterator, obj) match {
|
||||
case None =>
|
||||
false
|
||||
case Some(index) =>
|
||||
deployableList.remove(index)
|
||||
zone.actor ! ZoneActor.RemoveFromBlockMap(obj)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ package net.psforever.objects.zones
|
|||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.actors.zone.ZoneActor
|
||||
import net.psforever.objects.definition.VehicleDefinition
|
||||
import net.psforever.objects.serverobject.deploy.{Deployment, Interference}
|
||||
import net.psforever.objects.vital.InGameHistory
|
||||
import net.psforever.objects.{Default, Vehicle}
|
||||
import net.psforever.types.Vector3
|
||||
import net.psforever.types.{DriveState, PlanetSideEmpire, Vector3}
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.mutable
|
||||
|
|
@ -13,27 +15,14 @@ import scala.collection.mutable
|
|||
/**
|
||||
* Synchronize management of the list of `Vehicles` maintained by some `Zone`.
|
||||
*/
|
||||
//COMMENTS IMPORTED FROM FORMER VehicleContextActor:
|
||||
/*
|
||||
* Provide a context for a `Vehicle` `Actor` - the `VehicleControl`.<br>
|
||||
* <br>
|
||||
* A vehicle can be passed between different zones and, therefore, does not belong to the zone.
|
||||
* A vehicle cna be given to different players and can persist and change though players have gone.
|
||||
* Therefore, also does not belong to `WorldSessionActor`.
|
||||
* A vehicle must anchored to something that exists outside of the `InterstellarCluster` and its agents.<br>
|
||||
* <br>
|
||||
* The only purpose of this `Actor` is to allow vehicles to borrow a context for the purpose of `Actor` creation.
|
||||
* It is also be allowed to be responsible for cleaning up that context.
|
||||
* (In reality, it can be cleaned up anywhere a `PoisonPill` can be sent.)<br>
|
||||
* <br>
|
||||
* This `Actor` is intended to sit on top of the event system that handles broadcast messaging.
|
||||
*/
|
||||
class ZoneVehicleActor(
|
||||
zone: Zone,
|
||||
vehicleList: mutable.ListBuffer[Vehicle],
|
||||
turretToMount: mutable.HashMap[Int, Int]
|
||||
) extends Actor {
|
||||
//private[this] val log = org.log4s.getLogger
|
||||
private val log = org.log4s.getLogger(s"${zone.id}-vehicles")
|
||||
|
||||
private var temporaryInterference: Seq[(Vector3, PlanetSideEmpire.Value, VehicleDefinition)] = Seq()
|
||||
|
||||
def receive: Receive = {
|
||||
case Zone.Vehicle.Spawn(vehicle) =>
|
||||
|
|
@ -73,19 +62,62 @@ class ZoneVehicleActor(
|
|||
vehicle.ClearHistory()
|
||||
zone.actor ! ZoneActor.RemoveFromBlockMap(vehicle)
|
||||
sender() ! Zone.Vehicle.HasDespawned(zone, vehicle)
|
||||
case None => ;
|
||||
case None =>
|
||||
sender() ! Zone.Vehicle.CanNotDespawn(zone, vehicle, "can not find")
|
||||
}
|
||||
|
||||
case Zone.Vehicle.HasDespawned(_, _) => ;
|
||||
case Zone.Vehicle.TryDeploymentChange(vehicle, toDeployState)
|
||||
if toDeployState == DriveState.Deploying &&
|
||||
(ZoneVehicleActor.temporaryInterferenceTest(vehicle, temporaryInterference) || Interference.Test(zone, vehicle).nonEmpty) =>
|
||||
sender() ! Zone.Vehicle.CanNotDeploy(zone, vehicle, toDeployState, "blocked by a nearby entity")
|
||||
|
||||
case Zone.Vehicle.CanNotDespawn(_, _, _) => ;
|
||||
case Zone.Vehicle.TryDeploymentChange(vehicle, toDeployState)
|
||||
if toDeployState == DriveState.Deploying =>
|
||||
tryAddToInterferenceField(vehicle.Position, vehicle.Faction, vehicle.Definition)
|
||||
vehicle.Actor.tell(Deployment.TryDeploymentChange(toDeployState), sender())
|
||||
|
||||
case _ => ;
|
||||
case Zone.Vehicle.TryDeploymentChange(vehicle, toDeployState) =>
|
||||
vehicle.Actor.tell(Deployment.TryDeploymentChange(toDeployState), sender())
|
||||
|
||||
case Zone.Vehicle.HasDespawned(_, _) => ()
|
||||
|
||||
case Zone.Vehicle.CanNotDespawn(_, _, _) => ()
|
||||
|
||||
case Zone.Vehicle.CanNotDeploy(_, vehicle, _, reason) => ()
|
||||
val pos = vehicle.Position
|
||||
val driverMoniker = vehicle.Seats.headOption.flatMap(_._2.occupant).map(_.Name).getOrElse("Driver")
|
||||
log.warn(s"$driverMoniker's ${vehicle.Definition.Name} can not deploy in ${zone.id} because $reason")
|
||||
temporaryInterference = temporaryInterference.filterNot(_._1 == pos)
|
||||
|
||||
case ZoneVehicleActor.ClearInterference(pos) =>
|
||||
temporaryInterference = temporaryInterference.filterNot(_._1 == pos)
|
||||
|
||||
case _ => ()
|
||||
}
|
||||
|
||||
private def tryAddToInterferenceField(
|
||||
position: Vector3,
|
||||
faction: PlanetSideEmpire.Value,
|
||||
definition: VehicleDefinition
|
||||
): Boolean = {
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
val causesInterference = definition.interference ne Interference.AllowAll
|
||||
if (causesInterference) {
|
||||
temporaryInterference = temporaryInterference :+ (position, faction, definition)
|
||||
context.system.scheduler.scheduleOnce(
|
||||
definition.DeployTime.milliseconds,
|
||||
self,
|
||||
ZoneVehicleActor.ClearInterference(position)
|
||||
)
|
||||
}
|
||||
causesInterference
|
||||
}
|
||||
}
|
||||
|
||||
object ZoneVehicleActor {
|
||||
private case class ClearInterference(pos: Vector3)
|
||||
|
||||
@tailrec final def recursiveFindVehicle(iter: Iterator[Vehicle], target: Vehicle, index: Int = 0): Option[Int] = {
|
||||
if (!iter.hasNext) {
|
||||
None
|
||||
|
|
@ -97,4 +129,26 @@ object ZoneVehicleActor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def temporaryInterferenceTest(
|
||||
vehicle: Vehicle,
|
||||
existingInterferences: Seq[(Vector3, PlanetSideEmpire.Value, VehicleDefinition)]
|
||||
): Boolean = {
|
||||
val vPosition = vehicle.Position
|
||||
val vFaction = vehicle.Faction
|
||||
val vDefinition = vehicle.Definition
|
||||
if (vDefinition.interference eq Interference.AllowAll) {
|
||||
false
|
||||
} else {
|
||||
existingInterferences
|
||||
.collect { case (p, faction, d) if faction == vFaction => (p, d) }
|
||||
.exists { case (position, definition) =>
|
||||
val interference = definition.interference
|
||||
(interference ne Interference.AllowAll) && {
|
||||
lazy val distanceSq = Vector3.DistanceSquared(position, vPosition)
|
||||
definition == vDefinition && distanceSq < interference.main * interference.main
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ object DriveState extends Enumeration {
|
|||
val Undeploying = Value(1)
|
||||
val Deploying = Value(2)
|
||||
val Deployed = Value(3)
|
||||
val UNK4 = Value(4) // to have Xtoolspar working
|
||||
val UNK5 = Value(5) // to have Xtoolspar working
|
||||
val UNK6 = Value(6) // to have Xtoolspar working
|
||||
val UNK4 = Value(4) // to have decoding tool working
|
||||
val UNK5 = Value(5) // to have decoding tool working
|
||||
val UNK6 = Value(6) // to have decoding tool working
|
||||
val State7 = Value(7) //unknown; not encountered on a vehicle that can deploy; functions like Mobile
|
||||
val State127 = Value(127) //unknown
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue