mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
logic for declaring door occupants/users as inside or outside or within an open door using door declarations, geometry and environment fields, and math; divided the remaining object type definitions into their own files and removed those from the main global definitions file
This commit is contained in:
parent
d17c16fd9b
commit
b0d3c63b83
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(avatar.name),
|
||||
new WithWater(avatar.name),
|
||||
new WithLava(),
|
||||
new WithDeath(),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
// 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
|
||||
import net.psforever.objects.zones.InteractsWithZone
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class WithEntrance(val channel: String)
|
||||
extends InteractionWith {
|
||||
val attribute: EnvironmentTrait = EnvironmentAttribute.InteriorField
|
||||
|
||||
private var stopTest: Boolean = false
|
||||
private var sideAware: Sidedness = Sidedness.InBetweenSides
|
||||
|
||||
def doInteractingWith(
|
||||
obj: InteractsWithZone,
|
||||
body: PieceOfEnvironment,
|
||||
data: Option[Any]
|
||||
): Unit = {
|
||||
if (stopTest && data.contains("bellybutton")) {
|
||||
stopTest = false
|
||||
} else {
|
||||
val door = body.asInstanceOf[InteriorDoorPassage].door
|
||||
if (door.isOpen) {
|
||||
sideAware = Sidedness.InBetweenSides
|
||||
} else {
|
||||
performInteriorCheck(obj, 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 = {
|
||||
performInteriorCheck(obj, body.asInstanceOf[InteriorDoorPassage].door)
|
||||
stopTest = true
|
||||
}
|
||||
|
||||
private def performInteriorCheck(
|
||||
obj: InteractsWithZone,
|
||||
door: Door
|
||||
): Sidedness = {
|
||||
import net.psforever.packet.game.ChatMsg
|
||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
import net.psforever.types.{ChatMessageType, PlanetSideGUID}
|
||||
val result = Vector3.DotProduct(Vector3.Unit(obj.Position - door.Position), door.Outwards) > 0f
|
||||
if (result && sideAware != Sidedness.OutsideOf) {
|
||||
//outside
|
||||
sideAware = Sidedness.OutsideOf
|
||||
obj.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
channel,
|
||||
AvatarAction.SendResponse(PlanetSideGUID(0), ChatMsg(ChatMessageType.UNK_229, "You are now outside"))
|
||||
)
|
||||
} else if (!result && sideAware != Sidedness.InsideOf) {
|
||||
//inside
|
||||
sideAware = Sidedness.InsideOf
|
||||
obj.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
channel,
|
||||
AvatarAction.SendResponse(PlanetSideGUID(0), ChatMsg(ChatMessageType.UNK_229, "You are now inside"))
|
||||
)
|
||||
}
|
||||
sideAware
|
||||
}
|
||||
|
||||
def ThisSide: Sidedness = sideAware
|
||||
|
||||
def ThisSide_=(thisSide: Sidedness): Unit = {
|
||||
sideAware = thisSide
|
||||
ThisSide
|
||||
}
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ class WithWater(val channel: String)
|
|||
|
||||
override def recoverFromInteracting(obj: InteractsWithZone): Unit = {
|
||||
super.recoverFromInteracting(obj)
|
||||
if (condition.exists(_.state == OxygenState.Suffocation)) {
|
||||
if (condition.exists(info => info.state == OxygenState.Suffocation && info.progress < 99f)) {
|
||||
stopInteractingWith(obj, condition.map(_.body).get, None)
|
||||
}
|
||||
waterInteractionTime = 0L
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
// 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.doors.Door
|
||||
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentCollision, EnvironmentTrait, PieceOfEnvironment}
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
case class VolumetricEnvironmentCollision(door: Door)
|
||||
extends EnvironmentCollision {
|
||||
private lazy val geometry = door.Definition.Geometry.apply(door)
|
||||
private lazy val bound: Rectangle = {
|
||||
val g = geometry
|
||||
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 = geometry
|
||||
|
||||
def altitude: Float = geometry.pointOnOutside(Vector3(0,0,1)).z
|
||||
|
||||
def testInteraction(obj: PlanetSideGameObject, varDepth: Float): Boolean = {
|
||||
Zone.distanceCheck(obj.Definition.Geometry(obj), geometry) <= varDepth
|
||||
}
|
||||
|
||||
def bounding: Rectangle = bound
|
||||
}
|
||||
|
|
@ -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,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
|
||||
}
|
||||
}
|
||||
|
|
@ -483,7 +483,7 @@ object GlobalDefinitionsMiscellaneous {
|
|||
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
|
||||
|
|
@ -598,21 +598,91 @@ object GlobalDefinitionsMiscellaneous {
|
|||
lock_external.Damageable = false
|
||||
lock_external.Repairable = false
|
||||
|
||||
amp_cap_door.Name = "amp_cap_door"
|
||||
|
||||
ancient_door.Name = "ancient_door"
|
||||
ancient_door.geometryInteractionRadius = Some(1)
|
||||
|
||||
ancient_garage_door.Name = "ancient_garage_door"
|
||||
ancient_garage_door.geometryInteractionRadius = Some(1)
|
||||
|
||||
cryo_med_door.Name = "cryo_med_door"
|
||||
|
||||
cryo_room_door.Name = "cryo_room_door"
|
||||
|
||||
door.Name = "door"
|
||||
door.Damageable = false
|
||||
door.Repairable = false
|
||||
|
||||
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
|
||||
door_spawn_mb.Repairable = false
|
||||
|
||||
garage_door.Name = "garage_door"
|
||||
|
||||
gr_door_airlock.Name = "gr_door_airlock"
|
||||
|
||||
gr_door_ext.Name = "gr_door_ext"
|
||||
gr_door_ext.geometryInteractionRadius = Some(1)
|
||||
|
||||
gr_door_garage_ext.Name = "gr_door_garage_ext"
|
||||
gr_door_garage_ext.geometryInteractionRadius = Some(1)
|
||||
|
||||
gr_door_garage_int.Name = "gr_door_garage_int"
|
||||
|
||||
gr_door_int.Name = "gr_door_int"
|
||||
|
||||
gr_door_main.Name = "gr_door_main"
|
||||
gr_door_main.geometryInteractionRadius = Some(1)
|
||||
|
||||
gr_door_mb_ext.Name = "gr_door_mb_ext"
|
||||
gr_door_mb_ext.geometryInteractionRadius = Some(1)
|
||||
|
||||
gr_door_mb_int.Name = "gr_door_mb_int"
|
||||
|
||||
gr_door_mb_lrg.Name = "gr_door_mb_lrg"
|
||||
gr_door_mb_lrg.geometryInteractionRadius = Some(1)
|
||||
|
||||
gr_door_mb_obsd.Name = "gr_door_mb_obsd"
|
||||
|
||||
gr_door_mb_orb.Name = "gr_door_mb_orb"
|
||||
gr_door_mb_orb.Damageable = false
|
||||
gr_door_mb_orb.Repairable = false
|
||||
|
||||
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.Repairable = false
|
||||
|
||||
spawn_tube_door_coffin.Name = "spawn_tube_door_coffin"
|
||||
spawn_tube_door_coffin.Damageable = true
|
||||
|
||||
resource_silo.Name = "resource_silo"
|
||||
resource_silo.Damageable = false
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import net.psforever.objects.definition.converter._
|
|||
import net.psforever.objects.equipment._
|
||||
import net.psforever.objects.inventory.InventoryTile
|
||||
|
||||
object GlobalDefinitionsTools {
|
||||
object GlobalDefinitionsTool {
|
||||
import GlobalDefinitions._
|
||||
|
||||
/**
|
||||
|
|
@ -5,6 +5,7 @@ import net.psforever.objects.Player
|
|||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
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 +13,7 @@ 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
|
||||
|
||||
def isOpen: Boolean = openState.isDefined
|
||||
|
||||
|
|
@ -26,6 +28,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
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.serverobject.doors
|
||||
|
||||
import net.psforever.objects.geometry.VolumetricEnvironmentCollision
|
||||
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentCollision, EnvironmentTrait, PieceOfEnvironment}
|
||||
|
||||
final case class InteriorDoorPassage(door: Door)
|
||||
extends PieceOfEnvironment {
|
||||
assert(door.Definition.geometryInteractionRadius.nonEmpty, s"door ${door.GUID} needs an interaction radius to be volumetric")
|
||||
//assert(door.Outwards != Vector3.Zero, s"door ${door.GUID} does not have an outwards direction")
|
||||
|
||||
/** 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 = VolumetricEnvironmentCollision(door)
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2020-2024 PSForever
|
||||
package net.psforever.objects.serverobject.environment
|
||||
|
||||
import enumeratum.{Enum, EnumEntry}
|
||||
import net.psforever.objects.serverobject.interior.InteriorAware
|
||||
import net.psforever.objects.{PlanetSideGameObject, Player, Vehicle}
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.types.Vector3
|
||||
|
|
@ -9,14 +9,11 @@ import net.psforever.types.Vector3
|
|||
/**
|
||||
* A general description of environment and its interactive possibilities.
|
||||
*/
|
||||
sealed abstract class EnvironmentTrait extends EnumEntry {
|
||||
abstract class EnvironmentTrait {
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean
|
||||
}
|
||||
|
||||
object EnvironmentAttribute extends Enum[EnvironmentTrait] {
|
||||
/** glue connecting `EnumEntry` to `Enumeration` */
|
||||
val values: IndexedSeq[EnvironmentTrait] = findValues
|
||||
|
||||
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 */
|
||||
|
|
@ -71,4 +68,14 @@ object EnvironmentAttribute extends Enum[EnvironmentTrait] {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
case object InteriorField
|
||||
extends EnvironmentTrait {
|
||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = {
|
||||
obj match {
|
||||
case _: InteriorAware => true
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,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?
|
||||
|
|
@ -34,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)
|
||||
|
||||
|
|
@ -61,9 +61,19 @@ object PieceOfEnvironment {
|
|||
* `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)
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -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,34 @@
|
|||
// 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 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(_.ThisSide).getOrElse(Sidedness.InBetweenSides)
|
||||
}
|
||||
|
||||
def WhichSide_=(thisSide: Sidedness): Sidedness = {
|
||||
withEntrance.foreach(_.ThisSide = thisSide)
|
||||
WhichSide
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.objects.serverobject.interior
|
||||
|
||||
sealed trait Sidedness
|
||||
|
||||
sealed trait Inside
|
||||
|
||||
sealed trait Outside
|
||||
|
||||
sealed trait InBetween extends Inside with Outside
|
||||
|
||||
object Sidedness {
|
||||
case object InsideOf extends Inside with Sidedness
|
||||
|
||||
case object OutsideOf extends Outside with Sidedness
|
||||
|
||||
case object InBetweenSides extends InBetween with Sidedness
|
||||
|
||||
def equals(a: Sidedness, b: Sidedness): Boolean = {
|
||||
(a eq b) || a == Sidedness.InBetweenSides || b == Sidedness.InBetweenSides
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +52,7 @@ import net.psforever.objects.vital.prop.DamageWithPosition
|
|||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.objects.zones.blockmap.BlockMap
|
||||
import net.psforever.services.Service
|
||||
import net.psforever.zones.Zones
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.mutable
|
||||
|
|
@ -664,13 +665,7 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
|
|||
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.AssignDoors(zone = this)
|
||||
//ntu management (eventually move to a generic building startup function)
|
||||
buildings.values
|
||||
.flatMap(_.Amenities.filter(_.Definition == GlobalDefinitions.resource_silo))
|
||||
|
|
@ -884,6 +879,124 @@ object Zone {
|
|||
new Zone(id, map, number)
|
||||
}
|
||||
|
||||
private def AssignDoors(zone: Zone): Unit = {
|
||||
//let ZoneActor's sanity check catch any missing entities
|
||||
val map = zone.map
|
||||
val guid = zone.guid
|
||||
val invalidOutwards = Vector3(0,0,-1) //down
|
||||
if (map.cavern) {
|
||||
//cavern doors
|
||||
//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)
|
||||
) {
|
||||
//sanctuary doors
|
||||
AssignIFFLockedDoors(zone)
|
||||
//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.filter(_.Definition == GlobalDefinitions.gr_door_mb_ext),
|
||||
amenities.filter(_.Definition == GlobalDefinitions.gr_door_mb_lrg),
|
||||
amenities.filter(_.Definition == GlobalDefinitions.order_terminal),
|
||||
amenities.filter(_.Definition == GlobalDefinitions.respawn_tube_sanctuary)
|
||||
)
|
||||
}
|
||||
amenityList.foreach { case (entranceDoors, _, 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.asInstanceOf[Door].Outwards = Vector3.Unit(closestTerminal.Position.xy - closestTube.Position.xy)
|
||||
}
|
||||
//todo training zone warp chamber doors
|
||||
}
|
||||
//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 doorPosition = door.Position
|
||||
val closestHartDoor = hartDoors.minBy(t => Vector3.DistanceSquared(doorPosition, t.Position))
|
||||
door.asInstanceOf[Door].Outwards = Vector3.Unit(doorPosition.xy - closestHartDoor.Position.xy)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//above ground zone doors
|
||||
AssignIFFLockedDoors(zone)
|
||||
//for major facilities, external doors in the courtyard are without locks but are paired in opposing directions
|
||||
val unpairedDoors = zone.Buildings
|
||||
.values
|
||||
.collect {
|
||||
case b
|
||||
if b.BuildingType == StructureType.Facility && b.Amenities.nonEmpty =>
|
||||
b.Amenities.collect {
|
||||
case d: Door
|
||||
if d.Definition == GlobalDefinitions.gr_door_ext && d.Outwards == Vector3.Zero =>
|
||||
d
|
||||
}
|
||||
}
|
||||
var pairedDoors = Seq[(Door, Door)]()
|
||||
unpairedDoors.foreach { buildingUnPairedDoors =>
|
||||
var volatileUnpairedDoors = buildingUnPairedDoors
|
||||
while (volatileUnpairedDoors.size > 1) {
|
||||
val sampleDoor = volatileUnpairedDoors.head
|
||||
val sampleDoorPosition = sampleDoor.Position.xy
|
||||
val distances = Float.MaxValue +: volatileUnpairedDoors
|
||||
.map(d => Vector3.DistanceSquared(d.Position.xy, sampleDoorPosition))
|
||||
.drop(1)
|
||||
val min = distances.min
|
||||
val indexOfClosestDoor = distances.indexWhere(_ == min)
|
||||
val otherDoor = volatileUnpairedDoors(indexOfClosestDoor)
|
||||
volatileUnpairedDoors = volatileUnpairedDoors.slice(1, indexOfClosestDoor) ++ volatileUnpairedDoors.drop(indexOfClosestDoor + 1)
|
||||
pairedDoors = pairedDoors :+ (sampleDoor, otherDoor)
|
||||
}
|
||||
volatileUnpairedDoors.foreach { door =>
|
||||
door.Outwards = invalidOutwards
|
||||
}
|
||||
}
|
||||
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
|
||||
door2.Outwards = Vector3.neg(outwards)
|
||||
}
|
||||
//bunker doors do not define an interior
|
||||
}
|
||||
}
|
||||
|
||||
private def AssignIFFLockedDoors(zone: Zone): Unit = {
|
||||
val map = zone.map
|
||||
val guid = zone.guid
|
||||
val invalidOutwards = Vector3(0,0,-1) //down
|
||||
//doors with nearby locks use those locks as their unlocking mechanism and their outwards indication
|
||||
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 (Some(door: Door), _) =>
|
||||
door.Outwards = invalidOutwards
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
||||
object Population {
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package net.psforever.objects.zones.blockmap
|
|||
import net.psforever.objects.ballistics.Projectile
|
||||
import net.psforever.objects.ce.Deployable
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.serverobject.doors.{Door, InteriorDoorPassage}
|
||||
import net.psforever.objects.serverobject.environment.PieceOfEnvironment
|
||||
import net.psforever.objects.serverobject.structures.{Amenity, Building}
|
||||
import net.psforever.objects.{Player, Vehicle}
|
||||
|
|
@ -199,6 +200,12 @@ class Sector(val longitude: Int, val latitude: Int, val span: Int)
|
|||
deployables.list.size < deployables.addTo(d).size
|
||||
case b: Building =>
|
||||
buildings.list.size < buildings.addTo(b).size
|
||||
case d: Door =>
|
||||
val doorAdded = amenities.list.size < amenities.addTo(d).size
|
||||
d.Definition.geometryInteractionRadius.collect {
|
||||
case _ if doorAdded => environment.addTo(InteriorDoorPassage(d))
|
||||
}
|
||||
doorAdded
|
||||
case a: Amenity =>
|
||||
amenities.list.size < amenities.addTo(a).size
|
||||
case e: PieceOfEnvironment =>
|
||||
|
|
|
|||
|
|
@ -431,16 +431,15 @@ object Zones {
|
|||
.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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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