mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-03-17 11:20:40 +00:00
warning fields and kill fields added to the perimeter surrounding most zone continents (#992)
This commit is contained in:
parent
71b8c011c9
commit
5787c14a29
11 changed files with 495 additions and 188 deletions
|
|
@ -9498,7 +9498,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
def updateBlockMap(target: BlockMapEntity, zone: Zone, newCoords: Vector3): Unit = {
|
||||
target.blockMapEntry match {
|
||||
case Some(entry) =>
|
||||
if (BlockMap.findSectorIndices(continent.blockMap, newCoords, entry.range).toSet.equals(entry.sectors)) {
|
||||
if (BlockMap.findSectorIndices(continent.blockMap, newCoords, entry.rangeX, entry.rangeY).toSet.equals(entry.sectors)) {
|
||||
target.updateBlockMapEntry(newCoords) //soft update
|
||||
} else {
|
||||
zone.actor ! ZoneActor.UpdateBlockMap(target, newCoords) //hard update
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ class ZoneActor(context: ActorContext[ZoneActor.Command], zone: Zone)
|
|||
zone.blockMap.addTo(target, toPosition)
|
||||
|
||||
case UpdateBlockMap(target, toPosition) =>
|
||||
target.updateBlockMapEntry(toPosition)
|
||||
zone.blockMap.move(target, toPosition)
|
||||
|
||||
case RemoveFromBlockMap(target) =>
|
||||
zone.blockMap.removeFrom(target)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ trait InteractsWithZone
|
|||
|
||||
def doInteractions(): Unit = {
|
||||
val sector = getInteractionSector()
|
||||
//println(sector.environmentList.map { _.attribute }.mkString(" "))
|
||||
interactions.foreach { _.interaction(sector, target = this) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
package net.psforever.objects.zones
|
||||
|
||||
import enumeratum.values.{StringEnum, StringEnumEntry}
|
||||
import net.psforever.objects.PlanetSideGameObject
|
||||
import net.psforever.objects.{PlanetSideGameObject, Player, Vehicle}
|
||||
import net.psforever.objects.serverobject.environment._
|
||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
|
||||
import net.psforever.packet.game.{ChatMsg, OffshoreVehicleMessage}
|
||||
import net.psforever.services.Service
|
||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGUID, Vector3}
|
||||
|
||||
sealed abstract class MapInfo(
|
||||
val value: String,
|
||||
|
|
@ -27,7 +31,15 @@ case object MapInfo extends StringEnum[MapInfo] {
|
|||
Pool(EnvironmentAttribute.Water, 43.515625f, 4805.5f, 4324.3984f, 4727.867f, 4280.2188f), //north of hapi
|
||||
Pool(EnvironmentAttribute.Water, 43.0625f, 3313.1094f, 4746.4844f, 3259.4219f, 4691.2266f), //east of thoth
|
||||
Pool(EnvironmentAttribute.Water, 43.51f, 1917.1016f, 4086.8984f, 1893.4844f, 4038.2734f) //between horus and amun
|
||||
) ++ MapEnvironment.zoneMapEdgeKillPlane(MapScale.Dim8192, 100, 400, 400, 100, 200, 600, 600, 600)
|
||||
) ++ MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim8192,
|
||||
(100, 400, 400, 100),
|
||||
List(
|
||||
(133, 450, 450, 200, 3),
|
||||
(166, 500, 500, 400, 2),
|
||||
(200, 600, 600, 600, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
case object Map02
|
||||
|
|
@ -55,7 +67,15 @@ case object MapInfo extends StringEnum[MapInfo] {
|
|||
Pool(EnvironmentAttribute.Water, 11, southNaum, eastNaum, 0, westNaum) //south of naum
|
||||
//TODO voltan Killplane
|
||||
//TODO naum Killplane
|
||||
) ++ MapEnvironment.zoneMapEdgeKillPlane(MapScale.Dim8192, 400, 400, 200, 400, 600, 600, 400, 600)
|
||||
) ++ MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim8192,
|
||||
(400, 400, 200, 400),
|
||||
List(
|
||||
(450, 450, 250, 450, 3),
|
||||
(500, 500, 300, 500, 2),
|
||||
(600, 600, 400, 600, 1)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -80,7 +100,15 @@ case object MapInfo extends StringEnum[MapInfo] {
|
|||
Pool(EnvironmentAttribute.Water, 36.921875f, 3162.1094f, 1689.5703f, 3085.7422f, 1612.7734f), //north of nzame
|
||||
Pool(EnvironmentAttribute.Water, 36.390625f, 4143.797f, 4872.3906f, 4021.9766f, 4798.578f), //south of gunuku
|
||||
Pool(EnvironmentAttribute.Water, 35.71875f, 2591.336f, 1752.5938f, 2512.7578f, 1663.1172f) //south of nzame
|
||||
) ++ MapEnvironment.zoneMapEdgeKillPlane(MapScale.Dim8192, 200, 100, 100, 100, 400, 200, 200, 200)
|
||||
) ++ MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim8192,
|
||||
(200, 100, 100, 100),
|
||||
List(
|
||||
(250, 133, 133, 133, 3),
|
||||
(300, 166, 166, 166, 2),
|
||||
(400, 200, 200, 200, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
case object Map04
|
||||
|
|
@ -89,7 +117,15 @@ case object MapInfo extends StringEnum[MapInfo] {
|
|||
checksum = 2455050867L,
|
||||
scale = MapScale.Dim8192,
|
||||
environment = List(SeaLevel(EnvironmentAttribute.Water, 19.984375f)) ++
|
||||
MapEnvironment.zoneMapEdgeKillPlane(MapScale.Dim8192, 200, 10, 10, 10, 400, 200, 200, 200)
|
||||
MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim8192,
|
||||
(200, 10, 10, 10),
|
||||
List(
|
||||
(250, 60, 60, 60, 3),
|
||||
(300, 110, 110, 110, 2),
|
||||
(400, 200, 200, 200, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
case object Map05
|
||||
|
|
@ -112,7 +148,15 @@ case object MapInfo extends StringEnum[MapInfo] {
|
|||
Pool(EnvironmentAttribute.Water, 41.765625f, 2073.914f, 4982.5938f, 1995.4688f, 4899.086f), //L15-M16
|
||||
Pool(EnvironmentAttribute.Water, 41.3125f, 3761.1484f, 2616.75f, 3627.4297f, 2505.1328f), //G11, south
|
||||
Pool(EnvironmentAttribute.Water, 40.421875f, 4058.8281f, 2791.6562f, 3985.1016f, 2685.3672f) //G11, north
|
||||
) ++ MapEnvironment.zoneMapEdgeKillPlane(MapScale.Dim8192, 400, 10, 200, 400, 600, 100, 400, 600)
|
||||
) ++ MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim8192,
|
||||
(400, 10, 200, 400),
|
||||
List(
|
||||
(450, 25, 250, 450, 3),
|
||||
(500, 50, 300, 500, 2),
|
||||
(600, 100, 400, 600, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
case object Map06
|
||||
|
|
@ -124,7 +168,15 @@ case object MapInfo extends StringEnum[MapInfo] {
|
|||
SeaLevel(EnvironmentAttribute.Water, 10.03125f),
|
||||
Pool(EnvironmentAttribute.Water, 213.03125f, 3116.7266f, 4724.414f, 2685.8281f, 4363.461f), //east side of southwest of tootega
|
||||
Pool(EnvironmentAttribute.Water, 213.03125f, 2994.2969f, 4363.461f, 2685.8281f, 4187.4375f), //west side of southwest of tootega
|
||||
) ++ MapEnvironment.zoneMapEdgeKillPlane(MapScale.Dim8192, 400, 400, 400, 400, 600, 600, 600, 600)
|
||||
) ++ MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim8192,
|
||||
(400, 400, 400, 400),
|
||||
List(
|
||||
(450, 450, 450, 450, 3),
|
||||
(500, 500, 500, 500, 2),
|
||||
(600, 600, 600, 600, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
case object Map07
|
||||
|
|
@ -132,8 +184,15 @@ case object MapInfo extends StringEnum[MapInfo] {
|
|||
value = "map07",
|
||||
checksum = 1564014762L,
|
||||
scale = MapScale.Dim8192,
|
||||
environment = List(SeaLevel(EnvironmentAttribute.Water, 29.984375f)) ++
|
||||
MapEnvironment.zoneMapEdgeKillPlane(MapScale.Dim8192, 10, 10, 10, 10, 200, 200, 200, 200)
|
||||
environment = List(SeaLevel(EnvironmentAttribute.Water, 29.984375f)) ++ MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim8192,
|
||||
(10, 10, 10, 10),
|
||||
List(
|
||||
(50, 50, 50, 50, 3),
|
||||
(100, 100, 100, 100, 2),
|
||||
(200, 200, 200, 200, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
case object Map08
|
||||
|
|
@ -141,8 +200,15 @@ case object MapInfo extends StringEnum[MapInfo] {
|
|||
value = "map08",
|
||||
checksum = 0L,
|
||||
scale = MapScale.Dim8192,
|
||||
environment = List(SeaLevel(EnvironmentAttribute.Water, 26.078125f)) ++
|
||||
MapEnvironment.zoneMapEdgeKillPlane(MapScale.Dim8192, 200, 200, 200, 200, 400, 400, 400, 400)
|
||||
environment = List(SeaLevel(EnvironmentAttribute.Water, 26.078125f)) ++ MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim8192,
|
||||
(200, 200, 200, 200),
|
||||
List(
|
||||
(250, 250, 250, 250, 3),
|
||||
(300, 300, 300, 300, 2),
|
||||
(400, 400, 400, 400, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
case object Map09
|
||||
|
|
@ -160,7 +226,15 @@ case object MapInfo extends StringEnum[MapInfo] {
|
|||
Pool(EnvironmentAttribute.Lava, DeepSurface(187.57812f, 4288.1484f, 4589.0703f, 3996.3125f, 4355.6406f)), //lower central lava pool
|
||||
Pool(EnvironmentAttribute.Lava, DeepSurface(181.45312f, 4635.1953f, 4579.3516f, 4406.3438f, 4303.828f)), //upper central lava pool
|
||||
Pool(EnvironmentAttribute.Lava, DeepSurface(176.64062f, 4274.8125f, 4969.9688f, 4101.7734f, 4766.3594f)) //east lava pool
|
||||
) ++ MapEnvironment.zoneMapEdgeKillPlane(MapScale.Dim8192, 200, 200, 200, 200, 400, 400, 400, 400)
|
||||
) ++ MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim8192,
|
||||
(200, 200, 200, 200),
|
||||
List(
|
||||
(250, 250, 250, 250, 3),
|
||||
(300, 300, 300, 300, 2),
|
||||
(400, 400, 400, 400, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
case object Map10
|
||||
|
|
@ -168,8 +242,15 @@ case object MapInfo extends StringEnum[MapInfo] {
|
|||
value = "map10",
|
||||
checksum = 230810349L,
|
||||
scale = MapScale.Dim8192,
|
||||
environment = List(SeaLevel(EnvironmentAttribute.Water, 28)) ++
|
||||
MapEnvironment.zoneMapEdgeKillPlane(MapScale.Dim8192, 200, 200, 200, 200, 400, 400, 400, 400)
|
||||
environment = List(SeaLevel(EnvironmentAttribute.Water, 28)) ++ MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim8192,
|
||||
(200, 200, 200, 200),
|
||||
List(
|
||||
(250, 250, 250, 250, 3),
|
||||
(300, 300, 300, 300, 2),
|
||||
(400, 400, 400, 400, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
case object Map11
|
||||
|
|
@ -186,8 +267,15 @@ case object MapInfo extends StringEnum[MapInfo] {
|
|||
Pool(EnvironmentAttribute.Water, 34.96875f, 5899.367f, 3235.5781f, 5573.8516f, 2865.7812f), //northeast of hart c campus
|
||||
Pool(EnvironmentAttribute.Water, 34.328125f, 3880.7422f, 5261.508f, 3780.9219f, 5166.953f), //east of hart a campus
|
||||
Pool(EnvironmentAttribute.Water, 31.03125f, 4849.797f, 2415.4297f, 4731.8594f, 2252.1484f) //south of hart c campus
|
||||
) ++ MapEnvironment.map11Environment ++
|
||||
MapEnvironment.zoneMapEdgeKillPlane(MapScale.Dim8192, 200, 400, 400, 200, 600, 800, 800, 600)
|
||||
) ++ MapEnvironment.map11Environment ++ MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim8192,
|
||||
(200, 400, 400, 200),
|
||||
List(
|
||||
(300, 500, 500, 300, 3),
|
||||
(400, 600, 600, 400, 2),
|
||||
(600, 800, 800, 600, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
case object Map12
|
||||
|
|
@ -363,11 +451,34 @@ object MapEnvironment {
|
|||
hartGantryDenialFields(PlanetSideGUID(787), Vector3(3688, 2808, 90.85312f), vsHartMountPoints) ++
|
||||
hartGantryDenialFields(PlanetSideGUID(788), Vector3(5610, 4238, 103.228859f), vsHartMountPoints)
|
||||
|
||||
/** common map edge kill planes */
|
||||
final val dim1024MapEdgeKillPlanes: List[PieceOfEnvironment] = zoneMapEdgeKillPlane(MapScale.Dim1024)
|
||||
final val dim2560MapEdgeKillPlanes: List[PieceOfEnvironment] = zoneMapEdgeKillPlane(MapScale.Dim2560)
|
||||
final val dim4096MapEdgeKillPlanes: List[PieceOfEnvironment] = zoneMapEdgeKillPlane(MapScale.Dim4096)
|
||||
final val dim8192MapEdgeKillPlanes: List[PieceOfEnvironment] = zoneMapEdgeKillPlane(MapScale.Dim8192)
|
||||
/** common map edge kill planes; may be defunct eventually */
|
||||
final val dim1024MapEdgeKillPlanes: List[PieceOfEnvironment] = MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim1024,
|
||||
(102, 102, 102, 102),
|
||||
List(
|
||||
(125, 125, 125, 125, 3),
|
||||
(156, 156, 156, 156, 2),
|
||||
(204, 204, 204, 204, 1)
|
||||
)
|
||||
)
|
||||
final val dim4096MapEdgeKillPlanes: List[PieceOfEnvironment] = MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim4096,
|
||||
(204, 204, 204, 204),
|
||||
List(
|
||||
(255, 255, 255, 255, 3),
|
||||
(306, 306, 306, 306, 2),
|
||||
(408, 408, 408, 408, 1)
|
||||
)
|
||||
)
|
||||
final val dim8192MapEdgeKillPlanes: List[PieceOfEnvironment] = MapEnvironment.zoneMapEdgeKillPlane(
|
||||
MapScale.Dim8192,
|
||||
(400, 400, 400, 400),
|
||||
List(
|
||||
(500, 500, 500, 500, 3),
|
||||
(600, 600, 600, 600, 2),
|
||||
(800, 800, 800, 800, 1)
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* Generate eight environmental representations that serve to eject players
|
||||
|
|
@ -444,116 +555,160 @@ object MapEnvironment {
|
|||
}
|
||||
|
||||
/**
|
||||
* Generate the bounded fields on the egde of the zone maps
|
||||
* Generate the bounded fields on the edge of the zone maps
|
||||
* that kill players and vehicles the moment those game entities enter the region
|
||||
* to disallow players from reaching and traversing the edge of the map.
|
||||
* Bounded regions that warn players against going too far are also generated.
|
||||
* @param scale the scale of the map, indicating an outer perimeter
|
||||
* @return a list of environmental representations
|
||||
*/
|
||||
def zoneMapEdgeKillPlane(scale: MapScale): List[PieceOfEnvironment] = {
|
||||
val killBoundingW = scale.width / 20f
|
||||
val killBoundingH = scale.height / 20f
|
||||
val warnBoundingW = killBoundingW * 2f
|
||||
val warnBoundingH = killBoundingH * 2f
|
||||
zoneMapEdgeKillPlane(
|
||||
scale,
|
||||
killBoundingH, killBoundingW, killBoundingH, killBoundingW,
|
||||
warnBoundingH, warnBoundingW, warnBoundingH, warnBoundingW
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the bounded regions along the edges of the zone maps
|
||||
* that kill players and vehicles the moment those game entities enter the region
|
||||
* to disallow players from reaching and traversing the edge of the map.
|
||||
* Warn players who are getting too close to the kill regions that they should be cautious and turn back.
|
||||
* @param scale the scale of the map, indicating an outer perimeter
|
||||
* @param killN distance of the kill field from the top edge of the zone map
|
||||
* @param killE distance of the kill field from the right edge of the zone map
|
||||
* @param killS distance of the kill field from the bottom edge of the zone map
|
||||
* @param killW distance of the kill field from the left edge of the zone map
|
||||
* @param warnN distance of the warning region from the top edge of the zone map to the kill field
|
||||
* @param warnE distance of the warning region from the right edge of the zone map to the kill field
|
||||
* @param warnS distance of the warning region from the bottom edge of the zone map to the kill field
|
||||
* @param warnW distance of the warning region from the left edge of the zone map to the kill field
|
||||
* @param killField the region defined as an "absolute death barrier" to any player or vehicle that enters it
|
||||
* @param warnFields consecutive inset perimeters
|
||||
* that indicate the bounded regions of warning before the `killField` region
|
||||
* @return a list of environmental representations
|
||||
*/
|
||||
def zoneMapEdgeKillPlane(
|
||||
scale: MapScale,
|
||||
killN: Float,
|
||||
killE: Float,
|
||||
killS: Float,
|
||||
killW: Float,
|
||||
warnN: Float,
|
||||
warnE: Float,
|
||||
warnS: Float,
|
||||
warnW: Float
|
||||
killField: (Float,Float,Float,Float),
|
||||
warnFields: List[(Float,Float,Float,Float,Int)]
|
||||
): List[PieceOfEnvironment] = {
|
||||
assert(killN < warnN, "north side warn region closer to map edge than kill region")
|
||||
assert(killE < warnE, "east side warn region closer to map edge than kill region")
|
||||
assert(killS < warnS, "south side warn region closer to map edge than kill region")
|
||||
assert(killW < warnW, "west side warn region closer to map edge than kill region")
|
||||
import net.psforever.objects.serverobject.environment.EnvironmentAttribute
|
||||
val height = scale.height
|
||||
val width = scale.width
|
||||
val heightKillN = height - killN
|
||||
val heightWarnN = height - warnN
|
||||
val widthKillE = width - killE
|
||||
val widthWarnE = width - warnE
|
||||
List(
|
||||
/*warnings*/
|
||||
GeneralMovementField(warnCloseToEdgeOfMap(direction = "NW"), DeepSquare(1024, heightKillN, warnW, heightWarnN, killW)), //NW
|
||||
GeneralMovementField(warnCloseToEdgeOfMap(direction = "N"), DeepSquare(1024, heightKillN, widthWarnE, heightWarnN, warnW)), //N
|
||||
GeneralMovementField(warnCloseToEdgeOfMap(direction = "NE"), DeepSquare(1024, heightKillN, widthKillE, heightWarnN, widthWarnE)), //NE
|
||||
GeneralMovementField(warnCloseToEdgeOfMap(direction = "E"), DeepSquare(1024, heightWarnN, widthKillE, warnS, widthWarnE)), //E
|
||||
GeneralMovementField(warnCloseToEdgeOfMap(direction = "SE"), DeepSquare(1024, warnS, widthKillE, killS, widthWarnE)), //SE
|
||||
GeneralMovementField(warnCloseToEdgeOfMap(direction = "S"), DeepSquare(1024, warnS, widthWarnE, killS, warnW)), //S
|
||||
GeneralMovementField(warnCloseToEdgeOfMap(direction = "SW"), DeepSquare(1024, warnS, warnW, killS, killW)), //SW
|
||||
GeneralMovementField(warnCloseToEdgeOfMap(direction = "W"), DeepSquare(1024, heightWarnN, warnW, warnS, killW)), //W
|
||||
/*kill fields*/
|
||||
Pool(EnvironmentAttribute.Death, 1024, height, width, heightKillN, 0), //N
|
||||
Pool(EnvironmentAttribute.Death, 1024, height, width, 0, widthKillE), //E
|
||||
Pool(EnvironmentAttribute.Death, 1024, killS, width, 0, 0), //S
|
||||
Pool(EnvironmentAttribute.Death, 1024, height, killW, 0, 0) //W
|
||||
val (kbn, kbe, kbs, kbw) = killField
|
||||
val killFields = List(
|
||||
Pool(EnvironmentAttribute.Death, 1024, height, width, height - kbn, 0), //N
|
||||
Pool(EnvironmentAttribute.Death, 1024, height, width, 0, width - kbe), //E
|
||||
Pool(EnvironmentAttribute.Death, 1024, kbs, width, 0, 0), //S
|
||||
Pool(EnvironmentAttribute.Death, 1024, height, kbw, 0, 0) //W
|
||||
)
|
||||
Nil
|
||||
}
|
||||
|
||||
private def warnCloseToEdgeOfMap(direction: String)(obj: PlanetSideGameObject): Unit = {
|
||||
import net.psforever.objects.{Player, Vehicle}
|
||||
import net.psforever.packet.game.ChatMsg
|
||||
import net.psforever.services.Service
|
||||
import net.psforever.services.avatar.{AvatarServiceMessage, AvatarAction}
|
||||
import net.psforever.services.vehicle.{VehicleServiceMessage, VehicleAction}
|
||||
import net.psforever.types.ChatMessageType
|
||||
val msg = s"Do not travel any further $direction from the battlefield or you"
|
||||
obj match {
|
||||
case p: Player =>
|
||||
val zone = p.Zone
|
||||
val punishment = if (p.Faction == PlanetSideEmpire.VS) {
|
||||
"r ongoing research venture will be defunded."
|
||||
} else if (p.Faction == PlanetSideEmpire.NC) {
|
||||
"r social credits will be liquidated."
|
||||
} else {
|
||||
" will be executed for desertion."
|
||||
}
|
||||
zone.AvatarEvents ! AvatarServiceMessage(
|
||||
p.Name,
|
||||
AvatarAction.SendResponseTargeted(
|
||||
Service.defaultPlayerGUID,
|
||||
ChatMsg(ChatMessageType.CMT_QUIT, false, "", s"$msg$punishment", None)
|
||||
)
|
||||
if (warnFields.nonEmpty) {
|
||||
val msgs = 0 +: warnFields.map(_._5)
|
||||
val mns = kbn +: warnFields.map (_._1)
|
||||
val mes = kbe +: warnFields.map (_._2)
|
||||
val mss = kbs +: warnFields.map (_._3)
|
||||
val mws = kbw +: warnFields.map (_._4)
|
||||
val warningFields = msgs.indices.drop(1).flatMap { index =>
|
||||
val old = index - 1
|
||||
val thisMsg = msgs(index)
|
||||
List(
|
||||
GeneralMovementField(
|
||||
warnCloseToEdgeOfMap(List(Vector3(0,1,0),Vector3(-1,0,0)), thisMsg),
|
||||
DeepSquare(1024, height - mns(old), mws(index), height - mns(index), mws(old))
|
||||
), //NW
|
||||
GeneralMovementField(
|
||||
warnCloseToEdgeOfMap(List(Vector3(0,1,0)), thisMsg),
|
||||
DeepSquare(1024, height - mns(old), width - mes(index), height - mns(index), mws(index))
|
||||
), //N
|
||||
GeneralMovementField(
|
||||
warnCloseToEdgeOfMap(List(Vector3(0,1,0),Vector3(1,0,0)), thisMsg),
|
||||
DeepSquare(1024, height - mns(old), width - mes(old), height - mns(index), width - mes(index))
|
||||
), //NE
|
||||
GeneralMovementField(
|
||||
warnCloseToEdgeOfMap(List(Vector3(1,0,0)), thisMsg),
|
||||
DeepSquare(1024, height - mns(index), width - mes(old), mss(index), width - mes(index))
|
||||
), //E
|
||||
GeneralMovementField(
|
||||
warnCloseToEdgeOfMap(List(Vector3(0,-1,0),Vector3(1,0,0)), thisMsg),
|
||||
DeepSquare(1024, mss(index), width - mes(old), mss(old), width - mes(index))
|
||||
), //SE
|
||||
GeneralMovementField(
|
||||
warnCloseToEdgeOfMap(List(Vector3(0,-1,0)), thisMsg),
|
||||
DeepSquare(1024, mss(index), width - mes(index), mss(old), mws(index))
|
||||
), //S
|
||||
GeneralMovementField(
|
||||
warnCloseToEdgeOfMap(List(Vector3(0,-1,0),Vector3(-1,0,0)), thisMsg),
|
||||
DeepSquare(1024, mss(index), mws(index), mss(old), mws(old))
|
||||
), //SW
|
||||
GeneralMovementField(
|
||||
warnCloseToEdgeOfMap(List(Vector3(-1,0,0)), thisMsg),
|
||||
DeepSquare(1024, height - mns(index), mws(index), mss(index), mws(old))
|
||||
) //W
|
||||
)
|
||||
case v: Vehicle =>
|
||||
val zone = v.Zone
|
||||
zone.VehicleEvents ! VehicleServiceMessage(
|
||||
v.Actor.toString(),
|
||||
VehicleAction.SendResponse(
|
||||
Service.defaultPlayerGUID,
|
||||
ChatMsg(ChatMessageType.CMT_QUIT, false, "",s"${msg}r ${v.Definition.Name} will be destroyed.", None)
|
||||
)
|
||||
)
|
||||
case _ => ;
|
||||
}
|
||||
(warningFields ++ killFields).toList
|
||||
} else {
|
||||
killFields
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upon entering a bounded warning region,
|
||||
* determine if entering from a dangerous angle,
|
||||
* and dispatch a warning message if so.
|
||||
* A "dangerous angle" means any projected motion that would inevitably lead to a kill region.
|
||||
* @param inDirectionOf directions to validate parallel movement triggering
|
||||
* @param msg the message index belonging to an `OffshoreVehicleMessage` packet
|
||||
*/
|
||||
private def warnCloseToEdgeOfMap(inDirectionOf: List[Vector3], msg: Int)(obj: PlanetSideGameObject): Unit = {
|
||||
val trespass: String = {
|
||||
val direction = Vector3.Unit(obj.Velocity.getOrElse(Vector3.Zero))
|
||||
inDirectionOf
|
||||
.filter { test => Vector3.ScalarProjection(direction, test) > 0.1f }
|
||||
.flatMap { directionToString }
|
||||
.mkString
|
||||
}
|
||||
if (trespass.nonEmpty) {
|
||||
obj match {
|
||||
case p : Player =>
|
||||
//if the player is moving independent of any vehicle towards a kill region, give them a flavorful message
|
||||
val punishment = if (p.Faction == PlanetSideEmpire.VS) {
|
||||
"r ongoing research venture will be defunded."
|
||||
} else if (p.Faction == PlanetSideEmpire.NC) {
|
||||
"r social credits will be liquidated."
|
||||
} else if (p.Faction == PlanetSideEmpire.TR) {
|
||||
" will be executed for desertion."
|
||||
} else {
|
||||
" will be executed for treason." //TODO for bops, eventually
|
||||
}
|
||||
val warning = s"Do not travel any further $trespass of the battlefield or you$punishment"
|
||||
p.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
p.Name,
|
||||
AvatarAction.SendResponseTargeted(
|
||||
Service.defaultPlayerGUID,
|
||||
ChatMsg(ChatMessageType.CMT_QUIT, false, "", warning, None)
|
||||
)
|
||||
)
|
||||
case _ => ;
|
||||
}
|
||||
obj match {
|
||||
case v: Vehicle =>
|
||||
v.Zone.VehicleEvents ! VehicleServiceMessage(
|
||||
v.Actor.toString(),
|
||||
VehicleAction.SendResponse(
|
||||
Service.defaultPlayerGUID,
|
||||
OffshoreVehicleMessage(v.Seats(0).occupant.get.GUID, v.GUID, msg)
|
||||
)
|
||||
)
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a directional `Vector3` entity that satisfies cardinal map directions
|
||||
* into one or two letters that indicate the same map direction
|
||||
* @param direction the raw direction
|
||||
* @return the clarified direction
|
||||
*/
|
||||
private def directionToString(direction: Vector3): String = {
|
||||
val ns = {
|
||||
val dir = Vector3.ScalarProjection(direction, Vector3(0,1,0))
|
||||
if (dir > 0) {
|
||||
"N"
|
||||
} else if (dir < 0) {
|
||||
"S"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
val ew = {
|
||||
val dir = Vector3.ScalarProjection(direction, Vector3(1,0,0))
|
||||
if (dir > 0) {
|
||||
"E"
|
||||
} else if (dir < 0) {
|
||||
"W"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
ns ++ ew
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,8 @@ class BlockMap(fullMapWidth: Int, fullMapHeight: Int, desiredSpanSize: Int) {
|
|||
* @return a conglomerate sector which lists all of the entities in the allocated sector(s)
|
||||
*/
|
||||
def addTo(target: BlockMapEntity, toPosition: Vector3): SectorPopulation = {
|
||||
addTo(target, toPosition, BlockMap.rangeFromEntity(target))
|
||||
val (y,x) = BlockMap.rangeFromEntity(target)
|
||||
addTo(target, toPosition, x, y)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -125,11 +126,25 @@ class BlockMap(fullMapWidth: Int, fullMapHeight: Int, desiredSpanSize: Int) {
|
|||
* @return a conglomerate sector which lists all of the entities in the allocated sector(s)
|
||||
*/
|
||||
def addTo(target: BlockMapEntity, toPosition: Vector3, range: Float): SectorPopulation = {
|
||||
val to = BlockMap.findSectorIndices(blockMap = this, toPosition, range)
|
||||
addTo(target, toPosition, range, range)
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate this entity into appropriate sectors on the blockmap
|
||||
* using the provided game world coordinates and the provided axis range.
|
||||
* @see `BlockMap.findSectorIndices`
|
||||
* @param target the entity
|
||||
* @param toPosition the game world coordinates that indicate the central sector
|
||||
* @param rangeX the distance from the central sector along the major x-axis
|
||||
* @param rangeY the distance from the central sector along the major y-axis
|
||||
* @return a conglomerate sector which lists all of the entities in the allocated sector(s)
|
||||
*/
|
||||
def addTo(target: BlockMapEntity, toPosition: Vector3, rangeX: Float, rangeY: Float): SectorPopulation = {
|
||||
val to = BlockMap.findSectorIndices(blockMap = this, toPosition, rangeX, rangeY)
|
||||
val toSectors = to.toSet.map { blocks }
|
||||
toSectors.foreach { block => block.addTo(target) }
|
||||
target.blockMapEntry = Some(BlockMapEntry(toPosition, range, to.toSet))
|
||||
BlockMap.quickToSectorGroup(range, toSectors)
|
||||
target.blockMapEntry = Some(BlockMapEntry(toPosition, rangeX, rangeY, to.toSet))
|
||||
BlockMap.quickToSectorGroup(rangeX, rangeY, toSectors)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -140,7 +155,7 @@ class BlockMap(fullMapWidth: Int, fullMapHeight: Int, desiredSpanSize: Int) {
|
|||
*/
|
||||
def removeFrom(target: BlockMapEntity): SectorPopulation = {
|
||||
target.blockMapEntry match {
|
||||
case Some(entry) => actuallyRemoveFrom(target, entry.coords, entry.range)
|
||||
case Some(entry) => actuallyRemoveFrom(target, entry.coords, entry.rangeX, entry.rangeY)
|
||||
case None => SectorGroup(Nil)
|
||||
}
|
||||
}
|
||||
|
|
@ -192,16 +207,17 @@ class BlockMap(fullMapWidth: Int, fullMapHeight: Int, desiredSpanSize: Int) {
|
|||
* Really.
|
||||
* @param target the entity
|
||||
* @param fromPosition the game world coordinates that indicate the central sector
|
||||
* @param range the distance from the central sector along the major axes
|
||||
* @param rangeX the distance from the central sector along the major x-axis
|
||||
* @param rangeY the distance from the central sector along the major y-axis
|
||||
* @return a conglomerate sector which lists all of the entities in the allocated sector(s)
|
||||
*/
|
||||
private def actuallyRemoveFrom(target: BlockMapEntity, fromPosition: Vector3, range: Float): SectorPopulation = {
|
||||
private def actuallyRemoveFrom(target: BlockMapEntity, fromPosition: Vector3, rangeX: Float, rangeY: Float): SectorPopulation = {
|
||||
target.blockMapEntry match {
|
||||
case Some(entry) =>
|
||||
target.blockMapEntry = None
|
||||
val from = entry.sectors.map { blocks }
|
||||
from.foreach { block => block.removeFrom(target) }
|
||||
BlockMap.quickToSectorGroup(range, from)
|
||||
BlockMap.quickToSectorGroup(rangeX, rangeY, from)
|
||||
case None =>
|
||||
SectorGroup(Nil)
|
||||
}
|
||||
|
|
@ -215,7 +231,7 @@ class BlockMap(fullMapWidth: Int, fullMapHeight: Int, desiredSpanSize: Int) {
|
|||
*/
|
||||
def move(target: BlockMapEntity): SectorPopulation = {
|
||||
target.blockMapEntry match {
|
||||
case Some(entry) => move(target, target.Position, entry.coords, entry.range)
|
||||
case Some(entry) => move(target, target.Position, entry.coords, entry.rangeX, entry.rangeY)
|
||||
case None => SectorGroup(Nil)
|
||||
}
|
||||
}
|
||||
|
|
@ -229,7 +245,7 @@ class BlockMap(fullMapWidth: Int, fullMapHeight: Int, desiredSpanSize: Int) {
|
|||
*/
|
||||
def move(target: BlockMapEntity, toPosition: Vector3): SectorPopulation = {
|
||||
target.blockMapEntry match {
|
||||
case Some(entry) => move(target, toPosition, entry.coords, entry.range)
|
||||
case Some(entry) => move(target, toPosition, entry.coords, entry.rangeX, entry.rangeY)
|
||||
case _ => SectorGroup(Nil)
|
||||
}
|
||||
}
|
||||
|
|
@ -255,14 +271,27 @@ class BlockMap(fullMapWidth: Int, fullMapHeight: Int, desiredSpanSize: Int) {
|
|||
* @return a conglomerate sector which lists all of the entities in the allocated sector(s)
|
||||
*/
|
||||
def move(target: BlockMapEntity, toPosition: Vector3, fromPosition: Vector3, range: Float): SectorPopulation = {
|
||||
move(target, toPosition, fromPosition, range, range)
|
||||
}
|
||||
|
||||
/**
|
||||
* Move an entity on the blockmap structure and update the prerequisite internal information.
|
||||
* @param target the entity
|
||||
* @param toPosition the next location of the entity in world coordinates
|
||||
* @param fromPosition the current location of the entity in world coordinates
|
||||
* @param rangeX the distance from the location along the major x-axis
|
||||
* @param rangeY the distance from the location along the major y-axis
|
||||
* @return a conglomerate sector which lists all of the entities in the allocated sector(s)
|
||||
*/
|
||||
def move(target: BlockMapEntity, toPosition: Vector3, fromPosition: Vector3, rangeX: Float, rangeY: Float): SectorPopulation = {
|
||||
target.blockMapEntry match {
|
||||
case Some(entry) =>
|
||||
val from = entry.sectors
|
||||
val to = BlockMap.findSectorIndices(blockMap = this, toPosition, range).toSet
|
||||
val to = BlockMap.findSectorIndices(blockMap = this, toPosition, rangeX, rangeY).toSet
|
||||
to.diff(from).foreach { index => blocks(index).addTo(target) }
|
||||
from.diff(to).foreach { index => blocks(index).removeFrom(target) }
|
||||
target.blockMapEntry = Some(BlockMapEntry(toPosition, range, to))
|
||||
BlockMap.quickToSectorGroup(range, to.map { blocks })
|
||||
target.blockMapEntry = Some(BlockMapEntry(toPosition, rangeX, rangeY, to))
|
||||
BlockMap.quickToSectorGroup(rangeX, rangeY, to.map { blocks })
|
||||
case None =>
|
||||
SectorGroup(Nil)
|
||||
}
|
||||
|
|
@ -290,7 +319,21 @@ object BlockMap {
|
|||
* @return the indices of the sectors in the blockmap structure
|
||||
*/
|
||||
def findSectorIndices(blockMap: BlockMap, p: Vector3, range: Float): Iterable[Int] = {
|
||||
findSectorIndices(blockMap.spanSize, blockMap.blocksInRow, blockMap.blocks.size, p, range)
|
||||
findSectorIndices(blockMap, p, range, range)
|
||||
}
|
||||
|
||||
/**
|
||||
* The blockmap is mapped to a coordinate range in two directions,
|
||||
* so find the indices of the sectors that correspond to the region
|
||||
* defined by the range around a coordinate position.
|
||||
* @param blockMap the blockmap structure
|
||||
* @param p the coordinate position
|
||||
* @param rangeX a rectangular range aigned with the lateral x-axis extending from a coordinate position
|
||||
* @param rangeY a rectangular range aigned with the lateral y-axis extending from a coordinate position
|
||||
* @return the indices of the sectors in the blockmap structure
|
||||
*/
|
||||
def findSectorIndices(blockMap: BlockMap, p: Vector3, rangeX: Float, rangeY: Float): Iterable[Int] = {
|
||||
findSectorIndices(blockMap.spanSize, blockMap.blocksInRow, blockMap.blocks.size, p, rangeX, rangeY)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -301,10 +344,18 @@ object BlockMap {
|
|||
* @param blocksInRow the number of sectors across the width (in a row) of the blockmap
|
||||
* @param blocksTotal the number of sectors in the blockmap
|
||||
* @param p the coordinate position
|
||||
* @param range a rectangular range aigned with lateral axes extending from a coordinate position
|
||||
* @param rangeX a rectangular range aigned with a lateral x-axis extending from a coordinate position
|
||||
* @param rangeY a rectangular range aigned with a lateral y-axis extending from a coordinate position
|
||||
* @return the indices of the sectors in the blockmap structure
|
||||
*/
|
||||
private def findSectorIndices(spanSize: Int, blocksInRow: Int, blocksTotal: Int, p: Vector3, range: Float): Iterable[Int] = {
|
||||
private def findSectorIndices(
|
||||
spanSize: Int,
|
||||
blocksInRow: Int,
|
||||
blocksTotal: Int,
|
||||
p: Vector3,
|
||||
rangeX: Float,
|
||||
rangeY: Float
|
||||
): Iterable[Int] = {
|
||||
val corners = {
|
||||
/*
|
||||
find the corners of a rectangular region extending in all cardinal directions from the position;
|
||||
|
|
@ -327,10 +378,10 @@ object BlockMap {
|
|||
[----][----][----][----] [----][----][----]
|
||||
*/
|
||||
val blocksInColumn = blocksTotal / blocksInRow
|
||||
val lowx = math.max(0, p.x - range)
|
||||
val highx = math.min(p.x + range, (blocksInRow * spanSize - 1).toFloat)
|
||||
val lowy = math.max(0, p.y - range)
|
||||
val highy = math.min(p.y + range, (blocksInColumn * spanSize - 1).toFloat)
|
||||
val lowx = math.max(0, p.x - rangeX)
|
||||
val highx = math.min(p.x + rangeX, (blocksInRow * spanSize - 1).toFloat)
|
||||
val lowy = math.max(0, p.y - rangeY)
|
||||
val highy = math.min(p.y + rangeY, (blocksInColumn * spanSize - 1).toFloat)
|
||||
Seq( (lowx, lowy), (highx, lowy), (lowx, highy), (highx, highy) )
|
||||
}.map { case (x, y) =>
|
||||
(y / spanSize).toInt * blocksInRow + (x / spanSize).toInt
|
||||
|
|
@ -350,34 +401,37 @@ object BlockMap {
|
|||
/**
|
||||
* Calculate the range expressed by a certain entity that can be allocated into a sector on the blockmap.
|
||||
* Entities have different ways of expressing these ranges.
|
||||
* @param target the entity
|
||||
* @param defaultRadius a default radius, if no specific case is discovered;
|
||||
* @param target the entity
|
||||
* @param defaultX a default range for the x-axis, if no specific case is discovered;
|
||||
* if no default case, the default-default case is a single unit (`1.0f`)
|
||||
* @param defaultY a default range for the y-axis, if no specific case is discovered;
|
||||
* if no default case, the default-default case is a single unit (`1.0f`)
|
||||
* @return the distance from a central position along the major axes
|
||||
* @return the distance from a central position along the major axes (y-axis, then x-axis)
|
||||
*/
|
||||
def rangeFromEntity(target: BlockMapEntity, defaultRadius: Option[Float] = None): Float = {
|
||||
def rangeFromEntity(target: BlockMapEntity, defaultX: Option[Float] = None, defaultY: Option[Float] = None): (Float, Float) = {
|
||||
target match {
|
||||
case b: Building =>
|
||||
//use the building's sphere of influence
|
||||
b.Definition.SOIRadius.toFloat// * 0.5f
|
||||
(b.Definition.SOIRadius.toFloat, b.Definition.SOIRadius.toFloat)
|
||||
|
||||
case o: PlanetSideGameObject =>
|
||||
//use the server geometry
|
||||
val pos = target.Position
|
||||
val v = o.Definition.Geometry(o)
|
||||
math.sqrt(math.max(
|
||||
val out = math.sqrt(math.max(
|
||||
Vector3.DistanceSquared(pos, v.pointOnOutside(Vector3(1,0,0)).asVector3),
|
||||
Vector3.DistanceSquared(pos, v.pointOnOutside(Vector3(0,1,0)).asVector3)
|
||||
)).toFloat
|
||||
(out, out)
|
||||
|
||||
case e: PieceOfEnvironment =>
|
||||
//use the bounds (like server geometry, but is alawys a rectangle on the XY-plane)
|
||||
//use the bounds (like server geometry, but is always a rectangle on the XY-plane)
|
||||
val bounds = e.collision.bounding
|
||||
math.max(bounds.top - bounds.base, bounds.right - bounds.left) * 0.5f
|
||||
((bounds.top - bounds.base) * 0.5f, (bounds.right - bounds.left) * 0.5f)
|
||||
|
||||
case _ =>
|
||||
//default and default-default
|
||||
defaultRadius.getOrElse(1.0f)
|
||||
(defaultX.getOrElse(1.0f), defaultY.getOrElse(1.0f))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -403,10 +457,24 @@ object BlockMap {
|
|||
* @return a conglomerate sector which lists all of the entities in the allocated sector(s)
|
||||
*/
|
||||
def quickToSectorGroup(range: Float, to: Iterable[Sector]): SectorPopulation = {
|
||||
quickToSectorGroup(range, range, to)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* If only one sector, just return that sector.
|
||||
* If a group of sectors, organize them into a single referential sector.
|
||||
* @param rangeX a custom range value for the x-axis
|
||||
* @param rangeY a custom range value for the y-axis
|
||||
* @param to all allocated sectors
|
||||
* @return a conglomerate sector which lists all of the entities in the allocated sector(s)
|
||||
*/
|
||||
def quickToSectorGroup(rangeX: Float, rangeY: Float, to: Iterable[Sector]): SectorPopulation = {
|
||||
if (to.size == 1) {
|
||||
SectorGroup(range, to.head)
|
||||
SectorGroup(rangeX, rangeY, to.head)
|
||||
} else {
|
||||
SectorGroup(range, to)
|
||||
SectorGroup(rangeX, rangeY, to)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import net.psforever.objects.entity.WorldEntity
|
|||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
sealed case class BlockMapEntry(coords: Vector3, range: Float, sectors: Set[Int])
|
||||
sealed case class BlockMapEntry(coords: Vector3, rangeX: Float, rangeY: Float, sectors: Set[Int])
|
||||
|
||||
/**
|
||||
* An game object that can be represented on a blockmap.
|
||||
|
|
@ -64,6 +64,16 @@ trait BlockMapEntity
|
|||
}
|
||||
|
||||
object BlockMapEntity {
|
||||
/**
|
||||
* Overloaded constructor that uses a single range to construct a block map entry.
|
||||
* @param coords the absolute game world coordinates
|
||||
* @param range the distance outwards from the game world coordinates along the major axes
|
||||
* @param sectors the indices of sectors on the blockmap
|
||||
* @return a `BlockMapEntry` entity
|
||||
*/
|
||||
def apply(coords: Vector3, range: Float, sectors: Set[Int]): BlockMapEntry =
|
||||
BlockMapEntry(coords, range, range, sectors)
|
||||
|
||||
/**
|
||||
* The entity is currently excluded from being represented on a blockmap structure.
|
||||
* There is no need to update.
|
||||
|
|
@ -87,7 +97,7 @@ object BlockMapEntity {
|
|||
private def updateBlockMap(target: BlockMapEntity, newCoords: Vector3): Boolean = {
|
||||
target.blockMapEntry match {
|
||||
case Some(oldEntry) =>
|
||||
target.blockMapEntry = Some(BlockMapEntry(newCoords, oldEntry.range, oldEntry.sectors))
|
||||
target.blockMapEntry = Some(BlockMapEntry(newCoords, oldEntry.rangeX, oldEntry.rangeY, oldEntry.sectors))
|
||||
true
|
||||
case None =>
|
||||
false
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ import scala.collection.mutable.ListBuffer
|
|||
* The collections of entities in a sector conglomerate.
|
||||
*/
|
||||
trait SectorPopulation {
|
||||
def range: Float
|
||||
def rangeX: Float
|
||||
|
||||
def rangeY: Float
|
||||
|
||||
def livePlayerList: List[Player]
|
||||
|
||||
|
|
@ -153,7 +155,9 @@ class Sector(val longitude: Int, val latitude: Int, val span: Int)
|
|||
(a: Projectile, b: Projectile) => a.id == b.id
|
||||
)
|
||||
|
||||
def range: Float = span.toFloat
|
||||
def rangeX: Float = span.toFloat
|
||||
|
||||
def rangeY: Float = span.toFloat
|
||||
|
||||
def livePlayerList : List[Player] = livePlayers.list
|
||||
|
||||
|
|
@ -248,7 +252,8 @@ class Sector(val longitude: Int, val latitude: Int, val span: Int)
|
|||
* @param environmentList fields that represent the game world environment
|
||||
*/
|
||||
class SectorGroup(
|
||||
val range: Float,
|
||||
val rangeX: Float,
|
||||
val rangeY: Float,
|
||||
val livePlayerList: List[Player],
|
||||
val corpseList: List[Player],
|
||||
val vehicleList: List[Vehicle],
|
||||
|
|
@ -269,18 +274,7 @@ object SectorGroup {
|
|||
* @return a `SectorGroup` object
|
||||
*/
|
||||
def apply(sector: Sector): SectorGroup = {
|
||||
new SectorGroup(
|
||||
sector.range,
|
||||
sector.livePlayerList,
|
||||
sector.corpseList,
|
||||
sector.vehicleList,
|
||||
sector.equipmentOnGroundList,
|
||||
sector.deployableList,
|
||||
sector.buildingList,
|
||||
sector.amenityList,
|
||||
sector.environmentList,
|
||||
sector.projectileList
|
||||
)
|
||||
SectorGroup(sector.rangeX, sector.rangeY, sector)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -291,8 +285,21 @@ object SectorGroup {
|
|||
* @return a `SectorGroup` object
|
||||
*/
|
||||
def apply(range: Float, sector: Sector): SectorGroup = {
|
||||
SectorGroup(range, range, sector)
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded constructor that takes a single sector
|
||||
* and transfers the lists of entities into a single conglomeration of the sector populations.
|
||||
* @param rangeX a custom range value for the x-axis
|
||||
* @param rangeY a custom range value for the y-axis
|
||||
* @param sector the sector to be counted
|
||||
* @return a `SectorGroup` object
|
||||
*/
|
||||
def apply(rangeX: Float, rangeY: Float, sector: Sector): SectorGroup = {
|
||||
new SectorGroup(
|
||||
range,
|
||||
rangeX,
|
||||
rangeY,
|
||||
sector.livePlayerList,
|
||||
sector.corpseList,
|
||||
sector.vehicleList,
|
||||
|
|
@ -315,9 +322,9 @@ object SectorGroup {
|
|||
if (sectors.isEmpty) {
|
||||
SectorGroup(range = 0, sectors = Nil)
|
||||
} else if (sectors.size == 1) {
|
||||
SectorGroup(sectors.head.range, sectors)
|
||||
SectorGroup(sectors.head.rangeX, sectors.head.rangeY, sectors)
|
||||
} else {
|
||||
SectorGroup(sectors.maxBy { _.range }.range, sectors)
|
||||
SectorGroup(sectors.maxBy { _.rangeX }.rangeX, sectors.maxBy { _.rangeY }.rangeY, sectors)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -329,12 +336,25 @@ object SectorGroup {
|
|||
* @return a `SectorGroup` object
|
||||
*/
|
||||
def apply(range: Float, sectors: Iterable[Sector]): SectorGroup = {
|
||||
SectorGroup(range, range, sectors)
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded constructor that takes a group of sectors
|
||||
* and condenses all of the lists of entities into a single conglomeration of the sector populations.
|
||||
* @param rangeX a custom range value for the x-axis
|
||||
* @param rangeY a custom range value for the y-axis
|
||||
* @param sectors the series of sectors to be counted
|
||||
* @return a `SectorGroup` object
|
||||
*/
|
||||
def apply(rangeX: Float, rangeY: Float, sectors: Iterable[Sector]): SectorGroup = {
|
||||
if (sectors.isEmpty) {
|
||||
new SectorGroup(range, Nil, Nil, Nil, Nil, Nil, Nil, Nil, Nil, Nil)
|
||||
new SectorGroup(rangeX, rangeY, Nil, Nil, Nil, Nil, Nil, Nil, Nil, Nil, Nil)
|
||||
} else if (sectors.size == 1) {
|
||||
val sector = sectors.head
|
||||
new SectorGroup(
|
||||
range,
|
||||
rangeX,
|
||||
rangeY,
|
||||
sector.livePlayerList,
|
||||
sector.corpseList,
|
||||
sector.vehicleList,
|
||||
|
|
@ -347,7 +367,8 @@ object SectorGroup {
|
|||
)
|
||||
} else {
|
||||
new SectorGroup(
|
||||
range,
|
||||
rangeX,
|
||||
rangeY,
|
||||
sectors.flatMap { _.livePlayerList }.toList.distinct,
|
||||
sectors.flatMap { _.corpseList }.toList.distinct,
|
||||
sectors.flatMap { _.vehicleList }.toList.distinct,
|
||||
|
|
|
|||
|
|
@ -460,7 +460,7 @@ object GamePacketOpcode extends Enumeration {
|
|||
case 0x82 => noDecoder(TriggerBotAction)
|
||||
case 0x83 => game.SquadWaypointRequest.decode
|
||||
case 0x84 => game.SquadWaypointEvent.decode
|
||||
case 0x85 => noDecoder(OffshoreVehicleMessage)
|
||||
case 0x85 => game.OffshoreVehicleMessage.decode
|
||||
case 0x86 => game.ObjectDeployedMessage.decode
|
||||
case 0x87 => noDecoder(ObjectDeployedCountMessage)
|
||||
// 0x88
|
||||
|
|
|
|||
|
|
@ -82,36 +82,36 @@ object AvatarAwardMessage extends Marshallable[AvatarAwardMessage] {
|
|||
|
||||
private val qualification_codec: Codec[AwardOption] = {
|
||||
uint32L.hlist
|
||||
}.xmap[AwardOption](
|
||||
}.xmap[AwardQualificationProgress](
|
||||
{
|
||||
case a :: HNil => AwardQualificationProgress(a)
|
||||
},
|
||||
{
|
||||
case AwardQualificationProgress(a) => a :: HNil
|
||||
}
|
||||
)
|
||||
).asInstanceOf[Codec[AwardOption]]
|
||||
|
||||
private val completion_codec: Codec[AwardOption] = {
|
||||
uint32L.hlist
|
||||
}.xmap[AwardOption](
|
||||
}.xmap[AwardCompletion](
|
||||
{
|
||||
case a :: HNil => AwardCompletion(a)
|
||||
},
|
||||
{
|
||||
case AwardCompletion(a) => a :: HNil
|
||||
}
|
||||
)
|
||||
).asInstanceOf[Codec[AwardOption]]
|
||||
|
||||
private val progress_codec: Codec[AwardOption] = {
|
||||
uint32L :: uint32L
|
||||
}.xmap[AwardOption](
|
||||
}.xmap[AwardProgress](
|
||||
{
|
||||
case a :: b :: HNil => AwardProgress(a, b)
|
||||
},
|
||||
{
|
||||
case AwardProgress(a, b) => a :: b :: HNil
|
||||
}
|
||||
)
|
||||
).asInstanceOf[Codec[AwardOption]]
|
||||
|
||||
implicit val codec: Codec[AvatarAwardMessage] = (
|
||||
("merit_commendation" | MeritCommendation.codec) ::
|
||||
|
|
@ -122,8 +122,8 @@ object AvatarAwardMessage extends Marshallable[AvatarAwardMessage] {
|
|||
case Right(d) => d
|
||||
},
|
||||
{
|
||||
case d: AwardProgress => Left(d)
|
||||
case d: AwardQualificationProgress => Right(d)
|
||||
case d: AwardProgress => Left(d)
|
||||
case d: AwardOption => Right(d)
|
||||
}
|
||||
),
|
||||
completion_codec
|
||||
|
|
@ -133,9 +133,8 @@ object AvatarAwardMessage extends Marshallable[AvatarAwardMessage] {
|
|||
case Right(d) => d
|
||||
},
|
||||
{
|
||||
case d: AwardProgress => Left(d)
|
||||
case d: AwardQualificationProgress => Left(d)
|
||||
case d: AwardCompletion => Right(d)
|
||||
case d: AwardCompletion => Right(d)
|
||||
case d: AwardOption => Left(d)
|
||||
}
|
||||
)) ::
|
||||
("unk" | uint8L)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2022 PSForever
|
||||
package net.psforever.packet.game
|
||||
|
||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
|
||||
import net.psforever.types.PlanetSideGUID
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
|
||||
/**
|
||||
* Dispatched from the server to indicate that the player is traveling too far from the primary battlefield
|
||||
* and needs to return.
|
||||
* At first the intention is to warn.
|
||||
* After the warning, the intent is to dispose.<br>
|
||||
* Do not dispatch this packet if the player is not seated in a vehicle or else the client will crash.<br>
|
||||
* <br>
|
||||
* Messages follow:<br>
|
||||
* 1) `WARNING: Power Link is weakening. Proceed back to the continent.`<br>
|
||||
* 2) `DANGER: Power Link is Dangerously Low. Turn back to the continent immediately!`<br>
|
||||
* 3) `Power Link lost.`<br>
|
||||
* Upon reception of #3, the player will lose control of their vehicle and it may explode depending on the vehicle.
|
||||
* The "Power Link" that is mentioned is a hand-wave.
|
||||
* @param player_guid na
|
||||
* @param vehicle_guid na
|
||||
* @param msg the number indexes of the message to be displayed by the client
|
||||
*/
|
||||
final case class OffshoreVehicleMessage(
|
||||
player_guid: PlanetSideGUID,
|
||||
vehicle_guid: PlanetSideGUID,
|
||||
msg: Int
|
||||
) extends PlanetSideGamePacket {
|
||||
type Packet = OffshoreVehicleMessage
|
||||
def opcode = GamePacketOpcode.OffshoreVehicleMessage
|
||||
def encode = OffshoreVehicleMessage.encode(this)
|
||||
}
|
||||
|
||||
object OffshoreVehicleMessage extends Marshallable[OffshoreVehicleMessage] {
|
||||
implicit val codec : Codec[OffshoreVehicleMessage] = (
|
||||
("player_guid" | PlanetSideGUID.codec) ::
|
||||
("vehicle_guid" | PlanetSideGUID.codec) ::
|
||||
("msg" | uint2L)
|
||||
).as[OffshoreVehicleMessage]
|
||||
}
|
||||
|
|
@ -51,6 +51,17 @@ final case class Vector3(x: Float, y: Float, z: Float) {
|
|||
Vector3(x / scalar, y / scalar, z / scalar)
|
||||
}
|
||||
|
||||
/**
|
||||
* Operator for multiplication of vector elements.
|
||||
* This applies a scaling to each element of one vector by the same element of the other.
|
||||
* The application of this overload is "vector ** v".
|
||||
* @param v the per-element scalars as a `Vector3` object
|
||||
* @return a new `Vector3` object
|
||||
*/
|
||||
def **(v: Vector3): Vector3 = {
|
||||
Vector3(x * v.x, y * v.y, z * v.z)
|
||||
}
|
||||
|
||||
/**
|
||||
* Operator for returning the ground-planar coordinates
|
||||
* and ignoring the perpendicular distance from the world floor.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue