mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
Merge branch 'master' into forseral-water
This commit is contained in:
commit
b76ab4cae6
|
|
@ -9,6 +9,7 @@ Code Contributors
|
|||
* aphedox
|
||||
* L-11
|
||||
* xTriad (initial database schema)
|
||||
* Jakob
|
||||
|
||||
Packet Capturing 2015-2016 (in order of most packets captured)
|
||||
=================
|
||||
|
|
|
|||
|
|
@ -542,9 +542,12 @@ network {
|
|||
}
|
||||
|
||||
development {
|
||||
# List of GM commands available to everyone
|
||||
# List of GM commands made available to everyone
|
||||
# Values are `ChatMessageType` members, for example: [CMT_ADDBATTLEEXPERIENCE, CMT_CAPTUREBASE]
|
||||
unprivileged-gm-commands = []
|
||||
# List of GM bang commands made available to everyone
|
||||
# Since the commands come in as plain chat preceded by a bang (!) character, values are the names of the commands
|
||||
unprivileged-gm-bang-commands = []
|
||||
|
||||
net-sim {
|
||||
# Enable artificial packet unreliability. Used for development testing.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import java.util.concurrent.atomic.AtomicInteger
|
|||
import net.psforever.actors.zone.ZoneActor
|
||||
import net.psforever.objects.avatar.scoring.{Assist, Death, EquipmentStat, KDAStat, Kill, Life, ScoreCard, SupportActivity}
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||
import net.psforever.objects.sourcing.VehicleSource
|
||||
import net.psforever.objects.sourcing.{TurretSource, VehicleSource}
|
||||
import net.psforever.objects.vital.{InGameHistory, ReconstructionActivity}
|
||||
import net.psforever.objects.vehicles.MountedWeapons
|
||||
import net.psforever.types.{ChatMessageType, StatisticalCategory, StatisticalElement}
|
||||
|
|
@ -3188,10 +3188,16 @@ class AvatarActor(
|
|||
player.HistoryAndContributions()
|
||||
}
|
||||
val target = killStat.info.targetAfter.asInstanceOf[PlayerSource]
|
||||
val targetMounted = target.seatedIn.map { case (v: VehicleSource, seat) =>
|
||||
val definition = v.Definition
|
||||
definition.ObjectId * 10 + Vehicles.SeatPermissionGroup(definition, seat).map { _.id }.getOrElse(0)
|
||||
}.getOrElse(0)
|
||||
val targetMounted = target.seatedIn
|
||||
.collect {
|
||||
case (v: VehicleSource, seat) =>
|
||||
val definition = v.Definition
|
||||
definition.ObjectId * 10 + Vehicles.SeatPermissionGroup(definition, seat).map { _.id }.getOrElse(0)
|
||||
case (t: TurretSource, seat) =>
|
||||
val definition = t.Definition
|
||||
definition.ObjectId * 10 + seat
|
||||
}
|
||||
.getOrElse(0)
|
||||
zones.exp.ToDatabase.reportKillBy(
|
||||
avatar.id.toLong,
|
||||
target.CharId,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -641,6 +641,7 @@ class SessionData(
|
|||
val dObj: Deployable = Deployables.Make(ammoType)()
|
||||
dObj.Position = pos
|
||||
dObj.Orientation = orient
|
||||
dObj.WhichSide = player.WhichSide
|
||||
dObj.Faction = player.Faction
|
||||
dObj.AssignOwnership(player)
|
||||
val tasking: TaskBundle = dObj match {
|
||||
|
|
@ -1449,6 +1450,7 @@ class SessionData(
|
|||
}) match {
|
||||
case Some((vehicle: Vehicle, Some(util: Utility.InternalTelepad))) =>
|
||||
zoning.CancelZoningProcessWithDescriptiveReason("cancel")
|
||||
player.WhichSide = vehicle.WhichSide
|
||||
useRouterTelepadSystem(
|
||||
router = vehicle,
|
||||
internalTelepad = util,
|
||||
|
|
@ -1474,6 +1476,7 @@ class SessionData(
|
|||
continent.GUID(obj.Telepad) match {
|
||||
case Some(pad: TelepadDeployable) =>
|
||||
zoning.CancelZoningProcessWithDescriptiveReason("cancel")
|
||||
player.WhichSide = pad.WhichSide
|
||||
useRouterTelepadSystem(
|
||||
router = obj.Owner.asInstanceOf[Vehicle],
|
||||
internalTelepad = obj,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package net.psforever.actors.session.support
|
|||
|
||||
import akka.actor.{ActorContext, typed}
|
||||
import net.psforever.objects.definition.ProjectileDefinition
|
||||
import net.psforever.objects.serverobject.doors.InteriorDoorPassage
|
||||
import net.psforever.objects.serverobject.interior.Sidedness
|
||||
import net.psforever.objects.serverobject.turret.auto.{AutomatedTurret, AutomatedTurretBehavior}
|
||||
import net.psforever.objects.zones.Zoning
|
||||
import net.psforever.objects.serverobject.turret.VanuSentry
|
||||
|
|
@ -303,11 +305,11 @@ private[support] class WeaponAndProjectileOperations(
|
|||
//find target(s)
|
||||
(hit_info match {
|
||||
case Some(hitInfo) =>
|
||||
val hitPos = hitInfo.hit_pos
|
||||
val hitPos = hitInfo.hit_pos
|
||||
sessionData.validObject(hitInfo.hitobject_guid, decorator = "Hit/hitInfo") match {
|
||||
case _ if projectile.profile == GlobalDefinitions.flail_projectile =>
|
||||
val radius = projectile.profile.DamageRadius * projectile.profile.DamageRadius
|
||||
val targets = Zone.findAllTargets(hitPos)(continent, player, projectile.profile)
|
||||
val targets = Zone.findAllTargets(continent, player, hitPos, projectile.profile)
|
||||
.filter { target =>
|
||||
Vector3.DistanceSquared(target.Position, hitPos) <= radius
|
||||
}
|
||||
|
|
@ -361,7 +363,6 @@ private[support] class WeaponAndProjectileOperations(
|
|||
FindProjectileEntry(projectile_guid) match {
|
||||
case Some(projectile) =>
|
||||
val profile = projectile.profile
|
||||
projectile.Position = explosion_pos
|
||||
projectile.Velocity = projectile_vel
|
||||
val (resolution1, resolution2) = profile.Aggravated match {
|
||||
case Some(_) if profile.ProjectileDamageTypes.contains(DamageType.Aggravated) =>
|
||||
|
|
@ -372,7 +373,7 @@ private[support] class WeaponAndProjectileOperations(
|
|||
//direct_victim_uid
|
||||
sessionData.validObject(direct_victim_uid, decorator = "SplashHit/direct_victim") match {
|
||||
case Some(target: PlanetSideGameObject with FactionAffinity with Vitality) =>
|
||||
CheckForHitPositionDiscrepancy(projectile_guid, target.Position, target)
|
||||
CheckForHitPositionDiscrepancy(projectile_guid, explosion_pos, target)
|
||||
ResolveProjectileInteraction(projectile, resolution1, target, target.Position).collect { resprojectile =>
|
||||
addShotsLanded(resprojectile.cause.attribution, shots = 1)
|
||||
sessionData.handleDealingDamage(target, resprojectile)
|
||||
|
|
@ -563,6 +564,7 @@ private[support] class WeaponAndProjectileOperations(
|
|||
ProjectileQuality.Normal
|
||||
}
|
||||
val qualityprojectile = projectile.quality(initialQuality)
|
||||
qualityprojectile.WhichSide = player.WhichSide
|
||||
projectiles(projectileIndex) = Some(qualityprojectile)
|
||||
if (projectile_info.ExistsOnRemoteClients) {
|
||||
log.trace(
|
||||
|
|
@ -1048,19 +1050,22 @@ private[support] class WeaponAndProjectileOperations(
|
|||
GlobalDefinitions.getDamageProxy(projectile, hitPos) match {
|
||||
case Nil =>
|
||||
Nil
|
||||
case list if list.isEmpty =>
|
||||
Nil
|
||||
case list =>
|
||||
HandleDamageProxySetupLittleBuddy(list, hitPos)
|
||||
UpdateProjectileSidednessAfterHit(projectile, hitPos)
|
||||
val projectileSide = projectile.WhichSide
|
||||
list.flatMap { proxy =>
|
||||
if (proxy.profile.ExistsOnRemoteClients) {
|
||||
proxy.Position = hitPos
|
||||
proxy.WhichSide = projectileSide
|
||||
continent.Projectile ! ZoneProjectile.Add(player.GUID, proxy)
|
||||
Nil
|
||||
} else if (proxy.tool_def == GlobalDefinitions.maelstrom) {
|
||||
//server-side maelstrom grenade target selection
|
||||
val radius = proxy.profile.LashRadius * proxy.profile.LashRadius
|
||||
val targets = continent.blockMap
|
||||
.sector(hitPos, proxy.profile.LashRadius)
|
||||
.livePlayerList
|
||||
val targets = Zone.findAllTargets(continent, hitPos, proxy.profile.LashRadius, { _.livePlayerList })
|
||||
.filter { target =>
|
||||
Vector3.DistanceSquared(target.Position, hitPos) <= radius
|
||||
}
|
||||
|
|
@ -1498,6 +1503,88 @@ private[support] class WeaponAndProjectileOperations(
|
|||
}
|
||||
}
|
||||
|
||||
private def UpdateProjectileSidednessAfterHit(projectile: Projectile, hitPosition: Vector3): Unit = {
|
||||
val origin = projectile.Position
|
||||
val distance = Vector3.Magnitude(hitPosition - origin)
|
||||
continent.blockMap
|
||||
.sector(hitPosition, distance)
|
||||
.environmentList
|
||||
.collect { case o: InteriorDoorPassage =>
|
||||
val door = o.door
|
||||
val intersectTest = quickLineSphereIntersectionPoints(
|
||||
origin,
|
||||
hitPosition,
|
||||
door.Position,
|
||||
door.Definition.UseRadius + 0.1f
|
||||
)
|
||||
(door, intersectTest)
|
||||
}
|
||||
.collect { case (door, intersectionTest) if intersectionTest.nonEmpty =>
|
||||
(door, Vector3.Magnitude(hitPosition - door.Position), intersectionTest)
|
||||
}
|
||||
.minByOption { case (_, dist, _) => dist }
|
||||
.foreach { case (door, _, intersects) =>
|
||||
val strictly = if (Vector3.DotProduct(Vector3.Unit(hitPosition - door.Position), door.Outwards) > 0f) {
|
||||
Sidedness.OutsideOf
|
||||
} else {
|
||||
Sidedness.InsideOf
|
||||
}
|
||||
projectile.WhichSide = if (intersects.size == 1) {
|
||||
Sidedness.InBetweenSides(door, strictly)
|
||||
} else {
|
||||
strictly
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a line segment line intersect with a sphere?<br>
|
||||
* This most likely belongs in `Geometry` or `GeometryForm` or somehow in association with the `\objects\geometry\` package.
|
||||
* @param start first point of the line segment
|
||||
* @param end second point of the line segment
|
||||
* @param center center of the sphere
|
||||
* @param radius radius of the sphere
|
||||
* @return list of all points of intersection, if any
|
||||
* @see `Vector3.DistanceSquared`
|
||||
* @see `Vector3.MagnitudeSquared`
|
||||
*/
|
||||
private def quickLineSphereIntersectionPoints(
|
||||
start: Vector3,
|
||||
end: Vector3,
|
||||
center: Vector3,
|
||||
radius: Float
|
||||
): Iterable[Vector3] = {
|
||||
/*
|
||||
Algorithm adapted from code found on https://paulbourke.net/geometry/circlesphere/index.html#linesphere,
|
||||
because I kept messing up proper substitution of the line formula and the circle formula into the quadratic equation.
|
||||
*/
|
||||
val Vector3(cx, cy, cz) = center
|
||||
val Vector3(sx, sy, sz) = start
|
||||
val vector = end - start
|
||||
//speed our way through a quadratic equation
|
||||
val (a, b) = {
|
||||
val Vector3(dx, dy, dz) = vector
|
||||
(
|
||||
dx * dx + dy * dy + dz * dz,
|
||||
2f * (dx * (sx - cx) + dy * (sy - cy) + dz * (sz - cz))
|
||||
)
|
||||
}
|
||||
val c = Vector3.MagnitudeSquared(center) + Vector3.MagnitudeSquared(start) - 2f * (cx * sx + cy * sy + cz * sz) - radius * radius
|
||||
val result = b * b - 4 * a * c
|
||||
if (result < 0f) {
|
||||
//negative, no intersection
|
||||
Seq()
|
||||
} else if (result < 0.00001f) {
|
||||
//zero-ish, one intersection point
|
||||
Seq(start - vector * (b / (2f * a)))
|
||||
} else {
|
||||
//positive, two intersection points
|
||||
val sqrt = math.sqrt(result).toFloat
|
||||
val endStart = vector / (2f * a)
|
||||
Seq(start + endStart * (sqrt - b), start + endStart * (b + sqrt) * -1f)
|
||||
}.filter(p => Vector3.DistanceSquared(start, p) <= a)
|
||||
}
|
||||
|
||||
override protected[session] def stop(): Unit = {
|
||||
if (player != null && player.HasGUID) {
|
||||
(prefire ++ shooting).foreach { guid =>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import net.psforever.login.WorldSession
|
|||
import net.psforever.objects.avatar.BattleRank
|
||||
import net.psforever.objects.avatar.scoring.{CampaignStatistics, ScoreCard, SessionStatistics}
|
||||
import net.psforever.objects.inventory.InventoryItem
|
||||
import net.psforever.objects.serverobject.interior.Sidedness
|
||||
import net.psforever.objects.serverobject.mount.Seat
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.serverobject.turret.auto.AutomatedTurret
|
||||
|
|
@ -2630,15 +2631,19 @@ class ZoningOperations(
|
|||
} else {
|
||||
Zones.zones.find { _.id.equals(zoneId) }.orElse(Some(Zone.Nowhere)).get.Number
|
||||
}
|
||||
val toSide = physSpawnPoint.map(_.Owner) match {
|
||||
case Some(_: WarpGate) => Sidedness.OutsideOf
|
||||
case Some(_: Building) => Sidedness.InsideOf
|
||||
case Some(v: Vehicle) => v.WhichSide //though usually OutsideOf
|
||||
case _ => Sidedness.StrictlyBetweenSides //todo needs better determination
|
||||
}
|
||||
val toSpawnPoint = physSpawnPoint.collect { case o: PlanetSideGameObject with FactionAffinity => SourceEntry(o) }
|
||||
respawnTimer = context.system.scheduler.scheduleOnce(respawnTime) {
|
||||
if (player.isBackpack) { // if the player is dead, he is handled as dead infantry, even if he died in a vehicle
|
||||
// new player is spawning
|
||||
val newPlayer = RespawnClone(player)
|
||||
newPlayer.Position = pos
|
||||
newPlayer.Orientation = ori
|
||||
newPlayer.LogActivity(SpawningActivity(PlayerSource(newPlayer), toZoneNumber, toSpawnPoint))
|
||||
LoadZoneAsPlayer(newPlayer, zoneId)
|
||||
LoadZoneAsPlayUsing(newPlayer, pos, ori, toSide, zoneId)
|
||||
} else {
|
||||
avatarActor ! AvatarActor.DeactivateActiveImplants()
|
||||
val betterSpawnPoint = physSpawnPoint.collect { case o: PlanetSideGameObject with FactionAffinity with InGameHistory => o }
|
||||
|
|
@ -2646,6 +2651,7 @@ class ZoningOperations(
|
|||
case Some(vehicle: Vehicle) => // driver or passenger in vehicle using a warp gate, or a droppod
|
||||
InGameHistory.SpawnReconstructionActivity(vehicle, toZoneNumber, betterSpawnPoint)
|
||||
InGameHistory.SpawnReconstructionActivity(player, toZoneNumber, betterSpawnPoint)
|
||||
vehicle.WhichSide = toSide
|
||||
LoadZoneInVehicle(vehicle, pos, ori, zoneId)
|
||||
|
||||
case _ if player.HasGUID => // player is deconstructing self or instant action
|
||||
|
|
@ -2655,21 +2661,38 @@ class ZoningOperations(
|
|||
continent.id,
|
||||
AvatarAction.ObjectDelete(player_guid, player_guid, 4)
|
||||
)
|
||||
player.Position = pos
|
||||
player.Orientation = ori
|
||||
InGameHistory.SpawnReconstructionActivity(player, toZoneNumber, betterSpawnPoint)
|
||||
LoadZoneAsPlayer(player, zoneId)
|
||||
LoadZoneAsPlayUsing(player, pos, ori, toSide, zoneId)
|
||||
|
||||
case _ => //player is logging in
|
||||
player.Position = pos
|
||||
player.Orientation = ori
|
||||
InGameHistory.SpawnReconstructionActivity(player, toZoneNumber, betterSpawnPoint)
|
||||
LoadZoneAsPlayer(player, zoneId)
|
||||
LoadZoneAsPlayUsing(player, pos, ori, toSide, zoneId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param target player being spawned
|
||||
* @param position where player is being placed in the game wqrld
|
||||
* @param orientation in what direction the player is facing in the game world
|
||||
* @param onThisSide description of the containing environment
|
||||
* @param goingToZone common designation for the zone
|
||||
*/
|
||||
private def LoadZoneAsPlayUsing(
|
||||
target: Player,
|
||||
position: Vector3,
|
||||
orientation: Vector3,
|
||||
onThisSide: Sidedness,
|
||||
goingToZone: String
|
||||
): Unit = {
|
||||
target.Position = position
|
||||
target.Orientation = orientation
|
||||
target.WhichSide = onThisSide
|
||||
LoadZoneAsPlayer(target, goingToZone)
|
||||
}
|
||||
|
||||
/**
|
||||
* The user is either already in the current zone and merely transporting from one location to another,
|
||||
* also called "dying", or occasionally "deconstructing,"
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects
|
||||
|
||||
import net.psforever.objects.avatar.interaction.{WithGantry, WithLava, WithWater}
|
||||
import net.psforever.objects.avatar.interaction.{WithEntrance, WithGantry, WithLava, WithWater}
|
||||
import net.psforever.objects.avatar.{Avatar, LoadoutManager, SpecialCarry}
|
||||
import net.psforever.objects.ballistics.InteractWithRadiationClouds
|
||||
import net.psforever.objects.ce.{Deployable, InteractWithMines, InteractWithTurrets}
|
||||
|
|
@ -12,6 +12,7 @@ import net.psforever.objects.serverobject.{PlanetSideServerObject, environment}
|
|||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||
import net.psforever.objects.serverobject.aura.AuraContainer
|
||||
import net.psforever.objects.serverobject.environment.interaction.common.{WithDeath, WithMovementTrigger}
|
||||
import net.psforever.objects.serverobject.interior.InteriorAwareFromInteraction
|
||||
import net.psforever.objects.serverobject.mount.MountableEntity
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||
import net.psforever.objects.vital.{HealFromEquipment, InGameActivity, RepairFromEquipment, Vitality}
|
||||
|
|
@ -35,9 +36,11 @@ class Player(var avatar: Avatar)
|
|||
with Container
|
||||
with JammableUnit
|
||||
with ZoneAware
|
||||
with InteriorAwareFromInteraction
|
||||
with AuraContainer
|
||||
with MountableEntity {
|
||||
interaction(environment.interaction.InteractWithEnvironment(Seq(
|
||||
new WithEntrance(),
|
||||
new WithWater(avatar.name),
|
||||
new WithLava(),
|
||||
new WithDeath(),
|
||||
|
|
|
|||
|
|
@ -162,18 +162,10 @@ object SpawnPoint {
|
|||
}
|
||||
|
||||
trait SpawnPointDefinition {
|
||||
private var radius: Float = 0f //m
|
||||
private var delay: Long = 0 //s
|
||||
private var noWarp: Option[mutable.Set[VehicleDefinition]] = None
|
||||
private var spawningFunc: (SpawnPoint, PlanetSideGameObject) => (Vector3, Vector3) = SpawnPoint.Default
|
||||
|
||||
def UseRadius: Float = radius
|
||||
|
||||
def UseRadius_=(rad: Float): Float = {
|
||||
radius = rad
|
||||
UseRadius
|
||||
}
|
||||
|
||||
def Delay: Long = delay
|
||||
|
||||
def Delay_=(toDelay: Long): Long = {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects
|
||||
|
||||
import net.psforever.objects.avatar.interaction.WithEntrance
|
||||
import net.psforever.objects.ce.{InteractWithMines, InteractWithTurrets}
|
||||
import net.psforever.objects.definition.{ToolDefinition, VehicleDefinition}
|
||||
import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot, JammableUnit}
|
||||
|
|
@ -12,6 +13,7 @@ import net.psforever.objects.serverobject.aura.AuraContainer
|
|||
import net.psforever.objects.serverobject.deploy.Deployment
|
||||
import net.psforever.objects.serverobject.environment.interaction.common.{WithDeath, WithMovementTrigger}
|
||||
import net.psforever.objects.serverobject.hackable.Hackable
|
||||
import net.psforever.objects.serverobject.interior.{InteriorAwareFromInteraction, Sidedness}
|
||||
import net.psforever.objects.serverobject.structures.AmenityOwner
|
||||
import net.psforever.objects.vehicles._
|
||||
import net.psforever.objects.vehicles.interaction.{WithLava, WithWater}
|
||||
|
|
@ -90,8 +92,10 @@ class Vehicle(private val vehicleDef: VehicleDefinition)
|
|||
with CommonNtuContainer
|
||||
with Container
|
||||
with AuraContainer
|
||||
with MountableEntity {
|
||||
with MountableEntity
|
||||
with InteriorAwareFromInteraction {
|
||||
interaction(environment.interaction.InteractWithEnvironment(Seq(
|
||||
new WithEntrance(),
|
||||
new WithWater(),
|
||||
new WithLava(),
|
||||
new WithDeath(),
|
||||
|
|
@ -513,6 +517,12 @@ class Vehicle(private val vehicleDef: VehicleDefinition)
|
|||
!Definition.CanFly && super.BailProtection_=(protect)
|
||||
}
|
||||
|
||||
override def WhichSide_=(thisSide: Sidedness): Sidedness = {
|
||||
val toSide = super.WhichSide_=(thisSide)
|
||||
(Seats.values ++ CargoHolds.values).flatMap(_.occupants).foreach(_.WhichSide = toSide)
|
||||
toSide
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the definition entry that is used to store and unload pertinent information about the `Vehicle`.
|
||||
* @return the vehicle's definition entry
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.avatar.interaction
|
||||
|
||||
import net.psforever.objects.serverobject.doors.{Door, InteriorDoorPassage}
|
||||
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, PieceOfEnvironment, interaction}
|
||||
import net.psforever.objects.serverobject.environment.interaction.{InteractionWith, RespondsToZoneEnvironment}
|
||||
import net.psforever.objects.serverobject.interior.{Sidedness, TraditionalInteriorAware}
|
||||
import net.psforever.objects.zones.InteractsWithZone
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
import scala.annotation.unused
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class WithEntrance()
|
||||
extends InteractionWith
|
||||
with TraditionalInteriorAware {
|
||||
val attribute: EnvironmentTrait = EnvironmentAttribute.InteriorField
|
||||
|
||||
private var stopTest: Boolean = false
|
||||
|
||||
def doInteractingWith(
|
||||
obj: InteractsWithZone,
|
||||
body: PieceOfEnvironment,
|
||||
data: Option[Any]
|
||||
): Unit = {
|
||||
if (stopTest && data.contains("bellybutton")) {
|
||||
stopTest = false
|
||||
} else {
|
||||
doorInteriorCheck(obj, body.asInstanceOf[InteriorDoorPassage].door)
|
||||
obj.Actor ! RespondsToZoneEnvironment.Timer(attribute, delay = 250.milliseconds, obj.Actor, interaction.InteractingWithEnvironment(body, Some("bellybutton")))
|
||||
}
|
||||
}
|
||||
|
||||
override def stopInteractingWith(
|
||||
obj: InteractsWithZone,
|
||||
body: PieceOfEnvironment,
|
||||
data: Option[Any]
|
||||
): Unit = {
|
||||
straightforwardInteriorCheck(obj, body.asInstanceOf[InteriorDoorPassage].door)
|
||||
stopTest = true
|
||||
}
|
||||
|
||||
private def doorInteriorCheck(
|
||||
obj: InteractsWithZone,
|
||||
door: Door
|
||||
): Sidedness = {
|
||||
val strictly = interiorCheck(obj, door)
|
||||
val value = if (door.isOpen) {
|
||||
Sidedness.InBetweenSides(door, strictly)
|
||||
} else {
|
||||
strictly
|
||||
}
|
||||
WhichSide_=(value)
|
||||
value
|
||||
}
|
||||
|
||||
private def straightforwardInteriorCheck(
|
||||
obj: InteractsWithZone,
|
||||
door: Door
|
||||
): Sidedness = {
|
||||
WhichSide_=(interiorCheck(obj, door))
|
||||
}
|
||||
|
||||
private def interiorCheck(
|
||||
obj: InteractsWithZone,
|
||||
door: Door
|
||||
): Sidedness = {
|
||||
//debugInteriorCheck(obj, door)
|
||||
strictInteriorCheck(obj, door)
|
||||
}
|
||||
|
||||
@unused
|
||||
private def strictInteriorCheck(
|
||||
obj: InteractsWithZone,
|
||||
door: Door
|
||||
): Sidedness = {
|
||||
if (door.Outwards == Vector3.Zero) {
|
||||
WhichSide
|
||||
} else if (Vector3.DotProduct(Vector3.Unit(obj.Position - door.Position), door.Outwards) > 0f) {
|
||||
Sidedness.OutsideOf
|
||||
} else {
|
||||
Sidedness.InsideOf
|
||||
}
|
||||
}
|
||||
|
||||
@unused
|
||||
private def debugInteriorCheck(
|
||||
obj: InteractsWithZone,
|
||||
door: Door
|
||||
): Sidedness = {
|
||||
import net.psforever.objects.{Player, Vehicle}
|
||||
import net.psforever.packet.game.ChatMsg
|
||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
import net.psforever.types.{ChatMessageType, PlanetSideGUID}
|
||||
val channel = obj match {
|
||||
case p: Player => p.Name
|
||||
case v: Vehicle => v.Actor.toString()
|
||||
case _ => ""
|
||||
}
|
||||
if (door.Outwards == Vector3.Zero) {
|
||||
obj.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
channel,
|
||||
AvatarAction.SendResponse(PlanetSideGUID(0), ChatMsg(ChatMessageType.UNK_229, "Door not configured."))
|
||||
)
|
||||
WhichSide
|
||||
} else {
|
||||
val result = Vector3.DotProduct(Vector3.Unit(obj.Position - door.Position), door.Outwards) > 0f
|
||||
if (result && WhichSide != Sidedness.OutsideOf) {
|
||||
//outside
|
||||
obj.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
channel,
|
||||
AvatarAction.SendResponse(PlanetSideGUID(0), ChatMsg(ChatMessageType.UNK_229, "You are now outside"))
|
||||
)
|
||||
Sidedness.OutsideOf
|
||||
} else if (!result && WhichSide != Sidedness.InsideOf) {
|
||||
//inside
|
||||
obj.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
channel,
|
||||
AvatarAction.SendResponse(PlanetSideGUID(0), ChatMsg(ChatMessageType.UNK_229, "You are now inside"))
|
||||
)
|
||||
Sidedness.InsideOf
|
||||
} else {
|
||||
WhichSide
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ class InteractWithRadiationClouds(
|
|||
*/
|
||||
private var skipTargets: List[PlanetSideGUID] = List()
|
||||
|
||||
def Type = RadiationInteraction
|
||||
def Type: ZoneInteractionType = RadiationInteraction
|
||||
|
||||
/**
|
||||
* Wander into a radiation cloud and suffer the consequences.
|
||||
|
|
@ -40,12 +40,16 @@ class InteractWithRadiationClouds(
|
|||
target match {
|
||||
case t: Vitality =>
|
||||
val position = target.Position
|
||||
val targetList = List(target)
|
||||
//collect all projectiles in sector/range
|
||||
val projectiles = sector
|
||||
.projectileList
|
||||
.filter { cloud =>
|
||||
val radius = cloud.Definition.DamageRadius
|
||||
cloud.Definition.radiation_cloud && Zone.distanceCheck(target, cloud, radius * radius)
|
||||
val definition = cloud.Definition
|
||||
val radius = definition.DamageRadius
|
||||
definition.radiation_cloud &&
|
||||
Zone.allOnSameSide(cloud, definition, targetList).nonEmpty &&
|
||||
Zone.distanceCheck(target, cloud, radius * radius)
|
||||
}
|
||||
.distinct
|
||||
val notSkipped = projectiles.filterNot { t => skipTargets.contains(t.GUID) }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.ballistics
|
||||
|
||||
import net.psforever.objects.serverobject.interior.TraditionalInteriorAware
|
||||
import net.psforever.objects.sourcing.SourceEntry
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
|
@ -53,7 +54,8 @@ final case class Projectile(
|
|||
id: Long = Projectile.idGenerator.getAndIncrement(),
|
||||
fire_time: Long = System.currentTimeMillis()
|
||||
) extends PlanetSideGameObject
|
||||
with BlockMapEntity {
|
||||
with BlockMapEntity
|
||||
with TraditionalInteriorAware {
|
||||
Position = shot_origin
|
||||
Orientation = shot_angle
|
||||
Velocity = shot_velocity.getOrElse {
|
||||
|
|
@ -73,7 +75,8 @@ final case class Projectile(
|
|||
* Create a copy of this projectile with all the same information
|
||||
* save for the quality.
|
||||
* Used mainly for aggravated damage.
|
||||
* It is important to note that the new projectile shares the (otherwise) exclusive id of the original.
|
||||
* It is important to note that the new projectile shares the (otherwise) exclusive id of the original
|
||||
* and that it is not added to a block map structure.
|
||||
* @param value the new quality
|
||||
* @return a new `Projectile` entity
|
||||
*/
|
||||
|
|
@ -94,6 +97,7 @@ final case class Projectile(
|
|||
)
|
||||
if(isMiss) projectile.Miss()
|
||||
else if(isResolved) projectile.Resolve()
|
||||
projectile.WhichSide = this.WhichSide
|
||||
projectile
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import net.psforever.objects._
|
|||
import net.psforever.objects.definition.DeployableDefinition
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||
import net.psforever.objects.serverobject.interior.TraditionalInteriorAware
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.objects.vital.resolution.DamageResistanceModel
|
||||
import net.psforever.objects.zones.ZoneAware
|
||||
|
|
@ -18,7 +19,8 @@ trait BaseDeployable
|
|||
with BlockMapEntity
|
||||
with Vitality
|
||||
with OwnableByPlayer
|
||||
with ZoneAware {
|
||||
with ZoneAware
|
||||
with TraditionalInteriorAware {
|
||||
private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
||||
private var shields: Int = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -20,13 +20,23 @@ import net.psforever.types.OxygenState
|
|||
* So long as it is an `ObjectCreatePacket`, those methods can be called correctly for a game object of the desired type.
|
||||
* @param objectId the object's identifier number
|
||||
*/
|
||||
abstract class ObjectDefinition(private val objectId: Int) extends BasicDefinition {
|
||||
abstract class ObjectDefinition(private val objectId: Int)
|
||||
extends BasicDefinition {
|
||||
var registerAs: String = "generic"
|
||||
|
||||
/** a data converter for this type of object */
|
||||
protected var packet: PacketConverter = new ObjectCreateConverter[PlanetSideGameObject]() {}
|
||||
Name = "object_definition"
|
||||
|
||||
private var useRadius: Float = 0f
|
||||
|
||||
def UseRadius: Float = useRadius
|
||||
|
||||
def UseRadius_=(radius: Float): Float = {
|
||||
useRadius = radius
|
||||
UseRadius
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the conversion object.
|
||||
* @return
|
||||
|
|
|
|||
|
|
@ -46,8 +46,6 @@ class ProjectileDefinition(objectId: Int)
|
|||
/** projectile takes the form of a type of "grenade";
|
||||
* grenades arc with gravity rather than travel in a relatively straight path */
|
||||
private var grenade_projectile: Boolean = false
|
||||
/** radiation clouds create independent damage-dealing areas in a zone that last for the projectile's lifespan */
|
||||
var radiation_cloud: Boolean = false
|
||||
//derived calculations
|
||||
/** the calculated distance at which the projectile have traveled far enough to despawn (m);
|
||||
* typically handled as the projectile no longer performing damage;
|
||||
|
|
|
|||
|
|
@ -106,8 +106,24 @@ object GeometryForm {
|
|||
*/
|
||||
def representByCylinder(radius: Float, height: Float)(o: Any): VolumetricGeometry = {
|
||||
o match {
|
||||
case p: PlanetSideGameObject => Cylinder(p.Position, Vector3.relativeUp(p.Orientation), radius, height)
|
||||
case s: SourceEntry => Cylinder(s.Position, Vector3.relativeUp(s.Orientation), radius, height)
|
||||
case p: PlanetSideGameObject => Cylinder(p.Position, Vector3.relativeUp(p.Orientation), radius, math.abs(height))
|
||||
case s: SourceEntry => Cylinder(s.Position, Vector3.relativeUp(s.Orientation), radius, math.abs(height))
|
||||
case _ => invalidCylinder
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The geometric representation is a cylinder
|
||||
* offset with respects to the height of the entity's base.
|
||||
* @param radius half the distance across
|
||||
* @param height how tall the cylinder is (the distance of the top to the base)
|
||||
* @param o the entity
|
||||
* @return the representation
|
||||
*/
|
||||
def representByRaisedCylinder(radius: Float, height: Float)(o: Any): VolumetricGeometry = {
|
||||
o match {
|
||||
case p: PlanetSideGameObject => Cylinder(p.Position + Vector3.z(height * 0.5f), Vector3.relativeUp(p.Orientation), radius, math.abs(height))
|
||||
case s: SourceEntry => Cylinder(s.Position + Vector3.z(height * 0.5f), Vector3.relativeUp(s.Orientation), radius, math.abs(height))
|
||||
case _ => invalidCylinder
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.geometry
|
||||
|
||||
import net.psforever.objects.PlanetSideGameObject
|
||||
import net.psforever.objects.geometry.d2.Rectangle
|
||||
import net.psforever.objects.geometry.d3.VolumetricGeometry
|
||||
import net.psforever.objects.serverobject.environment.EnvironmentCollision
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
final case class VolumetricEnvironmentCollision(g: VolumetricGeometry)
|
||||
extends EnvironmentCollision {
|
||||
private lazy val bound: Rectangle = {
|
||||
Rectangle(
|
||||
g.pointOnOutside(Vector3(0, 1,0)).y,
|
||||
g.pointOnOutside(Vector3(-1,0,0)).x,
|
||||
g.pointOnOutside(Vector3(0,-1,0)).y,
|
||||
g.pointOnOutside(Vector3( 1,0,0)).x
|
||||
)
|
||||
}
|
||||
|
||||
def Geometry: VolumetricGeometry = g
|
||||
|
||||
def altitude: Float = g.pointOnOutside(Vector3(0,0,1)).z
|
||||
|
||||
def testInteraction(obj: PlanetSideGameObject, varDepth: Float): Boolean = {
|
||||
Zone.distanceCheck(obj.Definition.Geometry(obj), g) <= varDepth
|
||||
}
|
||||
|
||||
def bounding: Rectangle = bound
|
||||
}
|
||||
|
|
@ -57,6 +57,16 @@ object Segment {
|
|||
Segment(p, Point(p.x + d.x, p.y + d.y, p.z + d.z))
|
||||
}
|
||||
|
||||
/**
|
||||
* An overloaded constructor that uses individual coordinates.
|
||||
* @param a origin
|
||||
* @param b destination
|
||||
* @return a `Segment` entity
|
||||
*/
|
||||
def apply(a: Vector3, b: Vector3): Segment = {
|
||||
Segment(Point(a), Point(b))
|
||||
}
|
||||
|
||||
/**
|
||||
* An overloaded constructor that uses individual coordinates.
|
||||
* @param x the 'x' coordinate of the position
|
||||
|
|
|
|||
|
|
@ -0,0 +1,330 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.global
|
||||
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
import net.psforever.objects.equipment.EquipmentSize
|
||||
import net.psforever.objects.inventory.InventoryTile
|
||||
|
||||
object GlobalDefinitionsAmmo {
|
||||
import GlobalDefinitions._
|
||||
|
||||
/**
|
||||
* Initialize `AmmoBoxDefinition` globals.
|
||||
*/
|
||||
final def init(): Unit = {
|
||||
melee_ammo.Name = "melee_ammo"
|
||||
melee_ammo.Size = EquipmentSize.Blocked
|
||||
|
||||
frag_grenade_ammo.Name = "frag_grenade_ammo"
|
||||
frag_grenade_ammo.Size = EquipmentSize.Blocked
|
||||
|
||||
jammer_grenade_ammo.Name = "jammer_grenade_ammo"
|
||||
jammer_grenade_ammo.Size = EquipmentSize.Blocked
|
||||
|
||||
plasma_grenade_ammo.Name = "plasma_grenade_ammo"
|
||||
plasma_grenade_ammo.Size = EquipmentSize.Blocked
|
||||
|
||||
bullet_9mm.Name = "9mmbullet"
|
||||
bullet_9mm.Capacity = 50
|
||||
bullet_9mm.Tile = InventoryTile.Tile33
|
||||
|
||||
bullet_9mm_AP.Name = "9mmbullet_AP"
|
||||
bullet_9mm_AP.Capacity = 50
|
||||
bullet_9mm_AP.Tile = InventoryTile.Tile33
|
||||
|
||||
shotgun_shell.Name = "shotgun_shell"
|
||||
shotgun_shell.Capacity = 16
|
||||
shotgun_shell.Tile = InventoryTile.Tile33
|
||||
|
||||
shotgun_shell_AP.Name = "shotgun_shell_AP"
|
||||
shotgun_shell_AP.Capacity = 16
|
||||
shotgun_shell_AP.Tile = InventoryTile.Tile33
|
||||
|
||||
energy_cell.Name = "energy_cell"
|
||||
energy_cell.Capacity = 50
|
||||
energy_cell.Tile = InventoryTile.Tile33
|
||||
|
||||
anniversary_ammo.Name = "anniversary_ammo"
|
||||
anniversary_ammo.Capacity = 30
|
||||
anniversary_ammo.Tile = InventoryTile.Tile33
|
||||
|
||||
ancient_ammo_combo.Name = "ancient_ammo_combo"
|
||||
ancient_ammo_combo.Capacity = 30
|
||||
ancient_ammo_combo.Tile = InventoryTile.Tile33
|
||||
|
||||
maelstrom_ammo.Name = "maelstrom_ammo"
|
||||
maelstrom_ammo.Capacity = 50
|
||||
maelstrom_ammo.Tile = InventoryTile.Tile33
|
||||
|
||||
phoenix_missile.Name = "phoenix_missile"
|
||||
phoenix_missile.Size = EquipmentSize.Blocked
|
||||
|
||||
striker_missile_ammo.Name = "striker_missile_ammo"
|
||||
striker_missile_ammo.Capacity = 15
|
||||
striker_missile_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
hunter_seeker_missile.Name = "hunter_seeker_missile"
|
||||
hunter_seeker_missile.Capacity = 9
|
||||
hunter_seeker_missile.Tile = InventoryTile.Tile44
|
||||
|
||||
lancer_cartridge.Name = "lancer_cartridge"
|
||||
lancer_cartridge.Capacity = 18
|
||||
lancer_cartridge.Tile = InventoryTile.Tile44
|
||||
|
||||
rocket.Name = "rocket"
|
||||
rocket.Capacity = 15
|
||||
rocket.Tile = InventoryTile.Tile33
|
||||
|
||||
frag_cartridge.Name = "frag_cartridge"
|
||||
frag_cartridge.Capacity = 12
|
||||
frag_cartridge.Tile = InventoryTile.Tile33
|
||||
|
||||
plasma_cartridge.Name = "plasma_cartridge"
|
||||
plasma_cartridge.Capacity = 12
|
||||
plasma_cartridge.Tile = InventoryTile.Tile33
|
||||
|
||||
jammer_cartridge.Name = "jammer_cartridge"
|
||||
jammer_cartridge.Capacity = 12
|
||||
jammer_cartridge.Tile = InventoryTile.Tile33
|
||||
|
||||
bolt.Name = "bolt"
|
||||
bolt.Capacity = 10
|
||||
bolt.Tile = InventoryTile.Tile33
|
||||
|
||||
oicw_ammo.Name = "oicw_ammo"
|
||||
oicw_ammo.Capacity = 10
|
||||
oicw_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
flamethrower_ammo.Name = "flamethrower_ammo"
|
||||
flamethrower_ammo.Capacity = 100
|
||||
flamethrower_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
winchester_ammo.Name = "winchester_ammo"
|
||||
winchester_ammo.Capacity = 10
|
||||
winchester_ammo.Tile = InventoryTile.Tile33
|
||||
|
||||
pellet_gun_ammo.Name = "pellet_gun_ammo"
|
||||
pellet_gun_ammo.Capacity = 8
|
||||
pellet_gun_ammo.Tile = InventoryTile.Tile33
|
||||
|
||||
six_shooter_ammo.Name = "six_shooter_ammo"
|
||||
six_shooter_ammo.Capacity = 12
|
||||
six_shooter_ammo.Tile = InventoryTile.Tile33
|
||||
|
||||
dualcycler_ammo.Name = "dualcycler_ammo"
|
||||
dualcycler_ammo.Capacity = 100
|
||||
dualcycler_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
pounder_ammo.Name = "pounder_ammo"
|
||||
pounder_ammo.Capacity = 50
|
||||
pounder_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
burster_ammo.Name = "burster_ammo"
|
||||
burster_ammo.Capacity = 100
|
||||
burster_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
scattercannon_ammo.Name = "scattercannon_ammo"
|
||||
scattercannon_ammo.Capacity = 50
|
||||
scattercannon_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
falcon_ammo.Name = "falcon_ammo"
|
||||
falcon_ammo.Capacity = 50
|
||||
falcon_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
sparrow_ammo.Name = "sparrow_ammo"
|
||||
sparrow_ammo.Capacity = 50
|
||||
sparrow_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
quasar_ammo.Name = "quasar_ammo"
|
||||
quasar_ammo.Capacity = 60
|
||||
quasar_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
comet_ammo.Name = "comet_ammo"
|
||||
comet_ammo.Capacity = 50
|
||||
comet_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
starfire_ammo.Name = "starfire_ammo"
|
||||
starfire_ammo.Capacity = 50
|
||||
starfire_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
health_canister.Name = "health_canister"
|
||||
health_canister.Capacity = 100
|
||||
health_canister.Tile = InventoryTile.Tile23
|
||||
|
||||
armor_canister.Name = "armor_canister"
|
||||
armor_canister.Capacity = 100
|
||||
armor_canister.repairAmount = 12f //ADB says 12.5, but 12 is better for the math
|
||||
armor_canister.Tile = InventoryTile.Tile23
|
||||
|
||||
upgrade_canister.Name = "upgrade_canister"
|
||||
upgrade_canister.Capacity = 1
|
||||
upgrade_canister.Tile = InventoryTile.Tile23
|
||||
|
||||
trek_ammo.Name = "trek_ammo"
|
||||
trek_ammo.Size = EquipmentSize.Blocked
|
||||
|
||||
bullet_35mm.Name = "35mmbullet"
|
||||
bullet_35mm.Capacity = 100
|
||||
bullet_35mm.Tile = InventoryTile.Tile44
|
||||
|
||||
aphelion_laser_ammo.Name = "aphelion_laser_ammo"
|
||||
aphelion_laser_ammo.Capacity = 165
|
||||
aphelion_laser_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
aphelion_immolation_cannon_ammo.Name = "aphelion_immolation_cannon_ammo"
|
||||
aphelion_immolation_cannon_ammo.Capacity = 100
|
||||
aphelion_immolation_cannon_ammo.Tile = InventoryTile.Tile55
|
||||
|
||||
aphelion_plasma_rocket_ammo.Name = "aphelion_plasma_rocket_ammo"
|
||||
aphelion_plasma_rocket_ammo.Capacity = 195
|
||||
aphelion_plasma_rocket_ammo.Tile = InventoryTile.Tile55
|
||||
|
||||
aphelion_ppa_ammo.Name = "aphelion_ppa_ammo"
|
||||
aphelion_ppa_ammo.Capacity = 110
|
||||
aphelion_ppa_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
aphelion_starfire_ammo.Name = "aphelion_starfire_ammo"
|
||||
aphelion_starfire_ammo.Capacity = 132
|
||||
aphelion_starfire_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
skyguard_flak_cannon_ammo.Name = "skyguard_flak_cannon_ammo"
|
||||
skyguard_flak_cannon_ammo.Capacity = 200
|
||||
skyguard_flak_cannon_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
firebird_missile.Name = "firebird_missile"
|
||||
firebird_missile.Capacity = 50
|
||||
firebird_missile.Tile = InventoryTile.Tile44
|
||||
|
||||
flux_cannon_thresher_battery.Name = "flux_cannon_thresher_battery"
|
||||
flux_cannon_thresher_battery.Capacity = 150
|
||||
flux_cannon_thresher_battery.Tile = InventoryTile.Tile44
|
||||
|
||||
fluxpod_ammo.Name = "fluxpod_ammo"
|
||||
fluxpod_ammo.Capacity = 80
|
||||
fluxpod_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
hellfire_ammo.Name = "hellfire_ammo"
|
||||
hellfire_ammo.Capacity = 24
|
||||
hellfire_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
liberator_bomb.Name = "liberator_bomb"
|
||||
liberator_bomb.Capacity = 20
|
||||
liberator_bomb.Tile = InventoryTile.Tile44
|
||||
|
||||
bullet_25mm.Name = "25mmbullet"
|
||||
bullet_25mm.Capacity = 150
|
||||
bullet_25mm.Tile = InventoryTile.Tile44
|
||||
|
||||
bullet_75mm.Name = "75mmbullet"
|
||||
bullet_75mm.Capacity = 100
|
||||
bullet_75mm.Tile = InventoryTile.Tile44
|
||||
|
||||
heavy_grenade_mortar.Name = "heavy_grenade_mortar"
|
||||
heavy_grenade_mortar.Capacity = 100
|
||||
heavy_grenade_mortar.Tile = InventoryTile.Tile44
|
||||
|
||||
pulse_battery.Name = "pulse_battery"
|
||||
pulse_battery.Capacity = 100
|
||||
pulse_battery.Tile = InventoryTile.Tile44
|
||||
|
||||
heavy_rail_beam_battery.Name = "heavy_rail_beam_battery"
|
||||
heavy_rail_beam_battery.Capacity = 100
|
||||
heavy_rail_beam_battery.Tile = InventoryTile.Tile44
|
||||
|
||||
reaver_rocket.Name = "reaver_rocket"
|
||||
reaver_rocket.Capacity = 12
|
||||
reaver_rocket.Tile = InventoryTile.Tile44
|
||||
|
||||
bullet_20mm.Name = "20mmbullet"
|
||||
bullet_20mm.Capacity = 200
|
||||
bullet_20mm.Tile = InventoryTile.Tile44
|
||||
|
||||
bullet_12mm.Name = "12mmbullet"
|
||||
bullet_12mm.Capacity = 300
|
||||
bullet_12mm.Tile = InventoryTile.Tile44
|
||||
|
||||
wasp_rocket_ammo.Name = "wasp_rocket_ammo"
|
||||
wasp_rocket_ammo.Capacity = 6
|
||||
wasp_rocket_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
wasp_gun_ammo.Name = "wasp_gun_ammo"
|
||||
wasp_gun_ammo.Capacity = 150
|
||||
wasp_gun_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
bullet_15mm.Name = "15mmbullet"
|
||||
bullet_15mm.Capacity = 360
|
||||
bullet_15mm.Tile = InventoryTile.Tile44
|
||||
|
||||
colossus_100mm_cannon_ammo.Name = "colossus_100mm_cannon_ammo"
|
||||
colossus_100mm_cannon_ammo.Capacity = 90
|
||||
colossus_100mm_cannon_ammo.Tile = InventoryTile.Tile55
|
||||
|
||||
colossus_burster_ammo.Name = "colossus_burster_ammo"
|
||||
colossus_burster_ammo.Capacity = 235
|
||||
colossus_burster_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
colossus_cluster_bomb_ammo.Name = "colossus_cluster_bomb_ammo"
|
||||
colossus_cluster_bomb_ammo.Capacity = 150
|
||||
colossus_cluster_bomb_ammo.Tile = InventoryTile.Tile55
|
||||
|
||||
colossus_chaingun_ammo.Name = "colossus_chaingun_ammo"
|
||||
colossus_chaingun_ammo.Capacity = 600
|
||||
colossus_chaingun_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
colossus_tank_cannon_ammo.Name = "colossus_tank_cannon_ammo"
|
||||
colossus_tank_cannon_ammo.Capacity = 110
|
||||
colossus_tank_cannon_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
bullet_105mm.Name = "105mmbullet"
|
||||
bullet_105mm.Capacity = 100
|
||||
bullet_105mm.Tile = InventoryTile.Tile44
|
||||
|
||||
gauss_cannon_ammo.Name = "gauss_cannon_ammo"
|
||||
gauss_cannon_ammo.Capacity = 15
|
||||
gauss_cannon_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
peregrine_dual_machine_gun_ammo.Name = "peregrine_dual_machine_gun_ammo"
|
||||
peregrine_dual_machine_gun_ammo.Capacity = 240
|
||||
peregrine_dual_machine_gun_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
peregrine_mechhammer_ammo.Name = "peregrine_mechhammer_ammo"
|
||||
peregrine_mechhammer_ammo.Capacity = 30
|
||||
peregrine_mechhammer_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
peregrine_particle_cannon_ammo.Name = "peregrine_particle_cannon_ammo"
|
||||
peregrine_particle_cannon_ammo.Capacity = 40
|
||||
peregrine_particle_cannon_ammo.Tile = InventoryTile.Tile55
|
||||
|
||||
peregrine_rocket_pod_ammo.Name = "peregrine_rocket_pod_ammo"
|
||||
peregrine_rocket_pod_ammo.Capacity = 275
|
||||
peregrine_rocket_pod_ammo.Tile = InventoryTile.Tile55
|
||||
|
||||
peregrine_sparrow_ammo.Name = "peregrine_sparrow_ammo"
|
||||
peregrine_sparrow_ammo.Capacity = 150
|
||||
peregrine_sparrow_ammo.Tile = InventoryTile.Tile44
|
||||
|
||||
bullet_150mm.Name = "150mmbullet"
|
||||
bullet_150mm.Capacity = 50
|
||||
bullet_150mm.Tile = InventoryTile.Tile44
|
||||
|
||||
phalanx_ammo.Name = "phalanx_ammo"
|
||||
phalanx_ammo.Size = EquipmentSize.Inventory
|
||||
|
||||
spitfire_ammo.Name = "spitfire_ammo"
|
||||
spitfire_ammo.Size = EquipmentSize.Inventory
|
||||
|
||||
spitfire_aa_ammo.Name = "spitfire_aa_ammo"
|
||||
spitfire_aa_ammo.Size = EquipmentSize.Inventory
|
||||
|
||||
energy_gun_ammo.Name = "energy_gun_ammo"
|
||||
energy_gun_ammo.Size = EquipmentSize.Inventory
|
||||
|
||||
armor_siphon_ammo.Name = "armor_siphon_ammo"
|
||||
armor_siphon_ammo.Capacity = 0
|
||||
armor_siphon_ammo.Size = EquipmentSize.Blocked
|
||||
|
||||
ntu_siphon_ammo.Name = "ntu_siphon_ammo"
|
||||
ntu_siphon_ammo.Capacity = 0
|
||||
ntu_siphon_ammo.Size = EquipmentSize.Blocked
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.global
|
||||
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
import net.psforever.objects.SpawnPoint
|
||||
import net.psforever.types.LatticeBenefit
|
||||
|
||||
object GlobalDefinitionsBuilding {
|
||||
import GlobalDefinitions._
|
||||
|
||||
/**
|
||||
* Initialize `BuildingDefinition` globals.
|
||||
*/
|
||||
def init(): Unit = {
|
||||
amp_station.Name = "amp_station"
|
||||
amp_station.SOIRadius = 300
|
||||
amp_station.LatticeLinkBenefit = LatticeBenefit.AmpStation
|
||||
|
||||
comm_station.Name = "comm_station"
|
||||
comm_station.SOIRadius = 300
|
||||
comm_station.LatticeLinkBenefit = LatticeBenefit.InterlinkFacility
|
||||
|
||||
comm_station_dsp.Name = "comm_station_dsp"
|
||||
comm_station_dsp.SOIRadius = 300
|
||||
comm_station_dsp.LatticeLinkBenefit = LatticeBenefit.DropshipCenter
|
||||
|
||||
cryo_facility.Name = "cryo_facility"
|
||||
cryo_facility.SOIRadius = 300
|
||||
cryo_facility.LatticeLinkBenefit = LatticeBenefit.BioLaboratory
|
||||
|
||||
tech_plant.Name = "tech_plant"
|
||||
tech_plant.SOIRadius = 300
|
||||
tech_plant.LatticeLinkBenefit = LatticeBenefit.TechnologyPlant
|
||||
|
||||
building.Name = "building"
|
||||
|
||||
vanu_core.Name = "vanu_core"
|
||||
|
||||
ground_bldg_a.Name = "ground_bldg_a"
|
||||
|
||||
ground_bldg_b.Name = "ground_bldg_b"
|
||||
|
||||
ground_bldg_c.Name = "ground_bldg_c"
|
||||
|
||||
ground_bldg_d.Name = "ground_bldg_d"
|
||||
|
||||
ground_bldg_e.Name = "ground_bldg_e"
|
||||
|
||||
ground_bldg_f.Name = "ground_bldg_f"
|
||||
|
||||
ground_bldg_g.Name = "ground_bldg_g"
|
||||
|
||||
ground_bldg_h.Name = "ground_bldg_h"
|
||||
|
||||
ground_bldg_i.Name = "ground_bldg_i"
|
||||
|
||||
ground_bldg_j.Name = "ground_bldg_j"
|
||||
|
||||
ground_bldg_z.Name = "ground_bldg_z"
|
||||
|
||||
ceiling_bldg_a.Name = "ceiling_bldg_a"
|
||||
|
||||
ceiling_bldg_b.Name = "ceiling_bldg_b"
|
||||
|
||||
ceiling_bldg_c.Name = "ceiling_bldg_c"
|
||||
|
||||
ceiling_bldg_d.Name = "ceiling_bldg_d"
|
||||
|
||||
ceiling_bldg_e.Name = "ceiling_bldg_e"
|
||||
|
||||
ceiling_bldg_f.Name = "ceiling_bldg_f"
|
||||
|
||||
ceiling_bldg_g.Name = "ceiling_bldg_g"
|
||||
|
||||
ceiling_bldg_h.Name = "ceiling_bldg_h"
|
||||
|
||||
ceiling_bldg_i.Name = "ceiling_bldg_i"
|
||||
|
||||
ceiling_bldg_j.Name = "ceiling_bldg_j"
|
||||
|
||||
ceiling_bldg_z.Name = "ceiling_bldg_z"
|
||||
|
||||
mainbase1.Name = "mainbase1"
|
||||
|
||||
mainbase2.Name = "mainbase2"
|
||||
|
||||
mainbase3.Name = "mainbase3"
|
||||
|
||||
meeting_center_nc.Name = "meeting_center_nc"
|
||||
|
||||
meeting_center_tr.Name = "meeting_center_tr"
|
||||
|
||||
meeting_center_vs.Name = "meeting_center_vs"
|
||||
|
||||
minibase1.Name = "minibase1"
|
||||
|
||||
minibase2.Name = "minibase2"
|
||||
|
||||
minibase3.Name = "minibase3"
|
||||
|
||||
redoubt.Name = "redoubt"
|
||||
redoubt.SOIRadius = 187
|
||||
|
||||
tower_a.Name = "tower_a"
|
||||
tower_a.SOIRadius = 50
|
||||
|
||||
tower_b.Name = "tower_b"
|
||||
tower_b.SOIRadius = 50
|
||||
|
||||
tower_c.Name = "tower_c"
|
||||
tower_c.SOIRadius = 50
|
||||
|
||||
vanu_control_point.Name = "vanu_control_point"
|
||||
vanu_control_point.SOIRadius = 187
|
||||
|
||||
vanu_vehicle_station.Name = "vanu_vehicle_station"
|
||||
vanu_vehicle_station.SOIRadius = 187
|
||||
|
||||
hst.Name = "hst"
|
||||
hst.UseRadius = 44.96882005f
|
||||
hst.SOIRadius = 82
|
||||
hst.VehicleAllowance = true
|
||||
hst.NoWarp += dropship
|
||||
hst.NoWarp += galaxy_gunship
|
||||
hst.NoWarp += lodestar
|
||||
hst.NoWarp += aphelion_gunner
|
||||
hst.NoWarp += aphelion_flight
|
||||
hst.NoWarp += colossus_gunner
|
||||
hst.NoWarp += colossus_flight
|
||||
hst.NoWarp += peregrine_gunner
|
||||
hst.NoWarp += peregrine_flight
|
||||
hst.SpecificPointFunc = SpawnPoint.CavernGate(innerRadius = 6f)
|
||||
|
||||
warpgate.Name = "warpgate"
|
||||
warpgate.UseRadius = 67.81070029f
|
||||
warpgate.SOIRadius = 302 //301.8713f
|
||||
warpgate.VehicleAllowance = true
|
||||
warpgate.SpecificPointFunc = SpawnPoint.Gate
|
||||
|
||||
warpgate_cavern.Name = "warpgate_cavern"
|
||||
warpgate_cavern.UseRadius = 19.72639434f
|
||||
warpgate_cavern.SOIRadius = 41
|
||||
warpgate_cavern.VehicleAllowance = true
|
||||
warpgate_cavern.SpecificPointFunc = SpawnPoint.CavernGate(innerRadius = 4.5f)
|
||||
|
||||
warpgate_small.Name = "warpgate_small"
|
||||
warpgate_small.UseRadius = 69.03687655f
|
||||
warpgate_small.SOIRadius = 103
|
||||
warpgate_small.VehicleAllowance = true
|
||||
warpgate_small.SpecificPointFunc = SpawnPoint.SmallGate(innerRadius = 27.60654127f, flightlessZOffset = 0.5f)
|
||||
|
||||
bunker_gauntlet.Name = "bunker_gauntlet"
|
||||
|
||||
bunker_lg.Name = "bunker_lg"
|
||||
|
||||
bunker_sm.Name = "bunker_sm"
|
||||
|
||||
orbital_building_nc.Name = "orbital_building_nc"
|
||||
|
||||
orbital_building_tr.Name = "orbital_building_tr"
|
||||
|
||||
orbital_building_vs.Name = "orbital_building_vs"
|
||||
|
||||
VT_building_nc.Name = "VT_building_nc"
|
||||
|
||||
VT_building_tr.Name = "VT_building_tr"
|
||||
|
||||
VT_building_vs.Name = "VT_building_vs"
|
||||
|
||||
vt_dropship.Name = "vt_dropship"
|
||||
|
||||
vt_spawn.Name = "vt_spawn"
|
||||
|
||||
vt_vehicle.Name = "vt_vehicle"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,461 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.global
|
||||
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
import net.psforever.objects.ce.DeployableCategory
|
||||
import net.psforever.objects.definition.DeployAnimation
|
||||
import net.psforever.objects.definition.converter.{FieldTurretConverter, InternalTelepadDeployableConverter, TelepadDeployableConverter}
|
||||
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.mount.{MountInfo, SeatDefinition}
|
||||
import net.psforever.objects.serverobject.turret.{AutoChecks, AutoCooldowns, AutoRanges, Automation, TurretUpgrade}
|
||||
import net.psforever.objects.vital.{CollisionXYData, CollisionZData, ComplexDeployableResolutions, SimpleResolutions}
|
||||
import net.psforever.objects.vital.base.DamageType
|
||||
import net.psforever.objects.vital.collision.TrapCollisionDamageMultiplier
|
||||
import net.psforever.objects.vital.etc.ExplodingRadialDegrade
|
||||
import net.psforever.objects.vital.prop.DamageWithPosition
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.duration._
|
||||
|
||||
object GlobalDefinitionsDeployable {
|
||||
import GlobalDefinitions._
|
||||
|
||||
/**
|
||||
* Initialize `Deployable` globals.
|
||||
*/
|
||||
def init(): Unit = {
|
||||
val mine: Any => VolumetricGeometry = GeometryForm.representByCylinder(radius = 0.1914f, height = 0.0957f)
|
||||
val smallTurret: Any => VolumetricGeometry = GeometryForm.representByCylinder(radius = 0.48435f, height = 1.23438f)
|
||||
val sensor: Any => VolumetricGeometry = GeometryForm.representByCylinder(radius = 0.1914f, height = 1.21875f)
|
||||
val largeTurret: Any => VolumetricGeometry = GeometryForm.representByCylinder(radius = 0.8437f, height = 2.29687f)
|
||||
|
||||
boomer.Name = "boomer"
|
||||
boomer.Descriptor = "Boomers"
|
||||
boomer.MaxHealth = 100
|
||||
boomer.Damageable = true
|
||||
boomer.DamageableByFriendlyFire = false
|
||||
boomer.Repairable = false
|
||||
boomer.DeployCategory = DeployableCategory.Boomers
|
||||
boomer.DeployTime = Duration.create(1000, "ms")
|
||||
boomer.deployAnimation = DeployAnimation.Standard
|
||||
boomer.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.Splash
|
||||
SympatheticExplosion = true
|
||||
Damage0 = 250
|
||||
Damage1 = 750
|
||||
Damage2 = 400
|
||||
Damage3 = 400
|
||||
Damage4 = 1850
|
||||
DamageRadius = 5.1f
|
||||
DamageAtEdge = 0.1f
|
||||
Modifiers = ExplodingRadialDegrade
|
||||
}
|
||||
boomer.Geometry = mine
|
||||
|
||||
he_mine.Name = "he_mine"
|
||||
he_mine.Descriptor = "Mines"
|
||||
he_mine.MaxHealth = 100
|
||||
he_mine.Damageable = true
|
||||
he_mine.DamageableByFriendlyFire = false
|
||||
he_mine.Repairable = false
|
||||
he_mine.DeployTime = Duration.create(1000, "ms")
|
||||
he_mine.deployAnimation = DeployAnimation.Standard
|
||||
he_mine.triggerRadius = 3f
|
||||
he_mine.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.Splash
|
||||
SympatheticExplosion = true
|
||||
Damage0 = 100
|
||||
Damage1 = 750
|
||||
Damage2 = 400
|
||||
Damage3 = 565
|
||||
Damage4 = 1600
|
||||
DamageRadius = 6.6f
|
||||
DamageAtEdge = 0.25f
|
||||
Modifiers = ExplodingRadialDegrade
|
||||
}
|
||||
he_mine.Geometry = mine
|
||||
|
||||
jammer_mine.Name = "jammer_mine"
|
||||
jammer_mine.Descriptor = "JammerMines"
|
||||
jammer_mine.MaxHealth = 100
|
||||
jammer_mine.Damageable = true
|
||||
jammer_mine.DamageableByFriendlyFire = false
|
||||
jammer_mine.Repairable = false
|
||||
jammer_mine.DeployTime = Duration.create(1000, "ms")
|
||||
jammer_mine.deployAnimation = DeployAnimation.Standard
|
||||
jammer_mine.DetonateOnJamming = false
|
||||
jammer_mine.triggerRadius = 3f
|
||||
jammer_mine.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.Splash
|
||||
Damage0 = 0
|
||||
DamageRadius = 10f
|
||||
DamageAtEdge = 1.0f
|
||||
AdditionalEffect = true
|
||||
JammedEffectDuration += TargetValidation(
|
||||
EffectTarget.Category.Player,
|
||||
EffectTarget.Validation.Player
|
||||
) -> 1000
|
||||
JammedEffectDuration += TargetValidation(
|
||||
EffectTarget.Category.Vehicle,
|
||||
EffectTarget.Validation.AMS
|
||||
) -> 5000
|
||||
JammedEffectDuration += TargetValidation(
|
||||
EffectTarget.Category.Deployable,
|
||||
EffectTarget.Validation.MotionSensor
|
||||
) -> 30000
|
||||
JammedEffectDuration += TargetValidation(
|
||||
EffectTarget.Category.Deployable,
|
||||
EffectTarget.Validation.Spitfire
|
||||
) -> 30000
|
||||
JammedEffectDuration += TargetValidation(
|
||||
EffectTarget.Category.Turret,
|
||||
EffectTarget.Validation.Turret
|
||||
) -> 30000
|
||||
JammedEffectDuration += TargetValidation(
|
||||
EffectTarget.Category.Vehicle,
|
||||
EffectTarget.Validation.VehicleNotAMS
|
||||
) -> 10000
|
||||
}
|
||||
jammer_mine.Geometry = mine
|
||||
|
||||
spitfire_turret.Name = "spitfire_turret"
|
||||
spitfire_turret.Descriptor = "Spitfires"
|
||||
spitfire_turret.MaxHealth = 100
|
||||
spitfire_turret.Damageable = true
|
||||
spitfire_turret.Repairable = true
|
||||
spitfire_turret.RepairIfDestroyed = false
|
||||
spitfire_turret.WeaponPaths += 1 -> new mutable.HashMap()
|
||||
spitfire_turret.WeaponPaths(1) += TurretUpgrade.None -> spitfire_weapon
|
||||
spitfire_turret.ReserveAmmunition = false
|
||||
spitfire_turret.DeployCategory = DeployableCategory.SmallTurrets
|
||||
spitfire_turret.DeployTime = Duration.create(5000, "ms")
|
||||
spitfire_turret.Model = ComplexDeployableResolutions.calculate
|
||||
spitfire_turret.deployAnimation = DeployAnimation.Standard
|
||||
spitfire_turret.AutoFire = Automation(
|
||||
AutoRanges(
|
||||
detection = 75f,
|
||||
trigger = 50f,
|
||||
escape = 50f
|
||||
),
|
||||
AutoChecks(
|
||||
validation = List(
|
||||
EffectTarget.Validation.SmallRoboticsTurretValidatePlayerTarget,
|
||||
EffectTarget.Validation.SmallRoboticsTurretValidateMaxTarget,
|
||||
EffectTarget.Validation.SmallRoboticsTurretValidateGroundVehicleTarget,
|
||||
EffectTarget.Validation.SmallRoboticsTurretValidateAircraftTarget,
|
||||
EffectTarget.Validation.AutoTurretValidateMountableEntityTarget
|
||||
)
|
||||
),
|
||||
retaliatoryDelay = 2000L, //8000L
|
||||
refireTime = 200.milliseconds //150.milliseconds
|
||||
)
|
||||
spitfire_turret.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 200
|
||||
Damage1 = 300
|
||||
DamageRadius = 8
|
||||
DamageAtEdge = 0.2f
|
||||
Modifiers = ExplodingRadialDegrade
|
||||
}
|
||||
spitfire_turret.Geometry = smallTurret
|
||||
spitfire_turret.collision.xy = CollisionXYData(Array((0.01f, 10), (0.02f, 40), (0.03f, 60), (0.04f, 80), (0.05f, 100)))
|
||||
spitfire_turret.collision.z = CollisionZData(Array((4f, 10), (4.25f, 40), (4.5f, 60), (4.75f, 80), (5f, 100)))
|
||||
spitfire_turret.mass = 5f
|
||||
|
||||
spitfire_cloaked.Name = "spitfire_cloaked"
|
||||
spitfire_cloaked.Descriptor = "CloakingSpitfires"
|
||||
spitfire_cloaked.MaxHealth = 100
|
||||
spitfire_cloaked.Damageable = true
|
||||
spitfire_cloaked.Repairable = true
|
||||
spitfire_cloaked.RepairIfDestroyed = false
|
||||
spitfire_cloaked.WeaponPaths += 1 -> new mutable.HashMap()
|
||||
spitfire_cloaked.WeaponPaths(1) += TurretUpgrade.None -> spitfire_weapon
|
||||
spitfire_cloaked.ReserveAmmunition = false
|
||||
spitfire_cloaked.DeployCategory = DeployableCategory.SmallTurrets
|
||||
spitfire_cloaked.DeployTime = Duration.create(5000, "ms")
|
||||
spitfire_cloaked.deployAnimation = DeployAnimation.Standard
|
||||
spitfire_cloaked.Model = ComplexDeployableResolutions.calculate
|
||||
spitfire_cloaked.AutoFire = Automation(
|
||||
AutoRanges(
|
||||
detection = 75f,
|
||||
trigger = 50f,
|
||||
escape = 75f
|
||||
),
|
||||
AutoChecks(
|
||||
validation = List(
|
||||
EffectTarget.Validation.SmallRoboticsTurretValidatePlayerTarget,
|
||||
EffectTarget.Validation.SmallRoboticsTurretValidateMaxTarget,
|
||||
EffectTarget.Validation.SmallRoboticsTurretValidateGroundVehicleTarget,
|
||||
EffectTarget.Validation.SmallRoboticsTurretValidateAircraftTarget,
|
||||
EffectTarget.Validation.AutoTurretValidateMountableEntityTarget
|
||||
)
|
||||
),
|
||||
cooldowns = AutoCooldowns(
|
||||
targetSelect = 0L,
|
||||
missedShot = 0L
|
||||
),
|
||||
detectionSweepTime = 500.milliseconds,
|
||||
retaliatoryDelay = 1L, //8000L
|
||||
retaliationOverridesTarget = false,
|
||||
refireTime = 200.milliseconds //150.milliseconds
|
||||
)
|
||||
spitfire_cloaked.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 50
|
||||
Damage1 = 75
|
||||
DamageRadius = 8
|
||||
DamageAtEdge = 0.2f
|
||||
Modifiers = ExplodingRadialDegrade
|
||||
}
|
||||
spitfire_cloaked.Geometry = smallTurret
|
||||
spitfire_cloaked.collision.xy = CollisionXYData(Array((0.01f, 10), (0.02f, 40), (0.03f, 60), (0.04f, 80), (0.05f, 100)))
|
||||
spitfire_cloaked.collision.z = CollisionZData(Array((4f, 10), (4.25f, 40), (4.5f, 60), (4.75f, 80), (5f, 100)))
|
||||
spitfire_cloaked.mass = 5f
|
||||
|
||||
spitfire_aa.Name = "spitfire_aa"
|
||||
spitfire_aa.Descriptor = "FlakSpitfires"
|
||||
spitfire_aa.MaxHealth = 100
|
||||
spitfire_aa.Damageable = true
|
||||
spitfire_aa.Repairable = true
|
||||
spitfire_aa.RepairIfDestroyed = false
|
||||
spitfire_aa.WeaponPaths += 1 -> new mutable.HashMap()
|
||||
spitfire_aa.WeaponPaths(1) += TurretUpgrade.None -> spitfire_aa_weapon
|
||||
spitfire_aa.ReserveAmmunition = false
|
||||
spitfire_aa.DeployCategory = DeployableCategory.SmallTurrets
|
||||
spitfire_aa.DeployTime = Duration.create(5000, "ms")
|
||||
spitfire_aa.deployAnimation = DeployAnimation.Standard
|
||||
spitfire_aa.Model = ComplexDeployableResolutions.calculate
|
||||
spitfire_aa.AutoFire = Automation(
|
||||
AutoRanges(
|
||||
detection = 125f,
|
||||
trigger = 100f,
|
||||
escape = 200f
|
||||
),
|
||||
AutoChecks(
|
||||
validation = List(EffectTarget.Validation.SmallRoboticsTurretValidateAircraftTarget)
|
||||
),
|
||||
retaliatoryDelay = 2000L, //8000L
|
||||
retaliationOverridesTarget = false,
|
||||
refireTime = 0.seconds, //300.milliseconds
|
||||
cylindrical = true,
|
||||
cylindricalExtraHeight = 50f
|
||||
)
|
||||
spitfire_aa.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 200
|
||||
Damage1 = 300
|
||||
DamageRadius = 8
|
||||
DamageAtEdge = 0.2f
|
||||
Modifiers = ExplodingRadialDegrade
|
||||
}
|
||||
spitfire_aa.Geometry = smallTurret
|
||||
spitfire_aa.collision.xy = CollisionXYData(Array((0.01f, 10), (0.02f, 40), (0.03f, 60), (0.04f, 80), (0.05f, 100)))
|
||||
spitfire_aa.collision.z = CollisionZData(Array((4f, 10), (4.25f, 40), (4.5f, 60), (4.75f, 80), (5f, 100)))
|
||||
spitfire_aa.mass = 5f
|
||||
|
||||
motionalarmsensor.Name = "motionalarmsensor"
|
||||
motionalarmsensor.Descriptor = "MotionSensors"
|
||||
motionalarmsensor.MaxHealth = 100
|
||||
motionalarmsensor.Damageable = true
|
||||
motionalarmsensor.Repairable = true
|
||||
motionalarmsensor.RepairIfDestroyed = false
|
||||
motionalarmsensor.DeployTime = Duration.create(1000, "ms")
|
||||
motionalarmsensor.deployAnimation = DeployAnimation.Standard
|
||||
motionalarmsensor.Geometry = sensor
|
||||
|
||||
sensor_shield.Name = "sensor_shield"
|
||||
sensor_shield.Descriptor = "SensorShields"
|
||||
sensor_shield.MaxHealth = 100
|
||||
sensor_shield.Damageable = true
|
||||
sensor_shield.Repairable = true
|
||||
sensor_shield.RepairIfDestroyed = false
|
||||
sensor_shield.DeployTime = Duration.create(5000, "ms")
|
||||
sensor_shield.deployAnimation = DeployAnimation.Standard
|
||||
sensor_shield.Geometry = sensor
|
||||
|
||||
tank_traps.Name = "tank_traps"
|
||||
tank_traps.Descriptor = "TankTraps"
|
||||
tank_traps.MaxHealth = 5000
|
||||
tank_traps.Damageable = true
|
||||
tank_traps.Repairable = true
|
||||
tank_traps.RepairIfDestroyed = false
|
||||
tank_traps.DeployCategory = DeployableCategory.TankTraps
|
||||
tank_traps.DeployTime = Duration.create(6000, "ms")
|
||||
tank_traps.deployAnimation = DeployAnimation.Fdu
|
||||
//tank_traps do not explode
|
||||
tank_traps.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 10
|
||||
Damage1 = 10
|
||||
DamageRadius = 8
|
||||
DamageAtEdge = 0.2f
|
||||
Modifiers = ExplodingRadialDegrade
|
||||
}
|
||||
tank_traps.Geometry = GeometryForm.representByCylinder(radius = 2.89680997f, height = 3.57812f)
|
||||
tank_traps.collision.xy = CollisionXYData(Array((0.01f, 5), (0.02f, 10), (0.03f, 15), (0.04f, 20), (0.05f, 25)))
|
||||
tank_traps.collision.z = CollisionZData(Array((4f, 10), (4.25f, 40), (4.5f, 60), (4.75f, 80), (5f, 100)))
|
||||
tank_traps.Modifiers = TrapCollisionDamageMultiplier(5f) //10f
|
||||
tank_traps.mass = 600f
|
||||
|
||||
val fieldTurretConverter = new FieldTurretConverter
|
||||
portable_manned_turret.Name = "portable_manned_turret"
|
||||
portable_manned_turret.Descriptor = "FieldTurrets"
|
||||
portable_manned_turret.MaxHealth = 1000
|
||||
portable_manned_turret.Damageable = true
|
||||
portable_manned_turret.Repairable = true
|
||||
portable_manned_turret.RepairIfDestroyed = false
|
||||
portable_manned_turret.WeaponPaths += 1 -> new mutable.HashMap()
|
||||
portable_manned_turret.WeaponPaths(1) += TurretUpgrade.None -> energy_gun
|
||||
portable_manned_turret.Seats += 0 -> new SeatDefinition()
|
||||
portable_manned_turret.controlledWeapons(seat = 0, weapon = 1)
|
||||
portable_manned_turret.MountPoints += 1 -> MountInfo(0)
|
||||
portable_manned_turret.MountPoints += 2 -> MountInfo(0)
|
||||
portable_manned_turret.ReserveAmmunition = true
|
||||
portable_manned_turret.FactionLocked = true
|
||||
portable_manned_turret.Packet = fieldTurretConverter
|
||||
portable_manned_turret.DeployCategory = DeployableCategory.FieldTurrets
|
||||
portable_manned_turret.DeployTime = Duration.create(6000, "ms")
|
||||
portable_manned_turret.deployAnimation = DeployAnimation.Fdu
|
||||
portable_manned_turret.Model = ComplexDeployableResolutions.calculate
|
||||
portable_manned_turret.RadiationShielding = 0.5f
|
||||
portable_manned_turret.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 150
|
||||
Damage1 = 300
|
||||
DamageRadius = 8
|
||||
DamageAtEdge = 0.1f
|
||||
Modifiers = ExplodingRadialDegrade
|
||||
}
|
||||
portable_manned_turret.Geometry = largeTurret
|
||||
portable_manned_turret.collision.xy = CollisionXYData(Array((0.01f, 10), (0.02f, 40), (0.03f, 60), (0.04f, 80), (0.05f, 100)))
|
||||
portable_manned_turret.collision.z = CollisionZData(Array((4f, 10), (4.25f, 40), (4.5f, 60), (4.75f, 80), (5f, 100)))
|
||||
portable_manned_turret.mass = 100f
|
||||
|
||||
portable_manned_turret_nc.Name = "portable_manned_turret_nc"
|
||||
portable_manned_turret_nc.Descriptor = "FieldTurrets"
|
||||
portable_manned_turret_nc.MaxHealth = 1000
|
||||
portable_manned_turret_nc.Damageable = true
|
||||
portable_manned_turret_nc.Repairable = true
|
||||
portable_manned_turret_nc.RepairIfDestroyed = false
|
||||
portable_manned_turret_nc.WeaponPaths += 1 -> new mutable.HashMap()
|
||||
portable_manned_turret_nc.WeaponPaths(1) += TurretUpgrade.None -> energy_gun_nc
|
||||
portable_manned_turret_nc.Seats += 0 -> new SeatDefinition()
|
||||
portable_manned_turret_nc.controlledWeapons(seat = 0, weapon = 1)
|
||||
portable_manned_turret_nc.MountPoints += 1 -> MountInfo(0)
|
||||
portable_manned_turret_nc.MountPoints += 2 -> MountInfo(0)
|
||||
portable_manned_turret_nc.ReserveAmmunition = true
|
||||
portable_manned_turret_nc.FactionLocked = true
|
||||
portable_manned_turret_nc.Packet = fieldTurretConverter
|
||||
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.Model = ComplexDeployableResolutions.calculate
|
||||
portable_manned_turret_nc.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 150
|
||||
Damage1 = 300
|
||||
DamageRadius = 8
|
||||
DamageAtEdge = 0.1f
|
||||
Modifiers = ExplodingRadialDegrade
|
||||
}
|
||||
portable_manned_turret_nc.Geometry = largeTurret
|
||||
portable_manned_turret_nc.collision.xy = CollisionXYData(Array((0.01f, 10), (0.02f, 40), (0.03f, 60), (0.04f, 80), (0.05f, 100)))
|
||||
portable_manned_turret_nc.collision.z = CollisionZData(Array((4f, 10), (4.25f, 40), (4.5f, 60), (4.75f, 80), (5f, 100)))
|
||||
portable_manned_turret_nc.mass = 100f
|
||||
|
||||
portable_manned_turret_tr.Name = "portable_manned_turret_tr"
|
||||
portable_manned_turret_tr.Descriptor = "FieldTurrets"
|
||||
portable_manned_turret_tr.MaxHealth = 1000
|
||||
portable_manned_turret_tr.Damageable = true
|
||||
portable_manned_turret_tr.Repairable = true
|
||||
portable_manned_turret_tr.RepairIfDestroyed = false
|
||||
portable_manned_turret_tr.WeaponPaths += 1 -> new mutable.HashMap()
|
||||
portable_manned_turret_tr.WeaponPaths(1) += TurretUpgrade.None -> energy_gun_tr
|
||||
portable_manned_turret_tr.Seats += 0 -> new SeatDefinition()
|
||||
portable_manned_turret_tr.controlledWeapons(seat = 0, weapon = 1)
|
||||
portable_manned_turret_tr.MountPoints += 1 -> MountInfo(0)
|
||||
portable_manned_turret_tr.MountPoints += 2 -> MountInfo(0)
|
||||
portable_manned_turret_tr.ReserveAmmunition = true
|
||||
portable_manned_turret_tr.FactionLocked = true
|
||||
portable_manned_turret_tr.Packet = fieldTurretConverter
|
||||
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.Model = ComplexDeployableResolutions.calculate
|
||||
portable_manned_turret_tr.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 150
|
||||
Damage1 = 300
|
||||
DamageRadius = 8
|
||||
DamageAtEdge = 0.1f
|
||||
Modifiers = ExplodingRadialDegrade
|
||||
}
|
||||
portable_manned_turret_tr.Geometry = largeTurret
|
||||
portable_manned_turret_tr.collision.xy = CollisionXYData(Array((0.01f, 10), (0.02f, 40), (0.03f, 60), (0.04f, 80), (0.05f, 100)))
|
||||
portable_manned_turret_tr.collision.z = CollisionZData(Array((4f, 10), (4.25f, 40), (4.5f, 60), (4.75f, 80), (5f, 100)))
|
||||
portable_manned_turret_tr.mass = 100f
|
||||
|
||||
portable_manned_turret_vs.Name = "portable_manned_turret_vs"
|
||||
portable_manned_turret_vs.Descriptor = "FieldTurrets"
|
||||
portable_manned_turret_vs.MaxHealth = 1000
|
||||
portable_manned_turret_vs.Damageable = true
|
||||
portable_manned_turret_vs.Repairable = true
|
||||
portable_manned_turret_vs.RepairIfDestroyed = false
|
||||
portable_manned_turret_vs.WeaponPaths += 1 -> new mutable.HashMap()
|
||||
portable_manned_turret_vs.WeaponPaths(1) += TurretUpgrade.None -> energy_gun_vs
|
||||
portable_manned_turret_vs.Seats += 0 -> new SeatDefinition()
|
||||
portable_manned_turret_vs.controlledWeapons(seat = 0, weapon = 1)
|
||||
portable_manned_turret_vs.MountPoints += 1 -> MountInfo(0)
|
||||
portable_manned_turret_vs.MountPoints += 2 -> MountInfo(0)
|
||||
portable_manned_turret_vs.ReserveAmmunition = true
|
||||
portable_manned_turret_vs.FactionLocked = true
|
||||
portable_manned_turret_vs.Packet = fieldTurretConverter
|
||||
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.Model = ComplexDeployableResolutions.calculate
|
||||
portable_manned_turret_vs.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 150
|
||||
Damage1 = 300
|
||||
DamageRadius = 8
|
||||
DamageAtEdge = 0.1f
|
||||
Modifiers = ExplodingRadialDegrade
|
||||
}
|
||||
portable_manned_turret_vs.Geometry = largeTurret
|
||||
portable_manned_turret_vs.collision.xy = CollisionXYData(Array((0.01f, 10), (0.02f, 40), (0.03f, 60), (0.04f, 80), (0.05f, 100)))
|
||||
portable_manned_turret_vs.collision.z = CollisionZData(Array((4f, 10), (4.25f, 40), (4.5f, 60), (4.75f, 80), (5f, 100)))
|
||||
portable_manned_turret_vs.mass = 100f
|
||||
|
||||
deployable_shield_generator.Name = "deployable_shield_generator"
|
||||
deployable_shield_generator.Descriptor = "ShieldGenerators"
|
||||
deployable_shield_generator.MaxHealth = 1700
|
||||
deployable_shield_generator.Damageable = true
|
||||
deployable_shield_generator.Repairable = true
|
||||
deployable_shield_generator.RepairIfDestroyed = false
|
||||
deployable_shield_generator.DeployTime = Duration.create(6000, "ms")
|
||||
deployable_shield_generator.deployAnimation = DeployAnimation.Fdu
|
||||
deployable_shield_generator.Model = ComplexDeployableResolutions.calculate
|
||||
deployable_shield_generator.Geometry = GeometryForm.representByCylinder(radius = 0.6562f, height = 2.17188f)
|
||||
|
||||
router_telepad_deployable.Name = "router_telepad_deployable"
|
||||
router_telepad_deployable.MaxHealth = 100
|
||||
router_telepad_deployable.Damageable = true
|
||||
router_telepad_deployable.Repairable = false
|
||||
router_telepad_deployable.DeployTime = Duration.create(1, "ms")
|
||||
router_telepad_deployable.DeployCategory = DeployableCategory.Telepads
|
||||
router_telepad_deployable.Packet = new TelepadDeployableConverter
|
||||
router_telepad_deployable.Model = SimpleResolutions.calculate
|
||||
router_telepad_deployable.Geometry = GeometryForm.representByRaisedSphere(radius = 1.2344f)
|
||||
|
||||
internal_router_telepad_deployable.Name = "router_telepad_deployable"
|
||||
internal_router_telepad_deployable.MaxHealth = 1
|
||||
internal_router_telepad_deployable.Damageable = false
|
||||
internal_router_telepad_deployable.Repairable = false
|
||||
internal_router_telepad_deployable.DeployTime = Duration.create(1, "ms")
|
||||
internal_router_telepad_deployable.DeployCategory = DeployableCategory.Telepads
|
||||
internal_router_telepad_deployable.Packet = new InternalTelepadDeployableConverter
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.global
|
||||
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
import net.psforever.objects.avatar.Certification
|
||||
import net.psforever.objects.definition.SpecialExoSuitDefinition
|
||||
import net.psforever.objects.equipment.EquipmentSize
|
||||
import net.psforever.objects.inventory.InventoryTile
|
||||
import net.psforever.objects.vital.MaxResolutions
|
||||
import net.psforever.objects.vital.damage.DamageCalculations
|
||||
|
||||
object GlobalDefinitionsExoSuit {
|
||||
import GlobalDefinitions._
|
||||
|
||||
/**
|
||||
* Initialize `ExoSuitType` globals.
|
||||
*/
|
||||
def init(): Unit = {
|
||||
Standard.Name = "standard"
|
||||
Standard.MaxArmor = 50
|
||||
Standard.InventoryScale = InventoryTile.Tile96
|
||||
Standard.InventoryOffset = 6
|
||||
Standard.Holster(0, EquipmentSize.Pistol)
|
||||
Standard.Holster(2, EquipmentSize.Rifle)
|
||||
Standard.Holster(4, EquipmentSize.Melee)
|
||||
Standard.ResistanceDirectHit = 4
|
||||
Standard.ResistanceSplash = 15
|
||||
Standard.ResistanceAggravated = 8
|
||||
Standard.collision.forceFactor = 1.5f
|
||||
Standard.collision.massFactor = 2f
|
||||
|
||||
Agile.Name = "lite_armor"
|
||||
Agile.Descriptor = "agile"
|
||||
Agile.MaxArmor = 100
|
||||
Agile.InventoryScale = InventoryTile.Tile99
|
||||
Agile.InventoryOffset = 6
|
||||
Agile.Holster(0, EquipmentSize.Pistol)
|
||||
Agile.Holster(1, EquipmentSize.Pistol)
|
||||
Agile.Holster(2, EquipmentSize.Rifle)
|
||||
Agile.Holster(4, EquipmentSize.Melee)
|
||||
Agile.ResistanceDirectHit = 6
|
||||
Agile.ResistanceSplash = 25
|
||||
Agile.ResistanceAggravated = 10
|
||||
Agile.collision.forceFactor = 1.5f
|
||||
Agile.collision.massFactor = 2f
|
||||
|
||||
Reinforced.Name = "med_armor"
|
||||
Reinforced.Descriptor = "reinforced"
|
||||
Reinforced.Permissions = List(Certification.ReinforcedExoSuit)
|
||||
Reinforced.MaxArmor = 200
|
||||
Reinforced.InventoryScale = InventoryTile.Tile1209
|
||||
Reinforced.InventoryOffset = 6
|
||||
Reinforced.Holster(0, EquipmentSize.Pistol)
|
||||
Reinforced.Holster(1, EquipmentSize.Pistol)
|
||||
Reinforced.Holster(2, EquipmentSize.Rifle)
|
||||
Reinforced.Holster(3, EquipmentSize.Rifle)
|
||||
Reinforced.Holster(4, EquipmentSize.Melee)
|
||||
Reinforced.ResistanceDirectHit = 10
|
||||
Reinforced.ResistanceSplash = 35
|
||||
Reinforced.ResistanceAggravated = 12
|
||||
Reinforced.collision.forceFactor = 2f
|
||||
Reinforced.collision.massFactor = 3f
|
||||
|
||||
Infiltration.Name = "infiltration_suit"
|
||||
Infiltration.Permissions = List(Certification.InfiltrationSuit)
|
||||
Infiltration.MaxArmor = 0
|
||||
Infiltration.InventoryScale = InventoryTile.Tile66
|
||||
Infiltration.InventoryOffset = 6
|
||||
Infiltration.Holster(0, EquipmentSize.Pistol)
|
||||
Infiltration.Holster(4, EquipmentSize.Melee)
|
||||
|
||||
def CommonMaxConfig(max: SpecialExoSuitDefinition): Unit = {
|
||||
max.Permissions = List(Certification.AIMAX, Certification.AVMAX, Certification.AAMAX, Certification.UniMAX)
|
||||
max.MaxArmor = 650
|
||||
max.InventoryScale = InventoryTile.Tile1612
|
||||
max.InventoryOffset = 6
|
||||
max.Holster(0, EquipmentSize.Max)
|
||||
max.Holster(4, EquipmentSize.Melee)
|
||||
max.Subtract.Damage1 = 2
|
||||
max.ResistanceDirectHit = 6
|
||||
max.ResistanceSplash = 35
|
||||
max.ResistanceAggravated = 10
|
||||
max.RadiationShielding = 0.5f
|
||||
max.collision.forceFactor = 4f
|
||||
max.collision.massFactor = 10f
|
||||
max.DamageUsing = DamageCalculations.AgainstMaxSuit
|
||||
max.Model = MaxResolutions.calculate
|
||||
}
|
||||
|
||||
CommonMaxConfig(VSMAX)
|
||||
VSMAX.Name = "vshev"
|
||||
VSMAX.MaxCapacitor = 50
|
||||
VSMAX.CapacitorRechargeDelayMillis = 5000
|
||||
VSMAX.CapacitorRechargePerSecond = 3
|
||||
VSMAX.CapacitorDrainPerSecond = 20
|
||||
|
||||
CommonMaxConfig(TRMAX)
|
||||
TRMAX.Name = "trhev"
|
||||
TRMAX.MaxCapacitor = 300
|
||||
TRMAX.CapacitorRechargeDelayMillis = 10000
|
||||
TRMAX.CapacitorRechargePerSecond = 10
|
||||
TRMAX.CapacitorDrainPerSecond = 30
|
||||
|
||||
CommonMaxConfig(NCMAX)
|
||||
NCMAX.Name = "nchev"
|
||||
NCMAX.MaxCapacitor = 400
|
||||
NCMAX.CapacitorRechargeDelayMillis = 10000
|
||||
NCMAX.CapacitorRechargePerSecond = 4
|
||||
NCMAX.CapacitorDrainPerSecond = 4
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.global
|
||||
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
import net.psforever.types.ExoSuitType
|
||||
|
||||
object GlobalDefinitionsImplant {
|
||||
import GlobalDefinitions._
|
||||
|
||||
/**
|
||||
* Initialize `ImplantDefinition` globals.
|
||||
*/
|
||||
def init(): Unit = {
|
||||
advanced_regen.Name = "advanced_regen"
|
||||
advanced_regen.InitializationDuration = 120
|
||||
advanced_regen.StaminaCost = 2
|
||||
advanced_regen.CostIntervalDefault = 500
|
||||
|
||||
targeting.Name = "targeting"
|
||||
targeting.InitializationDuration = 60
|
||||
|
||||
audio_amplifier.Name = "audio_amplifier"
|
||||
audio_amplifier.InitializationDuration = 60
|
||||
audio_amplifier.StaminaCost = 1
|
||||
audio_amplifier.CostIntervalDefault = 1000
|
||||
|
||||
darklight_vision.Name = "darklight_vision"
|
||||
darklight_vision.InitializationDuration = 60
|
||||
darklight_vision.ActivationStaminaCost = 3
|
||||
darklight_vision.StaminaCost = 1
|
||||
darklight_vision.CostIntervalDefault = 500
|
||||
|
||||
melee_booster.Name = "melee_booster"
|
||||
melee_booster.InitializationDuration = 120
|
||||
melee_booster.StaminaCost = 10
|
||||
|
||||
personal_shield.Name = "personal_shield"
|
||||
personal_shield.InitializationDuration = 120
|
||||
personal_shield.StaminaCost = 1
|
||||
personal_shield.CostIntervalDefault = 600
|
||||
|
||||
range_magnifier.Name = "range_magnifier"
|
||||
range_magnifier.InitializationDuration = 60
|
||||
|
||||
second_wind.Name = "second_wind"
|
||||
second_wind.InitializationDuration = 180
|
||||
|
||||
silent_run.Name = "silent_run"
|
||||
silent_run.InitializationDuration = 90
|
||||
silent_run.StaminaCost = 1
|
||||
silent_run.CostIntervalDefault = 333
|
||||
silent_run.CostIntervalByExoSuitHashMap(ExoSuitType.Infiltration) = 1000
|
||||
|
||||
surge.Name = "surge"
|
||||
surge.InitializationDuration = 90
|
||||
surge.StaminaCost = 1
|
||||
surge.CostIntervalDefault = 1000
|
||||
surge.CostIntervalByExoSuitHashMap(ExoSuitType.Agile) = 500
|
||||
surge.CostIntervalByExoSuitHashMap(ExoSuitType.Reinforced) = 333
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.global
|
||||
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
|
||||
object GlobalDefinitionsKit {
|
||||
import GlobalDefinitions._
|
||||
|
||||
/**
|
||||
* Initialize `KitDefinition` globals.
|
||||
*/
|
||||
def init(): Unit = {
|
||||
medkit.Name = "medkit"
|
||||
|
||||
super_medkit.Name = "super_medkit"
|
||||
|
||||
super_armorkit.Name = "super_armorkit"
|
||||
|
||||
super_staminakit.Name = "super_staminakit"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,938 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.global
|
||||
|
||||
import net.psforever.objects.{GlobalDefinitions, SpawnPoint}
|
||||
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.doors.InteriorDoorField
|
||||
import net.psforever.objects.serverobject.mount.{MountInfo, SeatDefinition}
|
||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPadDefinition
|
||||
import net.psforever.objects.serverobject.structures.AutoRepairStats
|
||||
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalDefinition
|
||||
import net.psforever.objects.serverobject.terminals.{EquipmentTerminalDefinition, VehicleTerminalDefinition}
|
||||
import net.psforever.objects.serverobject.terminals.tabs.{ArmorWithAmmoPage, BattleframeSpawnLoadoutPage, CavernEquipmentQuestion, CavernVehicleQuestion, CertificationPage, EquipmentPage, ImplantPage, InfantryLoadoutPage, NoCavernEquipmentRule, NoExoSuitRule, VehicleLoadoutPage, VehiclePage}
|
||||
import net.psforever.objects.serverobject.turret.{AutoChecks, AutoRanges, Automation, TurretUpgrade}
|
||||
import net.psforever.objects.vital.base.DamageType
|
||||
import net.psforever.objects.vital.etc.ExplodingRadialDegrade
|
||||
import net.psforever.objects.vital.prop.DamageWithPosition
|
||||
import net.psforever.types.{ExoSuitType, Vector3}
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.duration._
|
||||
|
||||
object GlobalDefinitionsMiscellaneous {
|
||||
import GlobalDefinitions._
|
||||
|
||||
/**
|
||||
* Initialize `Miscellaneous` globals.
|
||||
*/
|
||||
def init(): Unit = {
|
||||
val vterm: Any => VolumetricGeometry = GeometryForm.representByCylinder(radius = 1.03515f, height = 1.09374f)
|
||||
val certs: Seq[Certification] = Certification.values.filter(_.cost != 0)
|
||||
val page: CertificationPage = CertificationPage(certs)
|
||||
|
||||
ams_respawn_tube.Name = "ams_respawn_tube"
|
||||
ams_respawn_tube.Delay = 10 // Temporary -- Default value is 15
|
||||
ams_respawn_tube.SpecificPointFunc = SpawnPoint.AMS
|
||||
ams_respawn_tube.Damageable = false
|
||||
ams_respawn_tube.Repairable = false
|
||||
|
||||
matrix_terminala.Name = "matrix_terminala"
|
||||
matrix_terminala.Damageable = false
|
||||
matrix_terminala.Repairable = false
|
||||
|
||||
matrix_terminalb.Name = "matrix_terminalb"
|
||||
matrix_terminalb.Damageable = false
|
||||
matrix_terminalb.Repairable = false
|
||||
|
||||
matrix_terminalc.Name = "matrix_terminalc"
|
||||
matrix_terminalc.Damageable = false
|
||||
matrix_terminalc.Repairable = false
|
||||
|
||||
spawn_terminal.Name = "spawn_terminal"
|
||||
spawn_terminal.Damageable = false
|
||||
spawn_terminal.Repairable = false
|
||||
spawn_terminal.autoRepair = AutoRepairStats(1, 5000, 200, 1)
|
||||
|
||||
order_terminal.Name = "order_terminal"
|
||||
order_terminal.Tab += 0 -> {
|
||||
val tab = EquipmentPage(
|
||||
EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons
|
||||
)
|
||||
tab.Exclude = List(CavernEquipmentQuestion)
|
||||
tab
|
||||
}
|
||||
order_terminal.Tab += 1 -> ArmorWithAmmoPage(
|
||||
EquipmentTerminalDefinition.suits ++ EquipmentTerminalDefinition.maxSuits,
|
||||
EquipmentTerminalDefinition.maxAmmo
|
||||
)
|
||||
order_terminal.Tab += 2 -> EquipmentPage(
|
||||
EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons
|
||||
)
|
||||
order_terminal.Tab += 3 -> EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
||||
order_terminal.Tab += 4 -> {
|
||||
val tab = InfantryLoadoutPage()
|
||||
tab.Exclude = List(CavernEquipmentQuestion)
|
||||
tab
|
||||
}
|
||||
order_terminal.SellEquipmentByDefault = true
|
||||
order_terminal.MaxHealth = 500
|
||||
order_terminal.Damageable = true
|
||||
order_terminal.Repairable = true
|
||||
order_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.05f)
|
||||
order_terminal.RepairIfDestroyed = true
|
||||
order_terminal.Subtract.Damage1 = 8
|
||||
order_terminal.Geometry = GeometryForm.representByCylinder(radius = 0.8438f, height = 1.3f)
|
||||
|
||||
order_terminala.Name = "order_terminala"
|
||||
order_terminala.Tab += 0 -> {
|
||||
val tab = EquipmentPage(
|
||||
EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons
|
||||
)
|
||||
tab.Exclude = List(NoCavernEquipmentRule)
|
||||
tab
|
||||
}
|
||||
order_terminala.Tab += 1 -> ArmorWithAmmoPage(
|
||||
EquipmentTerminalDefinition.suits,
|
||||
EquipmentTerminalDefinition.maxAmmo
|
||||
)
|
||||
order_terminala.Tab += 2 -> EquipmentPage(
|
||||
EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons
|
||||
)
|
||||
order_terminala.Tab += 3 -> EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
||||
order_terminala.Tab += 4 -> {
|
||||
val tab = InfantryLoadoutPage()
|
||||
tab.Exclude = List(NoExoSuitRule(ExoSuitType.MAX), NoCavernEquipmentRule)
|
||||
tab
|
||||
}
|
||||
order_terminala.SellEquipmentByDefault = true
|
||||
order_terminala.Damageable = false
|
||||
order_terminala.Repairable = false
|
||||
|
||||
order_terminalb.Name = "order_terminalb"
|
||||
order_terminalb.Tab += 0 -> {
|
||||
val tab = EquipmentPage(
|
||||
EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons
|
||||
)
|
||||
tab.Exclude = List(NoCavernEquipmentRule)
|
||||
tab
|
||||
}
|
||||
order_terminalb.Tab += 1 -> ArmorWithAmmoPage(
|
||||
EquipmentTerminalDefinition.suits,
|
||||
EquipmentTerminalDefinition.maxAmmo
|
||||
)
|
||||
order_terminalb.Tab += 2 -> EquipmentPage(
|
||||
EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons
|
||||
)
|
||||
order_terminalb.Tab += 3 -> EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
||||
order_terminalb.Tab += 4 -> {
|
||||
val tab = InfantryLoadoutPage()
|
||||
tab.Exclude = List(NoExoSuitRule(ExoSuitType.MAX), NoCavernEquipmentRule)
|
||||
tab
|
||||
}
|
||||
order_terminalb.SellEquipmentByDefault = true
|
||||
order_terminalb.Damageable = false
|
||||
order_terminalb.Repairable = false
|
||||
|
||||
vanu_equipment_term.Name = "vanu_equipment_term"
|
||||
vanu_equipment_term.Tab += 0 -> EquipmentPage(
|
||||
EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons
|
||||
)
|
||||
vanu_equipment_term.Tab += 1 -> ArmorWithAmmoPage(
|
||||
EquipmentTerminalDefinition.suits ++ EquipmentTerminalDefinition.maxSuits,
|
||||
EquipmentTerminalDefinition.maxAmmo
|
||||
)
|
||||
vanu_equipment_term.Tab += 2 -> EquipmentPage(
|
||||
EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons
|
||||
)
|
||||
vanu_equipment_term.Tab += 3 -> EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
||||
vanu_equipment_term.Tab += 4 -> InfantryLoadoutPage()
|
||||
vanu_equipment_term.SellEquipmentByDefault = true
|
||||
vanu_equipment_term.Damageable = false
|
||||
vanu_equipment_term.Repairable = false
|
||||
|
||||
cert_terminal.Name = "cert_terminal"
|
||||
cert_terminal.Tab += 0 -> page
|
||||
cert_terminal.MaxHealth = 500
|
||||
cert_terminal.Damageable = true
|
||||
cert_terminal.Repairable = true
|
||||
cert_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.05f)
|
||||
cert_terminal.RepairIfDestroyed = true
|
||||
cert_terminal.Subtract.Damage1 = 8
|
||||
cert_terminal.Geometry = GeometryForm.representByCylinder(radius = 0.66405f, height = 1.09374f)
|
||||
|
||||
implant_terminal_mech.Name = "implant_terminal_mech"
|
||||
implant_terminal_mech.MaxHealth = 1500 //TODO 1000; right now, 1000 (mech) + 500 (interface)
|
||||
implant_terminal_mech.Damageable = true
|
||||
implant_terminal_mech.Repairable = true
|
||||
implant_terminal_mech.autoRepair = AutoRepairStats(1.6f, 5000, 2400, 0.05f)
|
||||
implant_terminal_mech.RepairIfDestroyed = true
|
||||
implant_terminal_mech.RadiationShielding = 0.5f
|
||||
implant_terminal_mech.Geometry = GeometryForm.representByCylinder(radius = 2.7813f, height = 6.4375f)
|
||||
|
||||
implant_terminal_interface.Name = "implant_terminal_interface"
|
||||
implant_terminal_interface.Tab += 0 -> ImplantPage(ImplantTerminalDefinition.implants)
|
||||
implant_terminal_interface.MaxHealth = 500
|
||||
implant_terminal_interface.Damageable = false //TODO true
|
||||
implant_terminal_interface.Repairable = true
|
||||
implant_terminal_interface.autoRepair = AutoRepairStats(1, 5000, 200, 1)
|
||||
implant_terminal_interface.RepairIfDestroyed = true
|
||||
//TODO will need geometry when Damageable = true
|
||||
|
||||
ground_vehicle_terminal.Name = "ground_vehicle_terminal"
|
||||
ground_vehicle_terminal.Tab += 46769 -> {
|
||||
val tab = VehiclePage(
|
||||
VehicleTerminalDefinition.groundVehicles,
|
||||
VehicleTerminalDefinition.trunk
|
||||
)
|
||||
tab.Exclude = List(CavernVehicleQuestion)
|
||||
tab
|
||||
}
|
||||
ground_vehicle_terminal.Tab += 4 -> {
|
||||
val tab = VehicleLoadoutPage(10)
|
||||
tab.Exclude = List(CavernEquipmentQuestion)
|
||||
tab
|
||||
}
|
||||
ground_vehicle_terminal.MaxHealth = 500
|
||||
ground_vehicle_terminal.Damageable = true
|
||||
ground_vehicle_terminal.Repairable = true
|
||||
ground_vehicle_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.05f)
|
||||
ground_vehicle_terminal.RepairIfDestroyed = true
|
||||
ground_vehicle_terminal.Subtract.Damage1 = 8
|
||||
ground_vehicle_terminal.Geometry = vterm
|
||||
|
||||
air_vehicle_terminal.Name = "air_vehicle_terminal"
|
||||
air_vehicle_terminal.Tab += 46769 -> VehiclePage(
|
||||
VehicleTerminalDefinition.flight1Vehicles,
|
||||
VehicleTerminalDefinition.trunk
|
||||
)
|
||||
air_vehicle_terminal.Tab += 4 -> {
|
||||
val tab = VehicleLoadoutPage(10)
|
||||
tab.Exclude = List(CavernVehicleQuestion, CavernEquipmentQuestion)
|
||||
tab
|
||||
}
|
||||
air_vehicle_terminal.MaxHealth = 500
|
||||
air_vehicle_terminal.Damageable = true
|
||||
air_vehicle_terminal.Repairable = true
|
||||
air_vehicle_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.05f)
|
||||
air_vehicle_terminal.RepairIfDestroyed = true
|
||||
air_vehicle_terminal.Subtract.Damage1 = 8
|
||||
air_vehicle_terminal.Geometry = vterm
|
||||
|
||||
dropship_vehicle_terminal.Name = "dropship_vehicle_terminal"
|
||||
dropship_vehicle_terminal.Tab += 46769 -> VehiclePage(
|
||||
VehicleTerminalDefinition.flight1Vehicles ++ VehicleTerminalDefinition.flight2Vehicles,
|
||||
VehicleTerminalDefinition.trunk
|
||||
)
|
||||
dropship_vehicle_terminal.Tab += 4 -> {
|
||||
val tab = VehicleLoadoutPage(10)
|
||||
tab.Exclude = List(CavernEquipmentQuestion)
|
||||
tab
|
||||
}
|
||||
dropship_vehicle_terminal.MaxHealth = 500
|
||||
dropship_vehicle_terminal.Damageable = true
|
||||
dropship_vehicle_terminal.Repairable = true
|
||||
dropship_vehicle_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.05f)
|
||||
dropship_vehicle_terminal.RepairIfDestroyed = true
|
||||
dropship_vehicle_terminal.Subtract.Damage1 = 8
|
||||
dropship_vehicle_terminal.Geometry = vterm
|
||||
|
||||
vehicle_terminal_combined.Name = "vehicle_terminal_combined"
|
||||
vehicle_terminal_combined.Tab += 46769 -> {
|
||||
val tab = VehiclePage(
|
||||
VehicleTerminalDefinition.flight1Vehicles ++ VehicleTerminalDefinition.groundVehicles,
|
||||
VehicleTerminalDefinition.trunk
|
||||
)
|
||||
tab.Exclude = List(CavernVehicleQuestion)
|
||||
tab
|
||||
}
|
||||
vehicle_terminal_combined.Tab += 4 -> {
|
||||
val tab = VehicleLoadoutPage(10)
|
||||
tab.Exclude = List(CavernEquipmentQuestion)
|
||||
tab
|
||||
}
|
||||
vehicle_terminal_combined.MaxHealth = 500
|
||||
vehicle_terminal_combined.Damageable = true
|
||||
vehicle_terminal_combined.Repairable = true
|
||||
vehicle_terminal_combined.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.05f)
|
||||
vehicle_terminal_combined.RepairIfDestroyed = true
|
||||
vehicle_terminal_combined.Subtract.Damage1 = 8
|
||||
vehicle_terminal_combined.Geometry = vterm
|
||||
|
||||
vanu_air_vehicle_term.Name = "vanu_air_vehicle_term"
|
||||
vanu_air_vehicle_term.Tab += 46769 -> VehiclePage(
|
||||
VehicleTerminalDefinition.flight1Vehicles,
|
||||
VehicleTerminalDefinition.trunk
|
||||
)
|
||||
vanu_air_vehicle_term.Tab += 4 -> VehicleLoadoutPage(10)
|
||||
vanu_air_vehicle_term.MaxHealth = 500
|
||||
vanu_air_vehicle_term.Damageable = true
|
||||
vanu_air_vehicle_term.Repairable = true
|
||||
vanu_air_vehicle_term.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.05f)
|
||||
vanu_air_vehicle_term.RepairIfDestroyed = true
|
||||
vanu_air_vehicle_term.Subtract.Damage1 = 8
|
||||
|
||||
vanu_vehicle_term.Name = "vanu_vehicle_term"
|
||||
vanu_vehicle_term.Tab += 46769 -> VehiclePage(
|
||||
VehicleTerminalDefinition.groundVehicles,
|
||||
VehicleTerminalDefinition.trunk
|
||||
)
|
||||
vanu_vehicle_term.Tab += 4 -> VehicleLoadoutPage(10)
|
||||
vanu_vehicle_term.MaxHealth = 500
|
||||
vanu_vehicle_term.Damageable = true
|
||||
vanu_vehicle_term.Repairable = true
|
||||
vanu_vehicle_term.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.05f)
|
||||
vanu_vehicle_term.RepairIfDestroyed = true
|
||||
vanu_vehicle_term.Subtract.Damage1 = 8
|
||||
|
||||
bfr_terminal.Name = "bfr_terminal"
|
||||
bfr_terminal.Tab += 0 -> VehiclePage(
|
||||
VehicleTerminalDefinition.bfrVehicles,
|
||||
VehicleTerminalDefinition.trunk
|
||||
)
|
||||
bfr_terminal.Tab += 1 -> EquipmentPage(
|
||||
EquipmentTerminalDefinition.bfrAmmunition ++ EquipmentTerminalDefinition.bfrArmWeapons
|
||||
) //inaccessible?
|
||||
bfr_terminal.Tab += 2 -> EquipmentPage(
|
||||
EquipmentTerminalDefinition.bfrAmmunition ++ EquipmentTerminalDefinition.bfrGunnerWeapons
|
||||
) //inaccessible?
|
||||
bfr_terminal.Tab += 3 -> {
|
||||
val tab = BattleframeSpawnLoadoutPage(VehicleTerminalDefinition.bfrVehicles)
|
||||
tab.Exclude = List(CavernEquipmentQuestion)
|
||||
tab
|
||||
}
|
||||
bfr_terminal.MaxHealth = 500
|
||||
bfr_terminal.Damageable = true
|
||||
bfr_terminal.Repairable = true
|
||||
bfr_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.05f)
|
||||
bfr_terminal.RepairIfDestroyed = true
|
||||
bfr_terminal.Subtract.Damage1 = 8
|
||||
bfr_terminal.Geometry = GeometryForm.representByCylinder(radius = 0.92185f, height = 2.64693f)
|
||||
|
||||
respawn_tube.Name = "respawn_tube"
|
||||
respawn_tube.Delay = 10
|
||||
respawn_tube.SpecificPointFunc = SpawnPoint.Tube
|
||||
respawn_tube.MaxHealth = 1000
|
||||
respawn_tube.Damageable = true
|
||||
respawn_tube.DamageableByFriendlyFire = false
|
||||
respawn_tube.Repairable = true
|
||||
respawn_tube.autoRepair = AutoRepairStats(1.6f, 10000, 2400, 1)
|
||||
respawn_tube.RepairIfDestroyed = true
|
||||
respawn_tube.Subtract.Damage1 = 8
|
||||
respawn_tube.Geometry = GeometryForm.representByCylinder(radius = 0.9336f, height = 2.84375f)
|
||||
|
||||
respawn_tube_sanctuary.Name = "respawn_tube"
|
||||
respawn_tube_sanctuary.Delay = 10
|
||||
respawn_tube_sanctuary.SpecificPointFunc = SpawnPoint.Default
|
||||
respawn_tube_sanctuary.MaxHealth = 1000
|
||||
respawn_tube_sanctuary.Damageable = false //true?
|
||||
respawn_tube_sanctuary.DamageableByFriendlyFire = false
|
||||
respawn_tube_sanctuary.Repairable = true
|
||||
respawn_tube_sanctuary.autoRepair = AutoRepairStats(1.6f, 10000, 2400, 1)
|
||||
//TODO will need geometry when Damageable = true
|
||||
|
||||
respawn_tube_tower.Name = "respawn_tube_tower"
|
||||
respawn_tube_tower.Delay = 10 // Temporary -- Default value is 20
|
||||
respawn_tube_tower.SpecificPointFunc = SpawnPoint.Tube
|
||||
respawn_tube_tower.MaxHealth = 1000
|
||||
respawn_tube_tower.Damageable = true
|
||||
respawn_tube_tower.DamageableByFriendlyFire = false
|
||||
respawn_tube_tower.Repairable = true
|
||||
respawn_tube_tower.autoRepair = AutoRepairStats(1.6f, 10000, 2400, 1)
|
||||
respawn_tube_tower.RepairIfDestroyed = true
|
||||
respawn_tube_tower.Subtract.Damage1 = 8
|
||||
respawn_tube_tower.Geometry = GeometryForm.representByCylinder(radius = 0.9336f, height = 2.84375f)
|
||||
|
||||
teleportpad_terminal.Name = "teleportpad_terminal"
|
||||
teleportpad_terminal.Tab += 0 -> EquipmentPage(EquipmentTerminalDefinition.routerTerminal)
|
||||
teleportpad_terminal.Damageable = false
|
||||
teleportpad_terminal.Repairable = false
|
||||
|
||||
targeting_laser_dispenser.Name = "targeting_laser_dispenser"
|
||||
targeting_laser_dispenser.Tab += 0 -> EquipmentPage(EquipmentTerminalDefinition.flailTerminal)
|
||||
targeting_laser_dispenser.Damageable = false
|
||||
targeting_laser_dispenser.Repairable = false
|
||||
|
||||
medical_terminal.Name = "medical_terminal"
|
||||
medical_terminal.Interval = 500
|
||||
medical_terminal.HealAmount = 5
|
||||
medical_terminal.ArmorAmount = 10
|
||||
medical_terminal.UseRadius = 0.75f
|
||||
medical_terminal.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.Medical
|
||||
medical_terminal.MaxHealth = 500
|
||||
medical_terminal.Damageable = true
|
||||
medical_terminal.Repairable = true
|
||||
medical_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.05f)
|
||||
medical_terminal.RepairIfDestroyed = true
|
||||
medical_terminal.Geometry = GeometryForm.representByCylinder(radius = 0.711f, height = 1.75f)
|
||||
|
||||
adv_med_terminal.Name = "adv_med_terminal"
|
||||
adv_med_terminal.Interval = 500
|
||||
adv_med_terminal.HealAmount = 8
|
||||
adv_med_terminal.ArmorAmount = 15
|
||||
adv_med_terminal.UseRadius = 0.75f
|
||||
adv_med_terminal.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.Medical
|
||||
adv_med_terminal.MaxHealth = 750
|
||||
adv_med_terminal.Damageable = true
|
||||
adv_med_terminal.Repairable = true
|
||||
adv_med_terminal.autoRepair = AutoRepairStats(1.57894f, 5000, 2400, 0.05f)
|
||||
adv_med_terminal.RepairIfDestroyed = true
|
||||
adv_med_terminal.Geometry = GeometryForm.representByCylinder(radius = 0.8662125f, height = 3.47f)
|
||||
|
||||
crystals_health_a.Name = "crystals_health_a"
|
||||
crystals_health_a.Interval = 500
|
||||
crystals_health_a.HealAmount = 4
|
||||
crystals_health_a.UseRadius = 5
|
||||
crystals_health_a.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.HealthCrystal
|
||||
crystals_health_a.Damageable = false
|
||||
crystals_health_a.Repairable = false
|
||||
|
||||
crystals_health_b.Name = "crystals_health_b"
|
||||
crystals_health_b.Interval = 500
|
||||
crystals_health_b.HealAmount = 4
|
||||
crystals_health_b.UseRadius = 5
|
||||
crystals_health_b.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.HealthCrystal
|
||||
crystals_health_b.Damageable = false
|
||||
crystals_health_b.Repairable = false
|
||||
|
||||
crystals_repair_a.Name = "crystals_repair_a"
|
||||
crystals_repair_a.Interval = 500
|
||||
crystals_repair_a.ArmorAmount = 4
|
||||
crystals_repair_a.UseRadius = 5
|
||||
crystals_repair_a.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.RepairCrystal
|
||||
crystals_repair_a.Damageable = false
|
||||
crystals_repair_a.Repairable = false
|
||||
|
||||
crystals_repair_b.Name = "crystals_repair_b"
|
||||
crystals_repair_b.Interval = 500
|
||||
crystals_repair_b.ArmorAmount = 4
|
||||
crystals_repair_b.UseRadius = 5
|
||||
crystals_repair_b.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.RepairCrystal
|
||||
crystals_repair_b.Damageable = false
|
||||
crystals_repair_b.Repairable = false
|
||||
|
||||
crystals_vehicle_a.Name = "crystals_vehicle_a"
|
||||
crystals_vehicle_a.Interval = 1000
|
||||
crystals_vehicle_a.HealAmount = 60
|
||||
crystals_vehicle_a.UseRadius = 15
|
||||
crystals_vehicle_a.TargetValidation += EffectTarget.Category.Vehicle -> EffectTarget.Validation.VehicleCrystal
|
||||
crystals_vehicle_a.Damageable = false
|
||||
crystals_vehicle_a.Repairable = false
|
||||
|
||||
crystals_vehicle_b.Name = "crystals_vehicle_b"
|
||||
crystals_vehicle_b.Interval = 1000
|
||||
crystals_vehicle_b.HealAmount = 60
|
||||
crystals_vehicle_b.UseRadius = 15
|
||||
crystals_vehicle_b.TargetValidation += EffectTarget.Category.Vehicle -> EffectTarget.Validation.VehicleCrystal
|
||||
crystals_vehicle_b.Damageable = false
|
||||
crystals_vehicle_b.Repairable = false
|
||||
|
||||
crystals_energy_a.Name = "crystals_energy_a"
|
||||
crystals_energy_a.Interval = 1000
|
||||
crystals_energy_a.UseRadius = 5
|
||||
crystals_energy_a.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.AncientWeaponRecharge
|
||||
crystals_energy_a.Damageable = false
|
||||
crystals_energy_a.Repairable = false
|
||||
|
||||
crystals_energy_b.Name = "crystals_energy_b"
|
||||
crystals_energy_b.Interval = 1000
|
||||
crystals_energy_b.UseRadius = 5
|
||||
crystals_energy_b.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.AncientWeaponRecharge
|
||||
crystals_energy_b.Damageable = false
|
||||
crystals_energy_b.Repairable = false
|
||||
|
||||
crystals_energy.Name = "crystals_energy"
|
||||
crystals_energy.Interval = 1000
|
||||
crystals_energy.UseRadius = 5
|
||||
crystals_energy.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.AncientWeaponRecharge
|
||||
crystals_energy.Damageable = false
|
||||
crystals_energy.Repairable = false
|
||||
|
||||
portable_med_terminal.Name = "portable_med_terminal"
|
||||
portable_med_terminal.Interval = 500
|
||||
portable_med_terminal.HealAmount = 5
|
||||
portable_med_terminal.ArmorAmount = 10
|
||||
portable_med_terminal.UseRadius = 3
|
||||
portable_med_terminal.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.Medical
|
||||
portable_med_terminal.MaxHealth = 500
|
||||
portable_med_terminal.Damageable = false //TODO actually true
|
||||
portable_med_terminal.Repairable = false
|
||||
portable_med_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.05f)
|
||||
|
||||
pad_landing_frame.Name = "pad_landing_frame"
|
||||
pad_landing_frame.Interval = 1000
|
||||
pad_landing_frame.HealAmount = 60
|
||||
pad_landing_frame.UseRadius = 20
|
||||
pad_landing_frame.TargetValidation += EffectTarget.Category.Aircraft -> EffectTarget.Validation.PadLanding
|
||||
pad_landing_frame.Damageable = false
|
||||
pad_landing_frame.Repairable = false
|
||||
|
||||
pad_landing_tower_frame.Name = "pad_landing_tower_frame"
|
||||
pad_landing_tower_frame.Interval = 1000
|
||||
pad_landing_tower_frame.HealAmount = 60
|
||||
pad_landing_tower_frame.UseRadius = 20
|
||||
pad_landing_tower_frame.TargetValidation += EffectTarget.Category.Aircraft -> EffectTarget.Validation.PadLanding
|
||||
pad_landing_tower_frame.Damageable = false
|
||||
pad_landing_tower_frame.Repairable = false
|
||||
|
||||
repair_silo.Name = "repair_silo"
|
||||
repair_silo.Interval = 1000
|
||||
repair_silo.HealAmount = 60
|
||||
repair_silo.UseRadius = 20
|
||||
repair_silo.TargetValidation += EffectTarget.Category.Vehicle -> EffectTarget.Validation.RepairSilo
|
||||
repair_silo.Damageable = false
|
||||
repair_silo.Repairable = false
|
||||
|
||||
recharge_terminal.Name = "recharge_terminal"
|
||||
recharge_terminal.Interval = 1000
|
||||
recharge_terminal.UseRadius = 20
|
||||
recharge_terminal.TargetValidation += EffectTarget.Category.Vehicle -> EffectTarget.Validation.AncientVehicleWeaponRecharge
|
||||
recharge_terminal.Damageable = false
|
||||
recharge_terminal.Repairable = false
|
||||
|
||||
recharge_terminal_weapon_module.Name = "recharge_terminal_weapon_module"
|
||||
recharge_terminal_weapon_module.Interval = 1000
|
||||
recharge_terminal_weapon_module.UseRadius = 300
|
||||
recharge_terminal_weapon_module.TargetValidation += EffectTarget.Category.Player -> EffectTarget.Validation.AncientWeaponRecharge
|
||||
recharge_terminal_weapon_module.Damageable = false
|
||||
recharge_terminal_weapon_module.Repairable = false
|
||||
|
||||
mb_pad_creation.Name = "mb_pad_creation"
|
||||
mb_pad_creation.Damageable = false
|
||||
mb_pad_creation.Repairable = false
|
||||
mb_pad_creation.VehicleCreationZOffset = 2.52604f
|
||||
mb_pad_creation.killBox = VehicleSpawnPadDefinition.prepareKillBox(
|
||||
forwardLimit = 14,
|
||||
backLimit = 10,
|
||||
sideLimit = 7.5f,
|
||||
aboveLimit = 5 //double to 10 when spawning a flying vehicle
|
||||
)
|
||||
mb_pad_creation.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 99999
|
||||
DamageRadiusMin = 14
|
||||
DamageRadius = 14.5f
|
||||
DamageAtEdge = 0.00002f
|
||||
//damage is 99999 at 14m, dropping rapidly to ~1 at 14.5m
|
||||
}
|
||||
|
||||
dropship_pad_doors.Name = "dropship_pad_doors"
|
||||
dropship_pad_doors.Damageable = false
|
||||
dropship_pad_doors.Repairable = false
|
||||
dropship_pad_doors.VehicleCreationZOffset = 4.89507f
|
||||
dropship_pad_doors.VehicleCreationZOrientOffset = -90f
|
||||
dropship_pad_doors.killBox = VehicleSpawnPadDefinition.prepareKillBox(
|
||||
forwardLimit = 14,
|
||||
backLimit = 14,
|
||||
sideLimit = 13.5f,
|
||||
aboveLimit = 5 //doubles to 10
|
||||
)
|
||||
dropship_pad_doors.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 99999
|
||||
DamageRadiusMin = 14
|
||||
DamageRadius = 14.5f
|
||||
DamageAtEdge = 0.00002f
|
||||
//damage is 99999 at 14m, dropping rapidly to ~1 at 14.5m
|
||||
}
|
||||
|
||||
vanu_vehicle_creation_pad.Name = "vanu_vehicle_creation_pad"
|
||||
vanu_vehicle_creation_pad.Damageable = false
|
||||
vanu_vehicle_creation_pad.Repairable = false
|
||||
vanu_vehicle_creation_pad.killBox = VehicleSpawnPadDefinition.prepareVanuKillBox(
|
||||
radius = 8.5f,
|
||||
aboveLimit = 5
|
||||
)
|
||||
vanu_vehicle_creation_pad.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 99999
|
||||
DamageRadiusMin = 14
|
||||
DamageRadius = 14.5f
|
||||
DamageAtEdge = 0.00002f
|
||||
//damage is 99999 at 14m, dropping rapidly to ~1 at 14.5m
|
||||
}
|
||||
|
||||
bfr_door.Name = "bfr_door"
|
||||
bfr_door.Damageable = false
|
||||
bfr_door.Repairable = false
|
||||
//bfr_door.VehicleCreationZOffset = -4.5f
|
||||
bfr_door.VehicleCreationZOrientOffset = 0f //90f
|
||||
bfr_door.killBox = VehicleSpawnPadDefinition.prepareBfrShedKillBox(
|
||||
radius = 10f,
|
||||
aboveLimit = 10f
|
||||
)
|
||||
bfr_door.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 99999
|
||||
DamageRadiusMin = 14 //TODO fix this
|
||||
DamageRadius = 14.5f //TODO fix this
|
||||
DamageAtEdge = 0.00002f
|
||||
//damage is 99999 at 14m, dropping rapidly to ~1 at 14.5m
|
||||
}
|
||||
|
||||
pad_create.Name = "pad_create"
|
||||
pad_create.Damageable = false
|
||||
pad_create.Repairable = false
|
||||
//pad_create.killBox = ...
|
||||
//pad_create.innateDamage = ...
|
||||
|
||||
pad_creation.Name = "pad_creation"
|
||||
pad_creation.Damageable = false
|
||||
pad_creation.Repairable = false
|
||||
pad_creation.VehicleCreationZOffset = 1.70982f
|
||||
//pad_creation.killBox = ...
|
||||
//pad_creation.innateDamage = ...
|
||||
|
||||
spawnpoint_vehicle.Name = "spawnpoint_vehicle"
|
||||
spawnpoint_vehicle.Damageable = false
|
||||
spawnpoint_vehicle.Repairable = false
|
||||
//spawnpoint_vehicle.killBox = ...
|
||||
//spawnpoint_vehicle.innateDamage = ...
|
||||
|
||||
mb_locker.Name = "mb_locker"
|
||||
mb_locker.Damageable = false
|
||||
mb_locker.Repairable = false
|
||||
|
||||
lock_external.Name = "lock_external"
|
||||
lock_external.Damageable = false
|
||||
lock_external.Repairable = false
|
||||
|
||||
amp_cap_door.Name = "amp_cap_door"
|
||||
|
||||
ancient_door.Name = "ancient_door"
|
||||
ancient_door.UseRadius = 1f
|
||||
//ancient_door.environmentField = InteriorDoorField()
|
||||
|
||||
ancient_garage_door.Name = "ancient_garage_door"
|
||||
ancient_garage_door.UseRadius = 1f
|
||||
//ancient_garage_door.environmentField = InteriorDoorField()
|
||||
|
||||
cryo_med_door.Name = "cryo_med_door"
|
||||
|
||||
cryo_room_door.Name = "cryo_room_door"
|
||||
|
||||
door.Name = "door"
|
||||
|
||||
door_airlock.Name = "door_airlock"
|
||||
|
||||
door_airlock_orb.Name = "door_airlock_orb"
|
||||
|
||||
door_dsp.Name = "door_dsp"
|
||||
|
||||
door_garage.Name = "door_garage"
|
||||
|
||||
door_interior.Name = "door_interior"
|
||||
|
||||
door_mb.Name = "door_mb"
|
||||
|
||||
door_mb_garage.Name = "door_mb_garage"
|
||||
|
||||
door_mb_main.Name = "door_mb_main"
|
||||
|
||||
door_mb_orb.Name = "door_mb_orb"
|
||||
|
||||
door_mb_side.Name = "door_mb_side"
|
||||
|
||||
door_nc_garage.Name = "door_nc_garage"
|
||||
|
||||
door_nc_rotating.Name = "door_nc_rotating"
|
||||
|
||||
door_ncside.Name = "door_ncside"
|
||||
|
||||
door_orbspawn.Name = "door_orbspawn"
|
||||
|
||||
door_spawn_mb.Name = "door_spawn_mb"
|
||||
door_spawn_mb.Damageable = true
|
||||
|
||||
garage_door.Name = "garage_door"
|
||||
|
||||
gr_door_airlock.Name = "gr_door_airlock"
|
||||
|
||||
gr_door_ext.Name = "gr_door_ext"
|
||||
gr_door_ext.UseRadius = 1.9f
|
||||
gr_door_ext.environmentField = InteriorDoorField()
|
||||
|
||||
gr_door_garage_ext.Name = "gr_door_garage_ext"
|
||||
gr_door_garage_ext.UseRadius = 11f
|
||||
gr_door_garage_ext.initialOpeningDistance = 8f
|
||||
gr_door_garage_ext.continuousOpenDistance = 9f
|
||||
gr_door_garage_ext.environmentField = InteriorDoorField(Some(-11), centerOn = true)
|
||||
|
||||
gr_door_garage_int.Name = "gr_door_garage_int"
|
||||
gr_door_garage_int.initialOpeningDistance = 8f
|
||||
gr_door_garage_int.continuousOpenDistance = 9f
|
||||
|
||||
gr_door_int.Name = "gr_door_int"
|
||||
|
||||
gr_door_main.Name = "gr_door_main"
|
||||
gr_door_main.UseRadius = 2.75f
|
||||
gr_door_main.environmentField = InteriorDoorField()
|
||||
|
||||
gr_door_mb_ext.Name = "gr_door_mb_ext"
|
||||
gr_door_mb_ext.UseRadius = 2f
|
||||
gr_door_mb_ext.environmentField = InteriorDoorField()
|
||||
|
||||
gr_door_mb_int.Name = "gr_door_mb_int"
|
||||
|
||||
gr_door_mb_lrg.Name = "gr_door_mb_lrg"
|
||||
gr_door_mb_lrg.UseRadius = 2.5f
|
||||
gr_door_mb_lrg.environmentField = InteriorDoorField()
|
||||
|
||||
gr_door_mb_obsd.Name = "gr_door_mb_obsd"
|
||||
|
||||
gr_door_mb_orb.Name = "gr_door_mb_orb"
|
||||
|
||||
gr_door_med.Name = "gr_door_med"
|
||||
|
||||
main_door.Name = "main_door"
|
||||
|
||||
shield_door.Name = "shield_door"
|
||||
|
||||
spawn_tube_door.Name = "spawn_tube_door"
|
||||
spawn_tube_door.Damageable = true
|
||||
|
||||
spawn_tube_door_coffin.Name = "spawn_tube_door_coffin"
|
||||
spawn_tube_door_coffin.Damageable = true
|
||||
|
||||
resource_silo.Name = "resource_silo"
|
||||
resource_silo.Damageable = false
|
||||
resource_silo.Repairable = false
|
||||
resource_silo.MaxNtuCapacitor = 1000
|
||||
resource_silo.ChargeTime = 105.seconds //from 0-100% in roughly 105s on live (~20%-100% https://youtu.be/veOWToR2nSk?t=1402)
|
||||
|
||||
capture_terminal.Name = "capture_terminal"
|
||||
capture_terminal.Damageable = false
|
||||
capture_terminal.Repairable = false
|
||||
capture_terminal.FacilityHackTime = 15.minutes
|
||||
|
||||
secondary_capture.Name = "secondary_capture"
|
||||
secondary_capture.Damageable = false
|
||||
secondary_capture.Repairable = false
|
||||
secondary_capture.FacilityHackTime = 1.millisecond
|
||||
|
||||
vanu_control_console.Name = "vanu_control_console"
|
||||
vanu_control_console.Damageable = false
|
||||
vanu_control_console.Repairable = false
|
||||
vanu_control_console.FacilityHackTime = 10.minutes
|
||||
|
||||
lodestar_repair_terminal.Name = "lodestar_repair_terminal"
|
||||
lodestar_repair_terminal.Interval = 1000
|
||||
lodestar_repair_terminal.HealAmount = 60
|
||||
lodestar_repair_terminal.UseRadius = 40
|
||||
lodestar_repair_terminal.TargetValidation += EffectTarget.Category.Vehicle -> EffectTarget.Validation.LodestarRepair
|
||||
lodestar_repair_terminal.Damageable = false
|
||||
lodestar_repair_terminal.Repairable = false
|
||||
|
||||
multivehicle_rearm_terminal.Name = "multivehicle_rearm_terminal"
|
||||
multivehicle_rearm_terminal.Tab += 3 -> EquipmentPage(
|
||||
EquipmentTerminalDefinition.vehicleAmmunition
|
||||
)
|
||||
multivehicle_rearm_terminal.Tab += 4 -> {
|
||||
val tab = VehicleLoadoutPage(10)
|
||||
tab.Exclude = List(CavernEquipmentQuestion)
|
||||
tab
|
||||
}
|
||||
multivehicle_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
||||
multivehicle_rearm_terminal.Damageable = false
|
||||
multivehicle_rearm_terminal.Repairable = false
|
||||
|
||||
bfr_rearm_terminal.Name = "bfr_rearm_terminal"
|
||||
bfr_rearm_terminal.Tab += 1 -> EquipmentPage(
|
||||
EquipmentTerminalDefinition.bfrAmmunition ++ EquipmentTerminalDefinition.bfrArmWeapons
|
||||
)
|
||||
bfr_rearm_terminal.Tab += 2 -> EquipmentPage(
|
||||
EquipmentTerminalDefinition.bfrAmmunition ++ EquipmentTerminalDefinition.bfrGunnerWeapons
|
||||
)
|
||||
bfr_rearm_terminal.Tab += 3 -> {
|
||||
val tab = VehicleLoadoutPage(15)
|
||||
tab.Exclude = List(CavernEquipmentQuestion)
|
||||
tab
|
||||
}
|
||||
bfr_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
||||
bfr_rearm_terminal.Damageable = false
|
||||
bfr_rearm_terminal.Repairable = false
|
||||
|
||||
air_rearm_terminal.Name = "air_rearm_terminal"
|
||||
air_rearm_terminal.Tab += 3 -> EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
||||
air_rearm_terminal.Tab += 4 -> {
|
||||
val tab = VehicleLoadoutPage(10)
|
||||
tab.Exclude = List(CavernEquipmentQuestion)
|
||||
tab
|
||||
}
|
||||
air_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
||||
air_rearm_terminal.Damageable = false
|
||||
air_rearm_terminal.Repairable = false
|
||||
|
||||
ground_rearm_terminal.Name = "ground_rearm_terminal"
|
||||
ground_rearm_terminal.Tab += 3 -> EquipmentPage(
|
||||
EquipmentTerminalDefinition.vehicleAmmunition
|
||||
)
|
||||
ground_rearm_terminal.Tab += 4 -> {
|
||||
val tab = VehicleLoadoutPage(10)
|
||||
tab.Exclude = List(CavernEquipmentQuestion)
|
||||
tab
|
||||
}
|
||||
ground_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
||||
ground_rearm_terminal.Damageable = false
|
||||
ground_rearm_terminal.Repairable = false
|
||||
|
||||
manned_turret.Name = "manned_turret"
|
||||
manned_turret.MaxHealth = 3600
|
||||
manned_turret.Damageable = true
|
||||
manned_turret.DamageDisablesAt = 1800
|
||||
manned_turret.Repairable = true
|
||||
manned_turret.autoRepair = AutoRepairStats(1.0909f, 10000, 1600, 0.05f)
|
||||
manned_turret.RepairIfDestroyed = true
|
||||
manned_turret.WeaponPaths += 1 -> new mutable.HashMap()
|
||||
manned_turret.WeaponPaths(1) += TurretUpgrade.None -> phalanx_sgl_hevgatcan
|
||||
manned_turret.WeaponPaths(1) += TurretUpgrade.AVCombo -> phalanx_avcombo
|
||||
manned_turret.WeaponPaths(1) += TurretUpgrade.FlakCombo -> phalanx_flakcombo
|
||||
manned_turret.Seats += 0 -> new SeatDefinition()
|
||||
manned_turret.controlledWeapons(seat = 0, weapon = 1)
|
||||
manned_turret.MountPoints += 1 -> MountInfo(0)
|
||||
manned_turret.FactionLocked = true
|
||||
manned_turret.ReserveAmmunition = false
|
||||
manned_turret.RadiationShielding = 0.5f
|
||||
manned_turret.AutoFire = Automation(
|
||||
AutoRanges(
|
||||
detection = 125f,
|
||||
trigger = 100f,
|
||||
escape = 200f
|
||||
),
|
||||
AutoChecks(
|
||||
validation = List(
|
||||
EffectTarget.Validation.FacilityTurretValidateMaxTarget,
|
||||
EffectTarget.Validation.FacilityTurretValidateGroundVehicleTarget,
|
||||
EffectTarget.Validation.FacilityTurretValidateAircraftTarget,
|
||||
EffectTarget.Validation.AutoTurretValidateMountableEntityTarget
|
||||
)
|
||||
),
|
||||
retaliatoryDelay = 4000L, //8000L
|
||||
cylindrical = true,
|
||||
cylindricalExtraHeight = 50f,
|
||||
detectionSweepTime = 2.seconds,
|
||||
refireTime = 362.milliseconds //312.milliseconds
|
||||
)
|
||||
manned_turret.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 150
|
||||
Damage1 = 300
|
||||
DamageRadius = 5
|
||||
DamageAtEdge = 0.1f
|
||||
Modifiers = ExplodingRadialDegrade
|
||||
}
|
||||
manned_turret.Geometry = GeometryForm.representByCylinder(radius = 1.2695f, height = 4.042f)
|
||||
|
||||
vanu_sentry_turret.Name = "vanu_sentry_turret"
|
||||
vanu_sentry_turret.MaxHealth = 1500
|
||||
vanu_sentry_turret.Damageable = true
|
||||
vanu_sentry_turret.DamageDisablesAt = 0
|
||||
vanu_sentry_turret.Repairable = true
|
||||
vanu_sentry_turret.autoRepair = AutoRepairStats(3.27272f, 10000, 1000, 0.05f)
|
||||
vanu_sentry_turret.RepairIfDestroyed = true
|
||||
vanu_sentry_turret.WeaponPaths += 1 -> new mutable.HashMap()
|
||||
vanu_sentry_turret.WeaponPaths(1) += TurretUpgrade.None -> vanu_sentry_turret_weapon
|
||||
vanu_sentry_turret.Seats += 0 -> new SeatDefinition()
|
||||
vanu_sentry_turret.controlledWeapons(seat = 0, weapon = 1)
|
||||
vanu_sentry_turret.MountPoints += 1 -> MountInfo(0)
|
||||
vanu_sentry_turret.MountPoints += 2 -> MountInfo(0)
|
||||
vanu_sentry_turret.FactionLocked = false
|
||||
vanu_sentry_turret.ReserveAmmunition = false
|
||||
vanu_sentry_turret.Geometry = GeometryForm.representByCylinder(radius = 1.76311f, height = 3.984375f)
|
||||
|
||||
painbox.Name = "painbox"
|
||||
painbox.alwaysOn = false
|
||||
painbox.sphereOffset = Vector3(0, 0, -0.4f)
|
||||
painbox.Damageable = false
|
||||
painbox.Repairable = false
|
||||
painbox.innateDamage = new DamageWithPosition {
|
||||
Damage0 = 2
|
||||
DamageRadius = 0
|
||||
DamageToHealthOnly = true
|
||||
}
|
||||
|
||||
painbox_continuous.Name = "painbox_continuous"
|
||||
painbox_continuous.sphereOffset = Vector3(0, 0, -0.4f)
|
||||
painbox_continuous.Damageable = false
|
||||
painbox_continuous.Repairable = false
|
||||
painbox_continuous.innateDamage = new DamageWithPosition {
|
||||
Damage0 = 2
|
||||
DamageRadius = 0
|
||||
DamageToHealthOnly = true
|
||||
}
|
||||
|
||||
painbox_door_radius.Name = "painbox_door_radius"
|
||||
painbox_door_radius.alwaysOn = false
|
||||
painbox_door_radius.sphereOffset = Vector3(0, 0, -0.4f)
|
||||
painbox_door_radius.hasNearestDoorDependency = true
|
||||
painbox_door_radius.Damageable = false
|
||||
painbox_door_radius.Repairable = false
|
||||
painbox_door_radius.innateDamage = new DamageWithPosition {
|
||||
Damage0 = 2
|
||||
DamageRadius = 10f * 0.6928f
|
||||
DamageToHealthOnly = true
|
||||
}
|
||||
|
||||
painbox_door_radius_continuous.Name = "painbox_door_radius_continuous"
|
||||
painbox_door_radius_continuous.sphereOffset = Vector3(0, 0, -0.4f)
|
||||
painbox_door_radius_continuous.hasNearestDoorDependency = true
|
||||
painbox_door_radius_continuous.Damageable = false
|
||||
painbox_door_radius_continuous.Repairable = false
|
||||
painbox_door_radius_continuous.innateDamage = new DamageWithPosition {
|
||||
Damage0 = 2
|
||||
DamageRadius = 10f * 0.6928f
|
||||
DamageToHealthOnly = true
|
||||
}
|
||||
|
||||
painbox_radius.Name = "painbox_radius"
|
||||
painbox_radius.alwaysOn = false
|
||||
painbox_radius.sphereOffset = Vector3(0, 0, -0.4f)
|
||||
painbox_radius.Damageable = false
|
||||
painbox_radius.Repairable = false
|
||||
painbox_radius.innateDamage = new DamageWithPosition {
|
||||
Damage0 = 2
|
||||
DamageRadius = 10f * 0.6928f
|
||||
DamageToHealthOnly = true
|
||||
}
|
||||
|
||||
painbox_radius_continuous.Name = "painbox_radius_continuous"
|
||||
painbox_radius_continuous.Damageable = false
|
||||
painbox_radius_continuous.Repairable = false
|
||||
painbox_radius_continuous.innateDamage = new DamageWithPosition {
|
||||
Damage0 = 2
|
||||
DamageRadius = 8.55f
|
||||
DamageToHealthOnly = true
|
||||
}
|
||||
|
||||
gen_control.Name = "gen_control"
|
||||
gen_control.Damageable = false
|
||||
gen_control.Repairable = false
|
||||
|
||||
generator.Name = "generator"
|
||||
generator.MaxHealth = 4000
|
||||
generator.Damageable = true
|
||||
generator.DamageableByFriendlyFire = false
|
||||
generator.Repairable = true
|
||||
generator.autoRepair = AutoRepairStats(0.77775f, 5000, 875, 1)
|
||||
generator.RepairDistance = 13.5f
|
||||
generator.RepairIfDestroyed = true
|
||||
generator.Subtract.Damage1 = 9
|
||||
generator.innateDamage = new DamageWithPosition {
|
||||
CausesDamageType = DamageType.One
|
||||
Damage0 = 99999
|
||||
DamageRadiusMin = 15
|
||||
DamageRadius = 15.1f
|
||||
DamageAtEdge = 0.000011f
|
||||
Modifiers = ExplodingRadialDegrade
|
||||
//damage is 99999 at 15m, dropping rapidly to ~1 at 15.1m
|
||||
}
|
||||
generator.Geometry = GeometryForm.representByCylinder(radius = 1.2617f, height = 9.14063f)
|
||||
|
||||
obbasemesh.Name = "obbasemesh"
|
||||
obbasemesh.Descriptor = "orbital_shuttle_pad"
|
||||
obbasemesh.Damageable = false
|
||||
obbasemesh.Repairable = false
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -3,8 +3,10 @@ package net.psforever.objects.serverobject.doors
|
|||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.serverobject.interior.Sidedness
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.packet.game.UseItemMessage
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
/**
|
||||
* A structure-owned server object that is a "door" that can open and can close.
|
||||
|
|
@ -12,6 +14,14 @@ import net.psforever.packet.game.UseItemMessage
|
|||
*/
|
||||
class Door(private val ddef: DoorDefinition) extends Amenity {
|
||||
private var openState: Option[Player] = None
|
||||
private var outwards: Option[Vector3] = None
|
||||
/*
|
||||
* Door sidedness does not reflect on the actual sidedness of anything that is in the door.
|
||||
* While sidedness will be correct for internal doors -
|
||||
* they are always passages between different between interior rooms in a facility -
|
||||
* external doors cross between the outside world and a interior room of a facility.
|
||||
*/
|
||||
WhichSide = Sidedness.InsideOf
|
||||
|
||||
def isOpen: Boolean = openState.isDefined
|
||||
|
||||
|
|
@ -26,6 +36,17 @@ class Door(private val ddef: DoorDefinition) extends Amenity {
|
|||
Open
|
||||
}
|
||||
|
||||
def Outwards: Vector3 = outwards.getOrElse(Orientation)
|
||||
|
||||
def Outwards_=(out: Vector3): Vector3 = {
|
||||
Outwards_=(Some(out))
|
||||
}
|
||||
|
||||
def Outwards_=(out: Option[Vector3]): Vector3 = {
|
||||
outwards = out
|
||||
Outwards
|
||||
}
|
||||
|
||||
/** Doors do not have health, so only check if they are damageable. */
|
||||
override def CanDamage : Boolean = Definition.Damageable
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,24 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.doors
|
||||
|
||||
import net.psforever.objects.serverobject.structures.AmenityDefinition
|
||||
import net.psforever.objects.geometry.GeometryForm
|
||||
import net.psforever.objects.geometry.d3.VolumetricGeometry
|
||||
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, PieceOfEnvironment}
|
||||
import net.psforever.objects.serverobject.structures.{Amenity, AmenityDefinition, CreateEnvironmentField}
|
||||
|
||||
final case class InteriorDoorField(
|
||||
cylinderHeight: Option[Float] = None,
|
||||
centerOn: Boolean = false
|
||||
) extends CreateEnvironmentField {
|
||||
def attribute: EnvironmentTrait = EnvironmentAttribute.InteriorField
|
||||
|
||||
def create(obj: Amenity): PieceOfEnvironment = {
|
||||
obj match {
|
||||
case door: Door => InteriorDoorPassage(door, cylinderHeight, centerOn)
|
||||
case _ => throw new IllegalArgumentException("expecting door")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The definition for any `Door`.
|
||||
|
|
@ -14,4 +31,6 @@ class DoorDefinition(objectId: Int)
|
|||
var initialOpeningDistance: Float = 7.5f
|
||||
/** range within which the door must detect a target player to remain open */
|
||||
var continuousOpenDistance: Float = 5.05f
|
||||
|
||||
override def Geometry: Any => VolumetricGeometry = GeometryForm.representBySphere(UseRadius)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.serverobject.doors
|
||||
|
||||
import net.psforever.objects.geometry.{GeometryForm, VolumetricEnvironmentCollision}
|
||||
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentCollision, EnvironmentTrait, PieceOfEnvironment}
|
||||
|
||||
final case class InteriorDoorPassage(
|
||||
door: Door,
|
||||
cylinderHeight: Option[Float] = None,
|
||||
centerOn: Boolean = false
|
||||
)
|
||||
extends PieceOfEnvironment {
|
||||
assert(door.Definition.UseRadius > 0f, s"door ${door.GUID} needs an interaction radius to be positive")
|
||||
private lazy val collisionObject = {
|
||||
val radius = door.Definition.UseRadius
|
||||
val g = (cylinderHeight, centerOn) match {
|
||||
case (Some(h), false) => GeometryForm.representByCylinder(radius, h) _
|
||||
case (Some(h), true) => GeometryForm.representByRaisedCylinder(radius, h) _
|
||||
case (None, false) => GeometryForm.representBySphereOnBase(radius) _
|
||||
case _ => GeometryForm.representBySphere(radius) _
|
||||
}
|
||||
VolumetricEnvironmentCollision(g.apply(door))
|
||||
}
|
||||
|
||||
/** a general description of this environment */
|
||||
override def attribute: EnvironmentTrait = EnvironmentAttribute.InteriorField
|
||||
|
||||
/** a special representation of the region that qualifies as "this environment" */
|
||||
override def collision: EnvironmentCollision = collisionObject
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) 2020-2024 PSForever
|
||||
package net.psforever.objects.serverobject.environment
|
||||
|
||||
import net.psforever.objects.{PlanetSideGameObject, Player, Vehicle}
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
/**
|
||||
* A general description of environment and its interactive possibilities.
|
||||
*/
|
||||
abstract class EnvironmentTrait {
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean
|
||||
}
|
||||
|
||||
object EnvironmentAttribute {
|
||||
case object Water extends EnvironmentTrait {
|
||||
/** water can only interact with objects that are negatively affected by being exposed to water;
|
||||
* it's better this way */
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = {
|
||||
obj.Definition.DrownAtMaxDepth ||
|
||||
obj.Definition.DisableAtMaxDepth ||
|
||||
canInteractWithPlayersAndVehicles(obj) ||
|
||||
(obj match {
|
||||
case p: Player => p.VehicleSeated.isEmpty
|
||||
case v: Vehicle => v.MountedIn.isEmpty
|
||||
case _ => false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
case object Lava extends EnvironmentTrait {
|
||||
/** lava can only interact with anything capable of registering damage */
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = canInteractWithDamagingFields(obj)
|
||||
}
|
||||
|
||||
case object Death extends EnvironmentTrait {
|
||||
/** death can only interact with anything capable of registering damage */
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = canInteractWithDamagingFields(obj)
|
||||
}
|
||||
|
||||
case object GantryDenialField
|
||||
extends EnvironmentTrait {
|
||||
/** only interact with living player characters */
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = {
|
||||
obj match {
|
||||
case p: Player => p.isAlive
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case object MovementFieldTrigger
|
||||
extends EnvironmentTrait {
|
||||
/** only interact with living player characters or vehicles */
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = canInteractWithPlayersAndVehicles(obj)
|
||||
}
|
||||
|
||||
case object InteriorField
|
||||
extends EnvironmentTrait {
|
||||
/** only interact with living player characters or vehicles */
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = canInteractWithPlayersAndVehicles(obj)
|
||||
}
|
||||
|
||||
/**
|
||||
* This environment field only interacts with anything capable of registering damage.
|
||||
* Also, exclude targets that are located at the game world origin.
|
||||
* @param obj target entity
|
||||
* @return whether or not this field affects the target entity
|
||||
*/
|
||||
def canInteractWithPlayersAndVehicles(obj: PlanetSideGameObject): Boolean = {
|
||||
(obj.Position != Vector3.Zero) ||
|
||||
(obj match {
|
||||
case p: Player => p.isAlive
|
||||
case v: Vehicle => !v.Destroyed
|
||||
case _ => false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* This environment field only interacts with living player characters or not-destroyed vehicles.
|
||||
* @param obj target entity
|
||||
* @return whether or not this field affects the target entity
|
||||
*/
|
||||
def canInteractWithDamagingFields(obj: PlanetSideGameObject): Boolean = {
|
||||
obj match {
|
||||
case o: Vitality => !o.Destroyed && o.Definition.Damageable
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2020 PSForever
|
||||
package net.psforever.objects.serverobject.environment
|
||||
|
||||
import net.psforever.objects.PlanetSideGameObject
|
||||
import net.psforever.objects.geometry.d2.Rectangle
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
|
|
@ -13,14 +14,22 @@ trait EnvironmentCollision {
|
|||
/** in general, the highest point in this geometry */
|
||||
def altitude: Float
|
||||
|
||||
/**
|
||||
* Is the test point "within" the bounds of the represented environment?
|
||||
* @param obj entity to test
|
||||
* @return `true`, if the point is sufficiently "deep";
|
||||
* `false`, otherwise
|
||||
*/
|
||||
def testInteraction(obj: PlanetSideGameObject): Boolean = testInteraction(obj, varDepth = 0)
|
||||
|
||||
/**
|
||||
* Is the test point "within" the bounds of the represented environment?
|
||||
* @param pos the test point
|
||||
* @param obj entity to test
|
||||
* @param varDepth how far "into" the environment the point must be
|
||||
* @return `true`, if the point is sufficiently "deep";
|
||||
* `false`, otherwise
|
||||
*/
|
||||
def testInteraction(pos: Vector3, varDepth: Float): Boolean
|
||||
def testInteraction(obj: PlanetSideGameObject, varDepth: Float): Boolean
|
||||
|
||||
def bounding: Rectangle
|
||||
}
|
||||
|
|
@ -32,8 +41,8 @@ trait EnvironmentCollision {
|
|||
*/
|
||||
final case class DeepPlane(altitude: Float)
|
||||
extends EnvironmentCollision {
|
||||
def testInteraction(pos: Vector3, varDepth: Float): Boolean = {
|
||||
pos.z + varDepth < altitude
|
||||
def testInteraction(obj: PlanetSideGameObject, varDepth: Float): Boolean = {
|
||||
obj.Position.z + varDepth < altitude
|
||||
}
|
||||
|
||||
def bounding: Rectangle = {
|
||||
|
|
@ -55,7 +64,8 @@ final case class DeepPlane(altitude: Float)
|
|||
*/
|
||||
final case class DeepSquare(altitude: Float, north: Float, east: Float, south: Float, west: Float)
|
||||
extends EnvironmentCollision {
|
||||
def testInteraction(pos: Vector3, varDepth: Float): Boolean = {
|
||||
def testInteraction(obj: PlanetSideGameObject, varDepth: Float): Boolean = {
|
||||
val pos = obj.Position
|
||||
pos.z + varDepth < altitude && north > pos.y && pos.y >= south && east > pos.x && pos.x >= west
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +86,8 @@ final case class DeepSquare(altitude: Float, north: Float, east: Float, south: F
|
|||
*/
|
||||
final case class DeepSurface(altitude: Float, north: Float, east: Float, south: Float, west: Float)
|
||||
extends EnvironmentCollision {
|
||||
def testInteraction(pos: Vector3, varDepth: Float): Boolean = {
|
||||
def testInteraction(obj: PlanetSideGameObject, varDepth: Float): Boolean = {
|
||||
val pos = obj.Position
|
||||
pos.z < altitude && north > pos.y && pos.y >= south && east > pos.x && pos.x >= west
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +106,8 @@ final case class DeepCircularSurface(center: Vector3, radius: Float)
|
|||
|
||||
def bounding: Rectangle = Rectangle(center.y + radius, center.x + radius, center.y - radius, center.x - radius)
|
||||
|
||||
def testInteraction(pos: Vector3, varDepth: Float): Boolean = {
|
||||
def testInteraction(obj: PlanetSideGameObject, varDepth: Float): Boolean = {
|
||||
val pos = obj.Position
|
||||
pos.z < center.z && Vector3.DistanceSquared(pos.xy, center.xy) < radius * radius
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
// Copyright (c) 2020 PSForever
|
||||
package net.psforever.objects.serverobject.environment
|
||||
|
||||
import enumeratum.{Enum, EnumEntry}
|
||||
import net.psforever.objects.{PlanetSideGameObject, Player, Vehicle}
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.objects.PlanetSideGameObject
|
||||
import net.psforever.objects.zones.blockmap.BlockMapEntity
|
||||
import net.psforever.types.{PlanetSideGUID, Vector3}
|
||||
|
||||
|
|
@ -20,12 +18,12 @@ trait PieceOfEnvironment
|
|||
|
||||
/**
|
||||
* Is the test point "within" the bounds of the represented environment?
|
||||
* @param pos the test point
|
||||
* @param obj entity to test
|
||||
* @param varDepth how far "into" the environment the point must be
|
||||
* @return `true`, if the point is sufficiently "deep";
|
||||
* `false`, otherwise
|
||||
*/
|
||||
def testInteraction(pos: Vector3, varDepth: Float): Boolean = collision.testInteraction(pos, varDepth)
|
||||
def testInteraction(obj: PlanetSideGameObject, varDepth: Float): Boolean = collision.testInteraction(obj, varDepth)
|
||||
|
||||
/**
|
||||
* Did the test point move into or leave the bounds of the represented environment since its previous test?
|
||||
|
|
@ -36,8 +34,8 @@ trait PieceOfEnvironment
|
|||
* `Some(false)`, if the point has left the sufficiently "deep" region;
|
||||
* `None`, otherwise
|
||||
*/
|
||||
def testStepIntoInteraction(pos: Vector3, previousPos: Vector3, varDepth: Float): Option[Boolean] =
|
||||
PieceOfEnvironment.testStepIntoInteraction(body = this, pos, previousPos, varDepth)
|
||||
def testStepIntoInteraction(pos: Vector3, obj: PlanetSideGameObject, previousPos: Vector3, varDepth: Float): Option[Boolean] =
|
||||
PieceOfEnvironment.testStepIntoInteraction(body = this, obj, pos, previousPos, varDepth)
|
||||
|
||||
def Position: Vector3 = collision.bounding.center.asVector3 + Vector3.z(collision.altitude)
|
||||
|
||||
|
|
@ -52,69 +50,34 @@ trait PieceOfEnvironment
|
|||
def Velocity_=(vec: Option[Vector3]): Option[Vector3] = None
|
||||
}
|
||||
|
||||
/**
|
||||
* A general description of environment and its interactive possibilities.
|
||||
*/
|
||||
sealed abstract class EnvironmentTrait extends EnumEntry {
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean
|
||||
}
|
||||
|
||||
object EnvironmentAttribute extends Enum[EnvironmentTrait] {
|
||||
/** glue connecting `EnumEntry` to `Enumeration` */
|
||||
val values: IndexedSeq[EnvironmentTrait] = findValues
|
||||
|
||||
case object Water extends EnvironmentTrait {
|
||||
/** water can only interact with objects that are negatively affected by being exposed to water;
|
||||
* it's better this way */
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = {
|
||||
obj.Definition.DrownAtMaxDepth || obj.Definition.DisableAtMaxDepth || (obj match {
|
||||
case p: Player => p.VehicleSeated.isEmpty
|
||||
case v: Vehicle => v.MountedIn.isEmpty
|
||||
case _ => true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
case object Lava extends EnvironmentTrait {
|
||||
/** lava can only interact with anything capable of registering damage */
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = {
|
||||
obj match {
|
||||
case o: Vitality => o.Definition.Damageable
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case object Death extends EnvironmentTrait {
|
||||
/** death can only interact with anything capable of registering damage */
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = {
|
||||
obj match {
|
||||
case o: Vitality => o.Definition.Damageable
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case object GantryDenialField
|
||||
extends EnvironmentTrait {
|
||||
/** only interact with living player characters */
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = {
|
||||
obj match {
|
||||
case p: Player => p.isAlive
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case object MovementFieldTrigger
|
||||
extends EnvironmentTrait {
|
||||
/** only interact with living player characters or vehicles */
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = {
|
||||
obj match {
|
||||
case p: Player => p.isAlive && p.Position != Vector3.Zero
|
||||
case v: Vehicle => !v.Destroyed && v.Position != Vector3.Zero
|
||||
case _ => false
|
||||
}
|
||||
object PieceOfEnvironment {
|
||||
/**
|
||||
* Did the test point move into or leave the bounds of the represented environment since its previous test?
|
||||
* @param body the environment
|
||||
* @param pos the test point
|
||||
* @param previousPos the previous test point which is being compared against
|
||||
* @param varDepth how far "into" the environment the point must be
|
||||
* @return `Some(true)`, if the point has become sufficiently "deep";
|
||||
* `Some(false)`, if the point has left the sufficiently "deep" region;
|
||||
* `None`, if the described points only exist outside of or only exists inside of the critical region
|
||||
*/
|
||||
def testStepIntoInteraction(
|
||||
body: PieceOfEnvironment,
|
||||
obj: PlanetSideGameObject,
|
||||
pos: Vector3,
|
||||
previousPos: Vector3,
|
||||
varDepth: Float
|
||||
): Option[Boolean] = {
|
||||
val originalPosition = obj.Position
|
||||
obj.Position = pos
|
||||
val isEncroaching = body.collision.testInteraction(obj, varDepth)
|
||||
obj.Position = previousPos
|
||||
val wasEncroaching = body.collision.testInteraction(obj, varDepth)
|
||||
obj.Position = originalPosition
|
||||
if (isEncroaching != wasEncroaching) {
|
||||
Some(isEncroaching)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -171,34 +134,12 @@ final case class GantryDenialField(
|
|||
mountPoint: Int,
|
||||
collision: EnvironmentCollision
|
||||
) extends PieceOfEnvironment {
|
||||
def attribute = EnvironmentAttribute.GantryDenialField
|
||||
def attribute: EnvironmentTrait = EnvironmentAttribute.GantryDenialField
|
||||
}
|
||||
|
||||
final case class GeneralMovementField(
|
||||
triggerAction: PlanetSideGameObject => Unit,
|
||||
collision: EnvironmentCollision
|
||||
) extends PieceOfEnvironment {
|
||||
def attribute = EnvironmentAttribute.MovementFieldTrigger
|
||||
}
|
||||
|
||||
object PieceOfEnvironment {
|
||||
/**
|
||||
* Did the test point move into or leave the bounds of the represented environment since its previous test?
|
||||
* @param body the environment
|
||||
* @param pos the test point
|
||||
* @param previousPos the previous test point which is being compared against
|
||||
* @param varDepth how far "into" the environment the point must be
|
||||
* @return `Some(true)`, if the point has become sufficiently "deep";
|
||||
* `Some(false)`, if the point has left the sufficiently "deep" region;
|
||||
* `None`, if the described points only exist outside of or only exists inside of the critical region
|
||||
*/
|
||||
def testStepIntoInteraction(body: PieceOfEnvironment, pos: Vector3, previousPos: Vector3, varDepth: Float): Option[Boolean] = {
|
||||
val isEncroaching = body.collision.testInteraction(pos, varDepth)
|
||||
val wasEncroaching = body.collision.testInteraction(previousPos, varDepth)
|
||||
if (isEncroaching != wasEncroaching) {
|
||||
Some(isEncroaching)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
def attribute: EnvironmentTrait = EnvironmentAttribute.MovementFieldTrigger
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,10 +117,9 @@ object InteractWithEnvironment {
|
|||
obj: PlanetSideServerObject,
|
||||
sector: SectorPopulation
|
||||
): Set[PieceOfEnvironment] = {
|
||||
val position = obj.Position
|
||||
val depth = GlobalDefinitions.MaxDepth(obj)
|
||||
sector.environmentList
|
||||
.filter(body => body.attribute.canInteractWith(obj) && body.testInteraction(position, depth))
|
||||
.filter(body => body.attribute.canInteractWith(obj) && body.testInteraction(obj, depth))
|
||||
.distinctBy(_.attribute)
|
||||
.toSet
|
||||
}
|
||||
|
|
@ -137,7 +136,7 @@ object InteractWithEnvironment {
|
|||
body: PieceOfEnvironment,
|
||||
obj: PlanetSideServerObject
|
||||
): Option[PieceOfEnvironment] = {
|
||||
if ((obj.Zone eq zone) && body.testInteraction(obj.Position, GlobalDefinitions.MaxDepth(obj))) {
|
||||
if ((obj.Zone eq zone) && body.testInteraction(obj, GlobalDefinitions.MaxDepth(obj))) {
|
||||
Some(body)
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.serverobject.interior
|
||||
|
||||
import net.psforever.objects.avatar.interaction.WithEntrance
|
||||
import net.psforever.objects.serverobject.environment.interaction.InteractWithEnvironment
|
||||
import net.psforever.objects.zones.InteractsWithZone
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
trait InteriorAware {
|
||||
def WhichSide: Sidedness
|
||||
def WhichSide_=(@unused thisSide: Sidedness): Sidedness
|
||||
}
|
||||
|
||||
trait TraditionalInteriorAware
|
||||
extends InteriorAware {
|
||||
private var side: Sidedness = Sidedness.StrictlyBetweenSides
|
||||
|
||||
def WhichSide: Sidedness = side
|
||||
|
||||
def WhichSide_=(thisSide: Sidedness): Sidedness = {
|
||||
side = thisSide
|
||||
WhichSide
|
||||
}
|
||||
}
|
||||
|
||||
trait InteriorAwareFromInteraction
|
||||
extends InteriorAware {
|
||||
awareness: InteractsWithZone =>
|
||||
private lazy val withEntrance: Option[WithEntrance] = {
|
||||
awareness
|
||||
.interaction()
|
||||
.collect { case i: InteractWithEnvironment => i.Interactions.values }
|
||||
.flatten
|
||||
.collectFirst { case i: WithEntrance => i }
|
||||
}
|
||||
|
||||
def WhichSide: Sidedness = {
|
||||
withEntrance.map(_.WhichSide).getOrElse(Sidedness.StrictlyBetweenSides)
|
||||
}
|
||||
|
||||
def WhichSide_=(thisSide: Sidedness): Sidedness = {
|
||||
withEntrance.foreach(_.WhichSide = thisSide)
|
||||
WhichSide
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.serverobject.interior
|
||||
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
|
||||
sealed trait SidenessComparison
|
||||
|
||||
sealed trait Sidedness {
|
||||
def opposite: Sidedness
|
||||
|
||||
protected def value: SidenessComparison
|
||||
}
|
||||
|
||||
object Sidedness {
|
||||
sealed trait Inside
|
||||
|
||||
sealed trait Outside
|
||||
|
||||
/* Comparison values */
|
||||
private case object IsInside extends SidenessComparison
|
||||
|
||||
private case object IsOutside extends SidenessComparison
|
||||
|
||||
private case object IsBetween extends SidenessComparison
|
||||
|
||||
/* Immutable value containers */
|
||||
case object InsideOf extends Inside with Sidedness {
|
||||
def opposite: Sidedness = OutsideOf
|
||||
protected def value: SidenessComparison = IsInside
|
||||
}
|
||||
|
||||
case object OutsideOf extends Outside with Sidedness {
|
||||
def opposite: Sidedness = InsideOf
|
||||
protected def value: SidenessComparison = IsOutside
|
||||
}
|
||||
|
||||
case object StrictlyBetweenSides extends Inside with Outside with Sidedness {
|
||||
def opposite: Sidedness = this
|
||||
protected def value: SidenessComparison = IsBetween
|
||||
}
|
||||
|
||||
/* Mutable value container */
|
||||
class InBetweenSides(
|
||||
private val door: Door,
|
||||
private val strictly: Sidedness
|
||||
) extends Inside with Outside with Sidedness {
|
||||
def opposite: Sidedness = this
|
||||
protected def value: SidenessComparison = {
|
||||
if (door.isOpen) {
|
||||
IsBetween
|
||||
} else {
|
||||
strictly.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object InBetweenSides {
|
||||
def apply(door: Door, strictly: Sidedness): InBetweenSides = new InBetweenSides(door, strictly)
|
||||
}
|
||||
|
||||
def equals(a: Sidedness, b: Sidedness): Boolean = {
|
||||
val avalue = a.value
|
||||
val bvalue = b.value
|
||||
(avalue eq bvalue) || avalue == IsBetween || bvalue == IsBetween
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import akka.actor.ActorRef
|
|||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
import net.psforever.objects.serverobject.hackable.Hackable
|
||||
import net.psforever.objects.serverobject.interior.Sidedness
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.packet.game.TriggeredSound
|
||||
import net.psforever.types.Vector3
|
||||
|
|
@ -23,6 +24,7 @@ class IFFLock(private val idef: IFFLockDefinition) extends Amenity with Hackable
|
|||
HackSound = TriggeredSound.HackDoor
|
||||
HackEffectDuration = Array(60, 180, 300, 360)
|
||||
HackDuration = Array(5, 3, 1, 1)
|
||||
WhichSide = Sidedness.InsideOf
|
||||
|
||||
/** a vector in the direction of the "outside" of a room;
|
||||
* typically, any locking utility is on that same "outside"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package net.psforever.objects.serverobject.mount
|
|||
import net.psforever.objects.ballistics.{Projectile, ProjectileQuality}
|
||||
import net.psforever.objects.sourcing.SourceEntry
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.objects.vital.base.{DamageResolution, DamageType}
|
||||
import net.psforever.objects.vital.base.DamageResolution
|
||||
import net.psforever.objects.vital.etc.RadiationReason
|
||||
import net.psforever.objects.vital.interaction.DamageInteraction
|
||||
import net.psforever.objects.vital.resistance.StandardResistanceProfile
|
||||
|
|
@ -38,17 +38,16 @@ class InteractWithRadiationCloudsSeatedInEntity(
|
|||
*/
|
||||
override def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit = {
|
||||
val position = target.Position
|
||||
val targetList = List(target)
|
||||
//collect all projectiles in sector/range
|
||||
val projectiles = sector
|
||||
.projectileList
|
||||
.filter { cloud =>
|
||||
val definition = cloud.Definition
|
||||
val radius = definition.DamageRadius
|
||||
definition.radiation_cloud &&
|
||||
definition.AllDamageTypes.contains(DamageType.Radiation) &&
|
||||
{
|
||||
val radius = definition.DamageRadius
|
||||
Zone.distanceCheck(target, cloud, radius * radius)
|
||||
}
|
||||
Zone.allOnSameSide(cloud, definition, targetList).nonEmpty &&
|
||||
Zone.distanceCheck(target, cloud, radius * radius)
|
||||
}
|
||||
.distinct
|
||||
val notSkipped = projectiles.filterNot { t => skipTargets.contains(t.GUID) }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.pad
|
||||
|
||||
import net.psforever.objects.serverobject.interior.Sidedness
|
||||
import net.psforever.objects.{Player, Vehicle}
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.objects.serverobject.terminals.Terminal
|
||||
|
|
@ -18,6 +19,8 @@ import net.psforever.types.PlanetSideGUID
|
|||
* @param spDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
||||
*/
|
||||
class VehicleSpawnPad(spDef: VehicleSpawnPadDefinition) extends Amenity {
|
||||
WhichSide = Sidedness.OutsideOf
|
||||
|
||||
def Definition: VehicleSpawnPadDefinition = spDef
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.pad.process
|
||||
|
||||
import akka.actor.Props
|
||||
import akka.actor.{ActorRef, Props}
|
||||
import akka.pattern.ask
|
||||
import akka.util.Timeout
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
|
|
@ -29,11 +29,11 @@ import scala.util.Success
|
|||
class VehicleSpawnControlLoadVehicle(pad: VehicleSpawnPad) extends VehicleSpawnControlBase(pad) {
|
||||
def LogId = "-loader"
|
||||
|
||||
val railJack = context.actorOf(Props(classOf[VehicleSpawnControlRailJack], pad), s"${context.parent.path.name}-rails")
|
||||
val railJack: ActorRef = context.actorOf(Props(classOf[VehicleSpawnControlRailJack], pad), s"${context.parent.path.name}-rails")
|
||||
|
||||
var temp: Option[VehicleSpawnControl.Order] = None
|
||||
|
||||
implicit val timeout = Timeout(3.seconds)
|
||||
implicit val timeout: Timeout = Timeout(3.seconds)
|
||||
|
||||
def receive: Receive = {
|
||||
case order @ VehicleSpawnControl.Order(driver, vehicle) =>
|
||||
|
|
@ -42,6 +42,7 @@ class VehicleSpawnControlLoadVehicle(pad: VehicleSpawnPad) extends VehicleSpawnC
|
|||
vehicle.Position = vehicle.Position - Vector3.z(
|
||||
if (GlobalDefinitions.isFlightVehicle(vehicle.Definition)) 9 else 5
|
||||
) //appear below the trench and doors
|
||||
vehicle.WhichSide = pad.WhichSide
|
||||
vehicle.Cloaked = vehicle.Definition.CanCloak && driver.Cloaked
|
||||
|
||||
temp = Some(order)
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ object PainboxControl {
|
|||
|| amenity.Definition == GlobalDefinitions.respawn_tube
|
||||
|| amenity.Definition == GlobalDefinitions.spawn_terminal
|
||||
|| amenity.Definition == GlobalDefinitions.order_terminal
|
||||
|| amenity.Definition == GlobalDefinitions.door)
|
||||
|| amenity.isInstanceOf[Door])
|
||||
&& amenity.Position.x > painbox.Position.x - planarRange && amenity.Position.x < painbox.Position.x + planarRange
|
||||
&& amenity.Position.y > painbox.Position.y - planarRange && amenity.Position.y < painbox.Position.y + planarRange
|
||||
&& amenity.Position.z > painbox.Position.z - belowRange && amenity.Position.z < painbox.Position.z + aboveRange
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
package net.psforever.objects.serverobject.resourcesilo
|
||||
|
||||
import akka.actor.{ActorContext, Props}
|
||||
import net.psforever.objects.serverobject.interior.Sidedness
|
||||
import net.psforever.objects.{CommonNtuContainer, GlobalDefinitions, Player}
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.packet.game.UseItemMessage
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
class ResourceSilo extends Amenity with CommonNtuContainer {
|
||||
|
||||
// For the flashing red light on top of the NTU silo on.
|
||||
|
|
@ -16,6 +19,7 @@ class ResourceSilo extends Amenity with CommonNtuContainer {
|
|||
// For the NTU display bar
|
||||
private var capacitorDisplay: Long = 0
|
||||
NtuCapacitor = Definition.MaxNtuCapacitor
|
||||
WhichSide = Sidedness.OutsideOf
|
||||
|
||||
def MaxNtuCapacitor : Float = Definition.MaxNtuCapacitor
|
||||
|
||||
|
|
@ -37,7 +41,7 @@ class ResourceSilo extends Amenity with CommonNtuContainer {
|
|||
|
||||
def Definition: ResourceSiloDefinition = GlobalDefinitions.resource_silo
|
||||
|
||||
def Use(player: Player, msg: UseItemMessage): ResourceSilo.Exchange = {
|
||||
def Use(@unused player: Player, @unused msg: UseItemMessage): ResourceSilo.Exchange = {
|
||||
ResourceSilo.ChargeEvent()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package net.psforever.objects.serverobject.structures
|
||||
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.serverobject.interior.{Sidedness, TraditionalInteriorAware}
|
||||
import net.psforever.objects.vital.resistance.StandardResistanceProfile
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.objects.vital.resolution.DamageAndResistance
|
||||
|
|
@ -25,7 +26,8 @@ abstract class Amenity
|
|||
extends PlanetSideServerObject
|
||||
with Vitality
|
||||
with StandardResistanceProfile
|
||||
with BlockMapEntity {
|
||||
with BlockMapEntity
|
||||
with TraditionalInteriorAware {
|
||||
private[this] val log = org.log4s.getLogger("Amenity")
|
||||
|
||||
/** what other entity has authority over this amenity; usually either a building or a vehicle */
|
||||
|
|
@ -34,6 +36,8 @@ abstract class Amenity
|
|||
/** if the entity exists at a specific position relative to the owner's position */
|
||||
private var offset: Option[Vector3] = None
|
||||
|
||||
WhichSide = Sidedness.InsideOf
|
||||
|
||||
def Faction: PlanetSideEmpire.Value = Owner.Faction
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,15 +2,25 @@
|
|||
package net.psforever.objects.serverobject.structures
|
||||
|
||||
import net.psforever.objects.definition.ObjectDefinition
|
||||
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment}
|
||||
import net.psforever.objects.vital.damage.DamageCalculations
|
||||
import net.psforever.objects.vital._
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
||||
import net.psforever.objects.vital.resolution.DamageResistanceModel
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
final case class AutoRepairStats(amount: Float, start: Long, repeat: Long, drain: Float)
|
||||
|
||||
trait CreateEnvironmentField {
|
||||
//todo a way to probe for this property from create(...)'s output
|
||||
def attribute: EnvironmentTrait
|
||||
|
||||
def create(@unused obj: Amenity): PieceOfEnvironment
|
||||
}
|
||||
|
||||
abstract class AmenityDefinition(objectId: Int)
|
||||
extends ObjectDefinition(objectId)
|
||||
extends ObjectDefinition(objectId)
|
||||
with ResistanceProfileMutators
|
||||
with DamageResistanceModel
|
||||
with VitalityDefinition {
|
||||
|
|
@ -21,10 +31,23 @@ abstract class AmenityDefinition(objectId: Int)
|
|||
|
||||
var autoRepair: Option[AutoRepairStats] = None
|
||||
|
||||
var fields: Seq[CreateEnvironmentField] = Seq()
|
||||
|
||||
def autoRepair_=(auto: AutoRepairStats): Option[AutoRepairStats] = {
|
||||
autoRepair = Some(auto)
|
||||
autoRepair
|
||||
}
|
||||
|
||||
def hasAutoRepair: Boolean = autoRepair.nonEmpty
|
||||
|
||||
def environmentField: Seq[CreateEnvironmentField] = fields
|
||||
|
||||
def environmentField_=(theField: CreateEnvironmentField): Seq[CreateEnvironmentField] = {
|
||||
environmentField_=(Seq(theField))
|
||||
}
|
||||
|
||||
def environmentField_=(theFields: Seq[CreateEnvironmentField]): Seq[CreateEnvironmentField] = {
|
||||
fields = fields ++ theFields
|
||||
environmentField
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import net.psforever.objects.PlanetSideGameObject
|
||||
import net.psforever.objects.definition.ObjectDefinition
|
||||
import net.psforever.objects.equipment.EffectTarget
|
||||
|
||||
import scala.collection.mutable
|
||||
|
|
@ -16,13 +15,12 @@ import scala.concurrent.duration.{Duration, FiniteDuration}
|
|||
* between the server and client using `ProximityTerminalUseMessage` game packets.
|
||||
*/
|
||||
trait ProximityDefinition {
|
||||
this: ObjectDefinition =>
|
||||
|
||||
private var interval: FiniteDuration = Duration(0, "seconds")
|
||||
private var useRadius: Float = 0f //TODO belongs on a wider range of object definitions
|
||||
private val targetValidation: mutable.HashMap[EffectTarget.Category.Value, PlanetSideGameObject => Boolean] =
|
||||
new mutable.HashMap[EffectTarget.Category.Value, PlanetSideGameObject => Boolean]()
|
||||
|
||||
def UseRadius: Float
|
||||
|
||||
def Interval: FiniteDuration = interval
|
||||
|
||||
def Interval_=(amount: Int): FiniteDuration = {
|
||||
|
|
@ -34,13 +32,6 @@ trait ProximityDefinition {
|
|||
Interval
|
||||
}
|
||||
|
||||
def UseRadius: Float = useRadius
|
||||
|
||||
def UseRadius_=(radius: Float): Float = {
|
||||
useRadius = radius
|
||||
UseRadius
|
||||
}
|
||||
|
||||
def TargetValidation: mutable.HashMap[EffectTarget.Category.Value, PlanetSideGameObject => Boolean] = targetValidation
|
||||
|
||||
def Validations: Seq[PlanetSideGameObject => Boolean] = {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import net.psforever.objects.serverobject.interior.Sidedness
|
||||
import net.psforever.objects.{Default, Player}
|
||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
|
|
@ -17,6 +18,8 @@ import net.psforever.services.Service
|
|||
* @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
||||
*/
|
||||
class ProximityTerminal(tdef: ProximityTerminalDefinition) extends Terminal(tdef) with ProximityUnit {
|
||||
WhichSide = Sidedness.StrictlyBetweenSides
|
||||
|
||||
override def Request(player: Player, msg: Any): Terminal.Exchange = {
|
||||
msg match {
|
||||
case message: CommonMessages.Use =>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package net.psforever.objects.serverobject.turret
|
||||
|
||||
import net.psforever.objects.equipment.JammableUnit
|
||||
import net.psforever.objects.serverobject.interior.Sidedness
|
||||
import net.psforever.objects.serverobject.structures.{Amenity, AmenityOwner, Building}
|
||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAware
|
||||
import net.psforever.objects.serverobject.turret.auto.AutomatedTurret
|
||||
|
|
@ -14,6 +15,7 @@ class FacilityTurret(tDef: FacilityTurretDefinition)
|
|||
with JammableUnit
|
||||
with CaptureTerminalAware {
|
||||
WeaponTurret.LoadDefinition(turret = this)
|
||||
WhichSide = Sidedness.OutsideOf
|
||||
|
||||
def TurretOwner: SourceEntry = {
|
||||
Seats
|
||||
|
|
@ -36,7 +38,6 @@ class FacilityTurret(tDef: FacilityTurretDefinition)
|
|||
}
|
||||
|
||||
object FacilityTurret {
|
||||
|
||||
/**
|
||||
* Overloaded constructor.
|
||||
* @param tDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ class VehicleControl(vehicle: Vehicle)
|
|||
if (seatNumber == 0 && !obj.OwnerName.contains(user.Name) && obj.Definition.CanBeOwned.nonEmpty) {
|
||||
//whatever vehicle was previously owned
|
||||
vehicle.Zone.GUID(user.avatar.vehicle) match {
|
||||
case Some(v : Vehicle) =>
|
||||
case Some(v: Vehicle) =>
|
||||
v.Actor ! Vehicle.Ownership(None)
|
||||
case _ =>
|
||||
user.avatar.vehicle = None
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.vehicles.interaction
|
||||
|
||||
import net.psforever.objects.Vehicle
|
||||
import net.psforever.objects.avatar.interaction.WithEntrance
|
||||
import net.psforever.objects.serverobject.doors.InteriorDoorPassage
|
||||
import net.psforever.objects.serverobject.environment.PieceOfEnvironment
|
||||
import net.psforever.objects.zones.InteractsWithZone
|
||||
|
||||
class WithEntranceInVehicle
|
||||
extends WithEntrance() {
|
||||
private var warningLevel: Int = 0
|
||||
private var lastWarning: Long = 0L
|
||||
|
||||
override def doInteractingWith(obj: InteractsWithZone, body: PieceOfEnvironment, data: Option[Any]): Unit = {
|
||||
super.doInteractingWith(obj, body, data)
|
||||
if (warningLevel == -1) {
|
||||
warnAboutProximity(obj, msg = "@InvalidTerrain_VehicleNowSafe")
|
||||
warningLevel = 0
|
||||
} else if (!body.asInstanceOf[InteriorDoorPassage].door.Definition.Name.contains("garage")) {
|
||||
val curr = System.currentTimeMillis()
|
||||
if (curr - lastWarning >= 5000L) {
|
||||
if (warningLevel > 3) {
|
||||
import scala.concurrent.duration._
|
||||
obj.Actor ! Vehicle.Deconstruct(Some(2.seconds))
|
||||
} else if (warningLevel > 0) {
|
||||
warnAboutProximity(obj, msg = "@InvalidTerrain_VehicleWillDeconstruct")
|
||||
}
|
||||
lastWarning = curr
|
||||
warningLevel += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def stopInteractingWith(obj: InteractsWithZone, body: PieceOfEnvironment, data: Option[Any]): Unit = {
|
||||
super.stopInteractingWith(obj, body, data)
|
||||
warningLevel = -1
|
||||
}
|
||||
|
||||
private def warnAboutProximity(obj: InteractsWithZone, msg: String): Unit = {
|
||||
import net.psforever.packet.game.ChatMsg
|
||||
import net.psforever.services.Service
|
||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
import net.psforever.types.ChatMessageType
|
||||
obj.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
obj.Actor.toString(),
|
||||
AvatarAction.SendResponse(Service.defaultPlayerGUID, ChatMsg(ChatMessageType.UNK_227, msg))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -42,6 +42,11 @@ trait DamageProperties
|
|||
private var charging: Option[ChargeDamage] = None
|
||||
/** a destroyed mine will detonate rather than fizzle-out */
|
||||
private var sympathy: Boolean = false
|
||||
/** radiation clouds create independent damage-dealing areas in a zone that last for the projectile's lifespan;
|
||||
* not implicate a damage type (primary or secondary or aggravated) of `Radiation` */
|
||||
private var radiationCloud: Boolean = false
|
||||
/** server damage is applied when comparing against sided-ness of the source and the target */
|
||||
private var damageThroughWalls: Boolean = false
|
||||
|
||||
def UseDamage1Subtract: Boolean = useDamage1Subtract
|
||||
|
||||
|
|
@ -132,4 +137,18 @@ trait DamageProperties
|
|||
sympathy = chain
|
||||
SympatheticExplosion
|
||||
}
|
||||
|
||||
def radiation_cloud: Boolean = radiationCloud
|
||||
|
||||
def radiation_cloud_=(isCloud: Boolean): Boolean = {
|
||||
radiationCloud = isCloud
|
||||
radiation_cloud
|
||||
}
|
||||
|
||||
def DamageThroughWalls: Boolean = damageThroughWalls
|
||||
|
||||
def DamageThroughWalls_=(through: Boolean): Boolean = {
|
||||
damageThroughWalls = through
|
||||
DamageThroughWalls
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,14 +35,19 @@ import net.psforever.actors.session.AvatarActor
|
|||
import net.psforever.actors.zone.ZoneActor
|
||||
import net.psforever.actors.zone.building.WarpGateLogic
|
||||
import net.psforever.objects.avatar.Avatar
|
||||
import net.psforever.objects.definition.ObjectDefinition
|
||||
import net.psforever.objects.geometry.d3.VolumetricGeometry
|
||||
import net.psforever.objects.guid.pool.NumberPool
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
import net.psforever.objects.serverobject.environment.EnvironmentAttribute
|
||||
import net.psforever.objects.serverobject.interior.{InteriorAware, Sidedness}
|
||||
import net.psforever.objects.serverobject.locks.IFFLock
|
||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
|
||||
import net.psforever.objects.serverobject.shuttle.OrbitalShuttlePad
|
||||
import net.psforever.objects.serverobject.terminals.{ProximityTerminal, Terminal}
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.sourcing.SourceEntry
|
||||
import net.psforever.objects.vehicles.{MountedWeapons, UtilityType}
|
||||
|
|
@ -50,8 +55,9 @@ import net.psforever.objects.vital.etc.ExplodingEntityReason
|
|||
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
|
||||
import net.psforever.objects.vital.prop.DamageWithPosition
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.objects.zones.blockmap.BlockMap
|
||||
import net.psforever.objects.zones.blockmap.{BlockMap, SectorPopulation}
|
||||
import net.psforever.services.Service
|
||||
import net.psforever.zones.Zones
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.mutable
|
||||
|
|
@ -469,6 +475,33 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
|
|||
}
|
||||
}
|
||||
|
||||
def GetEntities(definition: ObjectDefinition): List[PlanetSideGameObject] = {
|
||||
GetEntities(List(definition))
|
||||
}
|
||||
|
||||
def GetEntities(definitions: List[ObjectDefinition]): List[PlanetSideGameObject] = {
|
||||
definitions
|
||||
.distinct
|
||||
.groupBy(_.registerAs)
|
||||
.flatMap { case (registerName, defs) =>
|
||||
GetEntities(registerName)
|
||||
.filter(obj => defs.contains(obj.Definition))
|
||||
}
|
||||
.toList
|
||||
}
|
||||
|
||||
def GetEntities(name: String): List[PlanetSideGameObject] = {
|
||||
guid
|
||||
.GetPool(name)
|
||||
.map { pool =>
|
||||
pool
|
||||
.Numbers
|
||||
.flatMap(guid.apply(_))
|
||||
.collect { case obj: PlanetSideGameObject => obj }
|
||||
}
|
||||
.getOrElse(List[PlanetSideGameObject]())
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps around the globally unique identifier system to remove an existing number pool.
|
||||
* Throws exceptions for specific reasons if the pool can not be removed before the system has been started.
|
||||
|
|
@ -660,17 +693,11 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
|
|||
(buildings.get(building_id), guid(object_guid)) match {
|
||||
case (Some(building), Some(amenity: Amenity)) =>
|
||||
building.Amenities = amenity
|
||||
//amenity.History(EntitySpawn(SourceEntry(amenity), this))
|
||||
case (Some(_), _) | (None, _) | (_, None) => ; //let ZoneActor's sanity check catch this error
|
||||
case (Some(_), _) | (None, _) | (_, None) => () //let ZoneActor's sanity check catch this error
|
||||
}
|
||||
})
|
||||
//doors with nearby locks use those locks as their unlocking mechanism
|
||||
//let ZoneActor's sanity check catch missing entities
|
||||
map.doorToLock
|
||||
.map { case(doorGUID: Int, lockGUID: Int) => (guid(doorGUID), guid(lockGUID)) }
|
||||
.collect { case (Some(door: Door), Some(lock: IFFLock)) =>
|
||||
door.Actor ! Door.UpdateMechanism(IFFLock.testLock(lock))
|
||||
}
|
||||
Zone.AssignOutwardSideToDoors(zone = this)
|
||||
Zone.AssignSidednessToAmenities(zone = this)
|
||||
//ntu management (eventually move to a generic building startup function)
|
||||
buildings.values
|
||||
.flatMap(_.Amenities.filter(_.Definition == GlobalDefinitions.resource_silo))
|
||||
|
|
@ -884,6 +911,298 @@ object Zone {
|
|||
new Zone(id, map, number)
|
||||
}
|
||||
|
||||
private def AssignOutwardSideToDoors(zone: Zone): Unit = {
|
||||
//let ZoneActor's sanity check catch any missing entities
|
||||
//todo there are no doors in the training zones so we may skip that
|
||||
if (zone.map.cavern) {
|
||||
//todo what do?
|
||||
//almost all are type ancient_door and don't have many hints to determine outward-ness; there are no IFF locks
|
||||
} else if (
|
||||
PlanetSideEmpire.values
|
||||
.filterNot(_ == PlanetSideEmpire.NEUTRAL)
|
||||
.exists(fac => Zones.sanctuaryZoneNumber(fac) == zone.Number)
|
||||
) {
|
||||
AssignOutwardSideToSanctuaryDoors(zone)
|
||||
} else {
|
||||
AssignOutwardSidetoContinentDoors(zone)
|
||||
}
|
||||
}
|
||||
|
||||
private def AssignOutwardSideToSanctuaryDoors(zone: Zone): Unit = {
|
||||
val map = zone.map
|
||||
val guid = zone.guid
|
||||
AssignOutwardsToIFFLockedDoors(zone)
|
||||
//doors with IFF locks belong to towers and are always between; the locks are always outside
|
||||
map.doorToLock
|
||||
.map { case (door, lock) => (guid(door), guid(lock)) }
|
||||
.collect { case (Some(door: Door), Some(lock: IFFLock)) =>
|
||||
door.WhichSide = Sidedness.StrictlyBetweenSides
|
||||
lock.WhichSide = Sidedness.OutsideOf
|
||||
}
|
||||
//spawn building doors
|
||||
val buildings = zone.Buildings.values
|
||||
val amenityList = buildings
|
||||
.collect {
|
||||
case b
|
||||
if b.Definition.Name.startsWith("VT_building_") =>
|
||||
val amenities = b.Amenities
|
||||
(
|
||||
amenities.collect { case door: Door if door.Definition == GlobalDefinitions.gr_door_mb_ext => door },
|
||||
amenities.collect { case door: Door if door.Definition == GlobalDefinitions.gr_door_mb_lrg => door },
|
||||
amenities.filter(_.Definition == GlobalDefinitions.order_terminal),
|
||||
amenities.filter(_.Definition == GlobalDefinitions.respawn_tube_sanctuary)
|
||||
)
|
||||
}
|
||||
amenityList.foreach { case (entranceDoors, trainingRangeDoors, terminals, tubes) =>
|
||||
entranceDoors.foreach { door =>
|
||||
val doorPosition = door.Position
|
||||
val closestTerminal = terminals.minBy(t => Vector3.DistanceSquared(doorPosition, t.Position))
|
||||
val closestTube = tubes.minBy(t => Vector3.DistanceSquared(doorPosition, t.Position))
|
||||
door.WhichSide = Sidedness.StrictlyBetweenSides
|
||||
door.Outwards = Vector3.Unit(closestTerminal.Position.xy - closestTube.Position.xy)
|
||||
}
|
||||
//training zone warp doors
|
||||
val sampleDoor = entranceDoors.head.Position.xy;
|
||||
{
|
||||
val doorToDoorVector = Vector3.Unit(sampleDoor - entranceDoors(1).Position.xy)
|
||||
val (listADoors, listBDoors) = trainingRangeDoors
|
||||
.sortBy(door => Vector3.DistanceSquared(door.Position.xy, sampleDoor))
|
||||
.partition { door =>
|
||||
Vector3.ScalarProjection(doorToDoorVector, Vector3.Unit(door.Position.xy - sampleDoor)) > 0f
|
||||
}
|
||||
Seq(listADoors, listBDoors)
|
||||
}.foreach { doors =>
|
||||
val door0PosXY = doors.head.Position.xy
|
||||
val door1PosXY = doors(1).Position.xy
|
||||
val door2PosXY = doors(2).Position.xy
|
||||
val outwardsMiddle = Vector3.Unit((door0PosXY + door2PosXY) * 0.5f - door1PosXY)
|
||||
val center = door1PosXY + (outwardsMiddle * 19.5926f)
|
||||
doors.head.Outwards = Vector3.Unit(center - door0PosXY)
|
||||
doors(1).Outwards = outwardsMiddle
|
||||
doors(2).Outwards = Vector3.Unit(center - door2PosXY)
|
||||
}
|
||||
}
|
||||
//hart building doors
|
||||
buildings
|
||||
.collect {
|
||||
case b
|
||||
if b.Definition.Name.startsWith("orbital_building_") =>
|
||||
val amenities = b.Amenities
|
||||
(
|
||||
amenities.filter(_.Definition == GlobalDefinitions.gr_door_mb_ext),
|
||||
amenities.filter(_.Definition == GlobalDefinitions.gr_door_mb_orb)
|
||||
)
|
||||
}
|
||||
.foreach { case (entranceDoors, hartDoors) =>
|
||||
entranceDoors.foreach { door =>
|
||||
val isReallyADoor = door.asInstanceOf[Door]
|
||||
val doorPosition = door.Position
|
||||
val closestHartDoor = hartDoors.minBy(t => Vector3.DistanceSquared(doorPosition, t.Position))
|
||||
isReallyADoor.WhichSide = Sidedness.StrictlyBetweenSides
|
||||
isReallyADoor.Outwards = Vector3.Unit(doorPosition.xy - closestHartDoor.Position.xy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def AssignOutwardSidetoContinentDoors(zone: Zone): Unit = {
|
||||
val map = zone.map
|
||||
val guid = zone.guid
|
||||
AssignOutwardsToIFFLockedDoors(zone)
|
||||
val buildingsToDoors = zone.Buildings.values.map(b => (b, b.Amenities.collect { case d: Door => d })).toMap
|
||||
//external doors with IFF locks are always between and outside, respectively
|
||||
map.doorToLock
|
||||
.map { case (door, lock) => (guid(door), guid(lock)) }
|
||||
.collect { case (Some(door: Door), Some(lock: IFFLock))
|
||||
if door.Definition.environmentField.exists(f => f.attribute == EnvironmentAttribute.InteriorField) =>
|
||||
door.WhichSide = Sidedness.StrictlyBetweenSides
|
||||
lock.WhichSide = Sidedness.OutsideOf
|
||||
}
|
||||
//for major facilities, external doors in the courtyard are paired, connected by a passage between ground and walls
|
||||
//they are the only external doors that do not have iff locks
|
||||
buildingsToDoors
|
||||
.filter { case (b, _) => b.BuildingType == StructureType.Facility }
|
||||
.foreach { case (_, doors) =>
|
||||
var unpairedDoors = doors.collect {
|
||||
case d: Door
|
||||
if d.Definition == GlobalDefinitions.gr_door_ext && !map.doorToLock.contains(d.GUID.guid) =>
|
||||
d
|
||||
}
|
||||
var pairedDoors = Seq[(Door, Door)]()
|
||||
while (unpairedDoors.size > 1) {
|
||||
val sampleDoor = unpairedDoors.head
|
||||
val sampleDoorPosition = sampleDoor.Position.xy
|
||||
val distances = Float.MaxValue +: unpairedDoors
|
||||
.map(d => Vector3.DistanceSquared(d.Position.xy, sampleDoorPosition))
|
||||
.drop(1)
|
||||
val min = distances.min
|
||||
val indexOfClosestDoor = distances.indexWhere(_ == min)
|
||||
val otherDoor = unpairedDoors(indexOfClosestDoor)
|
||||
unpairedDoors = unpairedDoors.slice(1, indexOfClosestDoor) ++ unpairedDoors.drop(indexOfClosestDoor + 1)
|
||||
pairedDoors = pairedDoors :+ (sampleDoor, otherDoor)
|
||||
}
|
||||
pairedDoors.foreach { case (door1, door2) =>
|
||||
//give each paired courtyard door an outward-ness
|
||||
val outwards = Vector3.Unit(door1.Position.xy - door2.Position.xy)
|
||||
door1.Outwards = outwards
|
||||
door1.WhichSide = Sidedness.StrictlyBetweenSides
|
||||
door2.Outwards = Vector3.neg(outwards)
|
||||
door2.WhichSide = Sidedness.StrictlyBetweenSides
|
||||
}
|
||||
}
|
||||
//bunkers do not define a formal interior, so their doors are solely exterior
|
||||
buildingsToDoors
|
||||
.filter { case (b, _) => b.BuildingType == StructureType.Bunker }
|
||||
.foreach { case (_, doors) =>
|
||||
doors.foreach(_.WhichSide = Sidedness.OutsideOf)
|
||||
}
|
||||
}
|
||||
|
||||
private def AssignOutwardsToIFFLockedDoors(zone: Zone): Unit = {
|
||||
val guid = zone.guid
|
||||
//doors with nearby locks use those locks as their unlocking mechanism and their outwards indication
|
||||
zone.map.doorToLock
|
||||
.map { case (doorGUID: Int, lockGUID: Int) => (guid(doorGUID), guid(lockGUID)) }
|
||||
.collect {
|
||||
case (Some(door: Door), Some(lock: IFFLock)) =>
|
||||
door.Outwards = lock.Outwards
|
||||
door.Actor ! Door.UpdateMechanism(IFFLock.testLock(lock))
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
||||
private def AssignSidednessToAmenities(zone: Zone): Unit = {
|
||||
//let ZoneActor's sanity check catch any missing entities
|
||||
//todo training zones, where everything is outside
|
||||
if (zone.map.cavern) {
|
||||
//todo what do?
|
||||
/*
|
||||
quite a few amenities are disconnected from buildings
|
||||
there are two orientations of terminal/spawn pad
|
||||
as aforementioned, door outwards and sidedness is not assignable at the moment
|
||||
*/
|
||||
} else if (
|
||||
PlanetSideEmpire.values
|
||||
.filterNot(_ == PlanetSideEmpire.NEUTRAL)
|
||||
.exists(fac => Zones.sanctuaryZoneNumber(fac) == zone.Number)
|
||||
) {
|
||||
AssignSidednessToSanctuaryAmenities(zone)
|
||||
} else {
|
||||
AssignSidednessToContinentAmenities(zone)
|
||||
}
|
||||
}
|
||||
|
||||
private def AssignSidednessToSanctuaryAmenities(zone: Zone): Unit = {
|
||||
val map = zone.map
|
||||
val guid = zone.guid
|
||||
//only tower doors possess locks and those are always external
|
||||
map.doorToLock
|
||||
.map { case (_, lock) => guid(lock) }
|
||||
.collect {
|
||||
case Some(lock: IFFLock) =>
|
||||
lock.WhichSide = Sidedness.OutsideOf
|
||||
}
|
||||
//medical terminals are always inside
|
||||
zone.buildings
|
||||
.values
|
||||
.flatMap(_.Amenities)
|
||||
.collect {
|
||||
case pt: ProximityTerminal if pt.Definition == GlobalDefinitions.medical_terminal =>
|
||||
pt.WhichSide = Sidedness.InsideOf
|
||||
}
|
||||
//repair silos and landing pads have multiple components and all of these are outside
|
||||
//we have to search all terminal entities because the repair silos are not installed anywhere
|
||||
guid
|
||||
.GetPool(name = "terminals")
|
||||
.map(_.Numbers.flatMap(number => guid(number)))
|
||||
.getOrElse(List())
|
||||
.collect {
|
||||
case pt: ProximityTerminal
|
||||
if pt.Definition == GlobalDefinitions.repair_silo =>
|
||||
val guid = pt.GUID.guid
|
||||
Seq(guid, guid + 1, guid + 2, guid + 3)
|
||||
case pt: ProximityTerminal
|
||||
if pt.Definition.Name.startsWith("pad_landing_") =>
|
||||
val guid = pt.GUID.guid
|
||||
Seq(guid, guid + 1, guid + 2)
|
||||
}
|
||||
.flatten[Int]
|
||||
.map(guid(_))
|
||||
.collect {
|
||||
case Some(pt: ProximityTerminal) =>
|
||||
pt.WhichSide = Sidedness.OutsideOf
|
||||
}
|
||||
//the following terminals are installed outside
|
||||
map.terminalToSpawnPad
|
||||
.keys
|
||||
.flatMap(guid(_))
|
||||
.collect {
|
||||
case terminal: Terminal =>
|
||||
terminal.WhichSide = Sidedness.OutsideOf
|
||||
}
|
||||
}
|
||||
|
||||
private def AssignSidednessToContinentAmenities(zone: Zone): Unit = {
|
||||
val map = zone.map
|
||||
val guid = zone.guid
|
||||
val buildingsMap = zone.buildings.values
|
||||
//door locks on external doors are also external while the door is merely "between"; all other locks are internal
|
||||
map.doorToLock
|
||||
.map { case (door, lock) => (guid(door), guid(lock))}
|
||||
.collect {
|
||||
case (Some(door: Door), Some(lock: IFFLock))
|
||||
if door.Definition.environmentField.exists(f => f.attribute == EnvironmentAttribute.InteriorField) =>
|
||||
lock.WhichSide = Sidedness.OutsideOf
|
||||
}
|
||||
//medical terminals are always inside
|
||||
buildingsMap
|
||||
.flatMap(_.Amenities)
|
||||
.collect {
|
||||
case pt: ProximityTerminal
|
||||
if pt.Definition == GlobalDefinitions.medical_terminal || pt.Definition == GlobalDefinitions.adv_med_terminal =>
|
||||
pt.WhichSide = Sidedness.InsideOf
|
||||
}
|
||||
//repair silos and landing pads have multiple components and all of these are outside
|
||||
buildingsMap
|
||||
.flatMap(_.Amenities)
|
||||
.collect {
|
||||
case pt: ProximityTerminal
|
||||
if pt.Definition == GlobalDefinitions.repair_silo =>
|
||||
val guid = pt.GUID.guid
|
||||
Seq(guid, guid + 1, guid + 2, guid + 3)
|
||||
case pt: ProximityTerminal
|
||||
if pt.Definition.Name.startsWith("pad_landing_") =>
|
||||
val guid = pt.GUID.guid
|
||||
Seq(guid, guid + 1, guid + 2)
|
||||
}
|
||||
.toSeq
|
||||
.flatten[Int]
|
||||
.map(guid(_))
|
||||
.collect {
|
||||
case Some(pt: ProximityTerminal) =>
|
||||
pt.WhichSide = Sidedness.OutsideOf
|
||||
}
|
||||
//all vehicle spawn pads are outside, save for the ground vehicle pad in the tech plants
|
||||
buildingsMap.collect {
|
||||
case b
|
||||
if b.Definition == GlobalDefinitions.tech_plant =>
|
||||
b.Amenities
|
||||
.collect { case pad: VehicleSpawnPad => pad }
|
||||
.minBy(_.Position.z)
|
||||
.WhichSide = Sidedness.InsideOf
|
||||
}
|
||||
//all vehicle terminals are outside of their owning facilities in the courtyard
|
||||
//the only exceptions are vehicle terminals in tech plants and the dropship center air terminal
|
||||
map.terminalToSpawnPad
|
||||
.keys
|
||||
.flatMap(guid(_))
|
||||
.collect {
|
||||
case terminal: Terminal
|
||||
if terminal.Definition != GlobalDefinitions.dropship_vehicle_terminal &&
|
||||
terminal.Owner.asInstanceOf[Building].Definition != GlobalDefinitions.tech_plant =>
|
||||
terminal.WhichSide = Sidedness.OutsideOf
|
||||
}
|
||||
}
|
||||
|
||||
object Population {
|
||||
|
||||
/**
|
||||
|
|
@ -1329,42 +1648,96 @@ object Zone {
|
|||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* @see `DamageWithPosition`
|
||||
* @see `Zone.blockMap.sector`
|
||||
* @param zone the zone in which the explosion should occur
|
||||
* @param source a game entity that is treated as the origin and is excluded from results
|
||||
* @param damagePropertiesBySource information about the effect/damage
|
||||
* @return a list of affected entities
|
||||
*/
|
||||
def findAllTargets(
|
||||
zone: Zone,
|
||||
source: PlanetSideGameObject with Vitality,
|
||||
damagePropertiesBySource: DamageWithPosition
|
||||
): List[PlanetSideServerObject with Vitality] = {
|
||||
findAllTargets(zone, source.Position, damagePropertiesBySource).filter { target => target ne source }
|
||||
* na
|
||||
* @param source na
|
||||
* @param damageProperties na
|
||||
* @param targets na
|
||||
* @return na
|
||||
*/
|
||||
def allOnSameSide(
|
||||
source: PlanetSideGameObject,
|
||||
damageProperties: DamageWithPosition,
|
||||
targets: List[PlanetSideServerObject with Vitality]
|
||||
): List[PlanetSideServerObject with Vitality] = {
|
||||
source match {
|
||||
case awareSource: InteriorAware if !damageProperties.DamageThroughWalls =>
|
||||
allOnSameSide(awareSource.WhichSide, targets)
|
||||
case _ if !damageProperties.DamageThroughWalls =>
|
||||
val sourcePosition = source.Position
|
||||
targets
|
||||
.sortBy(t => Vector3.DistanceSquared(sourcePosition, t.Position))
|
||||
.collectFirst { case awareSource: InteriorAware => allOnSameSide(awareSource.WhichSide, targets) }
|
||||
.getOrElse(targets)
|
||||
case _ =>
|
||||
targets
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param side na
|
||||
* @param targets na
|
||||
* @return na
|
||||
*/
|
||||
def allOnSameSide(
|
||||
side: Sidedness,
|
||||
targets: List[PlanetSideServerObject with Vitality]
|
||||
): List[PlanetSideServerObject with Vitality] = {
|
||||
targets.flatMap {
|
||||
case awareTarget: InteriorAware if !Sidedness.equals(side, awareTarget.WhichSide) => None
|
||||
case anyTarget => Some(anyTarget)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* @see `DamageWithPosition`
|
||||
* @see `Zone.blockMap.sector`
|
||||
* @param sourcePosition a custom position that is used as the origin of the explosion;
|
||||
* not necessarily related to source
|
||||
* @param zone the zone in which the explosion should occur
|
||||
* @param source a game entity that is treated as the origin and is excluded from results
|
||||
* @param damagePropertiesBySource information about the effect/damage
|
||||
* @return a list of affected entities
|
||||
*/
|
||||
def findAllTargets(
|
||||
sourcePosition: Vector3
|
||||
)
|
||||
(
|
||||
zone: Zone,
|
||||
source: PlanetSideGameObject with Vitality,
|
||||
damagePropertiesBySource: DamageWithPosition
|
||||
): List[PlanetSideServerObject with Vitality] = {
|
||||
findAllTargets(zone, sourcePosition, damagePropertiesBySource).filter { target => target ne source }
|
||||
findAllTargets(
|
||||
zone,
|
||||
source,
|
||||
source.Position,
|
||||
damagePropertiesBySource,
|
||||
damagePropertiesBySource.DamageRadius,
|
||||
getAllTargets
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* @see `DamageWithPosition`
|
||||
* @see `Zone.blockMap.sector`
|
||||
* @param zone the zone in which the explosion should occur
|
||||
* @param sourcePosition a custom position that is used as the origin of the explosion;
|
||||
* not necessarily related to source
|
||||
* @param source a game entity that is treated as the origin and is excluded from results
|
||||
* @param damagePropertiesBySource information about the effect/damage
|
||||
* @return a list of affected entities
|
||||
*/
|
||||
def findAllTargets(
|
||||
zone: Zone,
|
||||
source: PlanetSideGameObject with Vitality,
|
||||
sourcePosition: Vector3,
|
||||
damagePropertiesBySource: DamageWithPosition
|
||||
): List[PlanetSideServerObject with Vitality] = {
|
||||
findAllTargets(
|
||||
zone,
|
||||
source,
|
||||
sourcePosition,
|
||||
damagePropertiesBySource,
|
||||
damagePropertiesBySource.DamageRadius,
|
||||
getAllTargets
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1374,24 +1747,66 @@ object Zone {
|
|||
* @param zone the zone in which the explosion should occur
|
||||
* @param sourcePosition a position that is used as the origin of the explosion
|
||||
* @param damagePropertiesBySource information about the effect/damage
|
||||
* @param getTargetsFromSector get this list of entities from a sector
|
||||
* @return a list of affected entities
|
||||
*/
|
||||
def findAllTargets(
|
||||
zone: Zone,
|
||||
source: PlanetSideGameObject with Vitality,
|
||||
sourcePosition: Vector3,
|
||||
damagePropertiesBySource: DamageWithPosition
|
||||
damagePropertiesBySource: DamageWithPosition,
|
||||
radius: Float,
|
||||
getTargetsFromSector: SectorPopulation => List[PlanetSideServerObject with Vitality]
|
||||
): List[PlanetSideServerObject with Vitality] = {
|
||||
val sourcePositionXY = sourcePosition.xy
|
||||
val sectors = zone.blockMap.sector(sourcePositionXY, damagePropertiesBySource.DamageRadius)
|
||||
allOnSameSide(
|
||||
source,
|
||||
damagePropertiesBySource,
|
||||
findAllTargets(zone, sourcePosition, radius, getTargetsFromSector).filter { target => target ne source }
|
||||
)
|
||||
}
|
||||
|
||||
def findAllTargets(
|
||||
sector: SectorPopulation,
|
||||
source: PlanetSideGameObject with Vitality,
|
||||
damagePropertiesBySource: DamageWithPosition,
|
||||
getTargetsFromSector: SectorPopulation => List[PlanetSideServerObject with Vitality]
|
||||
): List[PlanetSideServerObject with Vitality] = {
|
||||
allOnSameSide(
|
||||
source,
|
||||
damagePropertiesBySource,
|
||||
getTargetsFromSector(sector)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* @see `DamageWithPosition`
|
||||
* @see `Zone.blockMap.sector`
|
||||
* @param zone the zone in which the explosion should occur
|
||||
* @param sourcePosition a position that is used as the origin of the explosion
|
||||
* @param radius idistance
|
||||
* @param getTargetsFromSector get this list of entities from a sector
|
||||
* @return a list of affected entities
|
||||
*/
|
||||
def findAllTargets(
|
||||
zone: Zone,
|
||||
sourcePosition: Vector3,
|
||||
radius: Float,
|
||||
getTargetsFromSector: SectorPopulation => List[PlanetSideServerObject with Vitality]
|
||||
): List[PlanetSideServerObject with Vitality] = {
|
||||
getTargetsFromSector(zone.blockMap.sector(sourcePosition.xy, radius))
|
||||
}
|
||||
|
||||
def getAllTargets(sector: SectorPopulation): List[PlanetSideServerObject with Vitality] = {
|
||||
//collect all targets that can be damaged
|
||||
//players
|
||||
val playerTargets = sectors.livePlayerList.filterNot { _.VehicleSeated.nonEmpty }
|
||||
val playerTargets = sector.livePlayerList.filterNot { _.VehicleSeated.nonEmpty }
|
||||
//vehicles
|
||||
val vehicleTargets = sectors.vehicleList.filterNot { v => v.Destroyed || v.MountedIn.nonEmpty }
|
||||
val vehicleTargets = sector.vehicleList.filterNot { v => v.Destroyed || v.MountedIn.nonEmpty }
|
||||
//deployables
|
||||
val deployableTargets = sectors.deployableList.filterNot { _.Destroyed }
|
||||
val deployableTargets = sector.deployableList.filterNot { _.Destroyed }
|
||||
//amenities
|
||||
val soiTargets = sectors.amenityList.collect { case amenity: Vitality if !amenity.Destroyed => amenity }
|
||||
val soiTargets = sector.amenityList.collect { case amenity: Vitality if !amenity.Destroyed => amenity }
|
||||
//altogether ...
|
||||
playerTargets ++ vehicleTargets ++ deployableTargets ++ soiTargets
|
||||
}
|
||||
|
|
@ -1411,7 +1826,9 @@ object Zone {
|
|||
target: PlanetSideGameObject with FactionAffinity with Vitality
|
||||
): DamageInteraction = {
|
||||
explosionDamage(instigation, target.Position)(source, target)
|
||||
}/**
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param instigation what previous event happened, if any, that caused this explosion
|
||||
* @param explosionPosition the coordinates of the detected explosion
|
||||
|
|
|
|||
|
|
@ -200,7 +200,11 @@ class Sector(val longitude: Int, val latitude: Int, val span: Int)
|
|||
case b: Building =>
|
||||
buildings.list.size < buildings.addTo(b).size
|
||||
case a: Amenity =>
|
||||
amenities.list.size < amenities.addTo(a).size
|
||||
val added = amenities.list.size < amenities.addTo(a).size
|
||||
if (added) {
|
||||
a.Definition.environmentField.foreach(field => environment.addTo(field.create(a)))
|
||||
}
|
||||
added
|
||||
case e: PieceOfEnvironment =>
|
||||
environment.list.size < environment.addTo(e).size
|
||||
case p: Projectile =>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
// Copyright (c) 2021 PSForever
|
||||
package net.psforever.packet.game
|
||||
|
||||
import net.psforever.packet.GamePacketOpcode.Type
|
||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||
import net.psforever.types.{PlanetSideGUID, Vector3}
|
||||
import scodec.Attempt.Successful
|
||||
import scodec.Codec
|
||||
import scodec.bits.BitVector
|
||||
import scodec.{Attempt, Codec}
|
||||
import scodec.codecs._
|
||||
import shapeless.{::, HNil}
|
||||
|
||||
|
|
@ -15,7 +17,7 @@ object TerrainCondition extends Enumeration {
|
|||
type Type = Value
|
||||
val Safe, Unsafe = Value
|
||||
|
||||
implicit val codec = PacketHelpers.createEnumerationCodec(e = this, uint(bits = 1))
|
||||
implicit val codec: Codec[TerrainCondition.Value] = PacketHelpers.createEnumerationCodec(e = this, uint(bits = 1))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -34,8 +36,8 @@ final case class InvalidTerrainMessage(
|
|||
pos: Vector3
|
||||
) extends PlanetSideGamePacket {
|
||||
type Packet = InvalidTerrainMessage
|
||||
def opcode = GamePacketOpcode.InvalidTerrainMessage
|
||||
def encode = InvalidTerrainMessage.encode(this)
|
||||
def opcode: Type = GamePacketOpcode.InvalidTerrainMessage
|
||||
def encode: Attempt[BitVector] = InvalidTerrainMessage.encode(this)
|
||||
}
|
||||
|
||||
object InvalidTerrainMessage extends Marshallable[InvalidTerrainMessage] {
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ object ChatMessageType extends Enum[ChatMessageType] {
|
|||
case object CMT_ADD_VANUMODULE extends ChatMessageType // /moduleadd
|
||||
case object CMT_REMOVE_VANUMODULE extends ChatMessageType // /moduleremove OR /modulerm
|
||||
case object CMT_DEBUG_MASSIVE extends ChatMessageType // /debugmassive
|
||||
case object CMT_WARP_TO_NEXT_BILLBOARD extends ChatMessageType // ???
|
||||
case object CMT_WARP_TO_NEXT_BILLBOARD extends ChatMessageType // The "Next" button on the /debugmassive UI produces this message.
|
||||
case object UNK_222 extends ChatMessageType // "CTF Flag stolen"
|
||||
// Plays a trumpet-like sound and displays the message: "<Base Type> <Base Name> has spawned a LLU"
|
||||
// "It must be taken to <Base Type> <Base Name>'s Control Console within 15 minutes or the hack will fail!"
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ final case class Vector3(x: Float, y: Float, z: Float) {
|
|||
object Vector3 {
|
||||
final val Zero: Vector3 = Vector3(0f, 0f, 0f)
|
||||
|
||||
def unapply(v: Vector3): Option[(Float, Float, Float)] = Some((v.x, v.y, v.z))
|
||||
|
||||
private def closeToInsignificance(d: Float, epsilon: Float = 10f): Float = {
|
||||
val ulp = math.ulp(epsilon)
|
||||
math.signum(d) match {
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ case class HartConfig(
|
|||
|
||||
case class DevelopmentConfig(
|
||||
unprivilegedGmCommands: Seq[ChatMessageType],
|
||||
unprivilegedGmBangCommands: Seq[String],
|
||||
netSim: NetSimConfig
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -177,23 +177,44 @@ object Zones {
|
|||
)
|
||||
|
||||
private val doorTypes = Seq(
|
||||
"gr_door_garage_int",
|
||||
"gr_door_int",
|
||||
"gr_door_med",
|
||||
"spawn_tube_door",
|
||||
"amp_cap_door",
|
||||
"ancient_door",
|
||||
"ancient_garage_door",
|
||||
"cryo_med_door",
|
||||
"cryo_room_door",
|
||||
"door",
|
||||
"door_airlock",
|
||||
"door_airlock_orb",
|
||||
"door_dsp",
|
||||
"door_garage",
|
||||
"door_interior",
|
||||
"door_mb",
|
||||
"door_mb_garage",
|
||||
"door_mb_main",
|
||||
"door_mb_orb",
|
||||
"door_mb_side",
|
||||
"door_nc_garage",
|
||||
"door_nc_rotating",
|
||||
"door_ncside",
|
||||
"door_orbspawn",
|
||||
"door_spawn_mb",
|
||||
"garage_door",
|
||||
"gr_door_airlock",
|
||||
"gr_door_ext",
|
||||
"gr_door_garage_ext",
|
||||
"gr_door_garage_int",
|
||||
"gr_door_int",
|
||||
"gr_door_main",
|
||||
"gr_door_mb_ext",
|
||||
"gr_door_mb_int",
|
||||
"gr_door_mb_lrg",
|
||||
"gr_door_mb_obsd",
|
||||
"gr_door_mb_orb",
|
||||
"door_spawn_mb",
|
||||
"ancient_door",
|
||||
"ancient_garage_door"
|
||||
"gr_door_med",
|
||||
"main_door",
|
||||
"shield_door",
|
||||
"spawn_tube_door",
|
||||
"spawn_tube_door_coffin"
|
||||
)
|
||||
|
||||
lazy val zoneMaps: Seq[ZoneMap] = {
|
||||
|
|
@ -384,14 +405,6 @@ object Zones {
|
|||
owningBuildingGuid = ownerGuid
|
||||
)
|
||||
|
||||
case "gr_door_mb_orb" =>
|
||||
zoneMap
|
||||
.addLocalObject(
|
||||
obj.guid,
|
||||
Door.Constructor(obj.position, GlobalDefinitions.gr_door_mb_orb),
|
||||
owningBuildingGuid = ownerGuid
|
||||
)
|
||||
|
||||
case doorType if doorType.equals("door_spawn_mb") || doorType.equals("spawn_tube_door") =>
|
||||
zoneMap.addLocalObject(
|
||||
obj.guid,
|
||||
|
|
@ -404,23 +417,29 @@ object Zones {
|
|||
|
||||
case objectType if doorTypes.contains(objectType) =>
|
||||
zoneMap
|
||||
.addLocalObject(obj.guid, Door.Constructor(obj.position), owningBuildingGuid = ownerGuid)
|
||||
.addLocalObject(
|
||||
obj.guid,
|
||||
Door.Constructor(
|
||||
obj.position,
|
||||
DefinitionUtil.fromString(objectType).asInstanceOf[DoorDefinition]
|
||||
),
|
||||
owningBuildingGuid = ownerGuid
|
||||
)
|
||||
|
||||
case "locker_cryo" | "locker_med" | "mb_locker" =>
|
||||
zoneMap
|
||||
.addLocalObject(obj.guid, Locker.Constructor(obj.position), owningBuildingGuid = ownerGuid)
|
||||
|
||||
case "lock_external" | "lock_garage" | "lock_small" =>
|
||||
val closestDoor = doors.minBy(d => Vector3.Distance(d.position, obj.position))
|
||||
|
||||
// Since tech plant garage locks are the only type where the lock does not face the same direction as the door we need to apply an offset for those, otherwise the door won't operate properly when checking inside/outside angles.
|
||||
val yawOffset = if (obj.objectType == "lock_garage") 90 else 0
|
||||
|
||||
val position = obj.position
|
||||
val closestDoor = doors.minBy(d => Vector3.Distance(d.position, position))
|
||||
// Ignore duplicate lock objects, for example Sobek (and other Dropship Centers) CC door has 2 locks stacked on top of each other
|
||||
if (!zoneMap.doorToLock.keys.iterator.contains(closestDoor.guid)) {
|
||||
// Since tech plant garage locks are the only type where the lock does not face the same direction as the door we need to apply an offset for those, otherwise the door won't operate properly when checking inside/outside angles.
|
||||
val yawOffset = if (obj.objectType == "lock_garage") 90 else 0
|
||||
zoneMap.addLocalObject(
|
||||
obj.guid,
|
||||
IFFLock.Constructor(obj.position, Vector3(0, 0, obj.yaw + yawOffset)),
|
||||
IFFLock.Constructor(position, Vector3.z(obj.yaw + yawOffset)),
|
||||
owningBuildingGuid = ownerGuid,
|
||||
doorGuid = closestDoor.guid
|
||||
)
|
||||
|
|
@ -798,7 +817,7 @@ object Zones {
|
|||
}
|
||||
}
|
||||
|
||||
lazy val cavernLattice = {
|
||||
lazy val cavernLattice: Map[String, Iterable[Iterable[String]]] = {
|
||||
val res = Source.fromResource(s"zonemaps/lattice.json")
|
||||
val json = res.mkString
|
||||
res.close()
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
package objects
|
||||
|
||||
import net.psforever.objects.avatar.Avatar
|
||||
import net.psforever.objects.{GlobalDefinitions, Player, Tool, Vehicle}
|
||||
import net.psforever.objects.definition.VehicleDefinition
|
||||
import net.psforever.objects.{GlobalDefinitions, PlanetSideGameObject, Player, Tool, Vehicle}
|
||||
import net.psforever.objects.definition.{ObjectDefinition, VehicleDefinition}
|
||||
import net.psforever.objects.serverobject.environment._
|
||||
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalDefinition}
|
||||
import net.psforever.objects.vital.Vitality
|
||||
|
|
@ -11,6 +11,10 @@ import net.psforever.packet.game.objectcreate.ObjectClass
|
|||
import net.psforever.types._
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
private class PSGOTest() extends PlanetSideGameObject() {
|
||||
override def Definition: ObjectDefinition = null
|
||||
}
|
||||
|
||||
class EnvironmentCollisionTest extends Specification {
|
||||
"DeepPlane" should {
|
||||
val point: Float = 10f
|
||||
|
|
@ -21,15 +25,23 @@ class EnvironmentCollisionTest extends Specification {
|
|||
}
|
||||
|
||||
"must have interaction that passes" in {
|
||||
plane.testInteraction(Vector3(0,0,10), varDepth = -1) mustEqual true
|
||||
plane.testInteraction(Vector3(0,0, 9), varDepth = 0) mustEqual true
|
||||
plane.testInteraction(Vector3(0,0, 8), varDepth = 1) mustEqual true
|
||||
val obj = new PSGOTest()
|
||||
obj.Position = Vector3(0,0,10)
|
||||
plane.testInteraction(obj, varDepth = -1) mustEqual true
|
||||
obj.Position = Vector3(0,0,9)
|
||||
plane.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(0,0,8)
|
||||
plane.testInteraction(obj, varDepth = 1) mustEqual true
|
||||
}
|
||||
|
||||
"must have interaction that fails" in {
|
||||
plane.testInteraction(Vector3(0,0,11), varDepth = -1) mustEqual false
|
||||
plane.testInteraction(Vector3(0,0,10), varDepth = 0) mustEqual false
|
||||
plane.testInteraction(Vector3(0,0, 9), varDepth = 1) mustEqual false
|
||||
val obj = new PSGOTest()
|
||||
obj.Position = Vector3(0,0,11)
|
||||
plane.testInteraction(obj, varDepth = -1) mustEqual false
|
||||
obj.Position = Vector3(0,0,10)
|
||||
plane.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(0,0,9)
|
||||
plane.testInteraction(obj, varDepth = 1) mustEqual false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,23 +54,39 @@ class EnvironmentCollisionTest extends Specification {
|
|||
}
|
||||
|
||||
"must have interaction that passes" in {
|
||||
square.testInteraction(Vector3(1,1, 0), varDepth = 0) mustEqual true
|
||||
square.testInteraction(Vector3(1,8, 0), varDepth = 0) mustEqual true
|
||||
square.testInteraction(Vector3(8,8, 0), varDepth = 0) mustEqual true
|
||||
square.testInteraction(Vector3(8,1, 0), varDepth = 0) mustEqual true
|
||||
square.testInteraction(Vector3(1,1,10), varDepth = -1) mustEqual true
|
||||
square.testInteraction(Vector3(1,1, 9), varDepth = 0) mustEqual true
|
||||
square.testInteraction(Vector3(1,1, 8), varDepth = 1) mustEqual true
|
||||
val obj = new PSGOTest()
|
||||
obj.Position = Vector3(1,1, 0)
|
||||
square.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(1,8, 0)
|
||||
square.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(8,8, 0)
|
||||
square.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(8,1, 0)
|
||||
square.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(1,1,10)
|
||||
square.testInteraction(obj, varDepth = -1) mustEqual true
|
||||
obj.Position = Vector3(1,1, 9)
|
||||
square.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(1,1, 8)
|
||||
square.testInteraction(obj, varDepth = 1) mustEqual true
|
||||
}
|
||||
|
||||
"must have interaction that fails" in {
|
||||
square.testInteraction(Vector3(1,0, 0), varDepth = 0) mustEqual false
|
||||
square.testInteraction(Vector3(1,9, 0), varDepth = 0) mustEqual false
|
||||
square.testInteraction(Vector3(0,9, 0), varDepth = 0) mustEqual false
|
||||
square.testInteraction(Vector3(0,1, 0), varDepth = 0) mustEqual false
|
||||
square.testInteraction(Vector3(1,1,11), varDepth = -1) mustEqual false
|
||||
square.testInteraction(Vector3(1,1,10), varDepth = 0) mustEqual false
|
||||
square.testInteraction(Vector3(1,1, 9), varDepth = 1) mustEqual false
|
||||
val obj = new PSGOTest()
|
||||
obj.Position = Vector3(1,0, 0)
|
||||
square.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(1,9, 0)
|
||||
square.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(0,9, 0)
|
||||
square.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(0,1, 0)
|
||||
square.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(1,1,11)
|
||||
square.testInteraction(obj, varDepth = -1) mustEqual false
|
||||
obj.Position = Vector3(1,1,10)
|
||||
square.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(1,1, 9)
|
||||
square.testInteraction(obj, varDepth = 1) mustEqual false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,22 +99,37 @@ class EnvironmentCollisionTest extends Specification {
|
|||
}
|
||||
|
||||
"must have interaction that passes" in {
|
||||
surface.testInteraction(Vector3(1,1,0), varDepth = 0) mustEqual true
|
||||
surface.testInteraction(Vector3(1,8,0), varDepth = 0) mustEqual true
|
||||
surface.testInteraction(Vector3(8,8,0), varDepth = 0) mustEqual true
|
||||
surface.testInteraction(Vector3(8,1,0), varDepth = 0) mustEqual true
|
||||
surface.testInteraction(Vector3(1,1,9), varDepth = -1) mustEqual true
|
||||
surface.testInteraction(Vector3(1,1,9), varDepth = 0) mustEqual true
|
||||
surface.testInteraction(Vector3(1,1,9), varDepth = 1) mustEqual true
|
||||
val obj = new PSGOTest()
|
||||
obj.Position = Vector3(1,1,0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(1,8,0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(8,8,0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(8,1,0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(1,1,9)
|
||||
surface.testInteraction(obj, varDepth = -1) mustEqual true
|
||||
obj.Position = Vector3(1,1,9)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(1,1,9)
|
||||
surface.testInteraction(obj, varDepth = 1) mustEqual true
|
||||
}
|
||||
|
||||
"must have interaction that fails" in {
|
||||
surface.testInteraction(Vector3(1,0, 0), varDepth = 0) mustEqual false
|
||||
surface.testInteraction(Vector3(1,9, 0), varDepth = 0) mustEqual false
|
||||
surface.testInteraction(Vector3(0,9, 0), varDepth = 0) mustEqual false
|
||||
surface.testInteraction(Vector3(0,1, 0), varDepth = 0) mustEqual false
|
||||
surface.testInteraction(Vector3(1,1,11), varDepth = -1) mustEqual false
|
||||
surface.testInteraction(Vector3(1,1,10), varDepth = 0) mustEqual false
|
||||
val obj = new PSGOTest()
|
||||
obj.Position = Vector3(1,0, 0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(1,9, 0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(0,9, 0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(0,1, 0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(1,1,11)
|
||||
surface.testInteraction(obj, varDepth = -1) mustEqual false
|
||||
obj.Position = Vector3(1,1,10)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -100,22 +143,37 @@ class EnvironmentCollisionTest extends Specification {
|
|||
}
|
||||
|
||||
"must have interaction that passes" in {
|
||||
surface.testInteraction(Vector3(3,1,0), varDepth = 0) mustEqual true
|
||||
surface.testInteraction(Vector3(1,3,0), varDepth = 0) mustEqual true
|
||||
surface.testInteraction(Vector3(3,5,0), varDepth = 0) mustEqual true
|
||||
surface.testInteraction(Vector3(5,3,0), varDepth = 0) mustEqual true
|
||||
surface.testInteraction(Vector3(2,2,9), varDepth = -1) mustEqual true
|
||||
surface.testInteraction(Vector3(2,2,9), varDepth = 0) mustEqual true
|
||||
surface.testInteraction(Vector3(2,2,9), varDepth = 1) mustEqual true
|
||||
val obj = new PSGOTest()
|
||||
obj.Position = Vector3(3,1,0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(1,3,0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(3,5,0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(5,3,0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(2,2,9)
|
||||
surface.testInteraction(obj, varDepth = -1) mustEqual true
|
||||
obj.Position = Vector3(2,2,9)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual true
|
||||
obj.Position = Vector3(2,2,9)
|
||||
surface.testInteraction(obj, varDepth = 1) mustEqual true
|
||||
}
|
||||
|
||||
"must have interaction that fails" in {
|
||||
surface.testInteraction(Vector3(3,0, 0), varDepth = 0) mustEqual false
|
||||
surface.testInteraction(Vector3(0,3, 0), varDepth = 0) mustEqual false
|
||||
surface.testInteraction(Vector3(3,6, 0), varDepth = 0) mustEqual false
|
||||
surface.testInteraction(Vector3(6,3, 0), varDepth = 0) mustEqual false
|
||||
surface.testInteraction(Vector3(2,2,11), varDepth = -1) mustEqual false
|
||||
surface.testInteraction(Vector3(2,2,10), varDepth = 0) mustEqual false
|
||||
val obj = new PSGOTest()
|
||||
obj.Position = Vector3(3,0, 0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(0,3, 0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(3,6, 0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(6,3, 0)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
obj.Position = Vector3(2,2,11)
|
||||
surface.testInteraction(obj, varDepth = -1) mustEqual false
|
||||
obj.Position = Vector3(2,2,10)
|
||||
surface.testInteraction(obj, varDepth = 0) mustEqual false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -237,21 +295,23 @@ class SeaLevelTest extends Specification {
|
|||
}
|
||||
|
||||
"must have interaction that passes (same as DeepPlane)" in {
|
||||
plane.testInteraction(Vector3(0,0,10), varDepth = -1) mustEqual
|
||||
level.testInteraction(Vector3(0,0,10), varDepth = -1)
|
||||
plane.testInteraction(Vector3(0,0, 9), varDepth = 0) mustEqual
|
||||
level.testInteraction(Vector3(0,0, 9), varDepth = 0)
|
||||
plane.testInteraction(Vector3(0,0, 8), varDepth = 1) mustEqual
|
||||
level.testInteraction(Vector3(0,0, 8), varDepth = 1)
|
||||
val obj = new PSGOTest()
|
||||
obj.Position = Vector3(0,0,10)
|
||||
plane.testInteraction(obj, varDepth = -1) mustEqual level.testInteraction(obj, varDepth = -1)
|
||||
obj.Position = Vector3(0,0, 9)
|
||||
plane.testInteraction(obj, varDepth = 0) mustEqual level.testInteraction(obj, varDepth = 0)
|
||||
obj.Position = Vector3(0,0, 8)
|
||||
plane.testInteraction(obj, varDepth = 1) mustEqual level.testInteraction(obj, varDepth = 1)
|
||||
}
|
||||
|
||||
"must have interaction that fails (same as DeepPlane)" in {
|
||||
plane.testInteraction(Vector3(0,0,11), varDepth = -1) mustEqual
|
||||
level.testInteraction(Vector3(0,0,11), varDepth = -1)
|
||||
plane.testInteraction(Vector3(0,0,10), varDepth = 0) mustEqual
|
||||
level.testInteraction(Vector3(0,0,10), varDepth = 0)
|
||||
plane.testInteraction(Vector3(0,0, 9), varDepth = 1) mustEqual
|
||||
level.testInteraction(Vector3(0,0, 9), varDepth = 1)
|
||||
val obj = new PSGOTest()
|
||||
obj.Position = Vector3(0,0,11)
|
||||
plane.testInteraction(obj, varDepth = -1) mustEqual level.testInteraction(obj, varDepth = -1)
|
||||
obj.Position = Vector3(0,0,10)
|
||||
plane.testInteraction(obj, varDepth = 0) mustEqual level.testInteraction(obj, varDepth = 0)
|
||||
obj.Position = Vector3(0,0, 9)
|
||||
plane.testInteraction(obj, varDepth = 1) mustEqual level.testInteraction(obj, varDepth = 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -267,43 +327,45 @@ class PoolTest extends Specification {
|
|||
}
|
||||
|
||||
"must have interaction that passes (same as DeepSquare)" in {
|
||||
pool.testInteraction(Vector3(1,1, 0), varDepth = 0) mustEqual
|
||||
square.testInteraction(Vector3(1,1, 0), varDepth = 0)
|
||||
pool.testInteraction(Vector3(1,8, 0), varDepth = 0) mustEqual
|
||||
square.testInteraction(Vector3(1,8, 0), varDepth = 0)
|
||||
pool.testInteraction(Vector3(8,8, 0), varDepth = 0) mustEqual
|
||||
square.testInteraction(Vector3(8,8, 0), varDepth = 0)
|
||||
pool.testInteraction(Vector3(8,1, 0), varDepth = 0) mustEqual
|
||||
square.testInteraction(Vector3(8,1, 0), varDepth = 0)
|
||||
pool.testInteraction(Vector3(1,1,10), varDepth = -1) mustEqual
|
||||
square.testInteraction(Vector3(1,1,10), varDepth = -1)
|
||||
pool.testInteraction(Vector3(1,1, 9), varDepth = 0) mustEqual
|
||||
square.testInteraction(Vector3(1,1, 9), varDepth = 0)
|
||||
pool.testInteraction(Vector3(1,1, 8), varDepth = 1) mustEqual
|
||||
square.testInteraction(Vector3(1,1, 8), varDepth = 1)
|
||||
val obj = new PSGOTest()
|
||||
obj.Position = Vector3(1,1, 0)
|
||||
pool.testInteraction(obj, varDepth = 0) mustEqual square.testInteraction(obj, varDepth = 0)
|
||||
obj.Position = Vector3(1,8, 0)
|
||||
pool.testInteraction(obj, varDepth = 0) mustEqual square.testInteraction(obj, varDepth = 0)
|
||||
obj.Position = Vector3(8,8, 0)
|
||||
pool.testInteraction(obj, varDepth = 0) mustEqual square.testInteraction(obj, varDepth = 0)
|
||||
obj.Position = Vector3(8,1, 0)
|
||||
pool.testInteraction(obj, varDepth = 0) mustEqual square.testInteraction(obj, varDepth = 0)
|
||||
obj.Position = Vector3(1,1,10)
|
||||
pool.testInteraction(obj, varDepth = -1) mustEqual square.testInteraction(obj, varDepth = -1)
|
||||
obj.Position = Vector3(1,1, 9)
|
||||
pool.testInteraction(obj, varDepth = 0) mustEqual square.testInteraction(obj, varDepth = 0)
|
||||
obj.Position = Vector3(1,1, 8)
|
||||
pool.testInteraction(obj, varDepth = 1) mustEqual square.testInteraction(obj, varDepth = 1)
|
||||
}
|
||||
|
||||
"must have interaction that fails (same as DeepSquare)" in {
|
||||
pool.testInteraction(Vector3(1,0, 0), varDepth = 0) mustEqual
|
||||
square.testInteraction(Vector3(1,0, 0), varDepth = 0)
|
||||
pool.testInteraction(Vector3(1,9, 0), varDepth = 0) mustEqual
|
||||
square.testInteraction(Vector3(1,9, 0), varDepth = 0)
|
||||
pool.testInteraction(Vector3(0,9, 0), varDepth = 0) mustEqual
|
||||
square.testInteraction(Vector3(0,9, 0), varDepth = 0)
|
||||
pool.testInteraction(Vector3(0,1, 0), varDepth = 0) mustEqual
|
||||
square.testInteraction(Vector3(0,1, 0), varDepth = 0)
|
||||
pool.testInteraction(Vector3(1,1,11), varDepth = -1) mustEqual
|
||||
square.testInteraction(Vector3(1,1,11), varDepth = -1)
|
||||
pool.testInteraction(Vector3(1,1,10), varDepth = 0) mustEqual
|
||||
square.testInteraction(Vector3(1,1,10), varDepth = 0)
|
||||
pool.testInteraction(Vector3(1,1, 9), varDepth = 1) mustEqual
|
||||
square.testInteraction(Vector3(1,1, 9), varDepth = 1)
|
||||
val obj = new PSGOTest()
|
||||
obj.Position = Vector3(1,0, 0)
|
||||
pool.testInteraction(obj, varDepth = 0) mustEqual square.testInteraction(obj, varDepth = 0)
|
||||
obj.Position = Vector3(1,9, 0)
|
||||
pool.testInteraction(obj, varDepth = 0) mustEqual square.testInteraction(obj, varDepth = 0)
|
||||
obj.Position = Vector3(0,9, 0)
|
||||
pool.testInteraction(obj, varDepth = 0) mustEqual square.testInteraction(obj, varDepth = 0)
|
||||
obj.Position = Vector3(0,1, 0)
|
||||
pool.testInteraction(obj, varDepth = 0) mustEqual square.testInteraction(obj, varDepth = 0)
|
||||
obj.Position = Vector3(1,1,11)
|
||||
pool.testInteraction(obj, varDepth = -1) mustEqual square.testInteraction(obj, varDepth = -1)
|
||||
obj.Position = Vector3(1,1,10)
|
||||
pool.testInteraction(obj, varDepth = 0) mustEqual square.testInteraction(obj, varDepth = 0)
|
||||
obj.Position = Vector3(1,1, 9)
|
||||
pool.testInteraction(obj, varDepth = 1) mustEqual square.testInteraction(obj, varDepth = 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GantryDenialField extends Specification {
|
||||
val square = DeepSquare(0, 1, 10, 10, 1)
|
||||
val square: DeepSquare = DeepSquare(0, 1, 10, 10, 1)
|
||||
|
||||
"GantryDenialField" should {
|
||||
"always has the environmental attribute of 'GantryDenialField'" in {
|
||||
|
|
@ -319,19 +381,19 @@ class PieceOfEnvironmentTest extends Specification {
|
|||
val level = SeaLevel(10f)
|
||||
|
||||
"detect entering a critical region" in {
|
||||
testStepIntoInteraction(level, Vector3(0,0,9), Vector3(0,0,11), varDepth = 0).contains(true) mustEqual true
|
||||
testStepIntoInteraction(level, new PSGOTest(), Vector3(0,0,9), Vector3(0,0,11), varDepth = 0).contains(true) mustEqual true
|
||||
}
|
||||
|
||||
"detect leaving a critical region" in {
|
||||
testStepIntoInteraction(level, Vector3(0,0,11), Vector3(0,0,9), varDepth = 0).contains(false) mustEqual true
|
||||
testStepIntoInteraction(level, new PSGOTest(), Vector3(0,0,11), Vector3(0,0,9), varDepth = 0).contains(false) mustEqual true
|
||||
}
|
||||
|
||||
"not detect moving outside of a critical region" in {
|
||||
testStepIntoInteraction(level, Vector3(0,0,12), Vector3(0,0,11), varDepth = 0).isEmpty mustEqual true
|
||||
testStepIntoInteraction(level, new PSGOTest(), Vector3(0,0,12), Vector3(0,0,11), varDepth = 0).isEmpty mustEqual true
|
||||
}
|
||||
|
||||
"not detect moving within a critical region" in {
|
||||
testStepIntoInteraction(level, Vector3(0,0,9), Vector3(0,0,8), varDepth = 0).isEmpty mustEqual true
|
||||
testStepIntoInteraction(level, new PSGOTest(), Vector3(0,0,9), Vector3(0,0,8), varDepth = 0).isEmpty mustEqual true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue