mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-15 16:34:39 +00:00
Repeating the Obvious (#1233)
* adding chat and event messages that have been neglected since; these are easy additions * completely retooled water interactions for players and vehicles to handle a wading status, before drowning; when player with llu or vehicle with player with llu come into contact with water in this wading state, the llu is lost and the facility hack ends; adding messages to support this and differentiate from an llu facility capture timeout * periodic message while the llu is active, whether or not there is a carrier, until the hack is finished * message when inventory is full (assumes player inventory destination, but item winds up in hand due to lack of space, but it works) * when changing exo-suits, complain if equipment has to be deleted; dropped equipment is limited to special equipment; report a player pointlessly * announce ams decay to players who have just spawned on an ams, when they spawn on that ams, and for the last round of spawnees when the vehicle finally deconstructs; due to use of the word 'bound' this may be an incorrect application, but matrixing doesn't work anyway * deconstruction message for would-be driver when vehicle is abandoned on spawn pad; tempo on message delivery is different than usual * message when player is kicked from orbital shuttle gantry; message when player attempts to bail in a warp gate; message when player attempts to bail from a droppod; stop player from succeeding in bailing from a droppod * vehicle pad deconstruction complete message; message when nc max shield deactivates when out of capacitor power or when max opens fire; message when ams can not deploy because it is blocked by other entities; message when facility capture requires ntu * message for deployables being blocked; cleaning up dev test section * Yellow Ownership (#1226) * just some tinkering and clean-up * converted DeployItem from AvatarService to LocalService; attempt at resolving missing overwhip yellow ring is complicated; vehicle ownership packet wqorks on deployables that are mountable, but is less successful on normal simple deployables * restoration of yellow ring of ownership around deployables; changes to variant of CommonFieldData transcorder used on certain deployable transcoders; static values are assigned parameter names and public variables are given types for completion * initial packet for GenericObjectAction2Message and tests; repaired transcoders and tests for TRAP and small turrets * force redraw of the whole boomer to assert reassignment of ownership; it's heavy-handed but it works * deployable ownership should be asserted during both re-zoning and revival; refactoring of code in ZoningOperations * message when inventory is full (assumes player inventory destination, but item winds up in hand due to lack of space, but it works) * vehicle deployment messages added in, then deployment was fixed to accommodate an explicit caller, and that changed a whole lot of the deployment loop for messages; environmental activity was modified to maointain a more responsible start/stop transition; many many test changes (still an issue with a lot of them) * moving around conditions for losing the llu * the question of one extra bit for small deployables; also, all tests pass successfully, tho resource silo use remains coin flip; what sorcery is this * duplicate capture lost message eliminated; flag lost violently due to environment in general rather than just water interaction; flag lost violently due to warp gate envelope interaction; flag lost due to be dropped in an unsafe position * vary the testing depth for water interaction * darn tests * fixed vehicle interference; added missing ArmorShieldOff message; clearing countdown after vehicle spawn should stop countdown from appearing in subsequent vehicle spawns * the router needs 20m of clearance * removing the shared group interference information from routers
This commit is contained in:
parent
4b7d41db2f
commit
6a349d0fe1
63 changed files with 2245 additions and 998 deletions
|
|
@ -3,6 +3,7 @@ package net.psforever.actors.session.normal
|
||||||
|
|
||||||
import akka.actor.{ActorContext, typed}
|
import akka.actor.{ActorContext, typed}
|
||||||
import net.psforever.actors.session.support.AvatarHandlerFunctions
|
import net.psforever.actors.session.support.AvatarHandlerFunctions
|
||||||
|
import net.psforever.objects.serverobject.containable.ContainableBehavior
|
||||||
import net.psforever.packet.game.{AvatarImplantMessage, CreateShortcutMessage, ImplantAction}
|
import net.psforever.packet.game.{AvatarImplantMessage, CreateShortcutMessage, ImplantAction}
|
||||||
import net.psforever.types.ImplantType
|
import net.psforever.types.ImplantType
|
||||||
|
|
||||||
|
|
@ -295,6 +296,17 @@ class AvatarHandlerLogic(val ops: SessionAvatarHandlers, implicit val context: A
|
||||||
case (_, dguid) => sendResponse(ObjectDeleteMessage(dguid, unk1=0))
|
case (_, dguid) => sendResponse(ObjectDeleteMessage(dguid, unk1=0))
|
||||||
}
|
}
|
||||||
//functionally delete
|
//functionally delete
|
||||||
|
if (delete.size > 1 || delete.nonEmpty && !delete.exists {
|
||||||
|
case (e: Tool, _) => GlobalDefinitions.isMaxArms(e.Definition)
|
||||||
|
case _ => false
|
||||||
|
}) {
|
||||||
|
/*
|
||||||
|
if going x -> max, you will have enough space in max inventory for any displaced holster equipment
|
||||||
|
for max -> max, don't care about the max weapon arm being deleted (allow for 1)
|
||||||
|
for any other x -> x, any deleted equipment will raise this comment
|
||||||
|
*/
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@ItemsDeconstructed"))
|
||||||
|
}
|
||||||
delete.foreach { case (obj, _) => TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj)) }
|
delete.foreach { case (obj, _) => TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj)) }
|
||||||
//redraw
|
//redraw
|
||||||
if (maxhand) {
|
if (maxhand) {
|
||||||
|
|
@ -330,13 +342,17 @@ class AvatarHandlerLogic(val ops: SessionAvatarHandlers, implicit val context: A
|
||||||
}
|
}
|
||||||
DropLeftovers(player)(drop)
|
DropLeftovers(player)(drop)
|
||||||
|
|
||||||
case AvatarResponse.ChangeExosuit(target, armor, exosuit, subtype, slot, _, oldHolsters, holsters, _, _, _, delete) =>
|
case AvatarResponse.ChangeExosuit(target, armor, exosuit, subtype, slot, _, oldHolsters, holsters, _, _, drop, delete) =>
|
||||||
sendResponse(ArmorChangedMessage(target, exosuit, subtype))
|
sendResponse(ArmorChangedMessage(target, exosuit, subtype))
|
||||||
sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
|
sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
|
||||||
//happening to some other player
|
//happening to some other player
|
||||||
sendResponse(ObjectHeldMessage(target, slot, unk1 = false))
|
sendResponse(ObjectHeldMessage(target, slot, unk1 = false))
|
||||||
//cleanup
|
//cleanup
|
||||||
(oldHolsters ++ delete).foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
|
val dropPred = ContainableBehavior.DropPredicate(player)
|
||||||
|
val deleteFromDrop = drop.filterNot(dropPred)
|
||||||
|
(oldHolsters ++ delete ++ deleteFromDrop.map(f =>(f.obj, f.GUID)))
|
||||||
|
.distinctBy(_._2)
|
||||||
|
.foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
|
||||||
//draw holsters
|
//draw holsters
|
||||||
holsters.foreach {
|
holsters.foreach {
|
||||||
case InventoryItem(obj, index) =>
|
case InventoryItem(obj, index) =>
|
||||||
|
|
|
||||||
|
|
@ -145,8 +145,11 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
|
||||||
case (CMT_KICK, _, contents) if gmCommandAllowed =>
|
case (CMT_KICK, _, contents) if gmCommandAllowed =>
|
||||||
ops.commandKick(session, message, contents)
|
ops.commandKick(session, message, contents)
|
||||||
|
|
||||||
|
case (CMT_REPORTUSER, _, contents) =>
|
||||||
|
ops.commandReportUser(session, message, contents)
|
||||||
|
|
||||||
case _ =>
|
case _ =>
|
||||||
log.warn(s"Unhandled chat message $message")
|
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@no_permission"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -162,6 +162,11 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
|
||||||
}
|
}
|
||||||
case None => ()
|
case None => ()
|
||||||
}
|
}
|
||||||
|
//llu destruction check
|
||||||
|
if (player.Carrying.contains(SpecialCarry.CaptureFlag)) {
|
||||||
|
CaptureFlagManager.ReasonToLoseFlagViolently(continent, sessionLogic.general.specialItemSlotGuid, player)
|
||||||
|
}
|
||||||
|
//
|
||||||
val eagleEye: Boolean = ops.canSeeReallyFar
|
val eagleEye: Boolean = ops.canSeeReallyFar
|
||||||
val isNotVisible: Boolean = sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing ||
|
val isNotVisible: Boolean = sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing ||
|
||||||
(player.isAlive && sessionLogic.zoning.spawn.deadState == DeadState.RespawnTime)
|
(player.isAlive && sessionLogic.zoning.spawn.deadState == DeadState.RespawnTime)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
import net.psforever.objects.serverobject.environment.interaction.ResetAllEnvironmentInteractions
|
import net.psforever.objects.serverobject.environment.interaction.ResetAllEnvironmentInteractions
|
||||||
import net.psforever.objects.serverobject.hackable.GenericHackables
|
import net.psforever.objects.serverobject.hackable.GenericHackables
|
||||||
import net.psforever.objects.serverobject.mount.Mountable
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
|
import net.psforever.objects.serverobject.structures.WarpGate
|
||||||
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
|
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
|
||||||
import net.psforever.objects.serverobject.turret.{FacilityTurret, WeaponTurret}
|
import net.psforever.objects.serverobject.turret.{FacilityTurret, WeaponTurret}
|
||||||
import net.psforever.objects.vehicles.{AccessPermissionGroup, CargoBehavior}
|
import net.psforever.objects.vehicles.{AccessPermissionGroup, CargoBehavior}
|
||||||
|
|
@ -19,7 +20,7 @@ import net.psforever.packet.game.{ChatMsg, DelayedPathMountMsg, DismountVehicleC
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
import net.psforever.types.{BailType, ChatMessageType, PlanetSideGUID, Vector3}
|
import net.psforever.types.{BailType, ChatMessageType, DriveState, PlanetSideGUID, Vector3}
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
|
@ -71,18 +72,6 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
|
||||||
obj.Actor ! Mountable.TryDismount(player, seat_num, bailType)
|
obj.Actor ! Mountable.TryDismount(player, seat_num, bailType)
|
||||||
//short-circuit the temporary channel for transferring between zones, the player is no longer doing that
|
//short-circuit the temporary channel for transferring between zones, the player is no longer doing that
|
||||||
sessionLogic.zoning.interstellarFerry = None
|
sessionLogic.zoning.interstellarFerry = None
|
||||||
// Deconstruct the vehicle if the driver has bailed out and the vehicle is capable of flight
|
|
||||||
//todo: implement auto landing procedure if the pilot bails but passengers are still present instead of deconstructing the vehicle
|
|
||||||
//todo: continue flight path until aircraft crashes if no passengers present (or no passenger seats), then deconstruct.
|
|
||||||
//todo: kick cargo passengers out. To be added after PR #216 is merged
|
|
||||||
obj match {
|
|
||||||
case v: Vehicle
|
|
||||||
if bailType == BailType.Bailed &&
|
|
||||||
v.SeatPermissionGroup(seat_num).contains(AccessPermissionGroup.Driver) &&
|
|
||||||
v.isFlying =>
|
|
||||||
v.Actor ! Vehicle.Deconstruct(None) //immediate deconstruction
|
|
||||||
case _ => ()
|
|
||||||
}
|
|
||||||
|
|
||||||
case None =>
|
case None =>
|
||||||
dError(s"DismountVehicleMsg: can not find where player ${player.Name}_guid is seated in mountable ${player.VehicleSeated}", player)
|
dError(s"DismountVehicleMsg: can not find where player ${player.Name}_guid is seated in mountable ${player.VehicleSeated}", player)
|
||||||
|
|
@ -368,18 +357,19 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
|
||||||
DismountAction(tplayer, obj, seatNum)
|
DismountAction(tplayer, obj, seatNum)
|
||||||
obj.Actor ! Vehicle.Deconstruct()
|
obj.Actor ! Vehicle.Deconstruct()
|
||||||
|
|
||||||
|
case Mountable.CanDismount(obj: Vehicle, seatNum, _)
|
||||||
|
if tplayer.GUID == player.GUID &&
|
||||||
|
obj.isFlying &&
|
||||||
|
obj.SeatPermissionGroup(seatNum).contains(AccessPermissionGroup.Driver) =>
|
||||||
|
// Deconstruct the vehicle if the driver has bailed out and the vehicle is capable of flight
|
||||||
|
//todo: implement auto landing procedure if the pilot bails but passengers are still present instead of deconstructing the vehicle
|
||||||
|
//todo: continue flight path until aircraft crashes if no passengers present (or no passenger seats), then deconstruct.
|
||||||
|
//todo: kick cargo passengers out. To be added after PR #216 is merged
|
||||||
|
DismountVehicleAction(tplayer, obj, seatNum)
|
||||||
|
obj.Actor ! Vehicle.Deconstruct(None) //immediate deconstruction
|
||||||
|
|
||||||
case Mountable.CanDismount(obj: Vehicle, seatNum, _)
|
case Mountable.CanDismount(obj: Vehicle, seatNum, _)
|
||||||
if tplayer.GUID == player.GUID =>
|
if tplayer.GUID == player.GUID =>
|
||||||
//disembarking self
|
|
||||||
log.info(s"${player.Name} dismounts the ${obj.Definition.Name}'s ${
|
|
||||||
obj.SeatPermissionGroup(seatNum) match {
|
|
||||||
case Some(AccessPermissionGroup.Driver) => "driver seat"
|
|
||||||
case Some(seatType) => s"$seatType seat (#$seatNum)"
|
|
||||||
case None => "seat"
|
|
||||||
}
|
|
||||||
}")
|
|
||||||
sessionLogic.vehicles.ConditionalDriverVehicleControl(obj)
|
|
||||||
sessionLogic.general.unaccessContainer(obj)
|
|
||||||
DismountVehicleAction(tplayer, obj, seatNum)
|
DismountVehicleAction(tplayer, obj, seatNum)
|
||||||
|
|
||||||
case Mountable.CanDismount(obj: Vehicle, seat_num, _) =>
|
case Mountable.CanDismount(obj: Vehicle, seat_num, _) =>
|
||||||
|
|
@ -388,7 +378,7 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
|
||||||
VehicleAction.KickPassenger(tplayer.GUID, seat_num, unk2=true, obj.GUID)
|
VehicleAction.KickPassenger(tplayer.GUID, seat_num, unk2=true, obj.GUID)
|
||||||
)
|
)
|
||||||
|
|
||||||
case Mountable.CanDismount(obj: PlanetSideGameObject with PlanetSideGameObject with Mountable with FactionAffinity with InGameHistory, seatNum, _) =>
|
case Mountable.CanDismount(obj: PlanetSideGameObject with Mountable with FactionAffinity with InGameHistory, seatNum, _) =>
|
||||||
log.info(s"${tplayer.Name} dismounts a ${obj.Definition.asInstanceOf[ObjectDefinition].Name}")
|
log.info(s"${tplayer.Name} dismounts a ${obj.Definition.asInstanceOf[ObjectDefinition].Name}")
|
||||||
DismountAction(tplayer, obj, seatNum)
|
DismountAction(tplayer, obj, seatNum)
|
||||||
|
|
||||||
|
|
@ -407,7 +397,38 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
|
||||||
case Mountable.CanNotMount(obj: Mountable, seatNumber) =>
|
case Mountable.CanNotMount(obj: Mountable, seatNumber) =>
|
||||||
log.warn(s"MountVehicleMsg: ${tplayer.Name} attempted to mount $obj's seat $seatNumber, but was not allowed")
|
log.warn(s"MountVehicleMsg: ${tplayer.Name} attempted to mount $obj's seat $seatNumber, but was not allowed")
|
||||||
|
|
||||||
case Mountable.CanNotDismount(obj, seatNum) =>
|
case Mountable.CanNotDismount(obj: Vehicle, _, BailType.Normal)
|
||||||
|
if obj.DeploymentState == DriveState.AutoPilot =>
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_224, "@SA_CannotDismountAtThisTime"))
|
||||||
|
|
||||||
|
case Mountable.CanNotDismount(obj: Vehicle, _, BailType.Bailed)
|
||||||
|
if obj.Definition == GlobalDefinitions.droppod =>
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_224, "@CannotBailFromDroppod"))
|
||||||
|
|
||||||
|
case Mountable.CanNotDismount(obj: Vehicle, _, BailType.Bailed)
|
||||||
|
if obj.DeploymentState == DriveState.AutoPilot =>
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_224, "@SA_CannotBailAtThisTime"))
|
||||||
|
|
||||||
|
case Mountable.CanNotDismount(obj: Vehicle, _, BailType.Bailed)
|
||||||
|
if {
|
||||||
|
continent
|
||||||
|
.blockMap
|
||||||
|
.sector(obj)
|
||||||
|
.buildingList
|
||||||
|
.exists {
|
||||||
|
case wg: WarpGate =>
|
||||||
|
Vector3.DistanceSquared(obj.Position, wg.Position) < math.pow(wg.Definition.SOIRadius, 2)
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} =>
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@Vehicle_CannotBailInWarpgateEnvelope"))
|
||||||
|
|
||||||
|
case Mountable.CanNotDismount(obj: Vehicle, _, _)
|
||||||
|
if obj.isMoving(test = 1f) =>
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_224, "@TooFastToDismount"))
|
||||||
|
|
||||||
|
case Mountable.CanNotDismount(obj, seatNum, _) =>
|
||||||
log.warn(s"DismountVehicleMsg: ${tplayer.Name} attempted to dismount $obj's mount $seatNum, but was not allowed")
|
log.warn(s"DismountVehicleMsg: ${tplayer.Name} attempted to dismount $obj's mount $seatNum, but was not allowed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -465,7 +486,17 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
|
||||||
* @param obj the mountable object
|
* @param obj the mountable object
|
||||||
* @param seatNum the mount out of which which the player is disembarking
|
* @param seatNum the mount out of which which the player is disembarking
|
||||||
*/
|
*/
|
||||||
private def DismountVehicleAction(tplayer: Player, obj: PlanetSideGameObject with FactionAffinity with InGameHistory, seatNum: Int): Unit = {
|
private def DismountVehicleAction(tplayer: Player, obj: Vehicle, seatNum: Int): Unit = {
|
||||||
|
//disembarking self
|
||||||
|
log.info(s"${player.Name} dismounts the ${obj.Definition.Name}'s ${
|
||||||
|
obj.SeatPermissionGroup(seatNum) match {
|
||||||
|
case Some(AccessPermissionGroup.Driver) => "driver seat"
|
||||||
|
case Some(seatType) => s"$seatType seat (#$seatNum)"
|
||||||
|
case None => "seat"
|
||||||
|
}
|
||||||
|
}")
|
||||||
|
sessionLogic.vehicles.ConditionalDriverVehicleControl(obj)
|
||||||
|
sessionLogic.general.unaccessContainer(obj)
|
||||||
DismountAction(tplayer, obj, seatNum)
|
DismountAction(tplayer, obj, seatNum)
|
||||||
//until vehicles maintain synchronized momentum without a driver
|
//until vehicles maintain synchronized momentum without a driver
|
||||||
obj match {
|
obj match {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package net.psforever.actors.session.normal
|
||||||
import akka.actor.{ActorContext, ActorRef, typed}
|
import akka.actor.{ActorContext, ActorRef, typed}
|
||||||
import net.psforever.actors.session.AvatarActor
|
import net.psforever.actors.session.AvatarActor
|
||||||
import net.psforever.actors.session.support.{SessionData, SessionVehicleHandlers, VehicleHandlerFunctions}
|
import net.psforever.actors.session.support.{SessionData, SessionVehicleHandlers, VehicleHandlerFunctions}
|
||||||
|
import net.psforever.objects.avatar.SpecialCarry
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player, Tool, Vehicle, Vehicles}
|
import net.psforever.objects.{GlobalDefinitions, Player, Tool, Vehicle, Vehicles}
|
||||||
import net.psforever.objects.equipment.{Equipment, JammableMountedWeapons, JammableUnit}
|
import net.psforever.objects.equipment.{Equipment, JammableMountedWeapons, JammableUnit}
|
||||||
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
||||||
|
|
@ -12,6 +13,7 @@ import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||||
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
|
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
|
||||||
import net.psforever.packet.game.{ChangeAmmoMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ChatMsg, ChildObjectStateMessage, DeadState, DeployRequestMessage, DismountVehicleMsg, FrameVehicleStateMessage, GenericObjectActionMessage, HitHint, InventoryStateMessage, ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, PlanetsideAttributeMessage, ReloadMessage, ServerVehicleOverrideMsg, VehicleStateMessage, WeaponDryFireMessage}
|
import net.psforever.packet.game.{ChangeAmmoMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ChatMsg, ChildObjectStateMessage, DeadState, DeployRequestMessage, DismountVehicleMsg, FrameVehicleStateMessage, GenericObjectActionMessage, HitHint, InventoryStateMessage, ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, PlanetsideAttributeMessage, ReloadMessage, ServerVehicleOverrideMsg, VehicleStateMessage, WeaponDryFireMessage}
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
|
import net.psforever.services.local.support.CaptureFlagManager
|
||||||
import net.psforever.services.vehicle.{VehicleResponse, VehicleServiceResponse}
|
import net.psforever.services.vehicle.{VehicleResponse, VehicleServiceResponse}
|
||||||
import net.psforever.types.{BailType, ChatMessageType, PlanetSideGUID, Vector3}
|
import net.psforever.types.{BailType, ChatMessageType, PlanetSideGUID, Vector3}
|
||||||
|
|
||||||
|
|
@ -62,6 +64,14 @@ class VehicleHandlerLogic(val ops: SessionVehicleHandlers, implicit val context:
|
||||||
player.Orientation = orient
|
player.Orientation = orient
|
||||||
player.Velocity = vel
|
player.Velocity = vel
|
||||||
sessionLogic.updateLocalBlockMap(pos)
|
sessionLogic.updateLocalBlockMap(pos)
|
||||||
|
//llu destruction check
|
||||||
|
if (player.Carrying.contains(SpecialCarry.CaptureFlag)) {
|
||||||
|
continent
|
||||||
|
.GUID(player.VehicleSeated)
|
||||||
|
.collect { case vehicle: Vehicle =>
|
||||||
|
CaptureFlagManager.ReasonToLoseFlagViolently(continent, sessionLogic.general.specialItemSlotGuid, vehicle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case VehicleResponse.VehicleState(
|
case VehicleResponse.VehicleState(
|
||||||
vehicleGuid,
|
vehicleGuid,
|
||||||
|
|
@ -199,6 +209,9 @@ class VehicleHandlerLogic(val ops: SessionVehicleHandlers, implicit val context:
|
||||||
avatarActor ! AvatarActor.SetVehicle(Some(vehicleGuid))
|
avatarActor ! AvatarActor.SetVehicle(Some(vehicleGuid))
|
||||||
sendResponse(PlanetsideAttributeMessage(resolvedPlayerGuid, attribute_type=21, vehicleGuid))
|
sendResponse(PlanetsideAttributeMessage(resolvedPlayerGuid, attribute_type=21, vehicleGuid))
|
||||||
|
|
||||||
|
case VehicleResponse.LoseOwnership(_, vehicleGuid) =>
|
||||||
|
ops.announceAmsDecay(vehicleGuid,msg = "@ams_decaystarted")
|
||||||
|
|
||||||
case VehicleResponse.PlanetsideAttribute(vehicleGuid, attributeType, attributeValue) if isNotSameTarget =>
|
case VehicleResponse.PlanetsideAttribute(vehicleGuid, attributeType, attributeValue) if isNotSameTarget =>
|
||||||
sendResponse(PlanetsideAttributeMessage(vehicleGuid, attributeType, attributeValue))
|
sendResponse(PlanetsideAttributeMessage(vehicleGuid, attributeType, attributeValue))
|
||||||
|
|
||||||
|
|
@ -217,6 +230,16 @@ class VehicleHandlerLogic(val ops: SessionVehicleHandlers, implicit val context:
|
||||||
|
|
||||||
case VehicleResponse.UnloadVehicle(_, vehicleGuid) =>
|
case VehicleResponse.UnloadVehicle(_, vehicleGuid) =>
|
||||||
sendResponse(ObjectDeleteMessage(vehicleGuid, unk1=0))
|
sendResponse(ObjectDeleteMessage(vehicleGuid, unk1=0))
|
||||||
|
if (sessionLogic.zoning.spawn.prevSpawnPoint.map(_.Owner).exists {
|
||||||
|
case ams: Vehicle =>
|
||||||
|
ams.GUID == vehicleGuid &&
|
||||||
|
ams.OwnerGuid.isEmpty
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}) {
|
||||||
|
sessionLogic.zoning.spawn.prevSpawnPoint = None
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_229, "@ams_decayed"))
|
||||||
|
}
|
||||||
|
|
||||||
case VehicleResponse.UnstowEquipment(itemGuid) if isNotSameTarget =>
|
case VehicleResponse.UnstowEquipment(itemGuid) if isNotSameTarget =>
|
||||||
//TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly?
|
//TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly?
|
||||||
|
|
@ -308,13 +331,13 @@ class VehicleHandlerLogic(val ops: SessionVehicleHandlers, implicit val context:
|
||||||
sessionLogic.vehicles.ServerVehicleOverrideStop(vehicle)
|
sessionLogic.vehicles.ServerVehicleOverrideStop(vehicle)
|
||||||
|
|
||||||
case VehicleResponse.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, data) =>
|
case VehicleResponse.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, data) =>
|
||||||
sendResponse(ChatMsg(
|
val str = s"${data.getOrElse("The vehicle spawn pad where you placed your order is blocked.")}"
|
||||||
ChatMessageType.CMT_OPEN,
|
val msg = if (str.contains("@")) {
|
||||||
wideContents=true,
|
ChatMsg(ChatMessageType.UNK_229, str)
|
||||||
recipient="",
|
} else {
|
||||||
s"The vehicle spawn where you placed your order is blocked. ${data.getOrElse("")}",
|
ChatMsg(ChatMessageType.CMT_OPEN, wideContents = true, recipient = "", str, note = None)
|
||||||
note=None
|
}
|
||||||
))
|
sendResponse(msg)
|
||||||
|
|
||||||
case VehicleResponse.PeriodicReminder(_, data) =>
|
case VehicleResponse.PeriodicReminder(_, data) =>
|
||||||
val (isType, flag, msg): (ChatMessageType, Boolean, String) = data match {
|
val (isType, flag, msg): (ChatMessageType, Boolean, String) = data match {
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ import net.psforever.objects.serverobject.deploy.Deployment
|
||||||
import net.psforever.objects.serverobject.mount.Mountable
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
import net.psforever.objects.vehicles.control.BfrFlight
|
import net.psforever.objects.vehicles.control.BfrFlight
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.{ChildObjectStateMessage, DeployRequestMessage, FrameVehicleStateMessage, VehicleStateMessage, VehicleSubStateMessage}
|
import net.psforever.packet.game.{ChatMsg, ChildObjectStateMessage, DeployRequestMessage, FrameVehicleStateMessage, VehicleStateMessage, VehicleSubStateMessage}
|
||||||
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
import net.psforever.types.{DriveState, Vector3}
|
import net.psforever.types.{ChatMessageType, DriveState, Vector3}
|
||||||
|
|
||||||
object VehicleLogic {
|
object VehicleLogic {
|
||||||
def apply(ops: VehicleOperations): VehicleLogic = {
|
def apply(ops: VehicleOperations): VehicleLogic = {
|
||||||
|
|
@ -70,6 +70,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
|
||||||
obj.Velocity = None
|
obj.Velocity = None
|
||||||
obj.Flying = None
|
obj.Flying = None
|
||||||
}
|
}
|
||||||
|
//
|
||||||
continent.VehicleEvents ! VehicleServiceMessage(
|
continent.VehicleEvents ! VehicleServiceMessage(
|
||||||
continent.id,
|
continent.id,
|
||||||
VehicleAction.VehicleState(
|
VehicleAction.VehicleState(
|
||||||
|
|
@ -303,6 +304,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
|
||||||
log.trace(s"DeployRequest: $obj transitioning to deploy state")
|
log.trace(s"DeployRequest: $obj transitioning to deploy state")
|
||||||
} else if (state == DriveState.Deployed) {
|
} else if (state == DriveState.Deployed) {
|
||||||
log.trace(s"DeployRequest: $obj has been Deployed")
|
log.trace(s"DeployRequest: $obj has been Deployed")
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@DeployingMessage"))
|
||||||
} else {
|
} else {
|
||||||
CanNotChangeDeployment(obj, state, "incorrect deploy state")
|
CanNotChangeDeployment(obj, state, "incorrect deploy state")
|
||||||
}
|
}
|
||||||
|
|
@ -313,6 +315,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
|
||||||
log.trace(s"DeployRequest: $obj transitioning to undeploy state")
|
log.trace(s"DeployRequest: $obj transitioning to undeploy state")
|
||||||
} else if (state == DriveState.Mobile) {
|
} else if (state == DriveState.Mobile) {
|
||||||
log.trace(s"DeployRequest: $obj is Mobile")
|
log.trace(s"DeployRequest: $obj is Mobile")
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@UndeployingMessage"))
|
||||||
} else {
|
} else {
|
||||||
CanNotChangeDeployment(obj, state, "incorrect undeploy state")
|
CanNotChangeDeployment(obj, state, "incorrect undeploy state")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,11 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
|
||||||
case (CMT_WARP, _, contents) =>
|
case (CMT_WARP, _, contents) =>
|
||||||
ops.commandWarp(session, message, contents)
|
ops.commandWarp(session, message, contents)
|
||||||
|
|
||||||
case _ => ()
|
case (CMT_REPORTUSER, _, contents) =>
|
||||||
|
ops.commandReportUser(session, message, contents)
|
||||||
|
|
||||||
|
case _ =>
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@no_permission"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -203,9 +203,9 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
|
||||||
case Mountable.CanDismount(obj: PlanetSideGameObject with PlanetSideGameObject with Mountable with FactionAffinity with InGameHistory, seatNum, _) =>
|
case Mountable.CanDismount(obj: PlanetSideGameObject with PlanetSideGameObject with Mountable with FactionAffinity with InGameHistory, seatNum, _) =>
|
||||||
DismountAction(tplayer, obj, seatNum)
|
DismountAction(tplayer, obj, seatNum)
|
||||||
|
|
||||||
case Mountable.CanDismount(obj: Mountable, _, _) => ()
|
case Mountable.CanDismount(_: Mountable, _, _) => ()
|
||||||
|
|
||||||
case Mountable.CanNotDismount(obj: Vehicle, seatNum) =>
|
case Mountable.CanNotDismount(obj: Vehicle, _, _) =>
|
||||||
obj.Actor ! Vehicle.Deconstruct()
|
obj.Actor ! Vehicle.Deconstruct()
|
||||||
|
|
||||||
case _ => ()
|
case _ => ()
|
||||||
|
|
|
||||||
|
|
@ -279,11 +279,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
|
||||||
|
|
||||||
def handleCanDeploy(obj: Deployment.DeploymentObject, state: DriveState.Value): Unit = { /* intentionally blank */ }
|
def handleCanDeploy(obj: Deployment.DeploymentObject, state: DriveState.Value): Unit = { /* intentionally blank */ }
|
||||||
|
|
||||||
def handleCanUndeploy(obj: Deployment.DeploymentObject, state: DriveState.Value): Unit = {
|
def handleCanUndeploy(obj: Deployment.DeploymentObject, state: DriveState.Value): Unit = { /* intentionally blank */ }
|
||||||
if (state != DriveState.Undeploying && state != DriveState.Mobile) {
|
|
||||||
CanNotChangeDeployment(obj, state, "incorrect undeploy state")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def handleCanNotChangeDeployment(obj: Deployment.DeploymentObject, state: DriveState.Value, reason: String): Unit = {
|
def handleCanNotChangeDeployment(obj: Deployment.DeploymentObject, state: DriveState.Value, reason: String): Unit = {
|
||||||
if (Deployment.CheckForDeployState(state) && !Deployment.AngleCheck(obj)) {
|
if (Deployment.CheckForDeployState(state) && !Deployment.AngleCheck(obj)) {
|
||||||
|
|
|
||||||
|
|
@ -91,11 +91,13 @@ class ChatOperations(
|
||||||
}
|
}
|
||||||
|
|
||||||
def commandWatermark(contents: String): Unit = {
|
def commandWatermark(contents: String): Unit = {
|
||||||
val connectionState =
|
val connectionState = {
|
||||||
if (contents.contains("40 80")) 100
|
if (contents.contains("40 80")) 100
|
||||||
else if (contents.contains("120 200")) 25
|
else if (contents.contains("120 200")) 25
|
||||||
else 50
|
else 50
|
||||||
|
}
|
||||||
context.self ! SessionActor.SetConnectionState(connectionState)
|
context.self ! SessionActor.SetConnectionState(connectionState)
|
||||||
|
context.self ! SessionActor.SendResponse(ChatMsg(ChatMessageType.UNK_227, "@CMT_CULLWATERMARK_success"))
|
||||||
}
|
}
|
||||||
|
|
||||||
def commandSpeed(message: ChatMsg, contents: String): Unit = {
|
def commandSpeed(message: ChatMsg, contents: String): Unit = {
|
||||||
|
|
@ -647,6 +649,11 @@ class ChatOperations(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def commandReportUser(@unused session: Session, @unused message: ChatMsg, @unused contents: String): Unit = {
|
||||||
|
//todo get user from contents
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@rpt_i"))
|
||||||
|
}
|
||||||
|
|
||||||
def commandIncomingSendAllIfOnline(session: Session, message: ChatMsg): Unit = {
|
def commandIncomingSendAllIfOnline(session: Session, message: ChatMsg): Unit = {
|
||||||
if (AvatarActor.onlineIfNotIgnored(session.avatar, message.recipient)) {
|
if (AvatarActor.onlineIfNotIgnored(session.avatar, message.recipient)) {
|
||||||
sendResponse(message)
|
sendResponse(message)
|
||||||
|
|
|
||||||
|
|
@ -220,8 +220,12 @@ class GeneralOperations(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continent.LocalEvents ! CaptureFlagManager.DropFlag(llu)
|
if (!CaptureFlagManager.ReasonToLoseFlagViolently(continent, Some(guid), player)) {
|
||||||
case Some((llu, Some(carrier: Player))) if carrier.GUID == player.GUID =>
|
continent.LocalEvents ! CaptureFlagManager.DropFlag(llu)
|
||||||
|
}
|
||||||
|
case Some((llu, Some(carrier: Player)))
|
||||||
|
if carrier.GUID == player.GUID &&
|
||||||
|
!CaptureFlagManager.ReasonToLoseFlagViolently(continent, Some(guid), player) =>
|
||||||
continent.LocalEvents ! CaptureFlagManager.DropFlag(llu)
|
continent.LocalEvents ! CaptureFlagManager.DropFlag(llu)
|
||||||
case Some((_, Some(carrier: Player))) =>
|
case Some((_, Some(carrier: Player))) =>
|
||||||
log.warn(s"${player.toString} tried to drop LLU, but it is currently held by ${carrier.toString}")
|
log.warn(s"${player.toString} tried to drop LLU, but it is currently held by ${carrier.toString}")
|
||||||
|
|
@ -669,6 +673,9 @@ class GeneralOperations(
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (player.Capacitor < 1f && player.UsingSpecial == SpecialExoSuitDefinition.Mode.Shielded) {
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@ArmorShieldOff"))
|
||||||
|
}
|
||||||
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
|
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(
|
continent.AvatarEvents ! AvatarServiceMessage(
|
||||||
continent.id,
|
continent.id,
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@ package net.psforever.actors.session.support
|
||||||
|
|
||||||
import akka.actor.{ActorContext, ActorRef, typed}
|
import akka.actor.{ActorContext, ActorRef, typed}
|
||||||
import net.psforever.actors.session.AvatarActor
|
import net.psforever.actors.session.AvatarActor
|
||||||
|
import net.psforever.objects.Vehicle
|
||||||
|
import net.psforever.packet.game.ChatMsg
|
||||||
import net.psforever.services.vehicle.VehicleResponse
|
import net.psforever.services.vehicle.VehicleResponse
|
||||||
import net.psforever.types.PlanetSideGUID
|
import net.psforever.types.{ChatMessageType, DriveState, PlanetSideGUID}
|
||||||
|
|
||||||
trait VehicleHandlerFunctions extends CommonSessionInterfacingFunctionality {
|
trait VehicleHandlerFunctions extends CommonSessionInterfacingFunctionality {
|
||||||
def ops: SessionVehicleHandlers
|
def ops: SessionVehicleHandlers
|
||||||
|
|
@ -17,4 +19,17 @@ class SessionVehicleHandlers(
|
||||||
val avatarActor: typed.ActorRef[AvatarActor.Command],
|
val avatarActor: typed.ActorRef[AvatarActor.Command],
|
||||||
val galaxyService: ActorRef,
|
val galaxyService: ActorRef,
|
||||||
implicit val context: ActorContext
|
implicit val context: ActorContext
|
||||||
) extends CommonSessionInterfacingFunctionality
|
) extends CommonSessionInterfacingFunctionality {
|
||||||
|
def announceAmsDecay(vehicleGuid: PlanetSideGUID, msg: String): Unit = {
|
||||||
|
if (sessionLogic.zoning.spawn.prevSpawnPoint.map(_.Owner).exists {
|
||||||
|
case ams: Vehicle =>
|
||||||
|
ams.GUID == vehicleGuid &&
|
||||||
|
ams.DeploymentState == DriveState.Deployed &&
|
||||||
|
ams.OwnerGuid.isEmpty
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}) {
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_229, msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@
|
||||||
package net.psforever.actors.session.support
|
package net.psforever.actors.session.support
|
||||||
|
|
||||||
import akka.actor.{ActorContext, typed}
|
import akka.actor.{ActorContext, typed}
|
||||||
|
import net.psforever.objects.definition.SpecialExoSuitDefinition
|
||||||
import net.psforever.objects.zones.Zoning
|
import net.psforever.objects.zones.Zoning
|
||||||
import net.psforever.objects.serverobject.turret.VanuSentry
|
import net.psforever.objects.serverobject.turret.VanuSentry
|
||||||
import net.psforever.objects.zones.exp.ToDatabase
|
import net.psforever.objects.zones.exp.ToDatabase
|
||||||
|
import net.psforever.types.ChatMessageType
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
@ -83,9 +85,10 @@ class WeaponAndProjectileOperations(
|
||||||
if (player.ZoningRequest != Zoning.Method.None) {
|
if (player.ZoningRequest != Zoning.Method.None) {
|
||||||
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_fire")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_fire")
|
||||||
}
|
}
|
||||||
if (player.isShielded) {
|
if (player.UsingSpecial == SpecialExoSuitDefinition.Mode.Shielded) {
|
||||||
// Cancel NC MAX shield if it's active
|
// Cancel NC MAX shield if it's active
|
||||||
sessionLogic.general.toggleMaxSpecialState(enable = false)
|
sessionLogic.general.toggleMaxSpecialState(enable = false)
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@ArmorShieldOverride"))
|
||||||
}
|
}
|
||||||
val (o, tools) = FindContainedWeapon
|
val (o, tools) = FindContainedWeapon
|
||||||
val (_, enabledTools) = FindEnabledWeaponsToHandleWeaponFireAccountability(o, tools)
|
val (_, enabledTools) = FindEnabledWeaponsToHandleWeaponFireAccountability(o, tools)
|
||||||
|
|
|
||||||
|
|
@ -1792,6 +1792,7 @@ class ZoningOperations(
|
||||||
private[session] var setupAvatarFunc: () => Unit = AvatarCreate
|
private[session] var setupAvatarFunc: () => Unit = AvatarCreate
|
||||||
private[session] var setCurrentAvatarFunc: Player => Unit = SetCurrentAvatarNormally
|
private[session] var setCurrentAvatarFunc: Player => Unit = SetCurrentAvatarNormally
|
||||||
private[session] var nextSpawnPoint: Option[SpawnPoint] = None
|
private[session] var nextSpawnPoint: Option[SpawnPoint] = None
|
||||||
|
private[session] var prevSpawnPoint: Option[SpawnPoint] = None
|
||||||
private[session] var interimUngunnedVehicle: Option[PlanetSideGUID] = None
|
private[session] var interimUngunnedVehicle: Option[PlanetSideGUID] = None
|
||||||
private[session] var interimUngunnedVehicleSeat: Option[Int] = None
|
private[session] var interimUngunnedVehicleSeat: Option[Int] = None
|
||||||
/** Upstream message counter<br>
|
/** Upstream message counter<br>
|
||||||
|
|
@ -2811,6 +2812,7 @@ class ZoningOperations(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
nextSpawnPoint = physSpawnPoint
|
nextSpawnPoint = physSpawnPoint
|
||||||
|
prevSpawnPoint = physSpawnPoint
|
||||||
shiftPosition = Some(pos)
|
shiftPosition = Some(pos)
|
||||||
shiftOrientation = Some(ori)
|
shiftOrientation = Some(ori)
|
||||||
val toZoneNumber = if (continent.id.equals(zoneId)) {
|
val toZoneNumber = if (continent.id.equals(zoneId)) {
|
||||||
|
|
@ -2819,10 +2821,14 @@ class ZoningOperations(
|
||||||
Zones.zones.find { _.id.equals(zoneId) }.orElse(Some(Zone.Nowhere)).get.Number
|
Zones.zones.find { _.id.equals(zoneId) }.orElse(Some(Zone.Nowhere)).get.Number
|
||||||
}
|
}
|
||||||
val toSide = physSpawnPoint.map(_.Owner) match {
|
val toSide = physSpawnPoint.map(_.Owner) match {
|
||||||
case Some(_: WarpGate) => Sidedness.OutsideOf
|
case Some(_: WarpGate) =>
|
||||||
case Some(_: Building) => Sidedness.InsideOf
|
Sidedness.OutsideOf
|
||||||
case Some(v: Vehicle) => v.WhichSide //though usually OutsideOf
|
case Some(_: Building) =>
|
||||||
case _ => Sidedness.StrictlyBetweenSides //todo needs better determination
|
Sidedness.InsideOf
|
||||||
|
case Some(v: Vehicle) =>
|
||||||
|
v.WhichSide //though usually OutsideOf
|
||||||
|
case _ =>
|
||||||
|
Sidedness.StrictlyBetweenSides //todo needs better determination
|
||||||
}
|
}
|
||||||
val toSpawnPoint = physSpawnPoint.collect { case o: PlanetSideGameObject with FactionAffinity => SourceEntry(o) }
|
val toSpawnPoint = physSpawnPoint.collect { case o: PlanetSideGameObject with FactionAffinity => SourceEntry(o) }
|
||||||
respawnTimer = context.system.scheduler.scheduleOnce(respawnTime) {
|
respawnTimer = context.system.scheduler.scheduleOnce(respawnTime) {
|
||||||
|
|
@ -3124,11 +3130,17 @@ class ZoningOperations(
|
||||||
Config.app.game.savedMsg.short.fixed,
|
Config.app.game.savedMsg.short.fixed,
|
||||||
Config.app.game.savedMsg.short.variable
|
Config.app.game.savedMsg.short.variable
|
||||||
)
|
)
|
||||||
val effortBy = nextSpawnPoint
|
val effortBy = prevSpawnPoint
|
||||||
.collect { case sp: SpawnTube => (sp, continent.GUID(sp.Owner.GUID)) }
|
.collect { case sp: SpawnTube => (sp, continent.GUID(sp.Owner.GUID)) }
|
||||||
.collect {
|
.collect {
|
||||||
case (_, Some(v: Vehicle)) => continent.GUID(v.OwnerGuid)
|
case (_, Some(v: Vehicle)) =>
|
||||||
case (sp, Some(_: Building)) => Some(sp)
|
sessionLogic.vehicleResponseOperations.announceAmsDecay(
|
||||||
|
v.GUID,
|
||||||
|
msg = "The AMS you were bound to has lost its' owner. It will auto-deconstruct soon."
|
||||||
|
)
|
||||||
|
continent.GUID(v.OwnerGuid)
|
||||||
|
case (sp, Some(_: Building)) =>
|
||||||
|
Some(sp)
|
||||||
}
|
}
|
||||||
.collect { case Some(thing: PlanetSideGameObject with FactionAffinity) => Some(SourceEntry(thing)) }
|
.collect { case Some(thing: PlanetSideGameObject with FactionAffinity) => Some(SourceEntry(thing)) }
|
||||||
.flatten
|
.flatten
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ object WorldSession {
|
||||||
Zone.Ground.DropItem(localItem, localContainer.Position, Vector3.z(localContainer.Orientation.z)),
|
Zone.Ground.DropItem(localItem, localContainer.Position, Vector3.z(localContainer.Orientation.z)),
|
||||||
localContainer.Actor
|
localContainer.Actor
|
||||||
)
|
)
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
@ -163,7 +163,7 @@ object WorldSession {
|
||||||
result.onComplete {
|
result.onComplete {
|
||||||
case Failure(_) | Success(_: Containable.CanNotPutItemInSlot) =>
|
case Failure(_) | Success(_: Containable.CanNotPutItemInSlot) =>
|
||||||
TaskWorkflow.execute(GUIDTask.unregisterEquipment(localContainer.Zone.GUID, localItem))
|
TaskWorkflow.execute(GUIDTask.unregisterEquipment(localContainer.Zone.GUID, localItem))
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
@ -361,17 +361,21 @@ object WorldSession {
|
||||||
val future = ask(localZone.Ground, Zone.Ground.PickupItem(item.GUID))
|
val future = ask(localZone.Ground, Zone.Ground.PickupItem(item.GUID))
|
||||||
future.onComplete {
|
future.onComplete {
|
||||||
case Success(Zone.Ground.ItemInHand(_)) =>
|
case Success(Zone.Ground.ItemInHand(_)) =>
|
||||||
PutEquipmentInInventoryOrDrop(localContainer)(localItem)
|
PutEquipmentInInventoryOrDrop(localContainer)(localItem).onComplete {
|
||||||
|
case Success(Containable.ItemPutInSlot(_, _, Player.FreeHandSlot, _)) =>
|
||||||
|
localContainer.Actor ! Zone.Ground.CanNotPickupItem(localZone, localItem.GUID, "@InventoryPickupNoRoom")
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
case Success(Zone.Ground.CanNotPickupItem(_, item_guid, _)) =>
|
case Success(Zone.Ground.CanNotPickupItem(_, item_guid, _)) =>
|
||||||
localZone.GUID(item_guid) match {
|
localZone.GUID(item_guid) match {
|
||||||
case Some(_) => ;
|
case Some(_) => ()
|
||||||
case None => //acting on old data?
|
case None => //acting on old data?
|
||||||
localZone.AvatarEvents ! AvatarServiceMessage(
|
localZone.AvatarEvents ! AvatarServiceMessage(
|
||||||
localZone.id,
|
localZone.id,
|
||||||
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item_guid)
|
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item_guid)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
future
|
future
|
||||||
}
|
}
|
||||||
|
|
@ -407,7 +411,7 @@ object WorldSession {
|
||||||
.DropItem(localItem, localPos.getOrElse(localContainer.Position), Vector3.z(localContainer.Orientation.z)),
|
.DropItem(localItem, localPos.getOrElse(localContainer.Position), Vector3.z(localContainer.Orientation.z)),
|
||||||
localContainer.Actor
|
localContainer.Actor
|
||||||
)
|
)
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
@ -584,7 +588,7 @@ object WorldSession {
|
||||||
case Success(Containable.ItemPutInSlot(_, _, _, Some(swapItem))) =>
|
case Success(Containable.ItemPutInSlot(_, _, _, Some(swapItem))) =>
|
||||||
//swapItem is not registered right now, we can not drop the item without re-registering it
|
//swapItem is not registered right now, we can not drop the item without re-registering it
|
||||||
TaskWorkflow.execute(PutNewEquipmentInInventorySlot(localSource)(swapItem, localSrcSlot))
|
TaskWorkflow.execute(PutNewEquipmentInInventorySlot(localSource)(swapItem, localSrcSlot))
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def description(): String = s"unregistering $localItem before stowing in $localDestination"
|
override def description(): String = s"unregistering $localItem before stowing in $localDestination"
|
||||||
|
|
@ -597,7 +601,7 @@ object WorldSession {
|
||||||
localChannel,
|
localChannel,
|
||||||
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
|
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
|
||||||
)
|
)
|
||||||
case None => ;
|
case None => ()
|
||||||
}
|
}
|
||||||
val moveResult = ask(localDestination.Actor, Containable.PutItemInSlotOrAway(localItem, Some(localDestSlot)))
|
val moveResult = ask(localDestination.Actor, Containable.PutItemInSlotOrAway(localItem, Some(localDestSlot)))
|
||||||
moveResult.onComplete(localMoveOnComplete)
|
moveResult.onComplete(localMoveOnComplete)
|
||||||
|
|
@ -610,7 +614,7 @@ object WorldSession {
|
||||||
moveItemTaskFunc(fromSlot),
|
moveItemTaskFunc(fromSlot),
|
||||||
GUIDTask.unregisterEquipment(fromSource.Zone.GUID, itemToMove)
|
GUIDTask.unregisterEquipment(fromSource.Zone.GUID, itemToMove)
|
||||||
))
|
))
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
val result = ask(source.Actor, Containable.RemoveItemFromSlot(item))
|
val result = ask(source.Actor, Containable.RemoveItemFromSlot(item))
|
||||||
result.onComplete(resultOnComplete)
|
result.onComplete(resultOnComplete)
|
||||||
|
|
@ -689,7 +693,7 @@ object WorldSession {
|
||||||
case Success(Containable.ItemPutInSlot(_, _, _, Some(swapItem))) =>
|
case Success(Containable.ItemPutInSlot(_, _, _, Some(swapItem))) =>
|
||||||
//swapItem is not registered right now, we can not drop the item without re-registering it
|
//swapItem is not registered right now, we can not drop the item without re-registering it
|
||||||
TaskWorkflow.execute(PutNewEquipmentInInventorySlot(localSource)(swapItem, localSrcSlot))
|
TaskWorkflow.execute(PutNewEquipmentInInventorySlot(localSource)(swapItem, localSrcSlot))
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def description(): String = s"registering $localItem in ${localDestination.Zone.id} before removing from $localSource"
|
override def description(): String = s"registering $localItem in ${localDestination.Zone.id} before removing from $localSource"
|
||||||
|
|
@ -702,7 +706,7 @@ object WorldSession {
|
||||||
localChannel,
|
localChannel,
|
||||||
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
|
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
|
||||||
)
|
)
|
||||||
case None => ;
|
case None => ()
|
||||||
}
|
}
|
||||||
val moveResult = ask(localDestination.Actor, Containable.PutItemInSlotOrAway(localItem, Some(localDestSlot)))
|
val moveResult = ask(localDestination.Actor, Containable.PutItemInSlotOrAway(localItem, Some(localDestSlot)))
|
||||||
moveResult.onComplete(localMoveOnComplete)
|
moveResult.onComplete(localMoveOnComplete)
|
||||||
|
|
@ -715,7 +719,7 @@ object WorldSession {
|
||||||
moveItemTaskFunc(fromSlot),
|
moveItemTaskFunc(fromSlot),
|
||||||
GUIDTask.registerEquipment(fromSource.Zone.GUID, itemToMove)
|
GUIDTask.registerEquipment(fromSource.Zone.GUID, itemToMove)
|
||||||
))
|
))
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
val result = ask(source.Actor, Containable.RemoveItemFromSlot(item))
|
val result = ask(source.Actor, Containable.RemoveItemFromSlot(item))
|
||||||
result.onComplete(resultOnComplete)
|
result.onComplete(resultOnComplete)
|
||||||
|
|
@ -847,17 +851,17 @@ object WorldSession {
|
||||||
case Some(e) =>
|
case Some(e) =>
|
||||||
log.info(s"${tplayer.Name} has dropped ${tplayer.Sex.possessive} ${e.Definition.Name}")
|
log.info(s"${tplayer.Name} has dropped ${tplayer.Sex.possessive} ${e.Definition.Name}")
|
||||||
PutEquipmentInInventoryOrDrop(tplayer)(e)
|
PutEquipmentInInventoryOrDrop(tplayer)(e)
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
//restore previously-held-up equipment
|
//restore previously-held-up equipment
|
||||||
itemInPreviouslyDrawnSlotToDrop match {
|
itemInPreviouslyDrawnSlotToDrop match {
|
||||||
case Some(e) => PutEquipmentInInventorySlot(tplayer)(e, previouslyDrawnSlot)
|
case Some(e) => PutEquipmentInInventorySlot(tplayer)(e, previouslyDrawnSlot)
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
log.info(s"${tplayer.Name} has quickly drawn a ${grenade.Definition.Name}")
|
log.info(s"${tplayer.Name} has quickly drawn a ${grenade.Definition.Name}")
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
case None => ;
|
case None => ()
|
||||||
}
|
}
|
||||||
optGrenadeInSlot.nonEmpty
|
optGrenadeInSlot.nonEmpty
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ import net.psforever.objects.serverobject.transfer.TransferContainer
|
||||||
import net.psforever.objects.serverobject.structures.WarpGate
|
import net.psforever.objects.serverobject.structures.WarpGate
|
||||||
import net.psforever.objects.vehicles._
|
import net.psforever.objects.vehicles._
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.{HackMessage, HackState, HackState1, HackState7, TriggeredSound}
|
import net.psforever.packet.game.{ChatMsg, HackMessage, HackState, HackState1, HackState7, TriggeredSound}
|
||||||
import net.psforever.types.{DriveState, PlanetSideEmpire, PlanetSideGUID, Vector3}
|
import net.psforever.types.{ChatMessageType, DriveState, PlanetSideEmpire, PlanetSideGUID, Vector3}
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
|
@ -46,7 +46,7 @@ object Vehicles {
|
||||||
vehicle.Zone.id,
|
vehicle.Zone.id,
|
||||||
VehicleAction.Ownership(tplayer.GUID, vehicle.GUID)
|
VehicleAction.Ownership(tplayer.GUID, vehicle.GUID)
|
||||||
)
|
)
|
||||||
Vehicles.ReloadAccessPermissions(vehicle, tplayer.Name)
|
Vehicles.ReloadAccessPermissions(vehicle, tplayer.Faction.toString)
|
||||||
Some(vehicle)
|
Some(vehicle)
|
||||||
case None =>
|
case None =>
|
||||||
None
|
None
|
||||||
|
|
@ -61,31 +61,37 @@ object Vehicles {
|
||||||
* @return the vehicle, if it had a previous owner;
|
* @return the vehicle, if it had a previous owner;
|
||||||
* `None`, otherwise
|
* `None`, otherwise
|
||||||
*/
|
*/
|
||||||
def Disown(guid: PlanetSideGUID, vehicle: Vehicle): Option[Vehicle] =
|
def Disown(guid: PlanetSideGUID, vehicle: Vehicle): Option[Vehicle] = {
|
||||||
vehicle.Zone.GUID(vehicle.OwnerGuid) match {
|
val zone = vehicle.Zone
|
||||||
case Some(player: Player) =>
|
val ownerGuid = vehicle.OwnerGuid
|
||||||
if (player.avatar.vehicle.contains(guid)) {
|
val ownerName = vehicle.OwnerName
|
||||||
player.avatar.vehicle = None
|
vehicle.AssignOwnership(None)
|
||||||
// vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
|
val result = zone
|
||||||
// player.Name,
|
.GUID(ownerGuid)
|
||||||
// VehicleAction.Ownership(player.GUID, PlanetSideGUID(0))
|
.collect {
|
||||||
// )
|
case player: Player => player.avatar
|
||||||
}
|
}
|
||||||
vehicle.AssignOwnership(None)
|
.orElse {
|
||||||
val empire = VehicleLockState.Empire.id
|
zone
|
||||||
//val factionChannel = s"${vehicle.Faction}"
|
.Players
|
||||||
(0 to 2).foreach(group => {
|
.collectFirst {
|
||||||
vehicle.PermissionGroup(group, empire)
|
case avatar if ownerName.contains(avatar.name) => avatar
|
||||||
/*vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
|
}
|
||||||
factionChannel,
|
}
|
||||||
VehicleAction.SeatPermissions(Service.defaultPlayerGUID, guid, group, empire)
|
.collect {
|
||||||
)*/
|
case avatar if avatar.vehicle.contains(guid) =>
|
||||||
})
|
avatar.vehicle = None
|
||||||
ReloadAccessPermissions(vehicle, player.Name)
|
vehicle
|
||||||
Some(vehicle)
|
}
|
||||||
case _ =>
|
val empire = VehicleLockState.Empire.id
|
||||||
None
|
(0 to 2).foreach(group => vehicle.PermissionGroup(group, empire))
|
||||||
}
|
ReloadAccessPermissions(vehicle, vehicle.Faction.toString)
|
||||||
|
zone.VehicleEvents ! VehicleServiceMessage(
|
||||||
|
zone.id,
|
||||||
|
VehicleAction.LoseOwnership(ownerGuid.getOrElse(Service.defaultPlayerGUID), guid)
|
||||||
|
)
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disassociate a player from a vehicle that he owns.
|
* Disassociate a player from a vehicle that he owns.
|
||||||
|
|
@ -140,7 +146,7 @@ object Vehicles {
|
||||||
VehicleAction.SeatPermissions(pguid, vguid, group, empire)
|
VehicleAction.SeatPermissions(pguid, vguid, group, empire)
|
||||||
)*/
|
)*/
|
||||||
})
|
})
|
||||||
ReloadAccessPermissions(vehicle, player.Name)
|
ReloadAccessPermissions(vehicle, vehicle.Faction.toString)
|
||||||
Some(vehicle)
|
Some(vehicle)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -239,6 +245,8 @@ object Vehicles {
|
||||||
val zone = target.Zone
|
val zone = target.Zone
|
||||||
val zoneid = zone.id
|
val zoneid = zone.id
|
||||||
val vehicleEvents = zone.VehicleEvents
|
val vehicleEvents = zone.VehicleEvents
|
||||||
|
val localEvents = zone.LocalEvents
|
||||||
|
val previousOwnerName = target.OwnerName.getOrElse("")
|
||||||
vehicleEvents ! VehicleServiceMessage(
|
vehicleEvents ! VehicleServiceMessage(
|
||||||
zoneid,
|
zoneid,
|
||||||
VehicleAction.SendResponse(
|
VehicleAction.SendResponse(
|
||||||
|
|
@ -292,10 +300,20 @@ object Vehicles {
|
||||||
AvatarAction.SetEmpire(Service.defaultPlayerGUID, tGuid, hFaction)
|
AvatarAction.SetEmpire(Service.defaultPlayerGUID, tGuid, hFaction)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
zone.LocalEvents ! LocalServiceMessage(
|
localEvents ! LocalServiceMessage(
|
||||||
zoneid,
|
zoneid,
|
||||||
LocalAction.TriggerSound(hGuid, TriggeredSound.HackVehicle, target.Position, 30, 0.49803925f)
|
LocalAction.TriggerSound(hGuid, TriggeredSound.HackVehicle, target.Position, 30, 0.49803925f)
|
||||||
)
|
)
|
||||||
|
if (zone.Players.exists(_.name.equals(previousOwnerName))) {
|
||||||
|
localEvents ! LocalServiceMessage(
|
||||||
|
previousOwnerName,
|
||||||
|
LocalAction.SendResponse(ChatMsg(ChatMessageType.UNK_226, "@JackStolen"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
localEvents ! LocalServiceMessage(
|
||||||
|
hacker.Name,
|
||||||
|
LocalAction.SendResponse(ChatMsg(ChatMessageType.UNK_226, "@JackVehicleOwned"))
|
||||||
|
)
|
||||||
// Clean up after specific vehicles, e.g. remove router telepads
|
// Clean up after specific vehicles, e.g. remove router telepads
|
||||||
// If AMS is deployed, swap it to the new faction
|
// If AMS is deployed, swap it to the new faction
|
||||||
target.Definition match {
|
target.Definition match {
|
||||||
|
|
|
||||||
|
|
@ -522,6 +522,12 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
|
|
||||||
case Zone.Ground.CanNotPickupItem(_, item_guid, reason) =>
|
case Zone.Ground.CanNotPickupItem(_, item_guid, reason) =>
|
||||||
log.warn(s"${player.Name} failed to pick up an item ($item_guid) from the ground because $reason")
|
log.warn(s"${player.Name} failed to pick up an item ($item_guid) from the ground because $reason")
|
||||||
|
if (reason.startsWith("@")) {
|
||||||
|
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
player.Name,
|
||||||
|
AvatarAction.SendResponse(Service.defaultPlayerGUID, ChatMsg(ChatMessageType.UNK_227, reason))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
case Player.BuildDeployable(obj: TelepadDeployable, tool: Telepad) =>
|
case Player.BuildDeployable(obj: TelepadDeployable, tool: Telepad) =>
|
||||||
obj.Router = tool.Router //necessary; forwards link to the router that produced the telepad
|
obj.Router = tool.Router //necessary; forwards link to the router that produced the telepad
|
||||||
|
|
@ -631,6 +637,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
if (player.DrawnSlot != Player.HandsDownSlot) {
|
if (player.DrawnSlot != Player.HandsDownSlot) {
|
||||||
player.DrawnSlot = Player.HandsDownSlot
|
player.DrawnSlot = Player.HandsDownSlot
|
||||||
}
|
}
|
||||||
|
val dropPred = ContainableBehavior.DropPredicate(player)
|
||||||
val (toDelete, toDrop, afterHolsters, afterInventory) = if (originalSuit == ExoSuitType.MAX) {
|
val (toDelete, toDrop, afterHolsters, afterInventory) = if (originalSuit == ExoSuitType.MAX) {
|
||||||
//was max
|
//was max
|
||||||
val (delete, insert) = beforeHolsters.partition(elem => elem.obj.Size == EquipmentSize.Max)
|
val (delete, insert) = beforeHolsters.partition(elem => elem.obj.Size == EquipmentSize.Max)
|
||||||
|
|
@ -641,18 +648,21 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
//changing to a vanilla exo-suit
|
//changing to a vanilla exo-suit
|
||||||
val (newHolsters, unplacedHolsters) = Players.fillEmptyHolsters(player.Holsters().iterator, insert ++ beforeInventory)
|
val (newHolsters, unplacedHolsters) = Players.fillEmptyHolsters(player.Holsters().iterator, insert ++ beforeInventory)
|
||||||
val (inventory, unplacedInventory) = GridInventory.recoverInventory(unplacedHolsters, player.Inventory)
|
val (inventory, unplacedInventory) = GridInventory.recoverInventory(unplacedHolsters, player.Inventory)
|
||||||
(delete, unplacedInventory.map(InventoryItem(_, -1)), newHolsters, inventory)
|
val (dropFromUnplaced, deleteFromUnplaced) = unplacedInventory.map(InventoryItem(_, -1)).partition(dropPred)
|
||||||
|
(delete ++ deleteFromUnplaced, dropFromUnplaced, newHolsters, inventory)
|
||||||
}
|
}
|
||||||
} else if (willBecomeMax) {
|
} else if (willBecomeMax) {
|
||||||
//will be max, drop everything but melee slot
|
//will be max, drop everything but melee slot
|
||||||
val (melee, other) = beforeHolsters.partition(elem => elem.obj.Size == EquipmentSize.Melee)
|
val (melee, other) = beforeHolsters.partition(elem => elem.obj.Size == EquipmentSize.Melee)
|
||||||
val (inventory, unplacedInventory) = GridInventory.recoverInventory(beforeInventory ++ other, player.Inventory)
|
val (inventory, unplacedInventory) = GridInventory.recoverInventory(beforeInventory ++ other, player.Inventory)
|
||||||
(Nil, unplacedInventory.map(InventoryItem(_, -1)), melee, inventory)
|
val (dropFromUnplaced, deleteFromUnplaced) = unplacedInventory.map(InventoryItem(_, -1)).partition(dropPred)
|
||||||
|
(deleteFromUnplaced, dropFromUnplaced, melee, inventory)
|
||||||
} else {
|
} else {
|
||||||
//was not a max nor will become a max; vanilla exo-suit to a vanilla-exo-suit
|
//was not a max nor will become a max; vanilla exo-suit to a vanilla-exo-suit
|
||||||
val (insert, unplacedHolsters) = Players.fillEmptyHolsters(player.Holsters().iterator, beforeHolsters ++ beforeInventory)
|
val (insert, unplacedHolsters) = Players.fillEmptyHolsters(player.Holsters().iterator, beforeHolsters ++ beforeInventory)
|
||||||
val (inventory, unplacedInventory) = GridInventory.recoverInventory(unplacedHolsters, player.Inventory)
|
val (inventory, unplacedInventory) = GridInventory.recoverInventory(unplacedHolsters, player.Inventory)
|
||||||
(Nil, unplacedInventory.map(InventoryItem(_, -1)), insert, inventory)
|
val (dropFromUnplaced, deleteFromUnplaced) = unplacedInventory.map(InventoryItem(_, -1)).partition(dropPred)
|
||||||
|
(deleteFromUnplaced, dropFromUnplaced, insert, inventory)
|
||||||
}
|
}
|
||||||
//insert
|
//insert
|
||||||
afterHolsters.foreach(elem => player.Slot(elem.start).Equipment = elem.obj)
|
afterHolsters.foreach(elem => player.Slot(elem.start).Equipment = elem.obj)
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,15 @@
|
||||||
package net.psforever.objects.avatar.interaction
|
package net.psforever.objects.avatar.interaction
|
||||||
|
|
||||||
import net.psforever.objects.serverobject.environment.interaction.{InteractionWith, RespondsToZoneEnvironment}
|
import net.psforever.objects.serverobject.environment.interaction.{InteractionWith, RespondsToZoneEnvironment}
|
||||||
import net.psforever.objects.{Vehicle, Vehicles}
|
import net.psforever.objects.{Player, Vehicle, Vehicles}
|
||||||
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, GantryDenialField, PieceOfEnvironment, interaction}
|
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, GantryDenialField, PieceOfEnvironment, interaction}
|
||||||
import net.psforever.objects.serverobject.shuttle.OrbitalShuttlePad
|
import net.psforever.objects.serverobject.shuttle.OrbitalShuttlePad
|
||||||
import net.psforever.objects.zones.InteractsWithZone
|
import net.psforever.objects.zones.InteractsWithZone
|
||||||
import net.psforever.packet.game.{PlayerStateShiftMessage, ShiftState}
|
import net.psforever.packet.game.{ChatMsg, PlayerStateShiftMessage, ShiftState}
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
import net.psforever.services.hart.ShuttleState
|
import net.psforever.services.hart.ShuttleState
|
||||||
|
import net.psforever.types.ChatMessageType
|
||||||
|
|
||||||
import scala.annotation.unused
|
import scala.annotation.unused
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
@ -28,17 +29,26 @@ class WithGantry(val channel: String)
|
||||||
(zone.GUID(field.obbasemesh) match {
|
(zone.GUID(field.obbasemesh) match {
|
||||||
case Some(pad : OrbitalShuttlePad) => zone.GUID(pad.shuttle)
|
case Some(pad : OrbitalShuttlePad) => zone.GUID(pad.shuttle)
|
||||||
case _ => None
|
case _ => None
|
||||||
}) match {
|
}, obj) match {
|
||||||
case Some(shuttle: Vehicle)
|
case (Some(shuttle: Vehicle), player: Player)
|
||||||
if shuttle.Flying.contains(ShuttleState.State11.id) || shuttle.Faction != obj.Faction =>
|
if (shuttle.Flying.contains(ShuttleState.State11.id) || shuttle.Faction != player.Faction) &&
|
||||||
|
player.VehicleSeated.isEmpty =>
|
||||||
val (pos, ang) = Vehicles.dismountShuttle(shuttle, field.mountPoint)
|
val (pos, ang) = Vehicles.dismountShuttle(shuttle, field.mountPoint)
|
||||||
shuttle.Zone.AvatarEvents ! AvatarServiceMessage(
|
val events = shuttle.Zone.AvatarEvents
|
||||||
|
events ! AvatarServiceMessage(
|
||||||
channel,
|
channel,
|
||||||
AvatarAction.SendResponse(
|
AvatarAction.SendResponse(
|
||||||
Service.defaultPlayerGUID,
|
Service.defaultPlayerGUID,
|
||||||
PlayerStateShiftMessage(ShiftState(0, pos, ang, None)))
|
PlayerStateShiftMessage(ShiftState(0, pos, ang, None)))
|
||||||
)
|
)
|
||||||
case Some(_: Vehicle) =>
|
events ! AvatarServiceMessage(
|
||||||
|
channel,
|
||||||
|
AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
ChatMsg(ChatMessageType.UNK_227, "@Vehicle_OS_PlacedOutsideHallway")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
case (Some(_: Vehicle) , _)=>
|
||||||
obj.Actor ! RespondsToZoneEnvironment.Timer(
|
obj.Actor ! RespondsToZoneEnvironment.Timer(
|
||||||
attribute,
|
attribute,
|
||||||
delay = 250 milliseconds,
|
delay = 250 milliseconds,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
// Copyright (c) 2024 PSForever
|
// Copyright (c) 2024 PSForever
|
||||||
package net.psforever.objects.avatar.interaction
|
package net.psforever.objects.avatar.interaction
|
||||||
|
|
||||||
import net.psforever.objects.Player
|
import net.psforever.objects.{GlobalDefinitions, PlanetSideGameObject, Player}
|
||||||
import net.psforever.objects.serverobject.environment.interaction.{InteractionWith, RespondsToZoneEnvironment}
|
import net.psforever.objects.serverobject.environment.interaction.{InteractionWith, RespondsToZoneEnvironment}
|
||||||
import net.psforever.objects.serverobject.environment.interaction.common.Watery
|
import net.psforever.objects.serverobject.environment.interaction.common.Watery
|
||||||
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
||||||
import net.psforever.objects.serverobject.environment.{PieceOfEnvironment, interaction}
|
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment, interaction}
|
||||||
import net.psforever.objects.zones.InteractsWithZone
|
import net.psforever.objects.zones.InteractsWithZone
|
||||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
import net.psforever.types.OxygenState
|
import net.psforever.types.OxygenState
|
||||||
|
|
@ -15,9 +15,11 @@ import scala.concurrent.duration._
|
||||||
class WithWater(val channel: String)
|
class WithWater(val channel: String)
|
||||||
extends InteractionWith
|
extends InteractionWith
|
||||||
with Watery {
|
with Watery {
|
||||||
|
/** do this every time we're in sufficient contact with water */
|
||||||
|
private var doInteractingWithBehavior: (InteractsWithZone, PieceOfEnvironment, Option[Any]) => Unit = wadingBeforeDrowning
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Water causes players to slowly suffocate.
|
* Water is wet.
|
||||||
* When they (finally) drown, they will die.
|
|
||||||
* @param obj the target
|
* @param obj the target
|
||||||
* @param body the environment
|
* @param body the environment
|
||||||
*/
|
*/
|
||||||
|
|
@ -26,22 +28,84 @@ class WithWater(val channel: String)
|
||||||
body: PieceOfEnvironment,
|
body: PieceOfEnvironment,
|
||||||
data: Option[Any]
|
data: Option[Any]
|
||||||
): Unit = {
|
): Unit = {
|
||||||
val extra = data.collect {
|
if (getExtra(data).nonEmpty) {
|
||||||
case t: OxygenStateTarget => Some(t)
|
inheritAndPushExtraData(obj, body, data)
|
||||||
case w: Watery => w.Condition
|
|
||||||
}.flatten
|
|
||||||
if (extra.isDefined) {
|
|
||||||
//inform the player that their mounted vehicle is in trouble (that they are in trouble (but not from drowning (yet)))
|
|
||||||
stopInteractingWith(obj, body, data)
|
|
||||||
} else {
|
} else {
|
||||||
val (effect, time, percentage) = Watery.drowningInWateryConditions(obj, condition.map(_.state), waterInteractionTime)
|
depth = math.max(0f, body.collision.altitude - obj.Position.z)
|
||||||
if (effect) {
|
doInteractingWithBehavior(obj, body, data)
|
||||||
val cond = OxygenStateTarget(obj.GUID, body, OxygenState.Suffocation, percentage)
|
obj.Actor ! RespondsToZoneEnvironment.Timer(attribute, delay = 500 milliseconds, obj.Actor, interaction.InteractingWithEnvironment(body, Some("wading")))
|
||||||
waterInteractionTime = System.currentTimeMillis() + time
|
}
|
||||||
condition = Some(cond)
|
}
|
||||||
obj.Actor ! RespondsToZoneEnvironment.Timer(attribute, delay = time milliseconds, obj.Actor, Player.Die())
|
|
||||||
//inform the player that they are in trouble
|
/**
|
||||||
obj.Zone.AvatarEvents ! AvatarServiceMessage(channel, AvatarAction.OxygenState(cond, extra))
|
* Wading only happens while the player's head is above the water.
|
||||||
|
* @param obj the target
|
||||||
|
* @param body the environment
|
||||||
|
*/
|
||||||
|
private def wadingBeforeDrowning(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
body: PieceOfEnvironment,
|
||||||
|
data: Option[Any]
|
||||||
|
): Unit = {
|
||||||
|
//we're already "wading", let's see if we're drowning
|
||||||
|
if (depth >= GlobalDefinitions.MaxDepth(obj)) {
|
||||||
|
//drowning
|
||||||
|
beginDrowning(obj, body, data)
|
||||||
|
} else {
|
||||||
|
//inform the player that their mounted vehicle is in trouble (that they are in trouble (but not from drowning (yet)))
|
||||||
|
val extra = getExtra(data)
|
||||||
|
if (extra.nonEmpty) {
|
||||||
|
displayOxygenState(
|
||||||
|
obj,
|
||||||
|
condition.getOrElse(OxygenStateTarget(obj.GUID, body, OxygenState.Recovery, 95f)),
|
||||||
|
extra
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Too much water causes players to slowly suffocate.
|
||||||
|
* When they (finally) drown, they will die.
|
||||||
|
* @param obj the target
|
||||||
|
* @param body the environment
|
||||||
|
*/
|
||||||
|
private def beginDrowning(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
body: PieceOfEnvironment,
|
||||||
|
data: Option[Any]
|
||||||
|
): Unit = {
|
||||||
|
val (effect, time, percentage) = Watery.drowningInWateryConditions(obj, condition.map(_.state), waterInteractionTime)
|
||||||
|
if (effect) {
|
||||||
|
val cond = OxygenStateTarget(obj.GUID, body, OxygenState.Suffocation, percentage)
|
||||||
|
waterInteractionTime = System.currentTimeMillis() + time
|
||||||
|
condition = Some(cond)
|
||||||
|
obj.Actor ! RespondsToZoneEnvironment.StopTimer(WithWater.WaterAction)
|
||||||
|
obj.Actor ! RespondsToZoneEnvironment.Timer(WithWater.WaterAction, delay = time milliseconds, obj.Actor, Player.Die())
|
||||||
|
//inform the player that they are in trouble
|
||||||
|
displayOxygenState(obj, cond, getExtra(data))
|
||||||
|
doInteractingWithBehavior = drowning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Too much water causes players to slowly suffocate.
|
||||||
|
* When they (finally) drown, they will die.
|
||||||
|
* @param obj the target
|
||||||
|
* @param body the environment
|
||||||
|
*/
|
||||||
|
private def drowning(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
body: PieceOfEnvironment,
|
||||||
|
data: Option[Any]
|
||||||
|
): Unit = {
|
||||||
|
//test if player ever gets head above the water level
|
||||||
|
if (depth < GlobalDefinitions.MaxDepth(obj)) {
|
||||||
|
val (_, _, percentage) = Watery.recoveringFromWateryConditions(obj, condition.map(_.state), waterInteractionTime)
|
||||||
|
//switch to recovery
|
||||||
|
if (percentage > 0) {
|
||||||
|
recoverFromDrowning(obj, body, data)
|
||||||
|
doInteractingWithBehavior = recoverFromDrowning
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,16 +116,22 @@ class WithWater(val channel: String)
|
||||||
* @param obj the target
|
* @param obj the target
|
||||||
* @param body the environment
|
* @param body the environment
|
||||||
*/
|
*/
|
||||||
override def stopInteractingWith(
|
private def recoverFromDrowning(
|
||||||
obj: InteractsWithZone,
|
obj: InteractsWithZone,
|
||||||
body: PieceOfEnvironment,
|
body: PieceOfEnvironment,
|
||||||
data: Option[Any]
|
data: Option[Any]
|
||||||
): Unit = {
|
): Unit = {
|
||||||
val (effect, time, percentage) = Watery.recoveringFromWateryConditions(obj, condition.map(_.state), waterInteractionTime)
|
val state = condition.map(_.state)
|
||||||
if (percentage > 99f) {
|
if (state.contains(OxygenState.Suffocation)) {
|
||||||
recoverFromInteracting(obj)
|
//set up for recovery
|
||||||
|
val (effect, time, percentage) = Watery.recoveringFromWateryConditions(obj, state, waterInteractionTime)
|
||||||
|
if (percentage < 99f) {
|
||||||
|
//we're not too far gone
|
||||||
|
recoverFromDrowning(obj, body, data, effect, time, percentage)
|
||||||
|
}
|
||||||
|
doInteractingWithBehavior = recovering
|
||||||
} else {
|
} else {
|
||||||
stopInteractingAction(obj, body, data, effect, time, percentage)
|
doInteractingWithBehavior = wadingBeforeDrowning
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,38 +144,169 @@ class WithWater(val channel: String)
|
||||||
* @param time current time until completion of the next effect
|
* @param time current time until completion of the next effect
|
||||||
* @param percentage value to display in the drowning UI progress bar
|
* @param percentage value to display in the drowning UI progress bar
|
||||||
*/
|
*/
|
||||||
private def stopInteractingAction(
|
private def recoverFromDrowning(
|
||||||
obj: InteractsWithZone,
|
obj: InteractsWithZone,
|
||||||
body: PieceOfEnvironment,
|
body: PieceOfEnvironment,
|
||||||
data: Option[Any],
|
data: Option[Any],
|
||||||
effect: Boolean,
|
effect: Boolean,
|
||||||
time: Long,
|
time: Long,
|
||||||
percentage: Float
|
percentage: Float
|
||||||
): Unit = {
|
): Unit = {
|
||||||
val cond = OxygenStateTarget(obj.GUID, body, OxygenState.Recovery, percentage)
|
val cond = OxygenStateTarget(obj.GUID, body, OxygenState.Recovery, percentage)
|
||||||
val extra = data.collect {
|
val extra = data.collect {
|
||||||
case t: OxygenStateTarget => Some(t)
|
case t: OxygenStateTarget => Some(t)
|
||||||
case w: Watery => w.Condition
|
case w: Watery => w.Condition
|
||||||
}.flatten
|
}.flatten
|
||||||
if (effect) {
|
if (effect) {
|
||||||
condition = Some(cond)
|
condition = Some(cond)
|
||||||
waterInteractionTime = System.currentTimeMillis() + time
|
waterInteractionTime = System.currentTimeMillis() + time
|
||||||
obj.Actor ! RespondsToZoneEnvironment.Timer(attribute, delay = time milliseconds, obj.Actor, interaction.RecoveredFromEnvironmentInteraction(attribute))
|
obj.Actor ! RespondsToZoneEnvironment.StopTimer(WithWater.WaterAction)
|
||||||
|
obj.Actor ! RespondsToZoneEnvironment.Timer(WithWater.WaterAction, delay = time milliseconds, obj.Actor, interaction.RecoveredFromEnvironmentInteraction(attribute))
|
||||||
//inform the player
|
//inform the player
|
||||||
obj.Zone.AvatarEvents ! AvatarServiceMessage(channel, AvatarAction.OxygenState(cond, extra))
|
displayOxygenState(obj, cond, extra)
|
||||||
} else if (extra.isDefined) {
|
} else if (extra.isDefined) {
|
||||||
//inform the player
|
//inform the player
|
||||||
obj.Zone.AvatarEvents ! AvatarServiceMessage(channel, AvatarAction.OxygenState(cond, extra))
|
displayOxygenState(obj, cond, extra)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The recovery period is much faster than the drowning process.
|
||||||
|
* Check for when the player fully recovers,
|
||||||
|
* and that the player does not regress back to drowning.
|
||||||
|
* @param obj the target
|
||||||
|
* @param body the environment
|
||||||
|
*/
|
||||||
|
def recovering(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
body: PieceOfEnvironment,
|
||||||
|
data: Option[Any]
|
||||||
|
): Unit = {
|
||||||
|
lazy val state = condition.map(_.state)
|
||||||
|
if (depth >= GlobalDefinitions.MaxDepth(obj)) {
|
||||||
|
//go back to drowning
|
||||||
|
beginDrowning(obj, body, data)
|
||||||
|
} else if (state.contains(OxygenState.Recovery)) {
|
||||||
|
//check recovery conditions
|
||||||
|
val (_, _, percentage) = Watery.recoveringFromWateryConditions(obj, state, waterInteractionTime)
|
||||||
|
if (percentage < 1f) {
|
||||||
|
doInteractingWithBehavior = wadingBeforeDrowning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When out of water, the player is no longer suffocating.
|
||||||
|
* He's even stopped wading.
|
||||||
|
* The only thing we should let complete now is recovery.
|
||||||
|
* @param obj the target
|
||||||
|
* @param body the environment
|
||||||
|
*/
|
||||||
|
override def stopInteractingWith(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
body: PieceOfEnvironment,
|
||||||
|
data: Option[Any]
|
||||||
|
): Unit = {
|
||||||
|
if (getExtra(data).nonEmpty) {
|
||||||
|
inheritAndPushExtraData(obj, body, data)
|
||||||
|
} else {
|
||||||
|
stopInteractingWithAction(obj, body, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When out of water, the player is no longer suffocating.
|
||||||
|
* He's even stopped wading.
|
||||||
|
* The only thing we should let complete now is recovery.
|
||||||
|
* @param obj the target
|
||||||
|
* @param body the environment
|
||||||
|
*/
|
||||||
|
private def stopInteractingWithAction(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
body: PieceOfEnvironment,
|
||||||
|
data: Option[Any]
|
||||||
|
): Unit = {
|
||||||
|
val cond = condition.map(_.state)
|
||||||
|
if (cond.contains(OxygenState.Suffocation)) {
|
||||||
|
//go from suffocating to recovery
|
||||||
|
recoverFromDrowning(obj, body, data)
|
||||||
|
} else if (cond.isEmpty) {
|
||||||
|
//neither suffocating nor recovering, so just reset everything
|
||||||
|
recoverFromInteracting(obj)
|
||||||
|
obj.Actor ! RespondsToZoneEnvironment.StopTimer(attribute)
|
||||||
|
waterInteractionTime = 0L
|
||||||
|
depth = 0f
|
||||||
|
condition = None
|
||||||
|
doInteractingWithBehavior = wadingBeforeDrowning
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override def recoverFromInteracting(obj: InteractsWithZone): Unit = {
|
override def recoverFromInteracting(obj: InteractsWithZone): Unit = {
|
||||||
super.recoverFromInteracting(obj)
|
super.recoverFromInteracting(obj)
|
||||||
if (condition.exists(_.state == OxygenState.Suffocation)) {
|
val cond = condition.map(_.state)
|
||||||
val (effect, time, percentage) = Watery.recoveringFromWateryConditions(obj, condition.map(_.state), waterInteractionTime)
|
//whether or not we were suffocating or recovering, we need to undo the visuals for that
|
||||||
stopInteractingAction(obj, condition.map(_.body).get, None, effect, time, percentage)
|
if (cond.nonEmpty) {
|
||||||
|
obj.Actor ! RespondsToZoneEnvironment.StopTimer(WithWater.WaterAction)
|
||||||
|
displayOxygenState(
|
||||||
|
obj,
|
||||||
|
OxygenStateTarget(obj.GUID, condition.map(_.body).get, OxygenState.Recovery, 100f),
|
||||||
|
None
|
||||||
|
)
|
||||||
}
|
}
|
||||||
waterInteractionTime = 0L
|
|
||||||
condition = None
|
condition = None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From the "condition" of someone else's drowning status,
|
||||||
|
* extract target information and progress.
|
||||||
|
* @param data any information
|
||||||
|
* @return target information and drowning progress
|
||||||
|
*/
|
||||||
|
private def getExtra(data: Option[Any]): Option[OxygenStateTarget] = {
|
||||||
|
data.collect {
|
||||||
|
case t: OxygenStateTarget => Some(t)
|
||||||
|
case w: Watery => w.Condition
|
||||||
|
}.flatten
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the message regarding drowning and recovery
|
||||||
|
* that includes additional information about a related target that is drowning or recovering.
|
||||||
|
* @param obj the target
|
||||||
|
* @param body the environment
|
||||||
|
* @param data essential information about someone else's interaction with water
|
||||||
|
*/
|
||||||
|
private def inheritAndPushExtraData(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
body: PieceOfEnvironment,
|
||||||
|
data: Option[Any]
|
||||||
|
): Unit = {
|
||||||
|
val state = condition.map(_.state).getOrElse(OxygenState.Recovery)
|
||||||
|
val Some((_, _, percentage)) = state match {
|
||||||
|
case OxygenState.Suffocation => Some(Watery.drowningInWateryConditions(obj, Some(state), waterInteractionTime))
|
||||||
|
case OxygenState.Recovery => Some(Watery.recoveringFromWateryConditions(obj, Some(state), waterInteractionTime))
|
||||||
|
}
|
||||||
|
displayOxygenState(obj, OxygenStateTarget(obj.GUID, body, state, percentage), getExtra(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the message regarding drowning and recovery.
|
||||||
|
* @param obj the target
|
||||||
|
* @param cond the environment
|
||||||
|
*/
|
||||||
|
private def displayOxygenState(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
cond: OxygenStateTarget,
|
||||||
|
data: Option[OxygenStateTarget]
|
||||||
|
): Unit = {
|
||||||
|
obj.Zone.AvatarEvents ! AvatarServiceMessage(channel, AvatarAction.OxygenState(cond, data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object WithWater {
|
||||||
|
/** special environmental trait to queue actions independent from the primary wading test */
|
||||||
|
case object WaterAction extends EnvironmentTrait {
|
||||||
|
override def canInteractWith(obj: PlanetSideGameObject): Boolean = false
|
||||||
|
override def testingDepth(obj: PlanetSideGameObject): Float = Float.PositiveInfinity
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,15 +9,15 @@ import net.psforever.types.PlanetSideGUID
|
||||||
import scala.util.{Failure, Success, Try}
|
import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
class SmallDeployableConverter extends ObjectCreateConverter[Deployable]() {
|
class SmallDeployableConverter extends ObjectCreateConverter[Deployable]() {
|
||||||
override def ConstructorData(obj: Deployable): Try[CommonFieldDataWithPlacement] = {
|
override def ConstructorData(obj: Deployable): Try[SmallDeployableData] = {
|
||||||
Success(
|
Success(
|
||||||
CommonFieldDataWithPlacement(
|
SmallDeployableData(CommonFieldDataWithPlacement(
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
obj.Faction,
|
obj.Faction,
|
||||||
bops = false,
|
bops = false,
|
||||||
alternate = obj.Destroyed,
|
alternate = obj.Destroyed,
|
||||||
false,
|
v1 = false,
|
||||||
None,
|
None,
|
||||||
jammered = obj match {
|
jammered = obj match {
|
||||||
case o: JammableUnit => o.Jammed
|
case o: JammableUnit => o.Jammed
|
||||||
|
|
@ -30,10 +30,10 @@ class SmallDeployableConverter extends ObjectCreateConverter[Deployable]() {
|
||||||
case None => PlanetSideGUID(0)
|
case None => PlanetSideGUID(0)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def DetailedConstructorData(obj: Deployable): Try[CommonFieldDataWithPlacement] =
|
override def DetailedConstructorData(obj: Deployable): Try[SmallDeployableData] =
|
||||||
Failure(new Exception("converter should not be used to generate detailed small deployable data"))
|
Failure(new Exception("converter should not be used to generate detailed small deployable data"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -801,7 +801,7 @@ object GlobalDefinitionsMiscellaneous {
|
||||||
AutoRanges(
|
AutoRanges(
|
||||||
detection = 125f,
|
detection = 125f,
|
||||||
trigger = 100f,
|
trigger = 100f,
|
||||||
escape = 200f
|
escape = 150f
|
||||||
),
|
),
|
||||||
AutoChecks(
|
AutoChecks(
|
||||||
validation = List(
|
validation = List(
|
||||||
|
|
@ -813,7 +813,7 @@ object GlobalDefinitionsMiscellaneous {
|
||||||
),
|
),
|
||||||
retaliatoryDelay = 4000L, //8000L
|
retaliatoryDelay = 4000L, //8000L
|
||||||
cylindrical = true,
|
cylindrical = true,
|
||||||
cylindricalExtraHeight = 50f,
|
cylindricalExtraHeight = 25f,
|
||||||
detectionSweepTime = 2.seconds,
|
detectionSweepTime = 2.seconds,
|
||||||
refireTime = 362.milliseconds //312.milliseconds
|
refireTime = 362.milliseconds //312.milliseconds
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -971,7 +971,7 @@ object GlobalDefinitionsVehicle {
|
||||||
ams.DeployTime = 2000
|
ams.DeployTime = 2000
|
||||||
ams.UndeployTime = 2000
|
ams.UndeployTime = 2000
|
||||||
ams.interference = InterferenceRange(main = 125f, sharedGroupId = 3, shared = 30f)
|
ams.interference = InterferenceRange(main = 125f, sharedGroupId = 3, shared = 30f)
|
||||||
ams.DeconstructionTime = Some(20 minutes)
|
ams.DeconstructionTime = Some(15 minutes)
|
||||||
ams.AutoPilotSpeeds = (18, 6)
|
ams.AutoPilotSpeeds = (18, 6)
|
||||||
ams.Packet = utilityConverter
|
ams.Packet = utilityConverter
|
||||||
ams.DestroyedModel = Some(DestroyedVehicle.Ams)
|
ams.DestroyedModel = Some(DestroyedVehicle.Ams)
|
||||||
|
|
@ -1014,6 +1014,7 @@ object GlobalDefinitionsVehicle {
|
||||||
router.Deployment = true
|
router.Deployment = true
|
||||||
router.DeployTime = 2000
|
router.DeployTime = 2000
|
||||||
router.UndeployTime = 2000
|
router.UndeployTime = 2000
|
||||||
|
router.interference = InterferenceRange(main = 20f)
|
||||||
router.DeconstructionTime = Duration(20, "minutes")
|
router.DeconstructionTime = Duration(20, "minutes")
|
||||||
router.AutoPilotSpeeds = (16, 6)
|
router.AutoPilotSpeeds = (16, 6)
|
||||||
router.Packet = variantConverter
|
router.Packet = variantConverter
|
||||||
|
|
|
||||||
|
|
@ -676,6 +676,7 @@ object ContainableBehavior {
|
||||||
entry => {
|
entry => {
|
||||||
val objDef = entry.obj.Definition
|
val objDef = entry.obj.Definition
|
||||||
val faction = GlobalDefinitions.isFactionEquipment(objDef)
|
val faction = GlobalDefinitions.isFactionEquipment(objDef)
|
||||||
|
GlobalDefinitions.isCavernEquipment(objDef) ||
|
||||||
objDef == GlobalDefinitions.router_telepad ||
|
objDef == GlobalDefinitions.router_telepad ||
|
||||||
entry.obj.isInstanceOf[BoomerTrigger] ||
|
entry.obj.isInstanceOf[BoomerTrigger] ||
|
||||||
(faction != tplayer.Faction && faction != PlanetSideEmpire.NEUTRAL)
|
(faction != tplayer.Faction && faction != PlanetSideEmpire.NEUTRAL)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.deploy
|
package net.psforever.objects.serverobject.deploy
|
||||||
|
|
||||||
import akka.actor.{Actor, Cancellable}
|
import akka.actor.{Actor, ActorRef, Cancellable}
|
||||||
import net.psforever.objects.Default
|
import net.psforever.objects.Default
|
||||||
import net.psforever.types.{DriveState, Vector3}
|
import net.psforever.types.{DriveState, Vector3}
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
|
|
@ -33,24 +33,24 @@ trait DeploymentBehavior {
|
||||||
|
|
||||||
val deployBehavior: Receive = {
|
val deployBehavior: Receive = {
|
||||||
case Deployment.TryDeploymentChange(state) =>
|
case Deployment.TryDeploymentChange(state) =>
|
||||||
sender() ! TryDeploymentStateChange(state)
|
sender() ! TryDeploymentStateChange(state, sender())
|
||||||
|
|
||||||
case Deployment.TryDeploy(state) =>
|
case Deployment.TryDeploy(state) =>
|
||||||
sender() ! TryDeployStateChange(state)
|
sender() ! TryDeployStateChange(state, sender())
|
||||||
|
|
||||||
case Deployment.TryUndeploy(state) =>
|
case Deployment.TryUndeploy(state) =>
|
||||||
sender() ! TryUndeployStateChange(state)
|
sender() ! TryUndeployStateChange(state, sender())
|
||||||
}
|
}
|
||||||
|
|
||||||
def TryDeploymentStateChange(state: DriveState.Value): Any = {
|
def TryDeploymentStateChange(state: DriveState.Value, replyTo: ActorRef): Any = {
|
||||||
val obj = DeploymentObject
|
val obj = DeploymentObject
|
||||||
val prevState = obj.DeploymentState
|
val prevState = obj.DeploymentState
|
||||||
if (TryDeploymentChange(obj, state)) {
|
if (TryDeploymentChange(obj, state)) {
|
||||||
if (Deployment.CheckForDeployState(state)) {
|
if (Deployment.CheckForDeployState(state)) {
|
||||||
DeploymentAction(obj, state, prevState)
|
DeploymentAction(obj, state, prevState, replyTo)
|
||||||
Deployment.CanDeploy(obj, state)
|
Deployment.CanDeploy(obj, state)
|
||||||
} else {
|
} else {
|
||||||
UndeploymentAction(obj, state, prevState)
|
UndeploymentAction(obj, state, prevState, replyTo)
|
||||||
Deployment.CanUndeploy(obj, state)
|
Deployment.CanUndeploy(obj, state)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -58,22 +58,22 @@ trait DeploymentBehavior {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def TryDeployStateChange(state: DriveState.Value): Any = {
|
def TryDeployStateChange(state: DriveState.Value, replyTo: ActorRef): Any = {
|
||||||
val obj = DeploymentObject
|
val obj = DeploymentObject
|
||||||
val prevState = obj.DeploymentState
|
val prevState = obj.DeploymentState
|
||||||
if (Deployment.CheckForDeployState(state) && TryDeploymentChange(obj, state)) {
|
if (Deployment.CheckForDeployState(state) && TryDeploymentChange(obj, state)) {
|
||||||
DeploymentAction(obj, state, prevState)
|
DeploymentAction(obj, state, prevState, replyTo)
|
||||||
Deployment.CanDeploy(obj, state)
|
Deployment.CanDeploy(obj, state)
|
||||||
} else {
|
} else {
|
||||||
Deployment.CanNotChangeDeployment(obj, state, "incorrect deploy transition state")
|
Deployment.CanNotChangeDeployment(obj, state, "incorrect deploy transition state")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def TryUndeployStateChange(state: DriveState.Value): Any = {
|
def TryUndeployStateChange(state: DriveState.Value, replyTo: ActorRef): Any = {
|
||||||
val obj = DeploymentObject
|
val obj = DeploymentObject
|
||||||
val prevState = obj.DeploymentState
|
val prevState = obj.DeploymentState
|
||||||
if (Deployment.CheckForUndeployState(state) && TryUndeploymentChange(obj, state)) {
|
if (Deployment.CheckForUndeployState(state) && TryUndeploymentChange(obj, state)) {
|
||||||
UndeploymentAction(obj, state, prevState)
|
UndeploymentAction(obj, state, prevState, replyTo)
|
||||||
Deployment.CanUndeploy(obj, state)
|
Deployment.CanUndeploy(obj, state)
|
||||||
} else {
|
} else {
|
||||||
Deployment.CanNotChangeDeployment(obj, state, "incorrect undeploy transition state")
|
Deployment.CanNotChangeDeployment(obj, state, "incorrect undeploy transition state")
|
||||||
|
|
@ -91,7 +91,8 @@ trait DeploymentBehavior {
|
||||||
def DeploymentAction(
|
def DeploymentAction(
|
||||||
obj: Deployment.DeploymentObject,
|
obj: Deployment.DeploymentObject,
|
||||||
state: DriveState.Value,
|
state: DriveState.Value,
|
||||||
prevState: DriveState.Value
|
prevState: DriveState.Value,
|
||||||
|
replyTo: ActorRef
|
||||||
): DriveState.Value = {
|
): DriveState.Value = {
|
||||||
val guid = obj.GUID
|
val guid = obj.GUID
|
||||||
val zone = obj.Zone
|
val zone = obj.Zone
|
||||||
|
|
@ -108,11 +109,9 @@ trait DeploymentBehavior {
|
||||||
VehicleAction.DeployRequest(GUID0, guid, state, 0, unk2=false, Vector3.Zero)
|
VehicleAction.DeployRequest(GUID0, guid, state, 0, unk2=false, Vector3.Zero)
|
||||||
)
|
)
|
||||||
deploymentTimer.cancel()
|
deploymentTimer.cancel()
|
||||||
deploymentTimer = context.system.scheduler.scheduleOnce(
|
deploymentTimer = context.system.scheduler.scheduleOnce(obj.DeployTime.milliseconds)({
|
||||||
obj.DeployTime milliseconds,
|
obj.Actor.tell(Deployment.TryDeploy(DriveState.Deployed), replyTo)
|
||||||
obj.Actor,
|
})
|
||||||
Deployment.TryDeploy(DriveState.Deployed)
|
|
||||||
)
|
|
||||||
state
|
state
|
||||||
} else if (state == DriveState.Deployed) {
|
} else if (state == DriveState.Deployed) {
|
||||||
obj.Velocity = Some(Vector3.Zero) //no velocity
|
obj.Velocity = Some(Vector3.Zero) //no velocity
|
||||||
|
|
@ -129,7 +128,8 @@ trait DeploymentBehavior {
|
||||||
def UndeploymentAction(
|
def UndeploymentAction(
|
||||||
obj: Deployment.DeploymentObject,
|
obj: Deployment.DeploymentObject,
|
||||||
state: DriveState.Value,
|
state: DriveState.Value,
|
||||||
prevState: DriveState.Value
|
prevState: DriveState.Value,
|
||||||
|
replyTo: ActorRef
|
||||||
): DriveState.Value = {
|
): DriveState.Value = {
|
||||||
val guid = obj.GUID
|
val guid = obj.GUID
|
||||||
val zone = obj.Zone
|
val zone = obj.Zone
|
||||||
|
|
@ -142,11 +142,9 @@ trait DeploymentBehavior {
|
||||||
)
|
)
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
deploymentTimer.cancel()
|
deploymentTimer.cancel()
|
||||||
deploymentTimer = context.system.scheduler.scheduleOnce(
|
deploymentTimer = context.system.scheduler.scheduleOnce(obj.UndeployTime.milliseconds)({
|
||||||
obj.UndeployTime milliseconds,
|
obj.Actor.tell(Deployment.TryUndeploy(DriveState.Mobile), replyTo)
|
||||||
obj.Actor,
|
})
|
||||||
Deployment.TryUndeploy(DriveState.Mobile)
|
|
||||||
)
|
|
||||||
state
|
state
|
||||||
} else if (state == DriveState.Mobile) {
|
} else if (state == DriveState.Mobile) {
|
||||||
zone.VehicleEvents ! VehicleServiceMessage(
|
zone.VehicleEvents ! VehicleServiceMessage(
|
||||||
|
|
|
||||||
|
|
@ -46,11 +46,11 @@ object Interference {
|
||||||
* @param zone game world in which this test will be conducted;
|
* @param zone game world in which this test will be conducted;
|
||||||
* entity should be `ZoneAware`, but it may not be set correctly during this part of its internal process
|
* entity should be `ZoneAware`, but it may not be set correctly during this part of its internal process
|
||||||
* @param obj entity that may be interfered with
|
* @param obj entity that may be interfered with
|
||||||
* @return a different entity that causes the test entity to suffer interference
|
* @return other entities that causes the test entity to suffer interference
|
||||||
*/
|
*/
|
||||||
def Test(zone: Zone, obj: PlanetSideGameObject with FactionAffinity): Option[PlanetSideGameObject with FactionAffinity] = {
|
def Test(zone: Zone, obj: PlanetSideGameObject with FactionAffinity): Seq[PlanetSideGameObject with FactionAffinity] = {
|
||||||
val (data, filterFunc) = SetupForTest(zone, obj)
|
val (data, filterFunc) = SetupForTest(zone, obj)
|
||||||
data.find(filterFunc)
|
data.filter(filterFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import net.psforever.types.Vector3
|
||||||
*/
|
*/
|
||||||
abstract class EnvironmentTrait {
|
abstract class EnvironmentTrait {
|
||||||
def canInteractWith(obj: PlanetSideGameObject): Boolean
|
def canInteractWith(obj: PlanetSideGameObject): Boolean
|
||||||
|
|
||||||
|
def testingDepth(obj: PlanetSideGameObject): Float
|
||||||
}
|
}
|
||||||
|
|
||||||
object EnvironmentAttribute {
|
object EnvironmentAttribute {
|
||||||
|
|
@ -25,16 +27,33 @@ object EnvironmentAttribute {
|
||||||
case _ => false
|
case _ => false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def testingDepth(obj: PlanetSideGameObject): Float = {
|
||||||
|
obj match {
|
||||||
|
case v: Vehicle if v.Flying.nonEmpty =>
|
||||||
|
0f
|
||||||
|
case _: Vehicle if !obj.Definition.DrownAtMaxDepth =>
|
||||||
|
obj.Definition.MaxDepth * 0.9f
|
||||||
|
case _: Vehicle =>
|
||||||
|
obj.Definition.MaxDepth * 0.6f
|
||||||
|
case _ =>
|
||||||
|
0.2f
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case object Lava extends EnvironmentTrait {
|
case object Lava extends EnvironmentTrait {
|
||||||
/** lava can only interact with anything capable of registering damage */
|
/** lava can only interact with anything capable of registering damage */
|
||||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = canInteractWithDamagingFields(obj)
|
def canInteractWith(obj: PlanetSideGameObject): Boolean = canInteractWithDamagingFields(obj)
|
||||||
|
|
||||||
|
def testingDepth(obj: _root_.net.psforever.objects.PlanetSideGameObject): Float = 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
case object Death extends EnvironmentTrait {
|
case object Death extends EnvironmentTrait {
|
||||||
/** death can only interact with anything capable of registering damage */
|
/** death can only interact with anything capable of registering damage */
|
||||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = canInteractWithDamagingFields(obj)
|
def canInteractWith(obj: PlanetSideGameObject): Boolean = canInteractWithDamagingFields(obj)
|
||||||
|
|
||||||
|
def testingDepth(obj: _root_.net.psforever.objects.PlanetSideGameObject): Float = 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
case object GantryDenialField
|
case object GantryDenialField
|
||||||
|
|
@ -46,18 +65,24 @@ object EnvironmentAttribute {
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def testingDepth(obj: _root_.net.psforever.objects.PlanetSideGameObject): Float = 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
case object MovementFieldTrigger
|
case object MovementFieldTrigger
|
||||||
extends EnvironmentTrait {
|
extends EnvironmentTrait {
|
||||||
/** only interact with living player characters or vehicles */
|
/** only interact with living player characters or vehicles */
|
||||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = canInteractWithPlayersAndVehicles(obj)
|
def canInteractWith(obj: PlanetSideGameObject): Boolean = canInteractWithPlayersAndVehicles(obj)
|
||||||
|
|
||||||
|
def testingDepth(obj: _root_.net.psforever.objects.PlanetSideGameObject): Float = 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
case object InteriorField
|
case object InteriorField
|
||||||
extends EnvironmentTrait {
|
extends EnvironmentTrait {
|
||||||
/** only interact with living player characters or vehicles */
|
/** only interact with living player characters or vehicles */
|
||||||
def canInteractWith(obj: PlanetSideGameObject): Boolean = canInteractWithPlayersAndVehicles(obj)
|
def canInteractWith(obj: PlanetSideGameObject): Boolean = canInteractWithPlayersAndVehicles(obj)
|
||||||
|
|
||||||
|
def testingDepth(obj: _root_.net.psforever.objects.PlanetSideGameObject): Float = 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2021 PSForever
|
// Copyright (c) 2021 PSForever
|
||||||
package net.psforever.objects.serverobject.environment.interaction
|
package net.psforever.objects.serverobject.environment.interaction
|
||||||
|
|
||||||
import net.psforever.objects.GlobalDefinitions
|
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment}
|
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment}
|
||||||
import net.psforever.objects.zones._
|
import net.psforever.objects.zones._
|
||||||
|
|
@ -98,6 +97,8 @@ class InteractWithEnvironment()
|
||||||
.foreach(_.stopInteractingWith(obj, body, None))
|
.foreach(_.stopInteractingWith(obj, body, None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def OngoingInteractions: Set[EnvironmentTrait] = interactWith.map(_.attribute)
|
||||||
}
|
}
|
||||||
|
|
||||||
object InteractWithEnvironment {
|
object InteractWithEnvironment {
|
||||||
|
|
@ -117,9 +118,8 @@ object InteractWithEnvironment {
|
||||||
obj: PlanetSideServerObject,
|
obj: PlanetSideServerObject,
|
||||||
sector: SectorPopulation
|
sector: SectorPopulation
|
||||||
): Set[PieceOfEnvironment] = {
|
): Set[PieceOfEnvironment] = {
|
||||||
val depth = GlobalDefinitions.MaxDepth(obj)
|
|
||||||
sector.environmentList
|
sector.environmentList
|
||||||
.filter(body => body.attribute.canInteractWith(obj) && body.testInteraction(obj, depth))
|
.filter(body => body.attribute.canInteractWith(obj) && body.testInteraction(obj, body.attribute.testingDepth(obj)))
|
||||||
.distinctBy(_.attribute)
|
.distinctBy(_.attribute)
|
||||||
.toSet
|
.toSet
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +136,7 @@ object InteractWithEnvironment {
|
||||||
body: PieceOfEnvironment,
|
body: PieceOfEnvironment,
|
||||||
obj: PlanetSideServerObject
|
obj: PlanetSideServerObject
|
||||||
): Option[PieceOfEnvironment] = {
|
): Option[PieceOfEnvironment] = {
|
||||||
if ((obj.Zone eq zone) && body.testInteraction(obj, GlobalDefinitions.MaxDepth(obj))) {
|
if ((obj.Zone eq zone) && body.testInteraction(obj, body.attribute.testingDepth(obj))) {
|
||||||
Some(body)
|
Some(body)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -185,12 +185,12 @@ case class OnStableEnvironment() extends InteractionBehavior {
|
||||||
): Set[PieceOfEnvironment] = {
|
): Set[PieceOfEnvironment] = {
|
||||||
if (allow) {
|
if (allow) {
|
||||||
val interactions = obj.interaction().collectFirst { case inter: InteractWithEnvironment => inter.Interactions }
|
val interactions = obj.interaction().collectFirst { case inter: InteractWithEnvironment => inter.Interactions }
|
||||||
val env = InteractWithEnvironment.checkAllEnvironmentInteractions(obj, sector)
|
val bodies = InteractWithEnvironment.checkAllEnvironmentInteractions(obj, sector)
|
||||||
env.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.doInteractingWith(obj, body, None)))
|
bodies.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.doInteractingWith(obj, body, None)))
|
||||||
if (env.nonEmpty) {
|
if (bodies.nonEmpty) {
|
||||||
nextstep = AwaitOngoingInteraction(obj.Zone)
|
nextstep = AwaitOngoingInteraction(obj.Zone)
|
||||||
}
|
}
|
||||||
env
|
bodies
|
||||||
} else {
|
} else {
|
||||||
nextstep = BlockedFromInteracting()
|
nextstep = BlockedFromInteracting()
|
||||||
Set()
|
Set()
|
||||||
|
|
@ -225,17 +225,22 @@ final case class AwaitOngoingInteraction(zone: Zone) extends InteractionBehavior
|
||||||
): Set[PieceOfEnvironment] = {
|
): Set[PieceOfEnvironment] = {
|
||||||
val interactions = obj.interaction().collectFirst { case inter: InteractWithEnvironment => inter.Interactions }
|
val interactions = obj.interaction().collectFirst { case inter: InteractWithEnvironment => inter.Interactions }
|
||||||
if (allow) {
|
if (allow) {
|
||||||
val env = InteractWithEnvironment.checkAllEnvironmentInteractions(obj, sector)
|
val bodies = InteractWithEnvironment.checkAllEnvironmentInteractions(obj, sector)
|
||||||
val (in, out) = existing.partition(body => InteractWithEnvironment.checkSpecificEnvironmentInteraction(zone, body, obj).nonEmpty)
|
val (in, out) = existing.partition(body => InteractWithEnvironment.checkSpecificEnvironmentInteraction(zone, body, obj).nonEmpty)
|
||||||
env.diff(in).foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.doInteractingWith(obj, body, None)))
|
val inAttrs = bodies.map(_.attribute)
|
||||||
out.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.stopInteractingWith(obj, body, None)))
|
out
|
||||||
if (env.isEmpty) {
|
.filterNot(e => inAttrs.contains(e.attribute))
|
||||||
|
.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.stopInteractingWith(obj, body, None)))
|
||||||
|
bodies
|
||||||
|
.diff(in)
|
||||||
|
.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.doInteractingWith(obj, body, None)))
|
||||||
|
if (bodies.isEmpty) {
|
||||||
val n = OnStableEnvironment()
|
val n = OnStableEnvironment()
|
||||||
val out = n.perform(obj, sector, Set(), allow)
|
val out = n.perform(obj, sector, Set(), allow)
|
||||||
nextstep = n.next
|
nextstep = n.next
|
||||||
out
|
out
|
||||||
} else {
|
} else {
|
||||||
env
|
bodies
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
existing.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.stopInteractingWith(obj, body, None)))
|
existing.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.stopInteractingWith(obj, body, None)))
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,26 @@
|
||||||
// Copyright (c) 2024 PSForever
|
// Copyright (c) 2024 PSForever
|
||||||
package net.psforever.objects.serverobject.environment.interaction.common
|
package net.psforever.objects.serverobject.environment.interaction.common
|
||||||
|
|
||||||
|
import net.psforever.objects.PlanetSideGameObject
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
import net.psforever.objects.serverobject.environment.interaction.InteractWithEnvironment
|
||||||
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
||||||
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, PieceOfEnvironment}
|
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, PieceOfEnvironment}
|
||||||
|
import net.psforever.objects.zones.InteractsWithZone
|
||||||
import net.psforever.types.{OxygenState, PlanetSideGUID}
|
import net.psforever.types.{OxygenState, PlanetSideGUID}
|
||||||
|
|
||||||
trait Watery {
|
trait Watery {
|
||||||
val attribute: EnvironmentTrait = EnvironmentAttribute.Water
|
val attribute: EnvironmentTrait = EnvironmentAttribute.Water
|
||||||
|
|
||||||
/** how long the current interaction has been progressing in the current way */
|
/** how long the current interaction has been progressing in the current way */
|
||||||
protected var waterInteractionTime: Long = 0
|
protected var waterInteractionTime: Long = 0
|
||||||
/** information regarding the drowning state */
|
/** information regarding the drowning state */
|
||||||
protected var condition: Option[OxygenStateTarget] = None
|
protected var condition: Option[OxygenStateTarget] = None
|
||||||
/** information regarding the drowning state */
|
/** information regarding the drowning state */
|
||||||
def Condition: Option[OxygenStateTarget] = condition
|
def Condition: Option[OxygenStateTarget] = condition
|
||||||
|
/** how far the player's feet are below the surface of the water */
|
||||||
|
protected var depth: Float = 0f
|
||||||
|
/** how far the player's feet are below the surface of the water */
|
||||||
|
def Depth: Float = depth
|
||||||
}
|
}
|
||||||
|
|
||||||
object Watery {
|
object Watery {
|
||||||
|
|
@ -33,6 +39,27 @@ object Watery {
|
||||||
progress: Float
|
progress: Float
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param target evaluate this to determine if to continue with this loss
|
||||||
|
* @return whether or not we are sufficiently submerged in water
|
||||||
|
*/
|
||||||
|
def wading(target: PlanetSideGameObject with InteractsWithZone): Boolean = {
|
||||||
|
target
|
||||||
|
.interaction()
|
||||||
|
.collectFirst {
|
||||||
|
case env: InteractWithEnvironment =>
|
||||||
|
env
|
||||||
|
.Interactions
|
||||||
|
.get(EnvironmentAttribute.Water)
|
||||||
|
.collectFirst {
|
||||||
|
case water: Watery => water.Depth > 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.flatten
|
||||||
|
.contains(true)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the effect of being exposed to a watery environment beyond an entity's critical region.
|
* Calculate the effect of being exposed to a watery environment beyond an entity's critical region.
|
||||||
* @param obj the target
|
* @param obj the target
|
||||||
|
|
@ -122,10 +149,10 @@ object Watery {
|
||||||
//switching from suffocation to recovery
|
//switching from suffocation to recovery
|
||||||
val oldDuration: Long = obj.Definition.UnderwaterLifespan(OxygenState.Suffocation)
|
val oldDuration: Long = obj.Definition.UnderwaterLifespan(OxygenState.Suffocation)
|
||||||
val newDuration: Long = obj.Definition.UnderwaterLifespan(OxygenState.Recovery)
|
val newDuration: Long = obj.Definition.UnderwaterLifespan(OxygenState.Recovery)
|
||||||
val oldTimeRemaining: Long = completionTime - System.currentTimeMillis()
|
val oldTimeRemaining: Long = math.max(0, completionTime - System.currentTimeMillis())
|
||||||
val oldTimeRatio: Float = oldTimeRemaining / oldDuration.toFloat
|
val oldTimeRatio: Float = oldTimeRemaining / oldDuration.toFloat
|
||||||
val percentage: Float = oldTimeRatio * 100
|
val percentage: Float = oldTimeRatio * 100
|
||||||
val recoveryTime: Long = newDuration - (newDuration * oldTimeRatio).toLong
|
val recoveryTime: Long = newDuration * (1f - oldTimeRatio).toLong
|
||||||
(true, recoveryTime, percentage)
|
(true, recoveryTime, percentage)
|
||||||
case Some(OxygenState.Recovery) =>
|
case Some(OxygenState.Recovery) =>
|
||||||
//interrupted while recovering, calculate the progress and keep recovering
|
//interrupted while recovering, calculate the progress and keep recovering
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ class CaptureFlag(private val tDef: CaptureFlagDefinition) extends Amenity {
|
||||||
private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
||||||
private var carrier: Option[Player] = None
|
private var carrier: Option[Player] = None
|
||||||
private var lastTimeCollected: Long = System.currentTimeMillis()
|
private var lastTimeCollected: Long = System.currentTimeMillis()
|
||||||
|
private val spawnedTime: Long = lastTimeCollected
|
||||||
|
|
||||||
def Target: Building = target
|
def Target: Building = target
|
||||||
def Target_=(newTarget: Building): Building = {
|
def Target_=(newTarget: Building): Building = {
|
||||||
|
|
@ -56,10 +57,11 @@ class CaptureFlag(private val tDef: CaptureFlagDefinition) extends Amenity {
|
||||||
* When the flag is carried by a player, the position returned should be that of the carrier not the flag.
|
* When the flag is carried by a player, the position returned should be that of the carrier not the flag.
|
||||||
* @return the position of the carrier, if there is a player carrying the flag, or the flag itself
|
* @return the position of the carrier, if there is a player carrying the flag, or the flag itself
|
||||||
*/
|
*/
|
||||||
override def Position: Vector3 = if (Carrier.nonEmpty) {
|
override def Position: Vector3 = {
|
||||||
carrier.get.Position
|
carrier match {
|
||||||
} else {
|
case Some(player) => player.Position
|
||||||
super.Position
|
case None => super.Position
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def Carrier: Option[Player] = carrier
|
def Carrier: Option[Player] = carrier
|
||||||
|
|
@ -70,6 +72,8 @@ class CaptureFlag(private val tDef: CaptureFlagDefinition) extends Amenity {
|
||||||
}
|
}
|
||||||
|
|
||||||
def LastCollectionTime: Long = carrier.map { _ => lastTimeCollected }.getOrElse { System.currentTimeMillis() }
|
def LastCollectionTime: Long = carrier.map { _ => lastTimeCollected }.getOrElse { System.currentTimeMillis() }
|
||||||
|
|
||||||
|
def InitialSpawnTime: Long = spawnedTime
|
||||||
}
|
}
|
||||||
|
|
||||||
object CaptureFlag {
|
object CaptureFlag {
|
||||||
|
|
|
||||||
|
|
@ -146,5 +146,5 @@ object Mountable {
|
||||||
* @param obj the `Mountable` object
|
* @param obj the `Mountable` object
|
||||||
* @param seat_num the seat index
|
* @param seat_num the seat index
|
||||||
*/
|
*/
|
||||||
final case class CanNotDismount(obj: Mountable, seat_num: Int) extends Exchange
|
final case class CanNotDismount(obj: Mountable, seat_num: Int, bailType: BailType.Value) extends Exchange
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ trait MountableBehavior {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sender() ! Mountable.MountMessages(user, Mountable.CanNotDismount(obj, seat_number))
|
sender() ! Mountable.MountMessages(user, Mountable.CanNotDismount(obj, seat_number, bail_type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,9 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
|
||||||
/** how to process either the first order or every subsequent order */
|
/** how to process either the first order or every subsequent order */
|
||||||
private var handleOrderFunc: VehicleSpawnPad.VehicleOrder => Unit = NewTasking
|
private var handleOrderFunc: VehicleSpawnPad.VehicleOrder => Unit = NewTasking
|
||||||
|
|
||||||
|
/** ... */
|
||||||
|
private var reminderSeq: Seq[Int] = Seq()
|
||||||
|
|
||||||
def LogId = ""
|
def LogId = ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -77,7 +80,7 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def postStop() : Unit = {
|
override def postStop() : Unit = {
|
||||||
periodicReminder.cancel()
|
discontinueCurrentReminder()
|
||||||
queueManagement.cancel()
|
queueManagement.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,36 +116,11 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
|
||||||
case VehicleSpawnControl.ProcessControl.QueueManagement =>
|
case VehicleSpawnControl.ProcessControl.QueueManagement =>
|
||||||
queueManagementTask()
|
queueManagementTask()
|
||||||
|
|
||||||
/*
|
|
||||||
When the vehicle is spawned and added to the pad, it will "occupy" the pad and block it from further action.
|
|
||||||
Normally, the player who wanted to spawn the vehicle will be automatically put into the driver mount.
|
|
||||||
If this is blocked, the vehicle will idle on the pad and must be moved far enough away from the point of origin.
|
|
||||||
During this time, a periodic message about the spawn pad being blocked will be broadcast to the order queue.
|
|
||||||
*/
|
|
||||||
case VehicleSpawnControl.ProcessControl.Reminder =>
|
case VehicleSpawnControl.ProcessControl.Reminder =>
|
||||||
trackedOrder
|
evaluateBlockedReminder()
|
||||||
.collect {
|
|
||||||
case entry =>
|
|
||||||
if (periodicReminder.isCancelled) {
|
|
||||||
trace(s"the pad has become blocked by a ${entry.vehicle.Definition.Name} in its current order")
|
|
||||||
periodicReminder = context.system.scheduler.scheduleWithFixedDelay(
|
|
||||||
VehicleSpawnControl.periodicReminderTestDelay,
|
|
||||||
VehicleSpawnControl.periodicReminderTestDelay,
|
|
||||||
self,
|
|
||||||
VehicleSpawnControl.ProcessControl.Reminder
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
BlockedReminder(entry, orders)
|
|
||||||
}
|
|
||||||
trackedOrder
|
|
||||||
}
|
|
||||||
.orElse {
|
|
||||||
periodicReminder.cancel()
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
case VehicleSpawnControl.ProcessControl.Flush =>
|
case VehicleSpawnControl.ProcessControl.Flush =>
|
||||||
periodicReminder.cancel()
|
discontinueCurrentReminder()
|
||||||
orders.foreach { CancelOrder(_, Some("@SVCP_RemovedFromVehicleQueue_Generic")) }
|
orders.foreach { CancelOrder(_, Some("@SVCP_RemovedFromVehicleQueue_Generic")) }
|
||||||
orders = Nil
|
orders = Nil
|
||||||
trackedOrder.foreach {
|
trackedOrder.foreach {
|
||||||
|
|
@ -259,7 +237,7 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
|
||||||
* `None`, if no order found or submitted
|
* `None`, if no order found or submitted
|
||||||
*/
|
*/
|
||||||
private def ProcessOrder(order: Option[VehicleSpawnPad.VehicleOrder]): Unit = {
|
private def ProcessOrder(order: Option[VehicleSpawnPad.VehicleOrder]): Unit = {
|
||||||
periodicReminder.cancel()
|
discontinueCurrentReminder()
|
||||||
order.collect {
|
order.collect {
|
||||||
case VehicleSpawnPad.VehicleOrder(driver, vehicle, terminal) =>
|
case VehicleSpawnPad.VehicleOrder(driver, vehicle, terminal) =>
|
||||||
val size = orders.size + 1
|
val size = orders.size + 1
|
||||||
|
|
@ -324,37 +302,6 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* na
|
|
||||||
* @param blockedOrder the previous order whose vehicle is blocking the spawn pad from operating
|
|
||||||
* @param recipients all of the other customers who will be receiving the message
|
|
||||||
*/
|
|
||||||
private def BlockedReminder(blockedOrder: VehicleSpawnControl.Order, recipients: Seq[VehicleSpawnPad.VehicleOrder]): Unit = {
|
|
||||||
val user = blockedOrder.vehicle
|
|
||||||
.Seats(0).occupant
|
|
||||||
.orElse(pad.Zone.GUID(blockedOrder.vehicle.OwnerGuid))
|
|
||||||
.orElse(pad.Zone.GUID(blockedOrder.DriverGUID))
|
|
||||||
val relevantRecipients: Iterator[VehicleSpawnPad.VehicleOrder] = user match {
|
|
||||||
case Some(p: Player) if !p.HasGUID =>
|
|
||||||
recipients.iterator
|
|
||||||
case Some(_: Player) =>
|
|
||||||
(VehicleSpawnPad.VehicleOrder(
|
|
||||||
blockedOrder.driver,
|
|
||||||
blockedOrder.vehicle,
|
|
||||||
null //permissible
|
|
||||||
) +: recipients).iterator //one who took possession of the vehicle
|
|
||||||
case _ =>
|
|
||||||
recipients.iterator
|
|
||||||
}
|
|
||||||
recursiveBlockedReminder(
|
|
||||||
relevantRecipients,
|
|
||||||
if (blockedOrder.vehicle.Health == 0)
|
|
||||||
Option("Clear the wreckage.")
|
|
||||||
else
|
|
||||||
None
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel this vehicle order and inform the person who made it, if possible.
|
* Cancel this vehicle order and inform the person who made it, if possible.
|
||||||
* @param entry the order being cancelled
|
* @param entry the order being cancelled
|
||||||
|
|
@ -381,21 +328,136 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the vehicle is spawned and added to the pad, it will "occupy" the pad and block it from further action.
|
||||||
|
* During this time, a periodic message about the spawn pad being blocked will be broadcast to the order queue.<br>
|
||||||
|
* The vehicle is also queued to deconstruct in 30s if no one assumes the driver seat.
|
||||||
|
*/
|
||||||
|
private def evaluateBlockedReminder(): Unit = {
|
||||||
|
/*
|
||||||
|
Normally, the player who wanted to spawn the vehicle will be automatically put into the driver mount.
|
||||||
|
If this is blocked or aborted, the vehicle will idle on the pad and must be moved far enough away from the point of origin.
|
||||||
|
*/
|
||||||
|
trackedOrder
|
||||||
|
.collect {
|
||||||
|
case entry =>
|
||||||
|
if (reminderSeq.isEmpty) {
|
||||||
|
//begin reminder
|
||||||
|
trace(s"the pad has become blocked by a ${entry.vehicle.Definition.Name} in its current order")
|
||||||
|
retimePeriodicReminder(
|
||||||
|
shaveOffFirstElementAndDiffSecondElement(pad.Definition.BlockedReminderMessageDelays)
|
||||||
|
)
|
||||||
|
trackedOrder
|
||||||
|
} else if (reminderSeq.size == 1) {
|
||||||
|
//end reminder
|
||||||
|
standaloneBlockedReminder(
|
||||||
|
VehicleSpawnPad.VehicleOrder(entry.driver, entry.vehicle, null),
|
||||||
|
Some("@PadDeconstruct_Done")
|
||||||
|
)
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
//continue reminder
|
||||||
|
BlockedReminder(entry, orders)
|
||||||
|
retimePeriodicReminder(
|
||||||
|
shaveOffFirstElementAndDiffSecondElement(reminderSeq)
|
||||||
|
)
|
||||||
|
trackedOrder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.orElse {
|
||||||
|
discontinueCurrentReminder()
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The periodic reminder will no longer be repeated.
|
||||||
|
* Sequences tied to the periodic reminder should be reset.
|
||||||
|
*/
|
||||||
|
private def discontinueCurrentReminder(): Unit = {
|
||||||
|
periodicReminder.cancel()
|
||||||
|
periodicReminder = Default.Cancellable
|
||||||
|
reminderSeq = List()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param blockedOrder the previous order whose vehicle is blocking the spawn pad from operating
|
||||||
|
* @param recipients all of the other customers who will be receiving the message
|
||||||
|
*/
|
||||||
|
private def BlockedReminder(
|
||||||
|
blockedOrder: VehicleSpawnControl.Order,
|
||||||
|
recipients: Seq[VehicleSpawnPad.VehicleOrder]
|
||||||
|
): Unit = {
|
||||||
|
//everyone else
|
||||||
|
recursiveBlockedReminder(
|
||||||
|
recipients.iterator,
|
||||||
|
if (blockedOrder.vehicle.Health == 0)
|
||||||
|
Option("The vehicle spawn pad where you placed your order is blocked. Clearing the wreckage ...")
|
||||||
|
else
|
||||||
|
Option("The vehicle spawn pad where you placed your order is blocked.")
|
||||||
|
)
|
||||||
|
//would-be driver
|
||||||
|
blockedOrder.vehicle
|
||||||
|
.Seats(0).occupant
|
||||||
|
.orElse(pad.Zone.GUID(blockedOrder.vehicle.OwnerGuid))
|
||||||
|
.orElse(pad.Zone.GUID(blockedOrder.DriverGUID)) collect {
|
||||||
|
case p: Player if p.isAlive =>
|
||||||
|
standaloneBlockedReminder(
|
||||||
|
VehicleSpawnPad.VehicleOrder(blockedOrder.driver, blockedOrder.vehicle, null),
|
||||||
|
Some(s"@PadDeconstruct_secsA^${reminderSeq.head}~")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clip the first entry in a list of numbers and
|
||||||
|
* get the difference between the clipped entry and the next entry.
|
||||||
|
* The clipped-off list will be made to be the new sequence of reminder delays.
|
||||||
|
* @param sequence reminder delay test values
|
||||||
|
* @return difference between first delay and second delay
|
||||||
|
*/
|
||||||
|
private def shaveOffFirstElementAndDiffSecondElement(sequence: Seq[Int]): Int = {
|
||||||
|
val startTime = sequence.take(1).headOption.getOrElse(0)
|
||||||
|
val restTimes = sequence.drop(1)
|
||||||
|
val headOfRestTimes = restTimes.headOption.getOrElse(startTime)
|
||||||
|
reminderSeq = restTimes
|
||||||
|
startTime - headOfRestTimes
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a single instance of the "periodic reminder" to this kind of delay.
|
||||||
|
* @param delay how long until the next reminder
|
||||||
|
*/
|
||||||
|
private def retimePeriodicReminder(delay: Int): Unit = {
|
||||||
|
periodicReminder = context.system.scheduler.scheduleOnce(
|
||||||
|
delay.seconds,
|
||||||
|
self,
|
||||||
|
VehicleSpawnControl.ProcessControl.Reminder
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@tailrec private final def recursiveBlockedReminder(
|
@tailrec private final def recursiveBlockedReminder(
|
||||||
iter: Iterator[VehicleSpawnPad.VehicleOrder],
|
iter: Iterator[VehicleSpawnPad.VehicleOrder],
|
||||||
cause: Option[Any]
|
cause: Option[Any]
|
||||||
): Unit = {
|
): Unit = {
|
||||||
if (iter.hasNext) {
|
if (iter.hasNext) {
|
||||||
val recipient = iter.next()
|
standaloneBlockedReminder(iter.next(), cause)
|
||||||
pad.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder(
|
|
||||||
recipient.player.Name,
|
|
||||||
VehicleSpawnPad.Reminders.Blocked,
|
|
||||||
cause
|
|
||||||
)
|
|
||||||
recursiveBlockedReminder(iter, cause)
|
recursiveBlockedReminder(iter, cause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def standaloneBlockedReminder(
|
||||||
|
entry: VehicleSpawnPad.VehicleOrder,
|
||||||
|
cause: Option[Any]
|
||||||
|
): Unit = {
|
||||||
|
pad.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder(
|
||||||
|
entry.player.Name,
|
||||||
|
VehicleSpawnPad.Reminders.Blocked,
|
||||||
|
cause
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@tailrec private final def recursiveOrderReminder(
|
@tailrec private final def recursiveOrderReminder(
|
||||||
iter: Iterator[VehicleSpawnPad.VehicleOrder],
|
iter: Iterator[VehicleSpawnPad.VehicleOrder],
|
||||||
size: Int,
|
size: Int,
|
||||||
|
|
@ -414,19 +476,16 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
|
||||||
}
|
}
|
||||||
|
|
||||||
object VehicleSpawnControl {
|
object VehicleSpawnControl {
|
||||||
private final val periodicReminderTestDelay: FiniteDuration = 10 seconds
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Control messages for the vehicle spawn process.
|
* Control messages for the vehicle spawn process.
|
||||||
*/
|
*/
|
||||||
|
sealed trait ProcessControlOperation
|
||||||
object ProcessControl {
|
object ProcessControl {
|
||||||
sealed trait ProcessControl
|
case object Flush extends ProcessControlOperation
|
||||||
|
case object OrderCancelled extends ProcessControlOperation
|
||||||
case object Flush extends ProcessControl
|
case object GetNewOrder extends ProcessControlOperation
|
||||||
case object OrderCancelled extends ProcessControl
|
case object Reminder extends ProcessControlOperation
|
||||||
case object GetNewOrder extends ProcessControl
|
case object QueueManagement extends ProcessControlOperation
|
||||||
case object Reminder extends ProcessControl
|
|
||||||
case object QueueManagement extends ProcessControl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ class VehicleSpawnPadDefinition(objectId: Int) extends AmenityDefinition(objectI
|
||||||
|
|
||||||
// Different pads require a Z offset to stop vehicles falling through the world after the pad rises from the floor, these values are found in game_objects.adb.lst
|
// Different pads require a Z offset to stop vehicles falling through the world after the pad rises from the floor, these values are found in game_objects.adb.lst
|
||||||
private var vehicle_creation_z_offset = 0f
|
private var vehicle_creation_z_offset = 0f
|
||||||
|
|
||||||
// Different pads also require an orientation offset when detaching vehicles from the rails associated with the spawn pad, again in game_objects.adb.lst
|
// Different pads also require an orientation offset when detaching vehicles from the rails associated with the spawn pad, again in game_objects.adb.lst
|
||||||
// For example: 9754:add_property dropship_pad_doors vehiclecreationzorientoffset 90
|
// For example: 9754:add_property dropship_pad_doors vehiclecreationzorientoffset 90
|
||||||
// However, it seems these values need to be reversed to turn CCW to CW rotation (e.g. +90 to -90)
|
// However, it seems these values need to be reversed to turn CCW to CW rotation (e.g. +90 to -90)
|
||||||
|
|
@ -35,6 +34,12 @@ class VehicleSpawnPadDefinition(objectId: Int) extends AmenityDefinition(objectI
|
||||||
* @see `net.psforever.objects.serverobject.pad.process.VehicleSpawnControlRailJack` */
|
* @see `net.psforever.objects.serverobject.pad.process.VehicleSpawnControlRailJack` */
|
||||||
var killBox: (VehicleSpawnPad, Boolean)=>(PlanetSideGameObject, PlanetSideGameObject, Float)=> Boolean =
|
var killBox: (VehicleSpawnPad, Boolean)=>(PlanetSideGameObject, PlanetSideGameObject, Float)=> Boolean =
|
||||||
VehicleSpawnPadDefinition.prepareKillBox(forwardLimit = 0, backLimit = 0, sideLimit = 0, aboveLimit = 0)
|
VehicleSpawnPadDefinition.prepareKillBox(forwardLimit = 0, backLimit = 0, sideLimit = 0, aboveLimit = 0)
|
||||||
|
|
||||||
|
private val blockedReminderMessageDelays: Seq[Int] = Seq(30, 23, 15, 8, 0)
|
||||||
|
|
||||||
|
def VehicleCreationDeconstructTime: Int = blockedReminderMessageDelays.head
|
||||||
|
|
||||||
|
def BlockedReminderMessageDelays: Seq[Int] = blockedReminderMessageDelays
|
||||||
}
|
}
|
||||||
|
|
||||||
object VehicleSpawnPadDefinition {
|
object VehicleSpawnPadDefinition {
|
||||||
|
|
|
||||||
|
|
@ -50,26 +50,35 @@ class VehicleSpawnControlFinalClearance(pad: VehicleSpawnPad) extends VehicleSpa
|
||||||
self ! VehicleSpawnControlFinalClearance.Test(order)
|
self ! VehicleSpawnControlFinalClearance.Test(order)
|
||||||
|
|
||||||
case test @ VehicleSpawnControlFinalClearance.Test(entry) =>
|
case test @ VehicleSpawnControlFinalClearance.Test(entry) =>
|
||||||
//the vehicle has an initial decay of 30s in which time it needs to be mounted
|
//the vehicle has an initial decay in which time it needs to be mounted
|
||||||
//once mounted, it will complain to the current driver that it is blocking the spawn pad
|
//once mounted, it will complain to the current driver that it is blocking the spawn pad
|
||||||
//no time limit exists for that state
|
//no time limit exists for that state
|
||||||
val vehicle = entry.vehicle
|
val vehicle = entry.vehicle
|
||||||
if (Vector3.DistanceSquared(vehicle.Position, pad.Position) > 144) { //12m away from pad
|
val distanceTest = Vector3.DistanceSquared(vehicle.Position, pad.Position) > 144 //12m away from pad
|
||||||
trace("pad cleared")
|
if (vehicle.Destroyed) {
|
||||||
pad.Zone.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad)
|
trace("pad cleared of vehicle wreckage")
|
||||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
val delay = if (distanceTest) { 2000 } else { 5000 }
|
||||||
} else if (vehicle.Destroyed) {
|
|
||||||
trace("clearing the pad of vehicle wreckage")
|
|
||||||
VehicleSpawnControl.DisposeVehicle(vehicle, pad.Zone)
|
VehicleSpawnControl.DisposeVehicle(vehicle, pad.Zone)
|
||||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
temp = context.system.scheduler.scheduleOnce(delay.milliseconds, self, VehicleSpawnControlFinalClearance.NextOrder)
|
||||||
|
} else if (distanceTest) {
|
||||||
|
trace("pad cleared")
|
||||||
|
val delay = if (vehicle.Seats.head._2.occupant.isEmpty) { 4500 } else { 2000 }
|
||||||
|
temp = context.system.scheduler.scheduleOnce(delay.milliseconds, self, VehicleSpawnControlFinalClearance.NextOrder)
|
||||||
} else {
|
} else {
|
||||||
temp = context.system.scheduler.scheduleOnce(2000 milliseconds, self, test)
|
//retry test
|
||||||
|
temp = context.system.scheduler.scheduleOnce(delay = 2000.milliseconds, self, test)
|
||||||
}
|
}
|
||||||
|
|
||||||
case _ => ;
|
case VehicleSpawnControlFinalClearance.NextOrder =>
|
||||||
|
pad.Zone.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad)
|
||||||
|
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||||
|
|
||||||
|
case _ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object VehicleSpawnControlFinalClearance {
|
object VehicleSpawnControlFinalClearance {
|
||||||
private final case class Test(entry: VehicleSpawnControl.Order)
|
private case class Test(entry: VehicleSpawnControl.Order)
|
||||||
|
|
||||||
|
private case object NextOrder
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.pad.process
|
package net.psforever.objects.serverobject.pad.process
|
||||||
|
|
||||||
import akka.actor.Props
|
import akka.actor.{ActorRef, Props}
|
||||||
import net.psforever.objects.{Default, Vehicle}
|
import net.psforever.objects.{Default, Vehicle}
|
||||||
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ import scala.concurrent.duration._
|
||||||
class VehicleSpawnControlSeatDriver(pad: VehicleSpawnPad) extends VehicleSpawnControlBase(pad) {
|
class VehicleSpawnControlSeatDriver(pad: VehicleSpawnPad) extends VehicleSpawnControlBase(pad) {
|
||||||
def LogId = "-usher"
|
def LogId = "-usher"
|
||||||
|
|
||||||
val vehicleOverride = context.actorOf(
|
val vehicleOverride: ActorRef = context.actorOf(
|
||||||
Props(classOf[VehicleSpawnControlServerVehicleOverride], pad),
|
Props(classOf[VehicleSpawnControlServerVehicleOverride], pad),
|
||||||
s"${context.parent.path.name}-override"
|
s"${context.parent.path.name}-override"
|
||||||
)
|
)
|
||||||
|
|
@ -43,7 +43,7 @@ class VehicleSpawnControlSeatDriver(pad: VehicleSpawnPad) extends VehicleSpawnCo
|
||||||
val driver = entry.driver
|
val driver = entry.driver
|
||||||
val vehicle = entry.vehicle
|
val vehicle = entry.vehicle
|
||||||
//avoid unattended vehicle blocking the pad; user should mount (and does so normally) to reset decon timer
|
//avoid unattended vehicle blocking the pad; user should mount (and does so normally) to reset decon timer
|
||||||
vehicle.Actor ! Vehicle.Deconstruct(Some(30 seconds))
|
vehicle.Actor ! Vehicle.Deconstruct(Some(pad.Definition.VehicleCreationDeconstructTime.seconds))
|
||||||
if (VehicleSpawnControl.validateOrderCredentials(pad, driver, vehicle).isEmpty) {
|
if (VehicleSpawnControl.validateOrderCredentials(pad, driver, vehicle).isEmpty) {
|
||||||
trace("driver to be made seated in vehicle")
|
trace("driver to be made seated in vehicle")
|
||||||
pad.Zone.VehicleEvents ! VehicleSpawnPad.StartPlayerSeatedInVehicle(driver.Name, vehicle, pad)
|
pad.Zone.VehicleEvents ! VehicleSpawnPad.StartPlayerSeatedInVehicle(driver.Name, vehicle, pad)
|
||||||
|
|
@ -67,7 +67,7 @@ class VehicleSpawnControlSeatDriver(pad: VehicleSpawnPad) extends VehicleSpawnCo
|
||||||
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) =>
|
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) =>
|
||||||
context.parent ! msg
|
context.parent ! msg
|
||||||
|
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,16 @@ import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.sourcing.{PlayerSource, UniquePlayer}
|
import net.psforever.objects.sourcing.{PlayerSource, UniquePlayer}
|
||||||
import net.psforever.objects.zones.{HotSpotInfo, ZoneHotSpotProjector}
|
import net.psforever.objects.zones.{HotSpotInfo, ZoneHotSpotProjector}
|
||||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, Vector3}
|
||||||
import net.psforever.util.Config
|
import net.psforever.util.Config
|
||||||
import akka.pattern.ask
|
import akka.pattern.ask
|
||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
|
import net.psforever.objects.Player
|
||||||
import net.psforever.objects.avatar.scoring.Kill
|
import net.psforever.objects.avatar.scoring.Kill
|
||||||
|
import net.psforever.objects.serverobject.hackable.Hackable
|
||||||
import net.psforever.objects.zones.exp.ToDatabase
|
import net.psforever.objects.zones.exp.ToDatabase
|
||||||
|
import net.psforever.packet.game.ChatMsg
|
||||||
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
@ -31,6 +35,20 @@ final case class MajorFacilityHackParticipation(building: Building) extends Faci
|
||||||
updateHotSpotInfoOverTime()
|
updateHotSpotInfoOverTime()
|
||||||
updateTime(now)
|
updateTime(now)
|
||||||
}
|
}
|
||||||
|
building.CaptureTerminal
|
||||||
|
.map(_.HackedBy)
|
||||||
|
.collect {
|
||||||
|
case Some(info@Hackable.HackInfo(_, _, start, length, _))
|
||||||
|
if building.NtuLevel == 0 && {
|
||||||
|
val approximateHackTimeRemaining = math.max(0, start + length - System.currentTimeMillis())
|
||||||
|
approximateHackTimeRemaining <= 300.seconds.toMillis && approximateHackTimeRemaining > 295.seconds.toMillis
|
||||||
|
} =>
|
||||||
|
MajorFacilityHackParticipation.warningMessageForHackOccupiers(
|
||||||
|
building,
|
||||||
|
info,
|
||||||
|
ChatMsg(ChatMessageType.UNK_227, "@FacilityRequiresResourcesForHackCriticalWarning")
|
||||||
|
)
|
||||||
|
}
|
||||||
lastInfoRequest = now
|
lastInfoRequest = now
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -287,8 +305,8 @@ final case class MajorFacilityHackParticipation(building: Building) extends Faci
|
||||||
if (isResecured) {
|
if (isResecured) {
|
||||||
hackerScore
|
hackerScore
|
||||||
} else {
|
} else {
|
||||||
val flagCarrierScore = flagCarrier.map (p => List((p.CharId, 0L, "llu"))).getOrElse(Nil)
|
val flagCarrierScore = flagCarrier.map(p => List((p.CharId, 0L, "llu"))).getOrElse(Nil)
|
||||||
if (playersInSoi.exists(_.CharId == hackerId) && !flagCarrierScore.exists { case (charId, _,_) => charId == hackerId }) {
|
if (playersInSoi.exists(_.CharId == hackerId) && !flagCarrierScore.exists { case (charId, _, _) => charId == hackerId }) {
|
||||||
hackerScore ++ flagCarrierScore
|
hackerScore ++ flagCarrierScore
|
||||||
} else {
|
} else {
|
||||||
flagCarrierScore
|
flagCarrierScore
|
||||||
|
|
@ -326,3 +344,61 @@ final case class MajorFacilityHackParticipation(building: Building) extends Faci
|
||||||
.getOrElse(list)
|
.getOrElse(list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object MajorFacilityHackParticipation {
|
||||||
|
/**
|
||||||
|
* Dispatch a message to clients affected by some change.
|
||||||
|
* Establish the hack information by referencing the capture terminal.
|
||||||
|
* @param building building entity
|
||||||
|
* @param msg message to send to affected clients
|
||||||
|
*/
|
||||||
|
def warningMessageForHackOccupiers(
|
||||||
|
building: Building,
|
||||||
|
msg: ChatMsg
|
||||||
|
): Unit = {
|
||||||
|
building
|
||||||
|
.CaptureTerminal
|
||||||
|
.flatMap(_.HackedBy)
|
||||||
|
.foreach { hackedInfo =>
|
||||||
|
warningMessageForHackOccupiers(building, hackedInfo, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch a message to clients affected by some change.
|
||||||
|
* Select individuals belonging to the hacking faction to be targets for the message.
|
||||||
|
* @param building building entity
|
||||||
|
* @param hackedInfo confirmed information about the hack state
|
||||||
|
* @param msg message to send to affected clients
|
||||||
|
*/
|
||||||
|
def warningMessageForHackOccupiers(
|
||||||
|
building: Building,
|
||||||
|
hackedInfo: Hackable.HackInfo,
|
||||||
|
msg: ChatMsg
|
||||||
|
): Unit = {
|
||||||
|
val hackerFaction = hackedInfo.hackerFaction
|
||||||
|
warningMessageForHackOccupiers(
|
||||||
|
building,
|
||||||
|
building.PlayersInSOI.filter(_.Faction == hackerFaction),
|
||||||
|
msg
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch a message to clients affected by some change.
|
||||||
|
* @param building building entity
|
||||||
|
* @param targets affected clients by player
|
||||||
|
* @param msg message to send to affected clients
|
||||||
|
*/
|
||||||
|
private def warningMessageForHackOccupiers(
|
||||||
|
building: Building,
|
||||||
|
targets: Iterable[Player],
|
||||||
|
msg: ChatMsg
|
||||||
|
): Unit = {
|
||||||
|
val events = building.Zone.LocalEvents
|
||||||
|
val message = LocalAction.SendResponse(msg)
|
||||||
|
targets.foreach { player =>
|
||||||
|
events ! LocalServiceMessage(player.Name, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) 2021 PSForever
|
// Copyright (c) 2021 PSForever
|
||||||
package net.psforever.objects.vehicles.control
|
package net.psforever.objects.vehicles.control
|
||||||
|
|
||||||
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.objects.serverobject.deploy.Deployment.DeploymentObject
|
import net.psforever.objects.serverobject.deploy.Deployment.DeploymentObject
|
||||||
import net.psforever.objects.serverobject.deploy.{Deployment, DeploymentBehavior}
|
import net.psforever.objects.serverobject.deploy.{Deployment, DeploymentBehavior}
|
||||||
|
|
@ -58,7 +59,7 @@ class DeployingVehicleControl(vehicle: Vehicle)
|
||||||
* Even when disabled, the vehicle can be made to undeploy.
|
* Even when disabled, the vehicle can be made to undeploy.
|
||||||
*/
|
*/
|
||||||
override def PrepareForDisabled(kickPassengers: Boolean) : Unit = {
|
override def PrepareForDisabled(kickPassengers: Boolean) : Unit = {
|
||||||
TryUndeployStateChange(DriveState.Undeploying)
|
TryUndeployStateChange(DriveState.Undeploying, self)
|
||||||
super.PrepareForDisabled(kickPassengers)
|
super.PrepareForDisabled(kickPassengers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,9 +78,10 @@ class DeployingVehicleControl(vehicle: Vehicle)
|
||||||
override def DeploymentAction(
|
override def DeploymentAction(
|
||||||
obj: DeploymentObject,
|
obj: DeploymentObject,
|
||||||
state: DriveState.Value,
|
state: DriveState.Value,
|
||||||
prevState: DriveState.Value
|
prevState: DriveState.Value,
|
||||||
|
replyTo: ActorRef
|
||||||
): DriveState.Value = {
|
): DriveState.Value = {
|
||||||
val out = super.DeploymentAction(obj, state, prevState)
|
val out = super.DeploymentAction(obj, state, prevState, replyTo)
|
||||||
Vehicles.ReloadAccessPermissions(vehicle, vehicle.Faction.toString)
|
Vehicles.ReloadAccessPermissions(vehicle, vehicle.Faction.toString)
|
||||||
specificResponseToDeployment(state)
|
specificResponseToDeployment(state)
|
||||||
out
|
out
|
||||||
|
|
@ -90,9 +92,10 @@ class DeployingVehicleControl(vehicle: Vehicle)
|
||||||
override def UndeploymentAction(
|
override def UndeploymentAction(
|
||||||
obj: DeploymentObject,
|
obj: DeploymentObject,
|
||||||
state: DriveState.Value,
|
state: DriveState.Value,
|
||||||
prevState: DriveState.Value
|
prevState: DriveState.Value,
|
||||||
|
replyTo: ActorRef
|
||||||
): DriveState.Value = {
|
): DriveState.Value = {
|
||||||
val out = if (decaying) state else super.UndeploymentAction(obj, state, prevState)
|
val out = if (decaying) state else super.UndeploymentAction(obj, state, prevState, replyTo)
|
||||||
Vehicles.ReloadAccessPermissions(vehicle, vehicle.Faction.toString)
|
Vehicles.ReloadAccessPermissions(vehicle, vehicle.Faction.toString)
|
||||||
specificResponseToUndeployment(state)
|
specificResponseToUndeployment(state)
|
||||||
out
|
out
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,8 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
case Vehicle.Ownership(Some(player)) =>
|
case Vehicle.Ownership(Some(player)) =>
|
||||||
GainOwnership(player)
|
GainOwnership(player)
|
||||||
|
|
||||||
case Mountable.TryMount(user, mountPoint) if vehicle.DeploymentState == DriveState.AutoPilot =>
|
case Mountable.TryMount(user, mountPoint)
|
||||||
|
if vehicle.DeploymentState == DriveState.AutoPilot =>
|
||||||
sender() ! Mountable.MountMessages(user, Mountable.CanNotMount(vehicle, mountPoint))
|
sender() ! Mountable.MountMessages(user, Mountable.CanNotMount(vehicle, mountPoint))
|
||||||
|
|
||||||
case msg @ Mountable.TryMount(player, mount_point) =>
|
case msg @ Mountable.TryMount(player, mount_point) =>
|
||||||
|
|
@ -125,19 +126,23 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
mountCleanup(mount_point, player)
|
mountCleanup(mount_point, player)
|
||||||
|
|
||||||
// Issue 1133. Todo: There may be a better way to address the issue?
|
// Issue 1133. Todo: There may be a better way to address the issue?
|
||||||
case Mountable.TryDismount(user, seat_num, _) if GlobalDefinitions.isFlightVehicle(vehicle.Definition) &&
|
case Mountable.TryDismount(user, seat_num, bailType) if GlobalDefinitions.isFlightVehicle(vehicle.Definition) &&
|
||||||
(vehicle.History.find { entry => entry.isInstanceOf[SpawningActivity] } match {
|
(vehicle.History.find { entry => entry.isInstanceOf[SpawningActivity] } match {
|
||||||
case Some(entry) if System.currentTimeMillis() - entry.time < 3000L => true
|
case Some(entry) if System.currentTimeMillis() - entry.time < 3000L => true
|
||||||
case _ => false
|
case _ => false
|
||||||
}) =>
|
}) =>
|
||||||
sender() ! Mountable.MountMessages(user, Mountable.CanNotDismount(vehicle, seat_num))
|
sender() ! Mountable.MountMessages(user, Mountable.CanNotDismount(vehicle, seat_num, bailType))
|
||||||
|
|
||||||
case Mountable.TryDismount(user, seat_num, _) if !GlobalDefinitions.isFlightVehicle(vehicle.Definition) &&
|
case Mountable.TryDismount(user, seat_num, bailType) if !GlobalDefinitions.isFlightVehicle(vehicle.Definition) &&
|
||||||
(vehicle.History.find { entry => entry.isInstanceOf[SpawningActivity] } match {
|
(vehicle.History.find { entry => entry.isInstanceOf[SpawningActivity] } match {
|
||||||
case Some(entry) if System.currentTimeMillis() - entry.time < 8500L => true
|
case Some(entry) if System.currentTimeMillis() - entry.time < 8500L => true
|
||||||
case _ => false
|
case _ => false
|
||||||
}) =>
|
}) =>
|
||||||
sender() ! Mountable.MountMessages(user, Mountable.CanNotDismount(vehicle, seat_num))
|
sender() ! Mountable.MountMessages(user, Mountable.CanNotDismount(vehicle, seat_num, bailType))
|
||||||
|
|
||||||
|
case Mountable.TryDismount(user, seat_num, bailType)
|
||||||
|
if vehicle.DeploymentState == DriveState.AutoPilot =>
|
||||||
|
sender() ! Mountable.MountMessages(user, Mountable.CanNotDismount(vehicle, seat_num, bailType))
|
||||||
|
|
||||||
case msg @ Mountable.TryDismount(player, seat_num, _) =>
|
case msg @ Mountable.TryDismount(player, seat_num, _) =>
|
||||||
dismountBehavior.apply(msg)
|
dismountBehavior.apply(msg)
|
||||||
|
|
@ -601,9 +606,9 @@ class VehicleControl(vehicle: Vehicle)
|
||||||
c
|
c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
watery.doInteractingWithTargets(player, percentage, watery.Condition.map(_.body).get, List(player))
|
WithWater.doInteractingWithTargets(player, percentage, watery.Condition.map(_.body).get, List(player))
|
||||||
case watery: WithWater if watery.Condition.map(_.state).contains(OxygenState.Recovery) =>
|
case watery: WithWater if watery.Condition.map(_.state).contains(OxygenState.Recovery) =>
|
||||||
watery.stopInteractingWithTargets(
|
WithWater.stopInteractingWithTargets(
|
||||||
player,
|
player,
|
||||||
Watery.recoveringFromWater(vehicle, watery)._3,
|
Watery.recoveringFromWater(vehicle, watery)._3,
|
||||||
watery.Condition.map(_.body).get,
|
watery.Condition.map(_.body).get,
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,71 @@
|
||||||
// Copyright (c) 2024 PSForever
|
// Copyright (c) 2024 PSForever
|
||||||
package net.psforever.objects.vehicles.interaction
|
package net.psforever.objects.vehicles.interaction
|
||||||
|
|
||||||
import net.psforever.objects.{GlobalDefinitions, Vehicle}
|
import net.psforever.objects.{GlobalDefinitions, PlanetSideGameObject, Vehicle}
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.environment.interaction.{InteractionWith, RespondsToZoneEnvironment}
|
import net.psforever.objects.serverobject.environment.interaction.{InteractionWith, RespondsToZoneEnvironment}
|
||||||
import net.psforever.objects.serverobject.environment.interaction.common.Watery
|
import net.psforever.objects.serverobject.environment.interaction.common.Watery
|
||||||
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
||||||
import net.psforever.objects.serverobject.environment.{PieceOfEnvironment, interaction}
|
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment, interaction}
|
||||||
import net.psforever.objects.vehicles.control.VehicleControl
|
import net.psforever.objects.vehicles.control.VehicleControl
|
||||||
import net.psforever.objects.zones.InteractsWithZone
|
import net.psforever.objects.zones.InteractsWithZone
|
||||||
import net.psforever.types.OxygenState
|
import net.psforever.types.OxygenState
|
||||||
|
|
||||||
|
import scala.annotation.unused
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
class WithWater()
|
class WithWater()
|
||||||
extends InteractionWith
|
extends InteractionWith
|
||||||
with Watery {
|
with Watery {
|
||||||
|
/** do this every time we're in sufficient contact with water */
|
||||||
|
private var doInteractingWithBehavior: (InteractsWithZone, PieceOfEnvironment, Option[Any]) => Unit = wadingBeforeDrowning
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Water causes vehicles to become disabled if they dive off too far, too deep.
|
* Water is wet.
|
||||||
* Flying vehicles do not display progress towards being waterlogged.
|
* @param obj the target
|
||||||
* They just disable outright.
|
* @param body the environment
|
||||||
* @param obj the target
|
*/
|
||||||
* @param body the environment
|
|
||||||
* @param data additional interaction information, if applicable
|
|
||||||
*/
|
|
||||||
def doInteractingWith(
|
def doInteractingWith(
|
||||||
obj: InteractsWithZone,
|
obj: InteractsWithZone,
|
||||||
body: PieceOfEnvironment,
|
body: PieceOfEnvironment,
|
||||||
data: Option[Any]
|
data: Option[Any]
|
||||||
): Unit = {
|
): Unit = {
|
||||||
|
depth = math.max(0f, body.collision.altitude - obj.Position.z)
|
||||||
|
doInteractingWithBehavior(obj, body, data)
|
||||||
|
obj.Actor ! RespondsToZoneEnvironment.Timer(attribute, delay = 500 milliseconds, obj.Actor, interaction.InteractingWithEnvironment(body, Some("wading")))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wading only happens while the vehicle's wheels are mostly above the water.
|
||||||
|
* @param obj the target
|
||||||
|
* @param body the environment
|
||||||
|
*/
|
||||||
|
private def wadingBeforeDrowning(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
body: PieceOfEnvironment,
|
||||||
|
data: Option[Any]
|
||||||
|
): Unit = {
|
||||||
|
//we're already "wading", let's see if we're drowning
|
||||||
|
if (depth >= GlobalDefinitions.MaxDepth(obj)) {
|
||||||
|
//drowning
|
||||||
|
beginDrowning(obj, body, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Too much water causes players to slowly suffocate.
|
||||||
|
* When they (finally) drown, they will die.
|
||||||
|
* @param obj the target
|
||||||
|
* @param body the environment
|
||||||
|
*/
|
||||||
|
private def beginDrowning(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
body: PieceOfEnvironment,
|
||||||
|
@unused data: Option[Any]
|
||||||
|
): Unit = {
|
||||||
obj match {
|
obj match {
|
||||||
case vehicle: Vehicle =>
|
case vehicle: Vehicle =>
|
||||||
val (effect: Boolean, time: Long, percentage: Float) = {
|
val (effect, time, percentage): (Boolean, Long, Float) = {
|
||||||
val (a, b, c) = Watery.drowningInWateryConditions(obj, condition.map(_.state), waterInteractionTime)
|
val (a, b, c) = Watery.drowningInWateryConditions(obj, condition.map(_.state), waterInteractionTime)
|
||||||
if (a && GlobalDefinitions.isFlightVehicle(vehicle.Definition)) {
|
if (a && GlobalDefinitions.isFlightVehicle(vehicle.Definition)) {
|
||||||
(true, 0L, 0f) //no progress bar
|
(true, 0L, 0f) //no progress bar
|
||||||
|
|
@ -42,8 +76,94 @@ class WithWater()
|
||||||
if (effect) {
|
if (effect) {
|
||||||
condition = Some(OxygenStateTarget(obj.GUID, body, OxygenState.Suffocation, percentage))
|
condition = Some(OxygenStateTarget(obj.GUID, body, OxygenState.Suffocation, percentage))
|
||||||
waterInteractionTime = System.currentTimeMillis() + time
|
waterInteractionTime = System.currentTimeMillis() + time
|
||||||
obj.Actor ! RespondsToZoneEnvironment.Timer(attribute, delay = time milliseconds, obj.Actor, VehicleControl.Disable(true))
|
obj.Actor ! RespondsToZoneEnvironment.StopTimer(WithWater.WaterAction)
|
||||||
doInteractingWithTargets(
|
obj.Actor ! RespondsToZoneEnvironment.Timer(WithWater.WaterAction, delay = time milliseconds, obj.Actor, VehicleControl.Disable(true))
|
||||||
|
WithWater.doInteractingWithTargets(
|
||||||
|
obj,
|
||||||
|
percentage,
|
||||||
|
body,
|
||||||
|
vehicle.Seats.values.flatMap(_.occupants).filter(p => p.isAlive && (p.Zone eq obj.Zone))
|
||||||
|
)
|
||||||
|
doInteractingWithBehavior = drowning
|
||||||
|
}
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Too much water causes vehicles to slowly disable.
|
||||||
|
* When fully waterlogged, the vehicle is completely immobile.
|
||||||
|
* @param obj the target
|
||||||
|
* @param body the environment
|
||||||
|
*/
|
||||||
|
private def drowning(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
body: PieceOfEnvironment,
|
||||||
|
data: Option[Any]
|
||||||
|
): Unit = {
|
||||||
|
//test if player ever gets head above the water level
|
||||||
|
if (depth < GlobalDefinitions.MaxDepth(obj)) {
|
||||||
|
val (effect, time, percentage) = Watery.recoveringFromWateryConditions(obj, condition.map(_.state), waterInteractionTime)
|
||||||
|
//switch to recovery
|
||||||
|
if (percentage > 0) {
|
||||||
|
recoverFromDrowning(obj, body, data, effect, time, percentage)
|
||||||
|
doInteractingWithBehavior = recovering
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When out of water, the vehicle is no longer being waterlogged.
|
||||||
|
* It does have to endure a recovery period to get back to normal, though.
|
||||||
|
* @param obj the target
|
||||||
|
* @param body the environment
|
||||||
|
*/
|
||||||
|
private def recoverFromDrowning(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
body: PieceOfEnvironment,
|
||||||
|
data: Option[Any]
|
||||||
|
): Unit = {
|
||||||
|
val state = condition.map(_.state)
|
||||||
|
if (state.contains(OxygenState.Suffocation)) {
|
||||||
|
//set up for recovery
|
||||||
|
val (effect, time, percentage) = Watery.recoveringFromWateryConditions(obj, state, waterInteractionTime)
|
||||||
|
if (percentage < 99f) {
|
||||||
|
//we're not too far gone
|
||||||
|
recoverFromDrowning(obj, body, data, effect, time, percentage)
|
||||||
|
}
|
||||||
|
doInteractingWithBehavior = recovering
|
||||||
|
} else {
|
||||||
|
doInteractingWithBehavior = wadingBeforeDrowning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When out of water, the vehicle is no longer being waterlogged.
|
||||||
|
* It does have to endure a recovery period to get back to normal, though.
|
||||||
|
* @param obj the target
|
||||||
|
* @param body the environment
|
||||||
|
* @param effect na
|
||||||
|
* @param time current time until completion of the next effect
|
||||||
|
* @param percentage value to display in the drowning UI progress bar
|
||||||
|
*/
|
||||||
|
private def recoverFromDrowning(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
body: PieceOfEnvironment,
|
||||||
|
@unused data: Option[Any],
|
||||||
|
effect: Boolean,
|
||||||
|
time: Long,
|
||||||
|
percentage: Float
|
||||||
|
): Unit = {
|
||||||
|
obj match {
|
||||||
|
case vehicle: Vehicle =>
|
||||||
|
val cond = OxygenStateTarget(obj.GUID, body, OxygenState.Recovery, percentage)
|
||||||
|
if (effect) {
|
||||||
|
condition = Some(cond)
|
||||||
|
waterInteractionTime = System.currentTimeMillis() + time
|
||||||
|
obj.Actor ! RespondsToZoneEnvironment.StopTimer(WithWater.WaterAction)
|
||||||
|
obj.Actor ! RespondsToZoneEnvironment.Timer(WithWater.WaterAction, delay = time milliseconds, obj.Actor, interaction.RecoveredFromEnvironmentInteraction(attribute))
|
||||||
|
//inform the players
|
||||||
|
WithWater.stopInteractingWithTargets(
|
||||||
obj,
|
obj,
|
||||||
percentage,
|
percentage,
|
||||||
body,
|
body,
|
||||||
|
|
@ -55,34 +175,52 @@ class WithWater()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When out of water, the vehicle no longer risks becoming disabled.
|
* The recovery period is much faster than the waterlogging process.
|
||||||
* It does have to endure a recovery period to get back to full dehydration
|
* Check for when the vehicle fully recovers,
|
||||||
* Flying vehicles are exempt from this process due to the abrupt disability they experience.
|
* and that the vehicle does not regress back to waterlogging.
|
||||||
* @param obj the target
|
* @param obj the target
|
||||||
* @param body the environment
|
* @param body the environment
|
||||||
* @param data additional interaction information, if applicable
|
*/
|
||||||
*/
|
def recovering(
|
||||||
|
obj: InteractsWithZone,
|
||||||
|
body: PieceOfEnvironment,
|
||||||
|
data: Option[Any]
|
||||||
|
): Unit = {
|
||||||
|
lazy val state = condition.map(_.state)
|
||||||
|
if (depth >= GlobalDefinitions.MaxDepth(obj)) {
|
||||||
|
//go back to drowning
|
||||||
|
beginDrowning(obj, body, data)
|
||||||
|
} else if (state.contains(OxygenState.Recovery)) {
|
||||||
|
//check recovery conditions
|
||||||
|
val (_, _, percentage) = Watery.recoveringFromWateryConditions(obj, state, waterInteractionTime)
|
||||||
|
if (percentage < 1f) {
|
||||||
|
doInteractingWithBehavior = wadingBeforeDrowning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}/**
|
||||||
|
* When out of water, the vehicle no longer risks becoming disabled.
|
||||||
|
* It does have to endure a recovery period to get back to full dehydration
|
||||||
|
* Flying vehicles are exempt from this process due to the abrupt disability they experience.
|
||||||
|
* @param obj the target
|
||||||
|
* @param body the environment
|
||||||
|
*/
|
||||||
override def stopInteractingWith(
|
override def stopInteractingWith(
|
||||||
obj: InteractsWithZone,
|
obj: InteractsWithZone,
|
||||||
body: PieceOfEnvironment,
|
body: PieceOfEnvironment,
|
||||||
data: Option[Any]
|
data: Option[Any]
|
||||||
): Unit = {
|
): Unit = {
|
||||||
obj match {
|
val cond = condition.map(_.state)
|
||||||
case vehicle: Vehicle =>
|
if (cond.contains(OxygenState.Suffocation)) {
|
||||||
val (effect: Boolean, time: Long, percentage: Float) =
|
//go from suffocating to recovery
|
||||||
Watery.recoveringFromWateryConditions(obj, condition.map(_.state), waterInteractionTime)
|
recoverFromDrowning(obj, body, data)
|
||||||
if (effect) {
|
} else if (cond.isEmpty) {
|
||||||
condition = Some(OxygenStateTarget(obj.GUID, body, OxygenState.Recovery, percentage))
|
//neither suffocating nor recovering, so just reset everything
|
||||||
waterInteractionTime = System.currentTimeMillis() + time
|
recoverFromInteracting(obj)
|
||||||
obj.Actor ! RespondsToZoneEnvironment.Timer(attribute, delay = time milliseconds, obj.Actor, interaction.RecoveredFromEnvironmentInteraction(attribute))
|
obj.Actor ! RespondsToZoneEnvironment.StopTimer(attribute)
|
||||||
stopInteractingWithTargets(
|
waterInteractionTime = 0L
|
||||||
obj,
|
depth = 0f
|
||||||
percentage,
|
condition = None
|
||||||
body,
|
doInteractingWithBehavior = wadingBeforeDrowning
|
||||||
vehicle.Seats.values.flatMap(_.occupants).filter(p => p.isAlive && (p.Zone eq obj.Zone))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
case _ => ()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,46 +229,53 @@ class WithWater()
|
||||||
if (condition.exists(_.state == OxygenState.Suffocation)) {
|
if (condition.exists(_.state == OxygenState.Suffocation)) {
|
||||||
stopInteractingWith(obj, condition.map(_.body).get, None)
|
stopInteractingWith(obj, condition.map(_.body).get, None)
|
||||||
}
|
}
|
||||||
waterInteractionTime = 0L
|
|
||||||
condition = None
|
condition = None
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object WithWater {
|
||||||
|
/** special environmental trait to queue actions independent from the primary wading test */
|
||||||
|
case object WaterAction extends EnvironmentTrait {
|
||||||
|
override def canInteractWith(obj: PlanetSideGameObject): Boolean = false
|
||||||
|
override def testingDepth(obj: PlanetSideGameObject): Float = Float.PositiveInfinity
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell the given targets that water causes vehicles to become disabled if they dive off too far, too deep.
|
* Tell the given targets that water causes vehicles to become disabled if they dive off too far, too deep.
|
||||||
* @see `InteractingWithEnvironment`
|
* @see `InteractingWithEnvironment`
|
||||||
* @see `OxygenState`
|
* @see `OxygenState`
|
||||||
* @see `OxygenStateTarget`
|
* @see `OxygenStateTarget`
|
||||||
* @param obj the target
|
* @param obj the target
|
||||||
* @param percentage the progress bar completion state
|
* @param percentage the progress bar completion state
|
||||||
* @param body the environment
|
* @param body the environment
|
||||||
* @param targets recipients of the information
|
* @param targets recipients of the information
|
||||||
*/
|
*/
|
||||||
def doInteractingWithTargets(
|
def doInteractingWithTargets(
|
||||||
obj: PlanetSideServerObject,
|
obj: PlanetSideServerObject,
|
||||||
percentage: Float,
|
percentage: Float,
|
||||||
body: PieceOfEnvironment,
|
body: PieceOfEnvironment,
|
||||||
targets: Iterable[PlanetSideServerObject]
|
targets: Iterable[PlanetSideServerObject]
|
||||||
): Unit = {
|
): Unit = {
|
||||||
val state = Some(OxygenStateTarget(obj.GUID, body, OxygenState.Suffocation, percentage))
|
val state = Some(OxygenStateTarget(obj.GUID, body, OxygenState.Suffocation, percentage))
|
||||||
targets.foreach(_.Actor ! interaction.InteractingWithEnvironment(body, state))
|
targets.foreach(_.Actor ! interaction.InteractingWithEnvironment(body, state))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell the given targets that, when out of water, the vehicle no longer risks becoming disabled.
|
* Tell the given targets that, when out of water, the vehicle no longer risks becoming disabled.
|
||||||
* @see `EscapeFromEnvironment`
|
* @see `EscapeFromEnvironment`
|
||||||
* @see `OxygenState`
|
* @see `OxygenState`
|
||||||
* @see `OxygenStateTarget`
|
* @see `OxygenStateTarget`
|
||||||
* @param obj the target
|
* @param obj the target
|
||||||
* @param percentage the progress bar completion state
|
* @param percentage the progress bar completion state
|
||||||
* @param body the environment
|
* @param body the environment
|
||||||
* @param targets recipients of the information
|
* @param targets recipients of the information
|
||||||
*/
|
*/
|
||||||
def stopInteractingWithTargets(
|
def stopInteractingWithTargets(
|
||||||
obj: PlanetSideServerObject,
|
obj: PlanetSideServerObject,
|
||||||
percentage: Float,
|
percentage: Float,
|
||||||
body: PieceOfEnvironment,
|
body: PieceOfEnvironment,
|
||||||
targets: Iterable[PlanetSideServerObject]
|
targets: Iterable[PlanetSideServerObject]
|
||||||
): Unit = {
|
): Unit = {
|
||||||
val state = Some(OxygenStateTarget(obj.GUID, body, OxygenState.Recovery, percentage))
|
val state = Some(OxygenStateTarget(obj.GUID, body, OxygenState.Recovery, percentage))
|
||||||
targets.foreach(_.Actor ! interaction.EscapeFromEnvironment(body, state))
|
targets.foreach(_.Actor ! interaction.EscapeFromEnvironment(body, state))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -288,7 +288,7 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
|
||||||
* @return synchronized reference to the globally unique identifier system
|
* @return synchronized reference to the globally unique identifier system
|
||||||
*/
|
*/
|
||||||
def GUID(hub: NumberPoolHub): Boolean = {
|
def GUID(hub: NumberPoolHub): Boolean = {
|
||||||
if (actor == Default.typed.Actor && guid.Pools.values.foldLeft(0)(_ + _.Count) == 0) {
|
if (!zoneInitialized.isCompleted && guid.Pools.values.foldLeft(0)(_ + _.Count) == 0) {
|
||||||
import org.fusesource.jansi.Ansi.Color.RED
|
import org.fusesource.jansi.Ansi.Color.RED
|
||||||
import org.fusesource.jansi.Ansi.ansi
|
import org.fusesource.jansi.Ansi.ansi
|
||||||
println(
|
println(
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ import net.psforever.objects.serverobject.deploy.Interference
|
||||||
import net.psforever.objects.sourcing.ObjectSource
|
import net.psforever.objects.sourcing.ObjectSource
|
||||||
import net.psforever.objects.vehicles.MountedWeapons
|
import net.psforever.objects.vehicles.MountedWeapons
|
||||||
import net.psforever.objects.vital.SpawningActivity
|
import net.psforever.objects.vital.SpawningActivity
|
||||||
|
import net.psforever.packet.game.ChatMsg
|
||||||
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
import net.psforever.types.ChatMessageType
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
@ -103,7 +106,13 @@ object ZoneDeployableActor {
|
||||||
): Boolean = {
|
): Boolean = {
|
||||||
val position = obj.Position
|
val position = obj.Position
|
||||||
deployableList.find(_ eq obj) match {
|
deployableList.find(_ eq obj) match {
|
||||||
case None if Interference.Test(zone, obj).isEmpty =>
|
case _ if Interference.Test(zone, obj).nonEmpty =>
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
obj.OwnerName.getOrElse(""),
|
||||||
|
LocalAction.SendResponse(ChatMsg(ChatMessageType.UNK_227, "@nomove_intersecting"))
|
||||||
|
) //may not be the correct message but is sufficient at explaining why the deployable can not be built
|
||||||
|
false
|
||||||
|
case None =>
|
||||||
deployableList += obj
|
deployableList += obj
|
||||||
zone.actor ! ZoneActor.AddToBlockMap(obj, position)
|
zone.actor ! ZoneActor.AddToBlockMap(obj, position)
|
||||||
true
|
true
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,14 @@ package net.psforever.objects.zones
|
||||||
|
|
||||||
import akka.actor.Actor
|
import akka.actor.Actor
|
||||||
import net.psforever.actors.zone.ZoneActor
|
import net.psforever.actors.zone.ZoneActor
|
||||||
import net.psforever.objects.definition.VehicleDefinition
|
import net.psforever.objects.definition.{ObjectDefinition, VehicleDefinition}
|
||||||
import net.psforever.objects.serverobject.deploy.{Deployment, Interference}
|
import net.psforever.objects.serverobject.deploy.{Deployment, Interference}
|
||||||
import net.psforever.objects.vital.InGameHistory
|
import net.psforever.objects.vital.InGameHistory
|
||||||
import net.psforever.objects.{Default, Vehicle}
|
import net.psforever.objects.{Default, Vehicle}
|
||||||
import net.psforever.types.{DriveState, PlanetSideEmpire, Vector3}
|
import net.psforever.packet.game.ChatMsg
|
||||||
|
import net.psforever.services.Service
|
||||||
|
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
import net.psforever.types.{ChatMessageType, DriveState, PlanetSideEmpire, Vector3}
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
@ -66,15 +69,18 @@ class ZoneVehicleActor(
|
||||||
sender() ! Zone.Vehicle.CanNotDespawn(zone, vehicle, "can not find")
|
sender() ! Zone.Vehicle.CanNotDespawn(zone, vehicle, "can not find")
|
||||||
}
|
}
|
||||||
|
|
||||||
case Zone.Vehicle.TryDeploymentChange(vehicle, toDeployState)
|
case Zone.Vehicle.TryDeploymentChange(vehicle, DriveState.Deploying) =>
|
||||||
if toDeployState == DriveState.Deploying &&
|
if (ZoneVehicleActor.ReportOnInterferenceResults(
|
||||||
(ZoneVehicleActor.temporaryInterferenceTest(vehicle, temporaryInterference) || Interference.Test(zone, vehicle).nonEmpty) =>
|
zone,
|
||||||
sender() ! Zone.Vehicle.CanNotDeploy(zone, vehicle, toDeployState, "blocked by a nearby entity")
|
vehicle,
|
||||||
|
ZoneVehicleActor.temporaryInterferenceTest(vehicle, temporaryInterference) ++
|
||||||
case Zone.Vehicle.TryDeploymentChange(vehicle, toDeployState)
|
Interference.Test(zone, vehicle).map(_.Definition)
|
||||||
if toDeployState == DriveState.Deploying =>
|
)) {
|
||||||
tryAddToInterferenceField(vehicle.Position, vehicle.Faction, vehicle.Definition)
|
sender() ! Zone.Vehicle.CanNotDeploy(zone, vehicle, DriveState.Deploying, "blocked by a nearby entity")
|
||||||
vehicle.Actor.tell(Deployment.TryDeploymentChange(toDeployState), sender())
|
} else {
|
||||||
|
tryAddToInterferenceField(vehicle.Position, vehicle.Faction, vehicle.Definition)
|
||||||
|
vehicle.Actor.tell(Deployment.TryDeploymentChange(DriveState.Deploying), sender())
|
||||||
|
}
|
||||||
|
|
||||||
case Zone.Vehicle.TryDeploymentChange(vehicle, toDeployState) =>
|
case Zone.Vehicle.TryDeploymentChange(vehicle, toDeployState) =>
|
||||||
vehicle.Actor.tell(Deployment.TryDeploymentChange(toDeployState), sender())
|
vehicle.Actor.tell(Deployment.TryDeploymentChange(toDeployState), sender())
|
||||||
|
|
@ -83,7 +89,19 @@ class ZoneVehicleActor(
|
||||||
|
|
||||||
case Zone.Vehicle.CanNotDespawn(_, _, _) => ()
|
case Zone.Vehicle.CanNotDespawn(_, _, _) => ()
|
||||||
|
|
||||||
case Zone.Vehicle.CanNotDeploy(_, vehicle, _, reason) => ()
|
case Zone.Vehicle.CanNotDeploy(_, vehicle, DriveState.Deploying, reason) =>
|
||||||
|
ZoneVehicleActor.ReportOnInterferenceResults(
|
||||||
|
zone,
|
||||||
|
vehicle,
|
||||||
|
ZoneVehicleActor.temporaryInterferenceTest(vehicle, temporaryInterference) ++
|
||||||
|
Interference.Test(zone, vehicle).map(_.Definition)
|
||||||
|
)
|
||||||
|
val pos = vehicle.Position
|
||||||
|
val driverMoniker = vehicle.Seats.headOption.flatMap(_._2.occupant).map(_.Name).getOrElse("Driver")
|
||||||
|
log.warn(s"$driverMoniker's ${vehicle.Definition.Name} can not deploy in ${zone.id} because $reason")
|
||||||
|
temporaryInterference = temporaryInterference.filterNot(_._1 == pos)
|
||||||
|
|
||||||
|
case Zone.Vehicle.CanNotDeploy(_, vehicle, _, reason) =>
|
||||||
val pos = vehicle.Position
|
val pos = vehicle.Position
|
||||||
val driverMoniker = vehicle.Seats.headOption.flatMap(_._2.occupant).map(_.Name).getOrElse("Driver")
|
val driverMoniker = vehicle.Seats.headOption.flatMap(_._2.occupant).map(_.Name).getOrElse("Driver")
|
||||||
log.warn(s"$driverMoniker's ${vehicle.Definition.Name} can not deploy in ${zone.id} because $reason")
|
log.warn(s"$driverMoniker's ${vehicle.Definition.Name} can not deploy in ${zone.id} because $reason")
|
||||||
|
|
@ -133,22 +151,54 @@ object ZoneVehicleActor {
|
||||||
private def temporaryInterferenceTest(
|
private def temporaryInterferenceTest(
|
||||||
vehicle: Vehicle,
|
vehicle: Vehicle,
|
||||||
existingInterferences: Seq[(Vector3, PlanetSideEmpire.Value, VehicleDefinition)]
|
existingInterferences: Seq[(Vector3, PlanetSideEmpire.Value, VehicleDefinition)]
|
||||||
): Boolean = {
|
): Seq[VehicleDefinition] = {
|
||||||
val vPosition = vehicle.Position
|
val vPosition = vehicle.Position
|
||||||
val vFaction = vehicle.Faction
|
val vFaction = vehicle.Faction
|
||||||
val vDefinition = vehicle.Definition
|
val vDefinition = vehicle.Definition
|
||||||
if (vDefinition.interference eq Interference.AllowAll) {
|
if (vDefinition.interference eq Interference.AllowAll) {
|
||||||
false
|
Nil
|
||||||
} else {
|
} else {
|
||||||
existingInterferences
|
existingInterferences
|
||||||
.collect { case (p, faction, d) if faction == vFaction => (p, d) }
|
.collect { case (p, faction, d) if faction == vFaction => (p, d) }
|
||||||
.exists { case (position, definition) =>
|
.filter { case (position, definition) =>
|
||||||
val interference = definition.interference
|
val interference = definition.interference
|
||||||
(interference ne Interference.AllowAll) && {
|
(interference ne Interference.AllowAll) && {
|
||||||
lazy val distanceSq = Vector3.DistanceSquared(position, vPosition)
|
lazy val distanceSq = Vector3.DistanceSquared(position, vPosition)
|
||||||
definition == vDefinition && distanceSq < interference.main * interference.main
|
definition == vDefinition && distanceSq < interference.main * interference.main
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.map(_._2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def ReportOnInterferenceResults(
|
||||||
|
zone: Zone,
|
||||||
|
vehicle: Vehicle,
|
||||||
|
reportedInterferenceList: Seq[ObjectDefinition]
|
||||||
|
): Boolean = {
|
||||||
|
if (reportedInterferenceList.nonEmpty) {
|
||||||
|
reportedInterferenceList
|
||||||
|
.find(_.isInstanceOf[VehicleDefinition])
|
||||||
|
.map { definition => s"@nodeploy_${definition.Name}" }
|
||||||
|
.orElse {
|
||||||
|
val sharedGroupId = vehicle.Definition.interference.sharedGroupId
|
||||||
|
if (sharedGroupId > 0) {
|
||||||
|
reportedInterferenceList
|
||||||
|
.find(_.interference.sharedGroupId == sharedGroupId)
|
||||||
|
.map(_ => "@nodeploy_sharedinterference")
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.foreach { msg =>
|
||||||
|
zone.VehicleEvents ! VehicleServiceMessage(
|
||||||
|
vehicle.Seats.headOption.flatMap(_._2.occupant).map(_.Name).getOrElse(""),
|
||||||
|
VehicleAction.SendResponse(Service.defaultPlayerGUID, ChatMsg(ChatMessageType.UNK_227, msg))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,17 @@ object OxygenStateMessage extends Marshallable[OxygenStateMessage] {
|
||||||
204.8f,
|
204.8f,
|
||||||
11
|
11
|
||||||
) :: //hackish: 2^11 == 2047, so it should be 204.7; but, 204.8 allows decode == encode
|
) :: //hackish: 2^11 == 2047, so it should be 204.7; but, 204.8 allows decode == encode
|
||||||
OxygenState.codec
|
bool.xmap[OxygenState](
|
||||||
|
{
|
||||||
|
case false => OxygenState.Recovery
|
||||||
|
case true => OxygenState.Suffocation
|
||||||
|
},
|
||||||
|
{
|
||||||
|
case OxygenState.Recovery => false
|
||||||
|
case OxygenState.Suffocation => true
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
)
|
||||||
).as[DrowningTarget]
|
).as[DrowningTarget]
|
||||||
|
|
||||||
implicit val codec: Codec[OxygenStateMessage] = (
|
implicit val codec: Codec[OxygenStateMessage] = (
|
||||||
|
|
|
||||||
|
|
@ -1216,11 +1216,11 @@ object ObjectClass {
|
||||||
case ObjectClass.advanced_ace => DroppedItemData(HandheldData.codec, "advanced ace")
|
case ObjectClass.advanced_ace => DroppedItemData(HandheldData.codec, "advanced ace")
|
||||||
case ObjectClass.router_telepad => DroppedItemData(HandheldData.codec, "router telepad")
|
case ObjectClass.router_telepad => DroppedItemData(HandheldData.codec, "router telepad")
|
||||||
case ObjectClass.boomer_trigger => DroppedItemData(HandheldData.codec, "boomer trigger")
|
case ObjectClass.boomer_trigger => DroppedItemData(HandheldData.codec, "boomer trigger")
|
||||||
case ObjectClass.boomer => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
case ObjectClass.boomer => ConstructorData(SmallDeployableData.codec, "ace deployable")
|
||||||
case ObjectClass.he_mine => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
case ObjectClass.he_mine => ConstructorData(SmallDeployableData.codec, "ace deployable")
|
||||||
case ObjectClass.jammer_mine => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
case ObjectClass.jammer_mine => ConstructorData(SmallDeployableData.codec, "ace deployable")
|
||||||
case ObjectClass.motionalarmsensor => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
case ObjectClass.motionalarmsensor => ConstructorData(SmallDeployableData.codec, "ace deployable")
|
||||||
case ObjectClass.sensor_shield => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
case ObjectClass.sensor_shield => ConstructorData(SmallDeployableData.codec, "ace deployable")
|
||||||
case ObjectClass.spitfire_aa => ConstructorData(SmallTurretData.codec, "small turret")
|
case ObjectClass.spitfire_aa => ConstructorData(SmallTurretData.codec, "small turret")
|
||||||
case ObjectClass.spitfire_cloaked => ConstructorData(SmallTurretData.codec, "small turret")
|
case ObjectClass.spitfire_cloaked => ConstructorData(SmallTurretData.codec, "small turret")
|
||||||
case ObjectClass.spitfire_turret => ConstructorData(SmallTurretData.codec, "small turret")
|
case ObjectClass.spitfire_turret => ConstructorData(SmallTurretData.codec, "small turret")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright (c) 2024 PSForever
|
||||||
|
package net.psforever.packet.game.objectcreate
|
||||||
|
|
||||||
|
import net.psforever.packet.Marshallable
|
||||||
|
import scodec.{Attempt, Codec, Err}
|
||||||
|
import scodec.codecs._
|
||||||
|
import shapeless.{::, HNil}
|
||||||
|
|
||||||
|
final case class SmallDeployableData(deploy: CommonFieldDataWithPlacement) extends ConstructorData {
|
||||||
|
override def bitsize: Long = {
|
||||||
|
deploy.bitsize + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object SmallDeployableData extends Marshallable[SmallDeployableData] {
|
||||||
|
implicit val codec: Codec[SmallDeployableData] = (
|
||||||
|
("deploy" | CommonFieldDataWithPlacement.codec) ::
|
||||||
|
ignore(size = 1)
|
||||||
|
).exmap[SmallDeployableData](
|
||||||
|
{
|
||||||
|
case deploy :: _ :: HNil =>
|
||||||
|
Attempt.successful(SmallDeployableData(deploy))
|
||||||
|
|
||||||
|
case data =>
|
||||||
|
Attempt.failure(Err(s"invalid small deployable data format - $data"))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
case SmallDeployableData(deploy) =>
|
||||||
|
Attempt.successful(deploy :: () :: HNil)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -120,6 +120,8 @@ class LocalService(zone: Zone) extends Actor {
|
||||||
hackCapturer ! HackCaptureActor.StartCaptureTerminalHack(target, zone, 0, 8L)
|
hackCapturer ! HackCaptureActor.StartCaptureTerminalHack(target, zone, 0, 8L)
|
||||||
case LocalAction.LluCaptured(llu) =>
|
case LocalAction.LluCaptured(llu) =>
|
||||||
hackCapturer ! HackCaptureActor.FlagCaptured(llu)
|
hackCapturer ! HackCaptureActor.FlagCaptured(llu)
|
||||||
|
case LocalAction.LluLost(llu) =>
|
||||||
|
hackCapturer ! HackCaptureActor.FlagLost(llu)
|
||||||
|
|
||||||
case LocalAction.LluSpawned(player_guid, llu) =>
|
case LocalAction.LluSpawned(player_guid, llu) =>
|
||||||
// Forward to all clients to create object locally
|
// Forward to all clients to create object locally
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ object LocalAction {
|
||||||
final case class ResecureCaptureTerminal(target: CaptureTerminal, hacker: PlayerSource) extends Action
|
final case class ResecureCaptureTerminal(target: CaptureTerminal, hacker: PlayerSource) extends Action
|
||||||
final case class StartCaptureTerminalHack(target: CaptureTerminal) extends Action
|
final case class StartCaptureTerminalHack(target: CaptureTerminal) extends Action
|
||||||
final case class LluCaptured(llu: CaptureFlag) extends Action
|
final case class LluCaptured(llu: CaptureFlag) extends Action
|
||||||
|
final case class LluLost(llu: CaptureFlag) extends Action
|
||||||
final case class LluSpawned(player_guid: PlanetSideGUID, llu: CaptureFlag) extends Action
|
final case class LluSpawned(player_guid: PlanetSideGUID, llu: CaptureFlag) extends Action
|
||||||
final case class LluDespawned(player_guid: PlanetSideGUID, guid: PlanetSideGUID, position: Vector3) extends Action
|
final case class LluDespawned(player_guid: PlanetSideGUID, guid: PlanetSideGUID, position: Vector3) extends Action
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,14 @@ package net.psforever.services.local.support
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorRef, Cancellable}
|
import akka.actor.{Actor, ActorRef, Cancellable}
|
||||||
import net.psforever.login.WorldSession
|
import net.psforever.login.WorldSession
|
||||||
import net.psforever.objects.{Default, Player}
|
import net.psforever.objects.{Default, PlanetSideGameObject, Player}
|
||||||
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
||||||
|
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait}
|
||||||
|
import net.psforever.objects.serverobject.environment.interaction.InteractWithEnvironment
|
||||||
import net.psforever.objects.serverobject.llu.CaptureFlag
|
import net.psforever.objects.serverobject.llu.CaptureFlag
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, WarpGate}
|
||||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
|
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.{InteractsWithZone, Zone}
|
||||||
import net.psforever.packet.game._
|
import net.psforever.packet.game._
|
||||||
import net.psforever.services.{Service, ServiceManager}
|
import net.psforever.services.{Service, ServiceManager}
|
||||||
import net.psforever.services.ServiceManager.{Lookup, LookupResult}
|
import net.psforever.services.ServiceManager.{Lookup, LookupResult}
|
||||||
|
|
@ -22,12 +24,13 @@ import scala.concurrent.duration.DurationInt
|
||||||
* Responsible for handling capture flag related lifecycles
|
* Responsible for handling capture flag related lifecycles
|
||||||
*/
|
*/
|
||||||
class CaptureFlagManager(zone: Zone) extends Actor {
|
class CaptureFlagManager(zone: Zone) extends Actor {
|
||||||
|
import CaptureFlagManager.CaptureFlagEntry
|
||||||
private[this] val log = org.log4s.getLogger(self.path.name)
|
private[this] val log = org.log4s.getLogger(self.path.name)
|
||||||
|
|
||||||
private var galaxyService: ActorRef = ActorRef.noSender
|
private var galaxyService: ActorRef = ActorRef.noSender
|
||||||
private var mapUpdateTick: Cancellable = Default.Cancellable
|
private var mapUpdateTick: Cancellable = Default.Cancellable
|
||||||
/** An internally tracked list of cached flags, to avoid querying the amenity owner each second for flag lookups. */
|
/** An internally tracked list of cached flags, to avoid querying the amenity owner each second for flag lookups. */
|
||||||
private var flags: List[CaptureFlag] = Nil
|
private var flags: List[CaptureFlagEntry] = Nil
|
||||||
|
|
||||||
ServiceManager.serviceManager ! Lookup("galaxy")
|
ServiceManager.serviceManager ! Lookup("galaxy")
|
||||||
|
|
||||||
|
|
@ -39,7 +42,6 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
||||||
DoMapUpdate()
|
DoMapUpdate()
|
||||||
|
|
||||||
case CaptureFlagManager.SpawnCaptureFlag(capture_terminal, target, hackingFaction) =>
|
case CaptureFlagManager.SpawnCaptureFlag(capture_terminal, target, hackingFaction) =>
|
||||||
val zone = capture_terminal.Zone
|
|
||||||
val socket = capture_terminal.Owner.asInstanceOf[Building].GetFlagSocket.get
|
val socket = capture_terminal.Owner.asInstanceOf[Building].GetFlagSocket.get
|
||||||
// Override CC message when looked at
|
// Override CC message when looked at
|
||||||
zone.LocalEvents ! LocalServiceMessage(
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
|
@ -62,16 +64,16 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
||||||
socket.captureFlag = flag
|
socket.captureFlag = flag
|
||||||
TrackFlag(flag)
|
TrackFlag(flag)
|
||||||
TaskWorkflow.execute(WorldSession.CallBackForTask(
|
TaskWorkflow.execute(WorldSession.CallBackForTask(
|
||||||
GUIDTask.registerObject(socket.Zone.GUID, flag),
|
GUIDTask.registerObject(zone.GUID, flag),
|
||||||
socket.Zone.LocalEvents,
|
zone.LocalEvents,
|
||||||
LocalServiceMessage(
|
LocalServiceMessage(
|
||||||
socket.Zone.id,
|
zone.id,
|
||||||
LocalAction.LluSpawned(Service.defaultPlayerGUID, flag)
|
LocalAction.LluSpawned(Service.defaultPlayerGUID, flag)
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
// Broadcast chat message for LLU spawn
|
// Broadcast chat message for LLU spawn
|
||||||
val owner = flag.Owner.asInstanceOf[Building]
|
val owner = flag.Owner.asInstanceOf[Building]
|
||||||
ChatBroadcast(flag.Zone, CaptureFlagChatMessageStrings.CTF_FlagSpawned(owner, flag.Target))
|
CaptureFlagManager.ChatBroadcast(zone, CaptureFlagChatMessageStrings.CTF_FlagSpawned(owner, flag.Target))
|
||||||
|
|
||||||
case CaptureFlagManager.Captured(flag: CaptureFlag) =>
|
case CaptureFlagManager.Captured(flag: CaptureFlag) =>
|
||||||
val name = flag.Carrier match {
|
val name = flag.Carrier match {
|
||||||
|
|
@ -79,36 +81,46 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
||||||
case None => "A soldier"
|
case None => "A soldier"
|
||||||
}
|
}
|
||||||
// Trigger Install sound
|
// Trigger Install sound
|
||||||
flag.Zone.LocalEvents ! LocalServiceMessage(flag.Zone.id, LocalAction.TriggerSound(PlanetSideGUID(-1), TriggeredSound.LLUInstall, flag.Target.CaptureTerminal.get.Position, 20, 0.8000001f))
|
zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.TriggerSound(PlanetSideGUID(-1), TriggeredSound.LLUInstall, flag.Target.CaptureTerminal.get.Position, 20, 0.8000001f))
|
||||||
// Broadcast capture chat message
|
// Broadcast capture chat message
|
||||||
ChatBroadcast(flag.Zone, CaptureFlagChatMessageStrings.CTF_Success(name, flag.Faction, flag.Owner.asInstanceOf[Building].Name))
|
CaptureFlagManager.ChatBroadcast(zone, CaptureFlagChatMessageStrings.CTF_Success(name, flag.Faction, flag.Owner.asInstanceOf[Building].Name))
|
||||||
// Despawn flag
|
// Despawn flag
|
||||||
HandleFlagDespawn(flag)
|
HandleFlagDespawn(flag)
|
||||||
|
|
||||||
case CaptureFlagManager.Lost(flag: CaptureFlag, reason: CaptureFlagLostReasonEnum) =>
|
case CaptureFlagManager.Lost(flag: CaptureFlag, reason: CaptureFlagLostReasonEnum) =>
|
||||||
reason match {
|
reason match {
|
||||||
case CaptureFlagLostReasonEnum.Resecured =>
|
case CaptureFlagLostReasonEnum.Resecured =>
|
||||||
ChatBroadcast(
|
CaptureFlagManager.ChatBroadcast(
|
||||||
flag.Zone,
|
zone,
|
||||||
CaptureFlagChatMessageStrings.CTF_Failed_SourceResecured(flag.Owner.asInstanceOf[Building].Name, flag.Faction)
|
CaptureFlagChatMessageStrings.CTF_Failed_SourceResecured(flag.Owner.asInstanceOf[Building].Name, flag.Faction)
|
||||||
)
|
)
|
||||||
case CaptureFlagLostReasonEnum.TimedOut =>
|
case CaptureFlagLostReasonEnum.TimedOut =>
|
||||||
val building = flag.Owner.asInstanceOf[Building]
|
val building = flag.Owner.asInstanceOf[Building]
|
||||||
ChatBroadcast(
|
CaptureFlagManager.ChatBroadcast(
|
||||||
flag.Zone,
|
zone,
|
||||||
CaptureFlagChatMessageStrings.CTF_Failed_TimedOut(building.Name, flag.Target.Name, flag.Faction)
|
CaptureFlagChatMessageStrings.CTF_Failed_TimedOut(building.Name, flag.Target.Name, flag.Faction)
|
||||||
)
|
)
|
||||||
|
case CaptureFlagLostReasonEnum.FlagLost =>
|
||||||
|
val building = flag.Owner.asInstanceOf[Building]
|
||||||
|
CaptureFlagManager.ChatBroadcast(
|
||||||
|
zone,
|
||||||
|
CaptureFlagChatMessageStrings.CTF_Failed_FlagLost(building.Name, flag.Faction),
|
||||||
|
fanfare = false
|
||||||
|
)
|
||||||
case CaptureFlagLostReasonEnum.Ended =>
|
case CaptureFlagLostReasonEnum.Ended =>
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
HandleFlagDespawn(flag)
|
HandleFlagDespawn(flag)
|
||||||
|
|
||||||
case CaptureFlagManager.PickupFlag(flag: CaptureFlag, player: Player) =>
|
case CaptureFlagManager.PickupFlag(flag: CaptureFlag, player: Player) =>
|
||||||
val continent = flag.Zone
|
|
||||||
flag.Carrier = Some(player)
|
flag.Carrier = Some(player)
|
||||||
continent.LocalEvents ! LocalServiceMessage(continent.id, LocalAction.SendPacket(ObjectAttachMessage(player.GUID, flag.GUID, 252)))
|
zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.SendPacket(ObjectAttachMessage(player.GUID, flag.GUID, 252)))
|
||||||
continent.LocalEvents ! LocalServiceMessage(continent.id, LocalAction.TriggerSound(PlanetSideGUID(-1), TriggeredSound.LLUPickup, player.Position, 15, volume = 0.8f))
|
zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.TriggerSound(PlanetSideGUID(-1), TriggeredSound.LLUPickup, player.Position, 15, volume = 0.8f))
|
||||||
ChatBroadcast(flag.Zone, CaptureFlagChatMessageStrings.CTF_FlagPickedUp(player.Name, player.Faction, flag.Owner.asInstanceOf[Building].Name), fanfare = false)
|
CaptureFlagManager.ChatBroadcast(
|
||||||
|
zone,
|
||||||
|
CaptureFlagChatMessageStrings.CTF_FlagPickedUp(player.Name, player.Faction, flag.Owner.asInstanceOf[Building].Name),
|
||||||
|
fanfare = false
|
||||||
|
)
|
||||||
|
|
||||||
case CaptureFlagManager.DropFlag(flag: CaptureFlag) =>
|
case CaptureFlagManager.DropFlag(flag: CaptureFlag) =>
|
||||||
flag.Carrier match {
|
flag.Carrier match {
|
||||||
|
|
@ -119,9 +131,13 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
||||||
// Remove attached player from flag
|
// Remove attached player from flag
|
||||||
flag.Carrier = None
|
flag.Carrier = None
|
||||||
// Send drop packet
|
// Send drop packet
|
||||||
flag.Zone.LocalEvents ! LocalServiceMessage(flag.Zone.id, LocalAction.SendPacket(ObjectDetachMessage(player.GUID, flag.GUID, player.Position, 0, 0, 0)))
|
zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.SendPacket(ObjectDetachMessage(player.GUID, flag.GUID, player.Position, 0, 0, 0)))
|
||||||
// Send dropped chat message
|
// Send dropped chat message
|
||||||
ChatBroadcast(flag.Zone, CaptureFlagChatMessageStrings.CTF_FlagDropped(player.Name, player.Faction, flag.Owner.asInstanceOf[Building].Name), fanfare = false)
|
CaptureFlagManager.ChatBroadcast(
|
||||||
|
zone,
|
||||||
|
CaptureFlagChatMessageStrings.CTF_FlagDropped(player.Name, player.Faction, flag.Owner.asInstanceOf[Building].Name),
|
||||||
|
fanfare = false
|
||||||
|
)
|
||||||
HandleFlagDespawn(flag)
|
HandleFlagDespawn(flag)
|
||||||
// Register LLU object create task and callback to create on clients
|
// Register LLU object create task and callback to create on clients
|
||||||
val replacementLlu = CaptureFlag.Constructor(
|
val replacementLlu = CaptureFlag.Constructor(
|
||||||
|
|
@ -136,10 +152,10 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
||||||
socket.captureFlag = replacementLlu
|
socket.captureFlag = replacementLlu
|
||||||
TrackFlag(replacementLlu)
|
TrackFlag(replacementLlu)
|
||||||
TaskWorkflow.execute(WorldSession.CallBackForTask(
|
TaskWorkflow.execute(WorldSession.CallBackForTask(
|
||||||
GUIDTask.registerObject(socket.Zone.GUID, replacementLlu),
|
GUIDTask.registerObject(zone.GUID, replacementLlu),
|
||||||
socket.Zone.LocalEvents,
|
zone.LocalEvents,
|
||||||
LocalServiceMessage(
|
LocalServiceMessage(
|
||||||
socket.Zone.id,
|
zone.id,
|
||||||
LocalAction.LluSpawned(Service.defaultPlayerGUID, replacementLlu)
|
LocalAction.LluSpawned(Service.defaultPlayerGUID, replacementLlu)
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
|
@ -152,33 +168,42 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private def DoMapUpdate(): Unit = {
|
private def DoMapUpdate(): Unit = {
|
||||||
val flagInfo = flags.map(flag =>
|
val flagInfo = flags.map { case entry @ CaptureFlagManager.CaptureFlagEntry(flag) =>
|
||||||
|
val owner = flag.Owner.asInstanceOf[Building]
|
||||||
|
val pos = flag.Position
|
||||||
|
val hackTimeRemaining = owner.infoUpdateMessage().hack_time_remaining
|
||||||
|
val nextMessageAfterMinutes = CaptureFlagManager.CaptureFlagCountdownMessages(entry.currentMessageIndex)
|
||||||
|
if (hackTimeRemaining < nextMessageAfterMinutes.minutes.toMillis) {
|
||||||
|
entry.currentMessageIndex += 1
|
||||||
|
val msg = CaptureFlagManager.ComposeWarningMessage(flag, owner.Name, nextMessageAfterMinutes)
|
||||||
|
CaptureFlagManager.ChatBroadcast(zone, msg, fanfare = false)
|
||||||
|
}
|
||||||
FlagInfo(
|
FlagInfo(
|
||||||
u1 = 0,
|
u1 = 0,
|
||||||
owner_map_id = flag.Owner.asInstanceOf[Building].MapId,
|
owner_map_id = owner.MapId,
|
||||||
target_map_id = flag.Target.MapId,
|
target_map_id = flag.Target.MapId,
|
||||||
x = flag.Position.x,
|
x = pos.x,
|
||||||
y = flag.Position.y,
|
y = pos.y,
|
||||||
hack_time_remaining = flag.Owner.asInstanceOf[Building].infoUpdateMessage().hack_time_remaining,
|
hack_time_remaining = hackTimeRemaining,
|
||||||
is_monolith_unit = false
|
is_monolith_unit = false
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
galaxyService ! GalaxyServiceMessage(GalaxyAction.FlagMapUpdate(CaptureFlagUpdateMessage(zone.Number, flagInfo)))
|
galaxyService ! GalaxyServiceMessage(GalaxyAction.FlagMapUpdate(CaptureFlagUpdateMessage(zone.Number, flagInfo)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def TrackFlag(flag: CaptureFlag): Unit = {
|
private def TrackFlag(flag: CaptureFlag): Unit = {
|
||||||
flag.Owner.Amenities = flag
|
flag.Owner.Amenities = flag
|
||||||
flags = flags :+ flag
|
flags = flags :+ CaptureFlagEntry(flag)
|
||||||
if (mapUpdateTick.isCancelled) {
|
if (mapUpdateTick.isCancelled) {
|
||||||
// Start sending map updates periodically
|
// Start sending map updates periodically
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
mapUpdateTick = context.system.scheduler.scheduleAtFixedRate(0 seconds, 1 second, self, CaptureFlagManager.MapUpdate())
|
mapUpdateTick = context.system.scheduler.scheduleAtFixedRate(initialDelay = 0 seconds, interval = 1 second, self, CaptureFlagManager.MapUpdate())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def UntrackFlag(flag: CaptureFlag): Unit = {
|
private def UntrackFlag(flag: CaptureFlag): Unit = {
|
||||||
flag.Owner.RemoveAmenity(flag)
|
flag.Owner.RemoveAmenity(flag)
|
||||||
flags = flags.filterNot(x => x eq flag)
|
flags = flags.filterNot(x => x.flag eq flag)
|
||||||
if (flags.isEmpty) {
|
if (flags.isEmpty) {
|
||||||
mapUpdateTick.cancel()
|
mapUpdateTick.cancel()
|
||||||
DoMapUpdate()
|
DoMapUpdate()
|
||||||
|
|
@ -186,7 +211,6 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private def HandleFlagDespawn(flag: CaptureFlag): Unit = {
|
private def HandleFlagDespawn(flag: CaptureFlag): Unit = {
|
||||||
val zone = flag.Zone
|
|
||||||
// Remove the flag as an amenity
|
// Remove the flag as an amenity
|
||||||
flag.Owner.asInstanceOf[Building].GetFlagSocket.get.captureFlag = None
|
flag.Owner.asInstanceOf[Building].GetFlagSocket.get.captureFlag = None
|
||||||
UntrackFlag(flag)
|
UntrackFlag(flag)
|
||||||
|
|
@ -195,21 +219,6 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
||||||
// Then unregister it from the GUID pool
|
// Then unregister it from the GUID pool
|
||||||
TaskWorkflow.execute(GUIDTask.unregisterObject(zone.GUID, flag))
|
TaskWorkflow.execute(GUIDTask.unregisterObject(zone.GUID, flag))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def ChatBroadcast(zone: Zone, message: String, fanfare: Boolean = true): Unit = {
|
|
||||||
val messageType: ChatMessageType = if (fanfare) {
|
|
||||||
ChatMessageType.UNK_223
|
|
||||||
} else {
|
|
||||||
ChatMessageType.UNK_229
|
|
||||||
}
|
|
||||||
zone.LocalEvents ! LocalServiceMessage(
|
|
||||||
zone.id,
|
|
||||||
LocalAction.SendChatMsg(
|
|
||||||
PlanetSideGUID(-1),
|
|
||||||
ChatMsg(messageType, wideContents = false, "", message, None)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object CaptureFlagManager {
|
object CaptureFlagManager {
|
||||||
|
|
@ -221,18 +230,98 @@ object CaptureFlagManager {
|
||||||
final case class Captured(flag: CaptureFlag) extends Command
|
final case class Captured(flag: CaptureFlag) extends Command
|
||||||
final case class Lost(flag: CaptureFlag, reason: CaptureFlagLostReasonEnum) extends Command
|
final case class Lost(flag: CaptureFlag, reason: CaptureFlagLostReasonEnum) extends Command
|
||||||
final case class MapUpdate()
|
final case class MapUpdate()
|
||||||
|
|
||||||
|
private case class CaptureFlagEntry(flag: CaptureFlag) {
|
||||||
|
var currentMessageIndex: Int = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val CaptureFlagCountdownMessages: Seq[Int] = Seq(10, 5, 2, 1, 0)
|
||||||
|
|
||||||
|
private def ChatBroadcast(zone: Zone, message: String, fanfare: Boolean = true): Unit = {
|
||||||
|
//todo use UNK_222 sometimes
|
||||||
|
//todo I think the fanfare was relate to whether the message was celebratory is tone, based on the faction
|
||||||
|
val messageType: ChatMessageType = if (fanfare) {
|
||||||
|
ChatMessageType.UNK_223
|
||||||
|
} else {
|
||||||
|
ChatMessageType.UNK_229
|
||||||
|
}
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zone.id,
|
||||||
|
LocalAction.SendChatMsg(
|
||||||
|
PlanetSideGUID(-1),
|
||||||
|
ChatMsg(messageType, wideContents = true, "", message, None)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def ComposeWarningMessage(flag: CaptureFlag, buildingName: String, minutesLeft: Int): String = {
|
||||||
|
import CaptureFlagChatMessageStrings._
|
||||||
|
val carrier = flag.Carrier
|
||||||
|
val hasCarrier = carrier.nonEmpty
|
||||||
|
minutesLeft match {
|
||||||
|
case 1 if hasCarrier =>
|
||||||
|
CTF_Warning_Carrier1Min(carrier.get.Name, flag.Faction, buildingName, flag.Target.Name)
|
||||||
|
case 1 =>
|
||||||
|
CTF_Warning_NoCarrier1Min(buildingName, flag.Faction, flag.Target.Name)
|
||||||
|
case time if hasCarrier =>
|
||||||
|
CTF_Warning_Carrier(carrier.get.Name, flag.Faction, buildingName, flag.Target.Name, time)
|
||||||
|
case time =>
|
||||||
|
CTF_Warning_NoCarrier(buildingName, flag.Faction, flag.Target.Name, time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param flagGuid flag that may exist
|
||||||
|
* @param target evaluate this to determine if to continue with this loss
|
||||||
|
*/
|
||||||
|
def ReasonToLoseFlagViolently(
|
||||||
|
zone: Zone,
|
||||||
|
flagGuid: Option[PlanetSideGUID],
|
||||||
|
target: PlanetSideGameObject with InteractsWithZone
|
||||||
|
): Boolean = {
|
||||||
|
zone
|
||||||
|
.GUID(flagGuid)
|
||||||
|
.collect {
|
||||||
|
case flag: CaptureFlag
|
||||||
|
if LoseFlagViolentlyToEnvironment(target, Set(EnvironmentAttribute.Water, EnvironmentAttribute.Lava, EnvironmentAttribute.Death)) ||
|
||||||
|
LoseFlagViolentlyToWarpGateEnvelope(zone, target) =>
|
||||||
|
flag.Destroyed = true
|
||||||
|
zone.LocalEvents ! LocalServiceMessage("", LocalAction.LluLost(flag))
|
||||||
|
true
|
||||||
|
}
|
||||||
|
.getOrElse(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
def LoseFlagViolentlyToEnvironment(
|
||||||
|
target: PlanetSideGameObject with InteractsWithZone,
|
||||||
|
deniedEnvironments: Set[EnvironmentTrait]
|
||||||
|
): Boolean = {
|
||||||
|
target
|
||||||
|
.interaction()
|
||||||
|
.collectFirst { case env: InteractWithEnvironment => env.OngoingInteractions }
|
||||||
|
.map(_.intersect(deniedEnvironments))
|
||||||
|
.getOrElse(Set())
|
||||||
|
.nonEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
def LoseFlagViolentlyToWarpGateEnvelope(
|
||||||
|
zone: Zone,
|
||||||
|
target: PlanetSideGameObject with InteractsWithZone
|
||||||
|
): Boolean = {
|
||||||
|
val position = target.Position
|
||||||
|
zone
|
||||||
|
.blockMap
|
||||||
|
.sector(position, range = 10f)
|
||||||
|
.buildingList
|
||||||
|
.collectFirst {
|
||||||
|
case gate: WarpGate if Vector3.DistanceSquared(position, gate.Position) < math.pow(gate.Definition.SOIRadius, 2f) => gate
|
||||||
|
}
|
||||||
|
.nonEmpty
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object CaptureFlagChatMessageStrings {
|
object CaptureFlagChatMessageStrings {
|
||||||
/*
|
|
||||||
@CTF_Failed_TargetLost=%1's LLU target facility %2 was lost!\nHack canceled!
|
|
||||||
@CTF_Failed_FlagLost=The %1 lost %2's LLU!\nHack canceled!
|
|
||||||
@CTF_Warning_Carrier=%1 of the %2 has %3's LLU.\nIt must be taken to %4 within %5 minutes!
|
|
||||||
@CTF_Warning_NoCarrier=%1's LLU is in the field.\nThe %2 must take it to %3 within %4 minutes!
|
|
||||||
@CTF_Warning_Carrier1Min=%1 of the %2 has %3's LLU.\nIt must be taken to %4 within the next minute!
|
|
||||||
@CTF_Warning_NoCarrier1Min=%1's LLU is in the field.\nThe %2 must take it to %3 within the next minute!
|
|
||||||
*/
|
|
||||||
|
|
||||||
// @CTF_Success=%1 captured %2's LLU for the %3!
|
// @CTF_Success=%1 captured %2's LLU for the %3!
|
||||||
/** {player.Name} captured {ownerName}'s LLU for the {player.Faction}! */
|
/** {player.Name} captured {ownerName}'s LLU for the {player.Faction}! */
|
||||||
private[support] def CTF_Success(playerName:String, playerFaction: PlanetSideEmpire.Value, ownerName: String): String =
|
private[support] def CTF_Success(playerName:String, playerFaction: PlanetSideEmpire.Value, ownerName: String): String =
|
||||||
|
|
@ -243,10 +332,20 @@ object CaptureFlagChatMessageStrings {
|
||||||
private[support] def CTF_Failed_TimedOut(ownerName: String, name: String, faction: PlanetSideEmpire.Value): String =
|
private[support] def CTF_Failed_TimedOut(ownerName: String, name: String, faction: PlanetSideEmpire.Value): String =
|
||||||
s"@CTF_Failed_TimedOut^@${GetFactionString(faction)}~^@$ownerName~^@$name~"
|
s"@CTF_Failed_TimedOut^@${GetFactionString(faction)}~^@$ownerName~^@$name~"
|
||||||
|
|
||||||
|
// @CTF_Failed_Lost=The %1 lost %2's LLU!\nHack canceled!
|
||||||
|
/** The {faction} lost {ownerName}'s LLU!\nHack canceled! */
|
||||||
|
private[support] def CTF_Failed_FlagLost(ownerName: String, faction: PlanetSideEmpire.Value): String =
|
||||||
|
s"@CTF_Failed_FlagLost^@${GetFactionString(faction)}~^@$ownerName~"
|
||||||
|
|
||||||
|
// @CTF_Failed_TargetLost=%1's LLU target facility %2 was lost!\nHack canceled!
|
||||||
|
/** {hackFacility}'s LLU target facility {targetFacility} was lost!\nHack canceled! */
|
||||||
|
private[support] def CTF_Failed_TargetLost(hackFacility: String, targetFacility: String): String =
|
||||||
|
s"@CTF_Failed_TargetLost^@$hackFacility~^@$targetFacility~"
|
||||||
|
|
||||||
// @CTF_Failed_SourceResecured=The %1 resecured %2!\nThe LLU was lost!
|
// @CTF_Failed_SourceResecured=The %1 resecured %2!\nThe LLU was lost!
|
||||||
/** The {faction} resecured {name}!\nThe LLU was lost! */
|
/** The {faction} resecured {name}!\nThe LLU was lost! */
|
||||||
private[support] def CTF_Failed_SourceResecured(name: String, faction: PlanetSideEmpire.Value): String =
|
private[support] def CTF_Failed_SourceResecured(name: String, faction: PlanetSideEmpire.Value): String =
|
||||||
s"@CTF_Failed_SourceResecured^@${CaptureFlagChatMessageStrings.GetFactionString(faction)}~^@$name~"
|
s"@CTF_Failed_SourceResecured^@${GetFactionString(faction)}~^@$name~"
|
||||||
|
|
||||||
// @CTF_FlagSpawned=%1 %2 has spawned a LLU.\nIt must be taken to %3 %4's Control Console within %5 minutes or the hack will fail!
|
// @CTF_FlagSpawned=%1 %2 has spawned a LLU.\nIt must be taken to %3 %4's Control Console within %5 minutes or the hack will fail!
|
||||||
/** {facilityType} {facilityName} has spawned a LLU.\nIt must be taken to {targetFacilityType} {targetFacilityName}'s Control Console within 15 minutes or the hack will fail! */
|
/** {facilityType} {facilityName} has spawned a LLU.\nIt must be taken to {targetFacilityType} {targetFacilityName}'s Control Console within 15 minutes or the hack will fail! */
|
||||||
|
|
@ -255,13 +354,57 @@ object CaptureFlagChatMessageStrings {
|
||||||
|
|
||||||
// @CTF_FlagPickedUp=%1 of the %2 picked up %3's LLU
|
// @CTF_FlagPickedUp=%1 of the %2 picked up %3's LLU
|
||||||
/** {player.Name} of the {player.Faction} picked up {ownerName}'s LLU */
|
/** {player.Name} of the {player.Faction} picked up {ownerName}'s LLU */
|
||||||
def CTF_FlagPickedUp(playerName: String, playerFaction: PlanetSideEmpire.Value, ownerName: String): String =
|
private[support] def CTF_FlagPickedUp(playerName: String, playerFaction: PlanetSideEmpire.Value, ownerName: String): String =
|
||||||
s"@CTF_FlagPickedUp^$playerName~^@${CaptureFlagChatMessageStrings.GetFactionString(playerFaction)}~^@$ownerName~"
|
s"@CTF_FlagPickedUp^$playerName~^@${GetFactionString(playerFaction)}~^@$ownerName~"
|
||||||
|
|
||||||
// @CTF_FlagDropped=%1 of the %2 dropped %3's LLU
|
// @CTF_FlagDropped=%1 of the %2 dropped %3's LLU
|
||||||
/** {playerName} of the {faction} dropped {facilityName}'s LLU */
|
/** {playerName} of the {faction} dropped {facilityName}'s LLU */
|
||||||
def CTF_FlagDropped(playerName: String, playerFaction: PlanetSideEmpire.Value, ownerName: String): String =
|
private[support] def CTF_FlagDropped(playerName: String, playerFaction: PlanetSideEmpire.Value, ownerName: String): String =
|
||||||
s"@CTF_FlagDropped^$playerName~^@${CaptureFlagChatMessageStrings.GetFactionString(playerFaction)}~^@$ownerName~"
|
s"@CTF_FlagDropped^$playerName~^@${GetFactionString(playerFaction)}~^@$ownerName~"
|
||||||
|
|
||||||
|
// @CTF_Warning_Carrier=%1's LLU is in the field.\nThe %2 must take it to %3 within %4 minutes!
|
||||||
|
/** {facilityName}'s LLU is in the field.\nThe {faction} must take it to {targetFacilityName} within {time} minutes! */
|
||||||
|
private[support] def CTF_Warning_Carrier(
|
||||||
|
playerName:String,
|
||||||
|
playerFaction: PlanetSideEmpire.Value,
|
||||||
|
facilityName: String,
|
||||||
|
targetFacilityName: String,
|
||||||
|
time: Int
|
||||||
|
): String = {
|
||||||
|
s"@CTF_Warning_Carrier^$playerName~^@${GetFactionString(playerFaction)}~^@$facilityName~^@$targetFacilityName~^@$time~"
|
||||||
|
}
|
||||||
|
|
||||||
|
// @CTF_Warning_Carrier1Min=%1 of the %2 has %3's LLU.\nIt must be taken to %4 within the next minute!
|
||||||
|
/** {playerName} of the {faction} has {facilityName}'s LLU.\nIt must be taken to {targetFacilityName} within the next minute! */
|
||||||
|
private[support] def CTF_Warning_Carrier1Min(
|
||||||
|
playerName:String,
|
||||||
|
playerFaction: PlanetSideEmpire.Value,
|
||||||
|
facilityName: String,
|
||||||
|
targetFacilityName: String
|
||||||
|
): String = {
|
||||||
|
s"@CTF_Warning_Carrier1Min^$playerName~^@${GetFactionString(playerFaction)}~^@$facilityName~^@$targetFacilityName~"
|
||||||
|
}
|
||||||
|
|
||||||
|
// @CTF_Warning_NoCarrier=%1's LLU is in the field.\nThe %2 must take it to %3 within %4 minutes!
|
||||||
|
/** {facilityName}'s LLU is in the field.\nThe {faction} must take it to {targetFacilityName} within {time} minute! */
|
||||||
|
private[support] def CTF_Warning_NoCarrier(
|
||||||
|
facilityName: String,
|
||||||
|
playerFaction: PlanetSideEmpire.Value,
|
||||||
|
targetFacilityName: String,
|
||||||
|
time: Int
|
||||||
|
): String = {
|
||||||
|
s"@CTF_Warning_NoCarrier^@$facilityName~^@${GetFactionString(playerFaction)}~^@$targetFacilityName~^$time~"
|
||||||
|
}
|
||||||
|
|
||||||
|
// @CTF_Warning_NoCarrier1Min=%1's LLU is in the field.\nThe %2 must take it to %3 within the next minute!
|
||||||
|
/** {facilityName}'s LLU is in the field.\nThe {faction} must take it to {targetFacilityName} within the next minute! */
|
||||||
|
private[support] def CTF_Warning_NoCarrier1Min(
|
||||||
|
facilityName: String,
|
||||||
|
playerFaction: PlanetSideEmpire.Value,
|
||||||
|
targetFacilityName: String
|
||||||
|
): String = {
|
||||||
|
s"@CTF_Warning_NoCarrier1Min^@$facilityName~^@${GetFactionString(playerFaction)}~^@$targetFacilityName~"
|
||||||
|
}
|
||||||
|
|
||||||
private def GetFactionString: PlanetSideEmpire.Value=>String = {
|
private def GetFactionString: PlanetSideEmpire.Value=>String = {
|
||||||
case PlanetSideEmpire.TR => "TerranRepublic"
|
case PlanetSideEmpire.TR => "TerranRepublic"
|
||||||
|
|
@ -277,4 +420,5 @@ object CaptureFlagLostReasonEnum {
|
||||||
final case object Resecured extends CaptureFlagLostReasonEnum
|
final case object Resecured extends CaptureFlagLostReasonEnum
|
||||||
final case object TimedOut extends CaptureFlagLostReasonEnum
|
final case object TimedOut extends CaptureFlagLostReasonEnum
|
||||||
final case object Ended extends CaptureFlagLostReasonEnum
|
final case object Ended extends CaptureFlagLostReasonEnum
|
||||||
|
final case object FlagLost extends CaptureFlagLostReasonEnum
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,17 @@ import net.psforever.actors.zone.{BuildingActor, ZoneActor}
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
import net.psforever.objects.serverobject.CommonMessages
|
||||||
import net.psforever.objects.serverobject.hackable.Hackable
|
import net.psforever.objects.serverobject.hackable.Hackable
|
||||||
import net.psforever.objects.serverobject.llu.CaptureFlag
|
import net.psforever.objects.serverobject.llu.CaptureFlag
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
|
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.objects.Default
|
import net.psforever.objects.Default
|
||||||
import net.psforever.packet.game.{GenericAction, HackState7, PlanetsideAttributeEnum}
|
import net.psforever.objects.serverobject.structures.participation.MajorFacilityHackParticipation
|
||||||
|
import net.psforever.packet.game.{ChatMsg, GenericAction, HackState7, PlanetsideAttributeEnum}
|
||||||
import net.psforever.objects.sourcing.PlayerSource
|
import net.psforever.objects.sourcing.PlayerSource
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
import net.psforever.services.local.support.HackCaptureActor.GetHackingFaction
|
import net.psforever.services.local.support.HackCaptureActor.GetHackingFaction
|
||||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
|
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGUID}
|
||||||
|
|
||||||
import scala.concurrent.duration.{FiniteDuration, _}
|
import scala.concurrent.duration.{FiniteDuration, _}
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
@ -62,6 +63,11 @@ class HackCaptureActor extends Actor {
|
||||||
// If the base has a socket, but no flag spawned it means the hacked base is neutral with no friendly neighbouring bases to deliver to, making it a timed hack.
|
// If the base has a socket, but no flag spawned it means the hacked base is neutral with no friendly neighbouring bases to deliver to, making it a timed hack.
|
||||||
val building = terminal.Owner.asInstanceOf[Building]
|
val building = terminal.Owner.asInstanceOf[Building]
|
||||||
building.GetFlag match {
|
building.GetFlag match {
|
||||||
|
case Some(llu) if llu.Destroyed =>
|
||||||
|
// LLU was destroyed while in the field. Send resecured notifications
|
||||||
|
terminal.Zone.LocalEvents ! CaptureFlagManager.Lost(llu, CaptureFlagLostReasonEnum.FlagLost)
|
||||||
|
NotifyHackStateChange(terminal, isResecured = true)
|
||||||
|
|
||||||
case Some(llu) =>
|
case Some(llu) =>
|
||||||
// LLU was not delivered in time. Send resecured notifications
|
// LLU was not delivered in time. Send resecured notifications
|
||||||
terminal.Zone.LocalEvents ! CaptureFlagManager.Lost(llu, CaptureFlagLostReasonEnum.TimedOut)
|
terminal.Zone.LocalEvents ! CaptureFlagManager.Lost(llu, CaptureFlagLostReasonEnum.TimedOut)
|
||||||
|
|
@ -138,6 +144,28 @@ class HackCaptureActor extends Actor {
|
||||||
log.error(s"Attempted LLU capture for ${flag.Owner.asInstanceOf[Building].Name} but CC GUID ${flag.Owner.asInstanceOf[Building].CaptureTerminal.get.GUID} was not in list of hacked objects")
|
log.error(s"Attempted LLU capture for ${flag.Owner.asInstanceOf[Building].Name} but CC GUID ${flag.Owner.asInstanceOf[Building].CaptureTerminal.get.GUID} was not in list of hacked objects")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case HackCaptureActor.FlagLost(flag) =>
|
||||||
|
val owner = flag.Owner.asInstanceOf[Building]
|
||||||
|
val guid = owner.GUID
|
||||||
|
val terminalOpt = owner.CaptureTerminal
|
||||||
|
hackedObjects
|
||||||
|
.find(entry => guid == entry.target.Owner.GUID)
|
||||||
|
.collect { entry =>
|
||||||
|
val terminal = terminalOpt.get
|
||||||
|
hackedObjects = hackedObjects.filterNot(x => x eq entry)
|
||||||
|
log.info(s"FlagLost: ${flag.Carrier.map(_.Name).getOrElse("")} the flag carrier screwed up the capture for ${flag.Target.Name} and the LLU has been lost")
|
||||||
|
terminal.Actor ! CommonMessages.ClearHack()
|
||||||
|
NotifyHackStateChange(terminal, isResecured = true)
|
||||||
|
// If there's hacked objects left in the list restart the timer with the shortest hack time left
|
||||||
|
RestartTimer()
|
||||||
|
entry
|
||||||
|
}
|
||||||
|
.orElse{
|
||||||
|
log.warn(s"FlagLost: flag data does not match to an entry in the hacked objects list")
|
||||||
|
None
|
||||||
|
}
|
||||||
|
context.parent ! CaptureFlagManager.Lost(flag, CaptureFlagLostReasonEnum.FlagLost)
|
||||||
|
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,6 +237,18 @@ class HackCaptureActor extends Actor {
|
||||||
val owner = terminal.Owner.asInstanceOf[Building]
|
val owner = terminal.Owner.asInstanceOf[Building]
|
||||||
// Notify parent building that state has changed
|
// Notify parent building that state has changed
|
||||||
owner.Actor ! BuildingActor.AmenityStateChange(terminal, Some(isResecured))
|
owner.Actor ! BuildingActor.AmenityStateChange(terminal, Some(isResecured))
|
||||||
|
// If major facility, check NTU
|
||||||
|
owner.CaptureTerminal
|
||||||
|
.map(_.HackedBy)
|
||||||
|
.collect {
|
||||||
|
case Some(info: Hackable.HackInfo)
|
||||||
|
if owner.BuildingType == StructureType.Facility && owner.NtuLevel == 0 =>
|
||||||
|
MajorFacilityHackParticipation.warningMessageForHackOccupiers(
|
||||||
|
owner,
|
||||||
|
info,
|
||||||
|
ChatMsg(ChatMessageType.UNK_227, "@FacilityRequiresResourcesForHackWarning")
|
||||||
|
)
|
||||||
|
}
|
||||||
// Push map update to clients
|
// Push map update to clients
|
||||||
owner.Zone.actor ! ZoneActor.ZoneMapUpdate()
|
owner.Zone.actor ! ZoneActor.ZoneMapUpdate()
|
||||||
}
|
}
|
||||||
|
|
@ -256,6 +296,7 @@ object HackCaptureActor {
|
||||||
|
|
||||||
final case class ResecureCaptureTerminal(target: CaptureTerminal, zone: Zone, hacker: PlayerSource)
|
final case class ResecureCaptureTerminal(target: CaptureTerminal, zone: Zone, hacker: PlayerSource)
|
||||||
final case class FlagCaptured(flag: CaptureFlag)
|
final case class FlagCaptured(flag: CaptureFlag)
|
||||||
|
final case class FlagLost(flag: CaptureFlag)
|
||||||
|
|
||||||
private final case class ProcessCompleteHacks()
|
private final case class ProcessCompleteHacks()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,10 @@ class VehicleService(zone: Zone) extends Actor {
|
||||||
VehicleResponse.MountVehicle(vehicle_guid, seat)
|
VehicleResponse.MountVehicle(vehicle_guid, seat)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
case VehicleAction.LoseOwnership(owner_guid, vehicle_guid) =>
|
||||||
|
VehicleEvents.publish(
|
||||||
|
VehicleServiceResponse(s"/$forChannel/Vehicle", Service.defaultPlayerGUID, VehicleResponse.LoseOwnership(owner_guid, vehicle_guid))
|
||||||
|
)
|
||||||
case VehicleAction.Ownership(player_guid, vehicle_guid) =>
|
case VehicleAction.Ownership(player_guid, vehicle_guid) =>
|
||||||
VehicleEvents.publish(
|
VehicleEvents.publish(
|
||||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.Ownership(vehicle_guid))
|
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.Ownership(vehicle_guid))
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ object VehicleAction {
|
||||||
) extends Action
|
) extends Action
|
||||||
final case class MountVehicle(player_guid: PlanetSideGUID, object_guid: PlanetSideGUID, seat: Int) extends Action
|
final case class MountVehicle(player_guid: PlanetSideGUID, object_guid: PlanetSideGUID, seat: Int) extends Action
|
||||||
final case class ObjectDelete(guid: PlanetSideGUID) extends Action
|
final case class ObjectDelete(guid: PlanetSideGUID) extends Action
|
||||||
|
final case class LoseOwnership(owner_guid: PlanetSideGUID, vehicle_guid: PlanetSideGUID) extends Action
|
||||||
final case class Ownership(player_guid: PlanetSideGUID, vehicle_guid: PlanetSideGUID) extends Action
|
final case class Ownership(player_guid: PlanetSideGUID, vehicle_guid: PlanetSideGUID) extends Action
|
||||||
final case class PlanetsideAttribute(
|
final case class PlanetsideAttribute(
|
||||||
player_guid: PlanetSideGUID,
|
player_guid: PlanetSideGUID,
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,8 @@ object VehicleResponse {
|
||||||
final case class MountVehicle(object_guid: PlanetSideGUID, seat: Int) extends Response
|
final case class MountVehicle(object_guid: PlanetSideGUID, seat: Int) extends Response
|
||||||
final case class ObjectDelete(guid: PlanetSideGUID) extends Response
|
final case class ObjectDelete(guid: PlanetSideGUID) extends Response
|
||||||
final case class Ownership(vehicle_guid: PlanetSideGUID) extends Response
|
final case class Ownership(vehicle_guid: PlanetSideGUID) extends Response
|
||||||
|
final case class LoseOwnership(owner_guid: PlanetSideGUID, vehicle_guid: PlanetSideGUID)
|
||||||
|
extends Response
|
||||||
final case class PlanetsideAttribute(vehicle_guid: PlanetSideGUID, attribute_type: Int, attribute_value: Long)
|
final case class PlanetsideAttribute(vehicle_guid: PlanetSideGUID, attribute_type: Int, attribute_value: Long)
|
||||||
extends Response
|
extends Response
|
||||||
final case class Reload(weapon_guid: PlanetSideGUID) extends Response
|
final case class Reload(weapon_guid: PlanetSideGUID) extends Response
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
package net.psforever.types
|
package net.psforever.types
|
||||||
|
|
||||||
import enumeratum.{Enum, EnumEntry}
|
import enumeratum.{Enum, EnumEntry}
|
||||||
import net.psforever.packet.PacketHelpers
|
|
||||||
import scodec.Codec
|
|
||||||
import scodec.codecs.uint
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The progress state of being a drowning victim.
|
* The progress state of being a drowning victim.
|
||||||
|
|
@ -22,6 +19,4 @@ object OxygenState extends Enum[OxygenState] {
|
||||||
|
|
||||||
case object Recovery extends OxygenState
|
case object Recovery extends OxygenState
|
||||||
case object Suffocation extends OxygenState
|
case object Suffocation extends OxygenState
|
||||||
|
|
||||||
implicit val codec: Codec[OxygenState] = PacketHelpers.createEnumCodec(e = this, uint(bits = 1))
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ class CommonFieldDataWithPlacementTest extends Specification {
|
||||||
guid mustEqual PlanetSideGUID(3840)
|
guid mustEqual PlanetSideGUID(3840)
|
||||||
parent.isDefined mustEqual false
|
parent.isDefined mustEqual false
|
||||||
data match {
|
data match {
|
||||||
case CommonFieldDataWithPlacement(pos, com) =>
|
case SmallDeployableData(CommonFieldDataWithPlacement(pos, com)) =>
|
||||||
pos.coord mustEqual Vector3(4704.172f, 5546.4375f, 82.234375f)
|
pos.coord mustEqual Vector3(4704.172f, 5546.4375f, 82.234375f)
|
||||||
pos.orient mustEqual Vector3.z(272.8125f)
|
pos.orient mustEqual Vector3.z(272.8125f)
|
||||||
com match {
|
com match {
|
||||||
|
|
@ -31,9 +31,9 @@ class CommonFieldDataWithPlacementTest extends Specification {
|
||||||
v1 mustEqual false
|
v1 mustEqual false
|
||||||
v2.isEmpty mustEqual true
|
v2.isEmpty mustEqual true
|
||||||
v3 mustEqual false
|
v3 mustEqual false
|
||||||
v4.contains(false) mustEqual true
|
v4.isEmpty mustEqual true
|
||||||
v5.isEmpty mustEqual true
|
v5.isEmpty mustEqual true
|
||||||
fguid mustEqual PlanetSideGUID(8290)
|
fguid mustEqual PlanetSideGUID(4145)
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
@ -46,10 +46,10 @@ class CommonFieldDataWithPlacementTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode" in {
|
"encode" in {
|
||||||
val obj = CommonFieldDataWithPlacement(
|
val obj = SmallDeployableData(CommonFieldDataWithPlacement(
|
||||||
PlacementData(Vector3(4704.172f, 5546.4375f, 82.234375f), Vector3.z(272.8125f)),
|
PlacementData(Vector3(4704.172f, 5546.4375f, 82.234375f), Vector3.z(272.8125f)),
|
||||||
CommonFieldData(PlanetSideEmpire.TR, false, false, false, None, false, Some(false), None, PlanetSideGUID(8290))
|
CommonFieldData(PlanetSideEmpire.TR, bops = false, alternate = false, v1 = false, None, jammered = false, None, None, PlanetSideGUID(4145))
|
||||||
)
|
))
|
||||||
val msg = ObjectCreateMessage(ObjectClass.boomer, PlanetSideGUID(3840), obj)
|
val msg = ObjectCreateMessage(ObjectClass.boomer, PlanetSideGUID(3840), obj)
|
||||||
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||||
pkt mustEqual string_boomer
|
pkt mustEqual string_boomer
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,9 @@ class ConverterTest extends Specification {
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
bops = false,
|
bops = false,
|
||||||
alternate = false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -50,9 +50,9 @@ class ConverterTest extends Specification {
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
bops = false,
|
bops = false,
|
||||||
alternate = false,
|
alternate = false,
|
||||||
false,
|
v1 = false,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -71,7 +71,7 @@ class ConverterTest extends Specification {
|
||||||
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
||||||
case Success(pkt) =>
|
case Success(pkt) =>
|
||||||
pkt mustEqual DetailedWeaponData(
|
pkt mustEqual DetailedWeaponData(
|
||||||
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, bops = false, alternate = false, v1 = true, None, jammered = false, None, None, PlanetSideGUID(0)),
|
||||||
0,
|
0,
|
||||||
List(InternalSlot(Ammo.shotgun_shell.id, PlanetSideGUID(90), 0, DetailedAmmoBoxData(8, 12)))
|
List(InternalSlot(Ammo.shotgun_shell.id, PlanetSideGUID(90), 0, DetailedAmmoBoxData(8, 12)))
|
||||||
)
|
)
|
||||||
|
|
@ -81,7 +81,7 @@ class ConverterTest extends Specification {
|
||||||
obj.Definition.Packet.ConstructorData(obj) match {
|
obj.Definition.Packet.ConstructorData(obj) match {
|
||||||
case Success(pkt) =>
|
case Success(pkt) =>
|
||||||
pkt mustEqual WeaponData(
|
pkt mustEqual WeaponData(
|
||||||
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, bops = false, alternate = false, v1 = true, None, jammered = false, None, None, PlanetSideGUID(0)),
|
||||||
0,
|
0,
|
||||||
List(
|
List(
|
||||||
InternalSlot(
|
InternalSlot(
|
||||||
|
|
@ -90,11 +90,11 @@ class ConverterTest extends Specification {
|
||||||
0,
|
0,
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
false,
|
v1 = false,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -115,7 +115,7 @@ class ConverterTest extends Specification {
|
||||||
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
||||||
case Success(pkt) =>
|
case Success(pkt) =>
|
||||||
pkt mustEqual DetailedWeaponData(
|
pkt mustEqual DetailedWeaponData(
|
||||||
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, bops = false, alternate = false, v1 = true, None, jammered = false, None, None, PlanetSideGUID(0)),
|
||||||
0,
|
0,
|
||||||
List(
|
List(
|
||||||
InternalSlot(Ammo.bullet_9mm.id, PlanetSideGUID(90), 0, DetailedAmmoBoxData(8, 30)),
|
InternalSlot(Ammo.bullet_9mm.id, PlanetSideGUID(90), 0, DetailedAmmoBoxData(8, 30)),
|
||||||
|
|
@ -132,17 +132,17 @@ class ConverterTest extends Specification {
|
||||||
PlanetSideEmpire.NEUTRAL, //TODO need faction affinity
|
PlanetSideEmpire.NEUTRAL, //TODO need faction affinity
|
||||||
bops = false,
|
bops = false,
|
||||||
alternate = false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
),
|
),
|
||||||
0,
|
0,
|
||||||
List(
|
List(
|
||||||
InternalSlot(Ammo.bullet_9mm.id, PlanetSideGUID(90), 0, CommonFieldData()(false)),
|
InternalSlot(Ammo.bullet_9mm.id, PlanetSideGUID(90), 0, CommonFieldData()(flag = false)),
|
||||||
InternalSlot(Ammo.rocket.id, PlanetSideGUID(91), 1, CommonFieldData()(false))
|
InternalSlot(Ammo.rocket.id, PlanetSideGUID(91), 1, CommonFieldData()(flag = false))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -164,7 +164,7 @@ class ConverterTest extends Specification {
|
||||||
}
|
}
|
||||||
obj.Definition.Packet.ConstructorData(obj) match {
|
obj.Definition.Packet.ConstructorData(obj) match {
|
||||||
case Success(pkt) =>
|
case Success(pkt) =>
|
||||||
pkt mustEqual CommonFieldData()(false)
|
pkt mustEqual CommonFieldData()(flag = false)
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +177,7 @@ class ConverterTest extends Specification {
|
||||||
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
||||||
case Success(pkt) =>
|
case Success(pkt) =>
|
||||||
pkt mustEqual DetailedConstructionToolData(
|
pkt mustEqual DetailedConstructionToolData(
|
||||||
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0))
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, bops = false, alternate = false, v1 = true, None, jammered = false, None, None, PlanetSideGUID(0))
|
||||||
)
|
)
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
|
|
@ -188,11 +188,11 @@ class ConverterTest extends Specification {
|
||||||
pkt mustEqual HandheldData(
|
pkt mustEqual HandheldData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -216,11 +216,11 @@ class ConverterTest extends Specification {
|
||||||
pkt mustEqual DetailedREKData(
|
pkt mustEqual DetailedREKData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL, //TODO faction affinity
|
PlanetSideEmpire.NEUTRAL, //TODO faction affinity
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -234,11 +234,11 @@ class ConverterTest extends Specification {
|
||||||
pkt mustEqual REKData(
|
pkt mustEqual REKData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -257,7 +257,7 @@ class ConverterTest extends Specification {
|
||||||
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
||||||
case Success(pkt) =>
|
case Success(pkt) =>
|
||||||
pkt mustEqual DetailedConstructionToolData(
|
pkt mustEqual DetailedConstructionToolData(
|
||||||
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0))
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, bops = false, alternate = false, v1 = true, None, jammered = false, None, None, PlanetSideGUID(0))
|
||||||
)
|
)
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
|
|
@ -265,7 +265,7 @@ class ConverterTest extends Specification {
|
||||||
obj.Definition.Packet.ConstructorData(obj) match {
|
obj.Definition.Packet.ConstructorData(obj) match {
|
||||||
case Success(pkt) =>
|
case Success(pkt) =>
|
||||||
pkt mustEqual HandheldData(
|
pkt mustEqual HandheldData(
|
||||||
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0))
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, bops = false, alternate = false, v1 = false, None, jammered = false, None, None, PlanetSideGUID(0))
|
||||||
)
|
)
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
|
|
@ -282,11 +282,11 @@ class ConverterTest extends Specification {
|
||||||
pkt mustEqual HandheldData(
|
pkt mustEqual HandheldData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
false,
|
v1 = false,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
None,
|
None,
|
||||||
Some(1001),
|
Some(1001),
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -301,11 +301,11 @@ class ConverterTest extends Specification {
|
||||||
pkt mustEqual DetailedConstructionToolData(
|
pkt mustEqual DetailedConstructionToolData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
None,
|
None,
|
||||||
Some(1001),
|
Some(1001),
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -333,20 +333,20 @@ class ConverterTest extends Specification {
|
||||||
|
|
||||||
obj.Definition.Packet.ConstructorData(obj) match {
|
obj.Definition.Packet.ConstructorData(obj) match {
|
||||||
case Success(pkt) =>
|
case Success(pkt) =>
|
||||||
pkt mustEqual CommonFieldDataWithPlacement(
|
pkt mustEqual SmallDeployableData(CommonFieldDataWithPlacement(
|
||||||
PlacementData(Vector3.Zero, Vector3.Zero),
|
PlacementData(Vector3.Zero, Vector3.Zero),
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.TR,
|
PlanetSideEmpire.TR,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
false,
|
v1 = false,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
)
|
)
|
||||||
)
|
))
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
@ -369,12 +369,12 @@ class ConverterTest extends Specification {
|
||||||
PlacementData(Vector3.Zero, Vector3.Zero),
|
PlacementData(Vector3.Zero, Vector3.Zero),
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.TR,
|
PlanetSideEmpire.TR,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
|
None,
|
||||||
|
jammered = false,
|
||||||
None,
|
None,
|
||||||
false,
|
|
||||||
Some(true),
|
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
)
|
)
|
||||||
|
|
@ -389,11 +389,11 @@ class ConverterTest extends Specification {
|
||||||
WeaponData(
|
WeaponData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -406,11 +406,11 @@ class ConverterTest extends Specification {
|
||||||
0,
|
0,
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
false,
|
v1 = false,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -444,11 +444,11 @@ class ConverterTest extends Specification {
|
||||||
PlacementData(Vector3.Zero, Vector3.Zero),
|
PlacementData(Vector3.Zero, Vector3.Zero),
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.TR,
|
PlanetSideEmpire.TR,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -464,11 +464,11 @@ class ConverterTest extends Specification {
|
||||||
WeaponData(
|
WeaponData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -481,11 +481,11 @@ class ConverterTest extends Specification {
|
||||||
0,
|
0,
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
false,
|
v1 = false,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -519,10 +519,10 @@ class ConverterTest extends Specification {
|
||||||
PlanetSideEmpire.TR,
|
PlanetSideEmpire.TR,
|
||||||
bops = false,
|
bops = false,
|
||||||
alternate = false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
|
None,
|
||||||
|
jammered = false,
|
||||||
None,
|
None,
|
||||||
false,
|
|
||||||
Some(true),
|
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
)
|
)
|
||||||
|
|
@ -584,9 +584,9 @@ class ConverterTest extends Specification {
|
||||||
PlanetSideEmpire.TR,
|
PlanetSideEmpire.TR,
|
||||||
bops = false,
|
bops = false,
|
||||||
alternate = false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
None,
|
None,
|
||||||
Some(1001),
|
Some(1001),
|
||||||
PlanetSideGUID(5001)
|
PlanetSideGUID(5001)
|
||||||
|
|
@ -616,9 +616,9 @@ class ConverterTest extends Specification {
|
||||||
PlanetSideEmpire.TR,
|
PlanetSideEmpire.TR,
|
||||||
bops = false,
|
bops = false,
|
||||||
alternate = true,
|
alternate = true,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
None,
|
None,
|
||||||
Some(1001),
|
Some(1001),
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -751,7 +751,7 @@ class ConverterTest extends Specification {
|
||||||
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
||||||
case Success(pkt) =>
|
case Success(pkt) =>
|
||||||
pkt mustEqual DetailedLockerContainerData(
|
pkt mustEqual DetailedLockerContainerData(
|
||||||
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)),
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, bops = false, alternate = false, v1 = false, None, jammered = false, None, None, PlanetSideGUID(0)),
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -783,11 +783,11 @@ class ConverterTest extends Specification {
|
||||||
DetailedREKData(
|
DetailedREKData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -809,11 +809,11 @@ class ConverterTest extends Specification {
|
||||||
REKData(
|
REKData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -841,7 +841,7 @@ class ConverterTest extends Specification {
|
||||||
|
|
||||||
obj.Definition.Packet.ConstructorData(obj) match {
|
obj.Definition.Packet.ConstructorData(obj) match {
|
||||||
case Success(pkt) =>
|
case Success(pkt) =>
|
||||||
pkt mustEqual CommonFieldData(PlanetSideEmpire.NEUTRAL)(false)
|
pkt mustEqual CommonFieldData(PlanetSideEmpire.NEUTRAL)(flag = false)
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
@ -861,7 +861,7 @@ class ConverterTest extends Specification {
|
||||||
|
|
||||||
obj.Definition.Packet.ConstructorData(obj) match {
|
obj.Definition.Packet.ConstructorData(obj) match {
|
||||||
case Success(pkt) =>
|
case Success(pkt) =>
|
||||||
pkt mustEqual CommonFieldData(PlanetSideEmpire.NEUTRAL)(false)
|
pkt mustEqual CommonFieldData(PlanetSideEmpire.NEUTRAL)(flag = false)
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,26 +21,26 @@ class DefaultTest extends Specification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DefaultActorStartedTest extends ActorTest {
|
//class DefaultActorStartedTest extends ActorTest {
|
||||||
"Default.Actor" should {
|
// "Default.Actor" should {
|
||||||
"send messages to deadLetters" in {
|
// "send messages to deadLetters" in {
|
||||||
//after being started
|
// //after being started
|
||||||
val probe = new TestProbe(system)
|
// val probe = new TestProbe(system)
|
||||||
system.eventStream.subscribe(probe.ref, classOf[DeadLetter])
|
// system.eventStream.subscribe(probe.ref, classOf[DeadLetter])
|
||||||
Default.Actor ! "hello world"
|
// Default.Actor ! "hello world"
|
||||||
val msg1 = probe.receiveOne(5000 milliseconds)
|
// val msg1 = probe.receiveOne(5000 milliseconds)
|
||||||
assert(msg1.isInstanceOf[DeadLetter])
|
// assert(msg1.isInstanceOf[DeadLetter])
|
||||||
assert(msg1.asInstanceOf[DeadLetter].message equals "hello world")
|
// assert(msg1.asInstanceOf[DeadLetter].message equals "hello world")
|
||||||
|
//
|
||||||
//if it was stopped
|
// //if it was stopped
|
||||||
system.stop(Default.Actor)
|
// system.stop(Default.Actor)
|
||||||
Default.Actor ! "hello world"
|
// Default.Actor ! "hello world"
|
||||||
val msg2 = probe.receiveOne(5000 milliseconds)
|
// val msg2 = probe.receiveOne(5000 milliseconds)
|
||||||
assert(msg2.isInstanceOf[DeadLetter])
|
// assert(msg2.isInstanceOf[DeadLetter])
|
||||||
assert(msg2.asInstanceOf[DeadLetter].message equals "hello world")
|
// assert(msg2.asInstanceOf[DeadLetter].message equals "hello world")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
object DefaultActorTest {
|
object DefaultActorTest {
|
||||||
//due to being a singleton, the original original value of the Default.Actor is cached here
|
//due to being a singleton, the original original value of the Default.Actor is cached here
|
||||||
|
|
|
||||||
|
|
@ -48,21 +48,14 @@ class DeployableBehaviorSetupTest extends ActorTest {
|
||||||
assert(deployableList.isEmpty, "self-setup test - deployable list is not empty")
|
assert(deployableList.isEmpty, "self-setup test - deployable list is not empty")
|
||||||
zone.Deployables ! Zone.Deployable.Build(jmine)
|
zone.Deployables ! Zone.Deployable.Build(jmine)
|
||||||
|
|
||||||
val eventsMsgs = eventsProbe.receiveN(3, 10.seconds)
|
val eventsMsgs = eventsProbe.receiveN(2, 10.seconds)
|
||||||
eventsMsgs.head match {
|
eventsMsgs.head match {
|
||||||
case LocalServiceMessage(
|
|
||||||
"test",
|
|
||||||
LocalAction.TriggerEffectLocation(PlanetSideGUID(0), "spawn_object_effect", Vector3(1,2,3), Vector3(4,5,6))
|
|
||||||
) => ;
|
|
||||||
case _ => assert(false, "self-setup test - no spawn fx")
|
|
||||||
}
|
|
||||||
eventsMsgs(1) match {
|
|
||||||
case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
|
case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
|
||||||
assert(obj eq jmine, "self-setup test - not same mine")
|
assert(obj eq jmine, "self-setup test - not same mine")
|
||||||
case _ =>
|
case _ =>
|
||||||
assert( false, "self-setup test - wrong deploy message")
|
assert( false, "self-setup test - wrong deploy message")
|
||||||
}
|
}
|
||||||
eventsMsgs(2) match {
|
eventsMsgs(1) match {
|
||||||
case LocalServiceMessage(
|
case LocalServiceMessage(
|
||||||
"TR",
|
"TR",
|
||||||
LocalAction.DeployableMapIcon(
|
LocalAction.DeployableMapIcon(
|
||||||
|
|
@ -251,13 +244,13 @@ class DeployableBehaviorDeconstructTest extends ActorTest {
|
||||||
"DeployableBehavior" should {
|
"DeployableBehavior" should {
|
||||||
"deconstruct, by self" in {
|
"deconstruct, by self" in {
|
||||||
zone.Deployables ! Zone.Deployable.Build(jmine)
|
zone.Deployables ! Zone.Deployable.Build(jmine)
|
||||||
eventsProbe.receiveN(3, 10.seconds) //all of the messages from the construction (see other testing)
|
eventsProbe.receiveN(2, 10.seconds) //all of the messages from the construction (see other testing)
|
||||||
assert(deployableList.contains(jmine), "deconstruct test - deployable not appended to list")
|
assert(deployableList.contains(jmine), "deconstruct test - deployable not appended to list")
|
||||||
|
|
||||||
jmine.Actor ! Deployable.Deconstruct()
|
jmine.Actor ! Deployable.Deconstruct()
|
||||||
val eventsMsgs = eventsProbe.receiveN(2, 10.seconds)
|
val eventsMsgs = eventsProbe.receiveN(2, 10.seconds)
|
||||||
eventsMsgs.head match {
|
eventsMsgs.head match {
|
||||||
case LocalServiceMessage("test", LocalAction.EliminateDeployable(`jmine`, PlanetSideGUID(1), Vector3(1,2,3), 2)) => ;
|
case LocalServiceMessage("test", LocalAction.EliminateDeployable(_, PlanetSideGUID(1), Vector3(1,2,3), 2)) => ;
|
||||||
case _ => assert(false, "deconstruct test - not eliminating deployable")
|
case _ => assert(false, "deconstruct test - not eliminating deployable")
|
||||||
}
|
}
|
||||||
eventsMsgs(1) match {
|
eventsMsgs(1) match {
|
||||||
|
|
|
||||||
|
|
@ -314,7 +314,7 @@ class ExplosiveDeployableJammerTest extends ActorTest {
|
||||||
val guid = new NumberPoolHub(new MaxNumberSource(10))
|
val guid = new NumberPoolHub(new MaxNumberSource(10))
|
||||||
val eventsProbe = new TestProbe(system)
|
val eventsProbe = new TestProbe(system)
|
||||||
|
|
||||||
val j_mine = Deployables.Make(DeployedItem.jammer_mine)().asInstanceOf[ExplosiveDeployable] //guid=1
|
val mine = Deployables.Make(DeployedItem.he_mine)().asInstanceOf[ExplosiveDeployable] //guid=1
|
||||||
val avatar1 = Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute)
|
val avatar1 = Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute)
|
||||||
val player1 = Player(avatar1) //guid=3
|
val player1 = Player(avatar1) //guid=3
|
||||||
val avatar2 = Avatar(0, "TestCharacter2", PlanetSideEmpire.NC, CharacterSex.Male, 0, CharacterVoice.Mute)
|
val avatar2 = Avatar(0, "TestCharacter2", PlanetSideEmpire.NC, CharacterSex.Male, 0, CharacterVoice.Mute)
|
||||||
|
|
@ -335,17 +335,17 @@ class ExplosiveDeployableJammerTest extends ActorTest {
|
||||||
}
|
}
|
||||||
player1.Spawn()
|
player1.Spawn()
|
||||||
player2.Spawn()
|
player2.Spawn()
|
||||||
guid.register(j_mine, 1)
|
guid.register(mine, 1)
|
||||||
guid.register(player1, 3)
|
guid.register(player1, 3)
|
||||||
guid.register(player2, 4)
|
guid.register(player2, 4)
|
||||||
guid.register(weapon, 5)
|
guid.register(weapon, 5)
|
||||||
j_mine.Zone = zone
|
mine.Zone = zone
|
||||||
j_mine.OwnerGuid = player2
|
mine.OwnerGuid = player2
|
||||||
//j_mine.OwnerName = player2.Name
|
//j_mine.OwnerName = player2.Name
|
||||||
j_mine.Faction = PlanetSideEmpire.NC
|
mine.Faction = PlanetSideEmpire.NC
|
||||||
j_mine.Actor = system.actorOf(Props(classOf[MineDeployableControl], j_mine), "j-mine-control")
|
mine.Actor = system.actorOf(Props(classOf[MineDeployableControl], mine), "j-mine-control")
|
||||||
|
|
||||||
val jMineSource = SourceEntry(j_mine)
|
val jMineSource = SourceEntry(mine)
|
||||||
val pSource = PlayerSource(player1)
|
val pSource = PlayerSource(player1)
|
||||||
val projectile = weapon.Projectile
|
val projectile = weapon.Projectile
|
||||||
val resolved = DamageInteraction(
|
val resolved = DamageInteraction(
|
||||||
|
|
@ -353,7 +353,7 @@ class ExplosiveDeployableJammerTest extends ActorTest {
|
||||||
ProjectileReason(
|
ProjectileReason(
|
||||||
DamageResolution.Hit,
|
DamageResolution.Hit,
|
||||||
Projectile(projectile, weapon.Definition, weapon.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
|
Projectile(projectile, weapon.Definition, weapon.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
|
||||||
j_mine.DamageModel
|
mine.DamageModel
|
||||||
),
|
),
|
||||||
Vector3(1, 0, 0)
|
Vector3(1, 0, 0)
|
||||||
)
|
)
|
||||||
|
|
@ -361,26 +361,53 @@ class ExplosiveDeployableJammerTest extends ActorTest {
|
||||||
|
|
||||||
"ExplosiveDeployable" should {
|
"ExplosiveDeployable" should {
|
||||||
"handle being jammered appropriately (no detonation)" in {
|
"handle being jammered appropriately (no detonation)" in {
|
||||||
assert(!j_mine.Destroyed)
|
assert(!mine.Destroyed)
|
||||||
|
|
||||||
j_mine.Actor ! Vitality.Damage(applyDamageToJ)
|
mine.Actor ! Vitality.Damage(applyDamageToJ)
|
||||||
val eventMsgs = eventsProbe.receiveN(2, 200 milliseconds)
|
val eventMsgs = eventsProbe.receiveN(4, 200 milliseconds)
|
||||||
eventMsgs.head match {
|
eventMsgs.head match {
|
||||||
|
case Zone.HotSpot.Conflict(mineSrc, playerSrc, Vector3(1.0,0.0,0.0)) => ;
|
||||||
|
case _ => assert(false, "")
|
||||||
|
}
|
||||||
|
// eventMsgs.head match {
|
||||||
|
// case LocalServiceMessage(
|
||||||
|
// "NC",
|
||||||
|
// LocalAction.DeployableMapIcon(
|
||||||
|
// ValidPlanetSideGUID(0),
|
||||||
|
// DeploymentAction.Dismiss,
|
||||||
|
// DeployableInfo(ValidPlanetSideGUID(1), DeployableIcon.HEMine, Vector3.Zero, ValidPlanetSideGUID(0))
|
||||||
|
// )
|
||||||
|
// ) => ;
|
||||||
|
// case _ => assert(false, "")
|
||||||
|
// }
|
||||||
|
eventMsgs(1) match {
|
||||||
|
case LocalServiceMessage("test", LocalAction.Detonate(PlanetSideGUID(1), _)) => ;
|
||||||
|
case _ => assert(false, "")
|
||||||
|
}
|
||||||
|
eventMsgs(2) match {
|
||||||
case LocalServiceMessage(
|
case LocalServiceMessage(
|
||||||
"NC",
|
"NC",
|
||||||
LocalAction.DeployableMapIcon(
|
LocalAction.DeployableMapIcon(
|
||||||
ValidPlanetSideGUID(0),
|
ValidPlanetSideGUID(0),
|
||||||
DeploymentAction.Dismiss,
|
DeploymentAction.Dismiss,
|
||||||
DeployableInfo(ValidPlanetSideGUID(1), DeployableIcon.DisruptorMine, Vector3.Zero, ValidPlanetSideGUID(0))
|
DeployableInfo(ValidPlanetSideGUID(1), DeployableIcon.HEMine, Vector3.Zero, ValidPlanetSideGUID(0))
|
||||||
)
|
)
|
||||||
) => ;
|
) => ;
|
||||||
case _ => assert(false, "")
|
case _ => assert(false, "")
|
||||||
}
|
}
|
||||||
eventMsgs(1) match {
|
eventMsgs(3) match {
|
||||||
case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(1), _, Service.defaultPlayerGUID, _)) => ;
|
case AvatarServiceMessage(
|
||||||
|
"test",
|
||||||
|
AvatarAction.Destroy(
|
||||||
|
ValidPlanetSideGUID(1),
|
||||||
|
ValidPlanetSideGUID(3),
|
||||||
|
ValidPlanetSideGUID(0),
|
||||||
|
Vector3.Zero
|
||||||
|
)
|
||||||
|
) => ;
|
||||||
case _ => assert(false, "")
|
case _ => assert(false, "")
|
||||||
}
|
}
|
||||||
assert(j_mine.Destroyed)
|
assert(mine.Destroyed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,57 +65,59 @@ class DeploymentBehavior2Test extends ActorTest {
|
||||||
assert(obj.DeploymentState == DriveState.Mobile)
|
assert(obj.DeploymentState == DriveState.Mobile)
|
||||||
//to Deploying
|
//to Deploying
|
||||||
obj.Actor.tell(Deployment.TryDeploymentChange(DriveState.Deploying), probe.ref)
|
obj.Actor.tell(Deployment.TryDeploymentChange(DriveState.Deploying), probe.ref)
|
||||||
val reply1a = probe.receiveOne(Duration.create(500, "ms"))
|
val reply1 = probe.receiveN(2, Duration.create(2000, "ms"))
|
||||||
assert(reply1a match {
|
val reply2 = eventsProbe.receiveN(2, Duration.create(2000, "ms"))
|
||||||
case Deployment.CanDeploy(_, DriveState.Deploying) => true
|
reply1.head match {
|
||||||
case _ => false
|
case Deployment.CanDeploy(_, DriveState.Deploying) => ()
|
||||||
})
|
case _ => assert(false, "")
|
||||||
val reply1b = eventsProbe.receiveOne(Duration.create(500, "ms"))
|
}
|
||||||
assert(reply1b match {
|
reply2.head match {
|
||||||
case VehicleServiceMessage(
|
case VehicleServiceMessage(
|
||||||
"test",
|
"test",
|
||||||
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deploying, 0, false, Vector3.Zero)
|
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deploying, 0, false, Vector3.Zero)
|
||||||
) =>
|
) => ()
|
||||||
true
|
case _ => assert(false, "")
|
||||||
case _ => false
|
}
|
||||||
})
|
|
||||||
//to Deployed
|
//to Deployed
|
||||||
val reply2 = eventsProbe.receiveOne(Duration.create(500, "ms"))
|
reply1(1) match {
|
||||||
assert(reply2 match {
|
case Deployment.CanDeploy(_, DriveState.Deployed) => ()
|
||||||
|
case _ => assert(false, "")
|
||||||
|
}
|
||||||
|
reply2(1) match {
|
||||||
case VehicleServiceMessage(
|
case VehicleServiceMessage(
|
||||||
"test",
|
"test",
|
||||||
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deployed, 0, false, Vector3.Zero)
|
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deployed, 0, false, Vector3.Zero)
|
||||||
) =>
|
) => ()
|
||||||
true
|
case _ => assert(false, "")
|
||||||
case _ => false
|
}
|
||||||
})
|
|
||||||
assert(obj.DeploymentState == DriveState.Deployed)
|
assert(obj.DeploymentState == DriveState.Deployed)
|
||||||
//to Undeploying
|
//to Undeploying
|
||||||
obj.Actor.tell(Deployment.TryDeploymentChange(DriveState.Undeploying), probe.ref)
|
obj.Actor.tell(Deployment.TryDeploymentChange(DriveState.Undeploying), probe.ref)
|
||||||
val reply3a = probe.receiveOne(Duration.create(500, "ms"))
|
val reply3 = probe.receiveN(2, Duration.create(2000, "ms"))
|
||||||
assert(reply3a match {
|
val reply4 = eventsProbe.receiveN(2, Duration.create(2000, "ms"))
|
||||||
case Deployment.CanUndeploy(_, DriveState.Undeploying) => true
|
reply3.head match {
|
||||||
case _ => false
|
case Deployment.CanUndeploy(_, DriveState.Undeploying) => ()
|
||||||
})
|
case _ => assert(false, "")
|
||||||
val reply3b = eventsProbe.receiveOne(Duration.create(500, "ms"))
|
}
|
||||||
assert(reply3b match {
|
reply4.head match {
|
||||||
case VehicleServiceMessage(
|
case VehicleServiceMessage(
|
||||||
"test",
|
"test",
|
||||||
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Undeploying, 0, false, Vector3.Zero)
|
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Undeploying, 0, false, Vector3.Zero)
|
||||||
) =>
|
) => ()
|
||||||
true
|
case _ => assert(false, "")
|
||||||
case _ => false
|
}
|
||||||
})
|
|
||||||
//to Mobile
|
//to Mobile
|
||||||
val reply4 = eventsProbe.receiveOne(Duration.create(500, "ms"))
|
reply3(1) match {
|
||||||
assert(reply4 match {
|
case Deployment.CanUndeploy(_, DriveState.Mobile) => ()
|
||||||
|
case _ => assert(false, "")
|
||||||
|
}
|
||||||
|
reply4(1) match {
|
||||||
case VehicleServiceMessage(
|
case VehicleServiceMessage(
|
||||||
"test",
|
"test",
|
||||||
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Mobile, 0, false, Vector3.Zero)
|
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Mobile, 0, false, Vector3.Zero)
|
||||||
) =>
|
) => ()
|
||||||
true
|
case _ => assert(false, "")
|
||||||
case _ => false
|
}
|
||||||
})
|
|
||||||
assert(obj.DeploymentState == DriveState.Mobile)
|
assert(obj.DeploymentState == DriveState.Mobile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -131,57 +133,59 @@ class DeploymentBehavior3Test extends ActorTest {
|
||||||
assert(obj.DeploymentState == DriveState.Mobile)
|
assert(obj.DeploymentState == DriveState.Mobile)
|
||||||
//to Deploying
|
//to Deploying
|
||||||
obj.Actor.tell(Deployment.TryDeploy(DriveState.Deploying), probe.ref)
|
obj.Actor.tell(Deployment.TryDeploy(DriveState.Deploying), probe.ref)
|
||||||
val reply1a = probe.receiveOne(Duration.create(500, "ms"))
|
val reply1 = probe.receiveN(2, Duration.create(2000, "ms"))
|
||||||
assert(reply1a match {
|
val reply2 = eventsProbe.receiveN(2, Duration.create(2000, "ms"))
|
||||||
case Deployment.CanDeploy(_, DriveState.Deploying) => true
|
reply1.head match {
|
||||||
case _ => false
|
case Deployment.CanDeploy(_, DriveState.Deploying) => ()
|
||||||
})
|
case _ => assert(false, "")
|
||||||
val reply1b = eventsProbe.receiveOne(Duration.create(500, "ms"))
|
}
|
||||||
assert(reply1b match {
|
reply2.head match {
|
||||||
case VehicleServiceMessage(
|
case VehicleServiceMessage(
|
||||||
"test",
|
"test",
|
||||||
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deploying, 0, false, Vector3.Zero)
|
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deploying, 0, false, Vector3.Zero)
|
||||||
) =>
|
) => ()
|
||||||
true
|
case _ => assert(false, "")
|
||||||
case _ => false
|
}
|
||||||
})
|
|
||||||
//to Deployed
|
//to Deployed
|
||||||
val reply2 = eventsProbe.receiveOne(Duration.create(500, "ms"))
|
reply1(1) match {
|
||||||
assert(reply2 match {
|
case Deployment.CanDeploy(_, DriveState.Deployed) => ()
|
||||||
|
case _ => assert(false, "")
|
||||||
|
}
|
||||||
|
reply2(1) match {
|
||||||
case VehicleServiceMessage(
|
case VehicleServiceMessage(
|
||||||
"test",
|
"test",
|
||||||
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deployed, 0, false, Vector3.Zero)
|
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deployed, 0, false, Vector3.Zero)
|
||||||
) =>
|
) => ()
|
||||||
true
|
case _ => assert(false, "")
|
||||||
case _ => false
|
}
|
||||||
})
|
|
||||||
assert(obj.DeploymentState == DriveState.Deployed)
|
assert(obj.DeploymentState == DriveState.Deployed)
|
||||||
//to Undeploying
|
//to Undeploying
|
||||||
obj.Actor.tell(Deployment.TryUndeploy(DriveState.Undeploying), probe.ref)
|
obj.Actor.tell(Deployment.TryUndeploy(DriveState.Undeploying), probe.ref)
|
||||||
val reply3a = probe.receiveOne(Duration.create(500, "ms"))
|
val reply3 = probe.receiveN(2, Duration.create(2000, "ms"))
|
||||||
assert(reply3a match {
|
val reply4 = eventsProbe.receiveN(2, Duration.create(2000, "ms"))
|
||||||
case Deployment.CanUndeploy(_, DriveState.Undeploying) => true
|
reply3.head match {
|
||||||
case _ => false
|
case Deployment.CanUndeploy(_, DriveState.Undeploying) => ()
|
||||||
})
|
case _ => assert(false, "")
|
||||||
val reply3b = eventsProbe.receiveOne(Duration.create(500, "ms"))
|
}
|
||||||
assert(reply3b match {
|
reply4.head match {
|
||||||
case VehicleServiceMessage(
|
case VehicleServiceMessage(
|
||||||
"test",
|
"test",
|
||||||
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Undeploying, 0, false, Vector3.Zero)
|
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Undeploying, 0, false, Vector3.Zero)
|
||||||
) =>
|
) => ()
|
||||||
true
|
case _ => assert(false, "")
|
||||||
case _ => false
|
}
|
||||||
})
|
|
||||||
//to Mobile
|
//to Mobile
|
||||||
val reply4 = eventsProbe.receiveOne(Duration.create(500, "ms"))
|
reply3(1) match {
|
||||||
assert(reply4 match {
|
case Deployment.CanUndeploy(_, DriveState.Mobile) => ()
|
||||||
|
case _ => assert(false, "")
|
||||||
|
}
|
||||||
|
reply4(1) match {
|
||||||
case VehicleServiceMessage(
|
case VehicleServiceMessage(
|
||||||
"test",
|
"test",
|
||||||
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Mobile, 0, false, Vector3.Zero)
|
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Mobile, 0, false, Vector3.Zero)
|
||||||
) =>
|
) => ()
|
||||||
true
|
case _ => assert(false, "")
|
||||||
case _ => false
|
}
|
||||||
})
|
|
||||||
assert(obj.DeploymentState == DriveState.Mobile)
|
assert(obj.DeploymentState == DriveState.Mobile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -195,16 +199,18 @@ class DeploymentBehavior4Test extends ActorTest {
|
||||||
|
|
||||||
obj.Actor ! Deployment.TryDeploymentChange(DriveState.Deployed)
|
obj.Actor ! Deployment.TryDeploymentChange(DriveState.Deployed)
|
||||||
val reply1 = receiveOne(Duration.create(100, "ms"))
|
val reply1 = receiveOne(Duration.create(100, "ms"))
|
||||||
assert(reply1.isInstanceOf[Deployment.CanNotChangeDeployment])
|
reply1 match {
|
||||||
assert(reply1.asInstanceOf[Deployment.CanNotChangeDeployment].obj == obj)
|
case Deployment.CanNotChangeDeployment(_, DriveState.Deployed, _) => ()
|
||||||
assert(reply1.asInstanceOf[Deployment.CanNotChangeDeployment].to_state == DriveState.Deployed)
|
case _ => assert(false, "")
|
||||||
|
}
|
||||||
assert(obj.DeploymentState == DriveState.Mobile)
|
assert(obj.DeploymentState == DriveState.Mobile)
|
||||||
|
|
||||||
obj.Actor ! Deployment.TryDeploy(DriveState.Deployed)
|
obj.Actor ! Deployment.TryDeploy(DriveState.Deployed)
|
||||||
val reply2 = receiveOne(Duration.create(100, "ms"))
|
val reply2 = receiveOne(Duration.create(100, "ms"))
|
||||||
assert(reply2.isInstanceOf[Deployment.CanNotChangeDeployment])
|
reply2 match {
|
||||||
assert(reply2.asInstanceOf[Deployment.CanNotChangeDeployment].obj == obj)
|
case Deployment.CanNotChangeDeployment(_, DriveState.Deployed, _) => ()
|
||||||
assert(reply2.asInstanceOf[Deployment.CanNotChangeDeployment].to_state == DriveState.Deployed)
|
case _ => assert(false, "")
|
||||||
|
}
|
||||||
assert(obj.DeploymentState == DriveState.Mobile)
|
assert(obj.DeploymentState == DriveState.Mobile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -215,18 +221,22 @@ class DeploymentBehavior5Test extends ActorTest {
|
||||||
"not deploy to an undeploy state" in {
|
"not deploy to an undeploy state" in {
|
||||||
val obj = DeploymentTest.SetUpAgent
|
val obj = DeploymentTest.SetUpAgent
|
||||||
assert(obj.DeploymentState == DriveState.Mobile)
|
assert(obj.DeploymentState == DriveState.Mobile)
|
||||||
obj.Actor ! Deployment.TryDeploymentChange(DriveState.Deploying)
|
|
||||||
receiveOne(Duration.create(100, "ms")) //consume
|
obj.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying)
|
||||||
obj.Actor ! Deployment.TryDeploymentChange(DriveState.Deployed)
|
val reply1 = receiveOne(Duration.create(100, "ms"))
|
||||||
receiveOne(Duration.create(100, "ms")) //consume
|
reply1 match {
|
||||||
assert(obj.DeploymentState == DriveState.Deployed)
|
case Deployment.CanNotChangeDeployment(_, DriveState.Undeploying, _) => ()
|
||||||
|
case _ => assert(false, "")
|
||||||
|
}
|
||||||
|
assert(obj.DeploymentState == DriveState.Mobile)
|
||||||
|
|
||||||
obj.Actor ! Deployment.TryDeploy(DriveState.Undeploying)
|
obj.Actor ! Deployment.TryDeploy(DriveState.Undeploying)
|
||||||
val reply = receiveOne(Duration.create(100, "ms"))
|
val reply2 = receiveOne(Duration.create(100, "ms"))
|
||||||
assert(reply.isInstanceOf[Deployment.CanNotChangeDeployment])
|
reply2 match {
|
||||||
assert(reply.asInstanceOf[Deployment.CanNotChangeDeployment].obj == obj)
|
case Deployment.CanNotChangeDeployment(_, DriveState.Undeploying, _) => ()
|
||||||
assert(reply.asInstanceOf[Deployment.CanNotChangeDeployment].to_state == DriveState.Undeploying)
|
case _ => assert(false, "")
|
||||||
assert(obj.DeploymentState == DriveState.Deployed)
|
}
|
||||||
|
assert(obj.DeploymentState == DriveState.Mobile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -235,14 +245,24 @@ class DeploymentBehavior6Test extends ActorTest {
|
||||||
"Deployment" should {
|
"Deployment" should {
|
||||||
"not undeploy to a deploy state" in {
|
"not undeploy to a deploy state" in {
|
||||||
val obj = DeploymentTest.SetUpAgent
|
val obj = DeploymentTest.SetUpAgent
|
||||||
assert(obj.DeploymentState == DriveState.Mobile)
|
obj.DeploymentState = DriveState.Deployed
|
||||||
|
assert(obj.DeploymentState == DriveState.Deployed)
|
||||||
|
|
||||||
|
obj.Actor ! Deployment.TryDeploymentChange(DriveState.Deploying)
|
||||||
|
val reply1 = receiveOne(Duration.create(100, "ms"))
|
||||||
|
reply1 match {
|
||||||
|
case Deployment.CanNotChangeDeployment(_, DriveState.Deploying, _) => ()
|
||||||
|
case _ => assert(false, "")
|
||||||
|
}
|
||||||
|
assert(obj.DeploymentState == DriveState.Deployed)
|
||||||
|
|
||||||
obj.Actor ! Deployment.TryUndeploy(DriveState.Deploying)
|
obj.Actor ! Deployment.TryUndeploy(DriveState.Deploying)
|
||||||
val reply = receiveOne(Duration.create(100, "ms"))
|
val reply2 = receiveOne(Duration.create(100, "ms"))
|
||||||
assert(reply.isInstanceOf[Deployment.CanNotChangeDeployment])
|
reply2 match {
|
||||||
assert(reply.asInstanceOf[Deployment.CanNotChangeDeployment].obj == obj)
|
case Deployment.CanNotChangeDeployment(_, DriveState.Deploying, _) => ()
|
||||||
assert(reply.asInstanceOf[Deployment.CanNotChangeDeployment].to_state == DriveState.Deploying)
|
case _ => assert(false, "")
|
||||||
assert(obj.DeploymentState == DriveState.Mobile)
|
}
|
||||||
|
assert(obj.DeploymentState == DriveState.Deployed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,9 @@ import net.psforever.types.{CharacterSex, CharacterVoice, PlanetSideEmpire, Plan
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
class InteractsWithZoneEnvironmentTest extends ActorTest {
|
class InteractsWithZoneEnvironmentTest extends ActorTest {
|
||||||
val pool1: Pool = Pool(EnvironmentAttribute.Water, DeepSquare(5, 10, 10, 0, 0))
|
val pool1: Pool = Pool(EnvironmentAttribute.Water, DeepSquare(3, 2, 2, 0, 0))
|
||||||
val pool2: Pool = Pool(EnvironmentAttribute.Water, DeepSquare(5, 10, 15, 5, 10))
|
val pool2: Pool = Pool(EnvironmentAttribute.Water, DeepSquare(3, 4, 2, 2, 0))
|
||||||
val pool3: Pool = Pool(EnvironmentAttribute.Lava, DeepSquare(5, 15, 10, 10, 5))
|
val pool3: Pool = Pool(EnvironmentAttribute.Lava, DeepSquare(3, 2, 4, 0, 2))
|
||||||
val zoneEvents: TestProbe = TestProbe()
|
val zoneEvents: TestProbe = TestProbe()
|
||||||
val testZone: Zone = {
|
val testZone: Zone = {
|
||||||
val testMap = new ZoneMap(name = "test-map") {
|
val testMap = new ZoneMap(name = "test-map") {
|
||||||
|
|
@ -38,27 +38,26 @@ class InteractsWithZoneEnvironmentTest extends ActorTest {
|
||||||
val obj = InteractsWithZoneEnvironmentTest.testObject()
|
val obj = InteractsWithZoneEnvironmentTest.testObject()
|
||||||
obj.Zone = testZone
|
obj.Zone = testZone
|
||||||
obj.Actor = testProbe.ref
|
obj.Actor = testProbe.ref
|
||||||
obj.Position = Vector3(0,0,50)
|
obj.Position = Vector3(10,10,0)
|
||||||
|
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
testProbe.expectNoMessage(max = 500 milliseconds)
|
testProbe.expectNoMessage(max = 500 milliseconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
"acknowledge interaction when moved into the critical region of a registered environment object (just once)" in {
|
"acknowledge interaction when moved into the critical region of a registered environment object" in {
|
||||||
val testProbe = TestProbe()
|
val testProbe = TestProbe()
|
||||||
val obj = InteractsWithZoneEnvironmentTest.testObject()
|
val obj = InteractsWithZoneEnvironmentTest.testObject()
|
||||||
obj.Zone = testZone
|
obj.Zone = testZone
|
||||||
obj.Actor = testProbe.ref
|
obj.Actor = testProbe.ref
|
||||||
|
|
||||||
obj.Position = Vector3(1,1,2)
|
obj.Position = Vector3(1, 1, 2.7f)
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
val msg = testProbe.receiveOne(max = 250 milliseconds)
|
val msg = testProbe.receiveOne(4.seconds)
|
||||||
assert(
|
msg match {
|
||||||
msg match {
|
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => ()
|
||||||
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => true
|
case _ => assert(InteractsWithZoneEnvironmentTest.fail, s"$msg")
|
||||||
case _ => false
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
testProbe.expectNoMessage(max = 500 milliseconds)
|
testProbe.expectNoMessage(max = 500 milliseconds)
|
||||||
}
|
}
|
||||||
|
|
@ -69,54 +68,48 @@ class InteractsWithZoneEnvironmentTest extends ActorTest {
|
||||||
obj.Zone = testZone
|
obj.Zone = testZone
|
||||||
obj.Actor = testProbe.ref
|
obj.Actor = testProbe.ref
|
||||||
|
|
||||||
obj.Position = Vector3(1,1,2)
|
obj.Position = Vector3(1, 1, 2.7f)
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
val msg1 = testProbe.receiveOne(max = 250 milliseconds)
|
val msg1 = testProbe.receiveOne(4.seconds)
|
||||||
assert(
|
msg1 match {
|
||||||
msg1 match {
|
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => ()
|
||||||
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => true
|
case _ => assert(InteractsWithZoneEnvironmentTest.fail, "")
|
||||||
case _ => false
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
obj.Position = Vector3(1,1,50)
|
obj.Position = Vector3(1,1,5)
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
val msg2 = testProbe.receiveOne(max = 250 milliseconds)
|
val msg2 = testProbe.receiveOne(4.seconds)
|
||||||
assert(
|
msg2 match {
|
||||||
msg2 match {
|
case RespondsToZoneEnvironment.StopTimer(EnvironmentAttribute.Water) => ()
|
||||||
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => true
|
case _ => assert(InteractsWithZoneEnvironmentTest.fail, "")
|
||||||
case _ => false
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
testProbe.expectNoMessage(max = 500 milliseconds)
|
testProbe.expectNoMessage(max = 500 milliseconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
"transition between two different critical regions when the regions that the same attribute" in {
|
"transition between two different critical regions when the regions have the same attribute" in {
|
||||||
val testProbe = TestProbe()
|
val testProbe = TestProbe()
|
||||||
val obj = InteractsWithZoneEnvironmentTest.testObject()
|
val obj = InteractsWithZoneEnvironmentTest.testObject()
|
||||||
obj.Zone = testZone
|
obj.Zone = testZone
|
||||||
obj.Actor = testProbe.ref
|
obj.Actor = testProbe.ref
|
||||||
|
|
||||||
obj.Position = Vector3(7,7,2)
|
obj.Position = Vector3(1, 1, 2.7f)
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
val msg1 = testProbe.receiveOne(max = 250 milliseconds)
|
val msg1 = testProbe.receiveOne(4.seconds)
|
||||||
assert(
|
msg1 match {
|
||||||
msg1 match {
|
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => ()
|
||||||
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => true
|
case _ => assert(InteractsWithZoneEnvironmentTest.fail, "")
|
||||||
case _ => false
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
obj.Position = Vector3(12,7,2)
|
obj.Position = Vector3(1, 3, 2.7f)
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
val msg2 = testProbe.receiveOne(max = 250 milliseconds)
|
val msg2 = testProbe.receiveOne(4.seconds)
|
||||||
assert(
|
msg2 match {
|
||||||
msg2 match {
|
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => ()
|
||||||
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => true
|
case _ => assert(false, "")
|
||||||
case _ => false
|
}
|
||||||
}
|
testProbe.expectNoMessage()
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"transition between two different critical regions when the regions have different attributes" in {
|
"transition between two different critical regions when the regions have different attributes" in {
|
||||||
|
|
@ -125,37 +118,33 @@ class InteractsWithZoneEnvironmentTest extends ActorTest {
|
||||||
obj.Zone = testZone
|
obj.Zone = testZone
|
||||||
obj.Actor = testProbe.ref
|
obj.Actor = testProbe.ref
|
||||||
|
|
||||||
obj.Position = Vector3(7,7,2)
|
obj.Position = Vector3(1, 1, 2.7f)
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
val msg1 = testProbe.receiveOne(max = 250 milliseconds)
|
val msg1 = testProbe.receiveOne(4.seconds)
|
||||||
assert(
|
msg1 match {
|
||||||
msg1 match {
|
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => ()
|
||||||
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => true
|
case _ => assert(InteractsWithZoneEnvironmentTest.fail, "")
|
||||||
case _ => false
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
obj.Position = Vector3(7,12,2)
|
obj.Position = Vector3(3, 1, 2.7f)
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
val msgs = testProbe.receiveN(3, max = 250 milliseconds)
|
val msgs = testProbe.receiveN(4, 4.seconds)
|
||||||
assert(
|
msgs.head match {
|
||||||
msgs.head match {
|
case RespondsToZoneEnvironment.StopTimer(EnvironmentAttribute.Water) => ()
|
||||||
case Vitality.Damage(_) => true
|
case _ => assert(InteractsWithZoneEnvironmentTest.fail, "")
|
||||||
case _ => false
|
}
|
||||||
}
|
msgs(1) match {
|
||||||
)
|
case Vitality.Damage(_) => ()
|
||||||
assert(
|
case _ => assert(InteractsWithZoneEnvironmentTest.fail, "")
|
||||||
msgs(1) match {
|
}
|
||||||
case AuraEffectBehavior.StartEffect(Aura.Fire, _) => true
|
msgs(2) match {
|
||||||
case _ => false
|
case AuraEffectBehavior.StartEffect(Aura.Fire, _) => ()
|
||||||
}
|
case _ => assert(InteractsWithZoneEnvironmentTest.fail, "")
|
||||||
)
|
}
|
||||||
assert(
|
msgs(3) match {
|
||||||
msgs(2) match {
|
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Lava, _, _, _) => ()
|
||||||
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Lava, _, _, _) => true
|
case _ => assert(InteractsWithZoneEnvironmentTest.fail, "")
|
||||||
case _ => false
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,24 +154,21 @@ class InteractsWithZoneEnvironmentTest extends ActorTest {
|
||||||
obj.Zone = testZone
|
obj.Zone = testZone
|
||||||
obj.Actor = testProbe.ref
|
obj.Actor = testProbe.ref
|
||||||
|
|
||||||
obj.Position = Vector3(1,1,2)
|
obj.Position = Vector3(1, 1, 2.7f)
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
val msg1 = testProbe.receiveOne(max = 250 milliseconds)
|
val msg1 = testProbe.receiveOne(max = 250 milliseconds)
|
||||||
assert(
|
msg1 match {
|
||||||
msg1 match {
|
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => true
|
||||||
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => true
|
case _ => assert(InteractsWithZoneEnvironmentTest.fail, "")
|
||||||
case _ => false
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
obj.allowInteraction = false
|
obj.allowInteraction = false
|
||||||
val msg2 = testProbe.receiveOne(max = 250 milliseconds)
|
val msg2 = testProbe.receiveOne(max = 250 milliseconds)
|
||||||
assert(
|
msg2 match {
|
||||||
msg2 match {
|
case RespondsToZoneEnvironment.StopTimer(EnvironmentAttribute.Water) => true
|
||||||
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => true
|
case _ => assert(InteractsWithZoneEnvironmentTest.fail, "")
|
||||||
case _ => false
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
testProbe.expectNoMessage(max = 500 milliseconds)
|
testProbe.expectNoMessage(max = 500 milliseconds)
|
||||||
}
|
}
|
||||||
|
|
@ -194,22 +180,22 @@ class InteractsWithZoneEnvironmentTest extends ActorTest {
|
||||||
obj.Actor = testProbe.ref
|
obj.Actor = testProbe.ref
|
||||||
|
|
||||||
obj.allowInteraction = false
|
obj.allowInteraction = false
|
||||||
obj.Position = Vector3(1,1,2)
|
obj.Position = Vector3(1, 1, 2.7f)
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
testProbe.expectNoMessage(max = 500 milliseconds)
|
testProbe.expectNoMessage(max = 500 milliseconds)
|
||||||
|
|
||||||
obj.allowInteraction = true
|
obj.allowInteraction = true
|
||||||
val msg1 = testProbe.receiveOne(max = 250 milliseconds)
|
val msg1 = testProbe.receiveOne(max = 250 milliseconds)
|
||||||
assert(
|
msg1 match {
|
||||||
msg1 match {
|
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => true
|
||||||
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => true
|
case _ => assert(InteractsWithZoneEnvironmentTest.fail, "")
|
||||||
case _ => false
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object InteractsWithZoneEnvironmentTest {
|
object InteractsWithZoneEnvironmentTest {
|
||||||
|
val fail: Boolean = false
|
||||||
|
|
||||||
def testObject(): PlanetSideServerObject with InteractsWithZone = {
|
def testObject(): PlanetSideServerObject with InteractsWithZone = {
|
||||||
val p = new Player(Avatar(1, "test", PlanetSideEmpire.VS, CharacterSex.Male, 1, CharacterVoice.Mute))
|
val p = new Player(Avatar(1, "test", PlanetSideEmpire.VS, CharacterSex.Male, 1, CharacterVoice.Mute))
|
||||||
p.GUID = PlanetSideGUID(1)
|
p.GUID = PlanetSideGUID(1)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package objects
|
package objects
|
||||||
|
|
||||||
import akka.actor.Props
|
import akka.actor.{ActorRef, Props}
|
||||||
import akka.testkit.TestProbe
|
import akka.testkit.TestProbe
|
||||||
import base.{ActorTest, FreedContextActorTest}
|
import base.{ActorTest, FreedContextActorTest}
|
||||||
import net.psforever.actors.zone.BuildingActor
|
import net.psforever.actors.zone.BuildingActor
|
||||||
|
|
@ -63,7 +63,7 @@ class ResourceSiloTest extends Specification {
|
||||||
PlanetSideGUID(0),
|
PlanetSideGUID(0),
|
||||||
PlanetSideGUID(2),
|
PlanetSideGUID(2),
|
||||||
0L,
|
0L,
|
||||||
false,
|
unk3 = false,
|
||||||
Vector3(0f, 0f, 0f),
|
Vector3(0f, 0f, 0f),
|
||||||
Vector3(0f, 0f, 0f),
|
Vector3(0f, 0f, 0f),
|
||||||
0,
|
0,
|
||||||
|
|
@ -77,11 +77,11 @@ class ResourceSiloTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResourceSiloControlStartupTest extends ActorTest {
|
class ResourceSiloControlStartupTest extends ActorTest {
|
||||||
val obj = ResourceSilo()
|
val obj: ResourceSilo = ResourceSilo()
|
||||||
obj.GUID = PlanetSideGUID(1)
|
obj.GUID = PlanetSideGUID(1)
|
||||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||||
val buildingEvents = TestProbe("test-building-events")
|
val buildingEvents: TestProbe = TestProbe("test-building-events")
|
||||||
obj.Owner =
|
obj.Owner =
|
||||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
|
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
|
||||||
Actor = buildingEvents.ref
|
Actor = buildingEvents.ref
|
||||||
|
|
@ -97,11 +97,11 @@ class ResourceSiloControlStartupTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResourceSiloControlStartupMessageNoneTest extends ActorTest {
|
class ResourceSiloControlStartupMessageNoneTest extends ActorTest {
|
||||||
val obj = ResourceSilo()
|
val obj: ResourceSilo = ResourceSilo()
|
||||||
obj.GUID = PlanetSideGUID(1)
|
obj.GUID = PlanetSideGUID(1)
|
||||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||||
val buildingEvents = TestProbe("test-building-events")
|
val buildingEvents: TestProbe = TestProbe("test-building-events")
|
||||||
obj.Owner =
|
obj.Owner =
|
||||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
|
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
|
||||||
Actor = buildingEvents.ref
|
Actor = buildingEvents.ref
|
||||||
|
|
@ -123,11 +123,11 @@ class ResourceSiloControlStartupMessageNoneTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResourceSiloControlStartupMessageSomeTest extends ActorTest {
|
class ResourceSiloControlStartupMessageSomeTest extends ActorTest {
|
||||||
val obj = ResourceSilo()
|
val obj: ResourceSilo = ResourceSilo()
|
||||||
obj.GUID = PlanetSideGUID(1)
|
obj.GUID = PlanetSideGUID(1)
|
||||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||||
val buildingEvents = TestProbe("test-building-events")
|
val buildingEvents: TestProbe = TestProbe("test-building-events")
|
||||||
obj.Owner =
|
obj.Owner =
|
||||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
|
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
|
||||||
Actor = buildingEvents.ref
|
Actor = buildingEvents.ref
|
||||||
|
|
@ -154,19 +154,19 @@ class ResourceSiloControlUseTest extends FreedContextActorTest {
|
||||||
expectNoMessage(1000 milliseconds)
|
expectNoMessage(1000 milliseconds)
|
||||||
var buildingMap = new TrieMap[Int, Building]()
|
var buildingMap = new TrieMap[Int, Building]()
|
||||||
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||||
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute))
|
val player: Player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute))
|
||||||
val ant = Vehicle(GlobalDefinitions.ant)
|
val ant: Vehicle = Vehicle(GlobalDefinitions.ant)
|
||||||
val silo = new ResourceSilo()
|
val silo = new ResourceSilo()
|
||||||
val catchall = new TestProbe(system).ref
|
val catchall: ActorRef = new TestProbe(system).ref
|
||||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) {
|
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
|
||||||
override def SetupNumberPools() = {}
|
override def SetupNumberPools(): Unit = {}
|
||||||
GUID(guid)
|
GUID(guid)
|
||||||
override def AvatarEvents = catchall
|
override def AvatarEvents: ActorRef = catchall
|
||||||
override def LocalEvents = catchall
|
override def LocalEvents: ActorRef = catchall
|
||||||
override def VehicleEvents = catchall
|
override def VehicleEvents: ActorRef = catchall
|
||||||
override def Activity = catchall
|
override def Activity: ActorRef = catchall
|
||||||
override def Vehicles = List(ant)
|
override def Vehicles: List[Vehicle] = List(ant)
|
||||||
override def Buildings = { buildingMap.toMap }
|
override def Buildings: Map[Int, Building] = { buildingMap.toMap }
|
||||||
}
|
}
|
||||||
val building = new Building(
|
val building = new Building(
|
||||||
name = "integ-fac-test-building",
|
name = "integ-fac-test-building",
|
||||||
|
|
@ -186,7 +186,7 @@ class ResourceSiloControlUseTest extends FreedContextActorTest {
|
||||||
guid.register(silo, number = 5)
|
guid.register(silo, number = 5)
|
||||||
guid.register(building, number = 6)
|
guid.register(building, number = 6)
|
||||||
|
|
||||||
val maxNtuCap = ant.Definition.MaxNtuCapacitor
|
val maxNtuCap: Float = ant.Definition.MaxNtuCapacitor
|
||||||
player.Spawn()
|
player.Spawn()
|
||||||
ant.NtuCapacitor = maxNtuCap
|
ant.NtuCapacitor = maxNtuCap
|
||||||
val probe = new TestProbe(system)
|
val probe = new TestProbe(system)
|
||||||
|
|
@ -201,19 +201,18 @@ class ResourceSiloControlUseTest extends FreedContextActorTest {
|
||||||
"Resource silo" should {
|
"Resource silo" should {
|
||||||
"respond when being used" in {
|
"respond when being used" in {
|
||||||
expectNoMessage(1 seconds)
|
expectNoMessage(1 seconds)
|
||||||
silo.Actor ! CommonMessages.Use(ResourceSiloTest.player)
|
silo.Actor ! CommonMessages.Use(ResourceSiloTest.player, Some(ant))
|
||||||
|
val reply = probe.receiveOne(3000 milliseconds)
|
||||||
val reply = probe.receiveOne(2000 milliseconds)
|
reply match {
|
||||||
assert(reply match {
|
case TransferBehavior.Discharging(Ntu.Nanites) => ()
|
||||||
case TransferBehavior.Discharging(Ntu.Nanites) => true
|
case _ => assert(ResourceSiloTest.fail, "")
|
||||||
case _ => false
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResourceSiloControlNtuWarningTest extends ActorTest {
|
class ResourceSiloControlNtuWarningTest extends ActorTest {
|
||||||
val obj = ResourceSilo()
|
val obj: ResourceSilo = ResourceSilo()
|
||||||
obj.GUID = PlanetSideGUID(1)
|
obj.GUID = PlanetSideGUID(1)
|
||||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||||
|
|
@ -223,7 +222,7 @@ class ResourceSiloControlNtuWarningTest extends ActorTest {
|
||||||
}
|
}
|
||||||
obj.Owner.GUID = PlanetSideGUID(6)
|
obj.Owner.GUID = PlanetSideGUID(6)
|
||||||
|
|
||||||
val zoneEvents = TestProbe("zone-events")
|
val zoneEvents: TestProbe = TestProbe("zone-events")
|
||||||
zone.AvatarEvents = zoneEvents.ref
|
zone.AvatarEvents = zoneEvents.ref
|
||||||
obj.Actor ! Service.Startup()
|
obj.Actor ! Service.Startup()
|
||||||
obj.Actor ! ResourceSilo.UpdateChargeLevel(-obj.NtuCapacitor)
|
obj.Actor ! ResourceSilo.UpdateChargeLevel(-obj.NtuCapacitor)
|
||||||
|
|
@ -237,7 +236,7 @@ class ResourceSiloControlNtuWarningTest extends ActorTest {
|
||||||
val reply = zoneEvents.receiveOne(5000 milliseconds)
|
val reply = zoneEvents.receiveOne(5000 milliseconds)
|
||||||
reply match {
|
reply match {
|
||||||
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => ;
|
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => ;
|
||||||
case _ => assert(false, s"$reply is wrong")
|
case _ => assert(ResourceSiloTest.fail, s"$reply is wrong")
|
||||||
}
|
}
|
||||||
assert(!obj.LowNtuWarningOn)
|
assert(!obj.LowNtuWarningOn)
|
||||||
}
|
}
|
||||||
|
|
@ -245,7 +244,7 @@ class ResourceSiloControlNtuWarningTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResourceSiloControlUpdate1Test extends ActorTest {
|
class ResourceSiloControlUpdate1Test extends ActorTest {
|
||||||
val obj = ResourceSilo()
|
val obj: ResourceSilo = ResourceSilo()
|
||||||
obj.GUID = PlanetSideGUID(1)
|
obj.GUID = PlanetSideGUID(1)
|
||||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||||
|
|
@ -253,8 +252,8 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
|
||||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
||||||
bldg.GUID = PlanetSideGUID(6)
|
bldg.GUID = PlanetSideGUID(6)
|
||||||
obj.Owner = bldg
|
obj.Owner = bldg
|
||||||
val zoneEvents = TestProbe("zone-events")
|
val zoneEvents: TestProbe = TestProbe("zone-events")
|
||||||
val buildingEvents = TestProbe("building-events")
|
val buildingEvents: TestProbe = TestProbe("building-events")
|
||||||
zone.AvatarEvents = zoneEvents.ref
|
zone.AvatarEvents = zoneEvents.ref
|
||||||
bldg.Actor = buildingEvents.ref
|
bldg.Actor = buildingEvents.ref
|
||||||
obj.Actor ! Service.Startup()
|
obj.Actor ! Service.Startup()
|
||||||
|
|
@ -276,12 +275,12 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
|
||||||
assert(obj.CapacitorDisplay == 3)
|
assert(obj.CapacitorDisplay == 3)
|
||||||
reply1.head match {
|
reply1.head match {
|
||||||
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(1), 45, 3)) => ;
|
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(1), 45, 3)) => ;
|
||||||
case _ => assert(false, s"$reply1 is wrong")
|
case _ => assert(ResourceSiloTest.fail, s"$reply1 is wrong")
|
||||||
}
|
}
|
||||||
assert(reply2.isInstanceOf[BuildingActor.MapUpdate], s"$reply2 is wrong")
|
assert(reply2.isInstanceOf[BuildingActor.MapUpdate], s"$reply2 is wrong")
|
||||||
reply1(1) match {
|
reply1(1) match {
|
||||||
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => ;
|
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => ;
|
||||||
case _ => assert(false, s"${reply1(1)} is wrong")
|
case _ => assert(ResourceSiloTest.fail, s"${reply1(1)} is wrong")
|
||||||
}
|
}
|
||||||
assert(!obj.LowNtuWarningOn)
|
assert(!obj.LowNtuWarningOn)
|
||||||
}
|
}
|
||||||
|
|
@ -289,7 +288,7 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResourceSiloControlUpdate2Test extends ActorTest {
|
class ResourceSiloControlUpdate2Test extends ActorTest {
|
||||||
val obj = ResourceSilo()
|
val obj: ResourceSilo = ResourceSilo()
|
||||||
obj.GUID = PlanetSideGUID(1)
|
obj.GUID = PlanetSideGUID(1)
|
||||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||||
|
|
@ -297,8 +296,8 @@ class ResourceSiloControlUpdate2Test extends ActorTest {
|
||||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
||||||
bldg.GUID = PlanetSideGUID(6)
|
bldg.GUID = PlanetSideGUID(6)
|
||||||
obj.Owner = bldg
|
obj.Owner = bldg
|
||||||
val zoneEvents = TestProbe("zone-events")
|
val zoneEvents: TestProbe = TestProbe("zone-events")
|
||||||
val buildingEvents = TestProbe("building-events")
|
val buildingEvents: TestProbe = TestProbe("building-events")
|
||||||
zone.AvatarEvents = zoneEvents.ref
|
zone.AvatarEvents = zoneEvents.ref
|
||||||
bldg.Actor = buildingEvents.ref
|
bldg.Actor = buildingEvents.ref
|
||||||
obj.Actor ! Service.Startup()
|
obj.Actor ! Service.Startup()
|
||||||
|
|
@ -320,12 +319,12 @@ class ResourceSiloControlUpdate2Test extends ActorTest {
|
||||||
assert(obj.CapacitorDisplay == 2)
|
assert(obj.CapacitorDisplay == 2)
|
||||||
reply1.head match {
|
reply1.head match {
|
||||||
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(1), 45, 2)) => ;
|
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(1), 45, 2)) => ;
|
||||||
case _ => assert(false, s"$reply1 is wrong")
|
case _ => assert(ResourceSiloTest.fail, s"$reply1 is wrong")
|
||||||
}
|
}
|
||||||
assert(reply2.isInstanceOf[BuildingActor.MapUpdate])
|
assert(reply2.isInstanceOf[BuildingActor.MapUpdate])
|
||||||
reply1(1) match {
|
reply1(1) match {
|
||||||
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => ;
|
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => ;
|
||||||
case _ => assert(false, s"${reply1(1)} is wrong")
|
case _ => assert(ResourceSiloTest.fail, s"${reply1(1)} is wrong")
|
||||||
}
|
}
|
||||||
assert(!obj.LowNtuWarningOn)
|
assert(!obj.LowNtuWarningOn)
|
||||||
}
|
}
|
||||||
|
|
@ -333,7 +332,7 @@ class ResourceSiloControlUpdate2Test extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResourceSiloControlNoUpdateTest extends ActorTest {
|
class ResourceSiloControlNoUpdateTest extends ActorTest {
|
||||||
val obj = ResourceSilo()
|
val obj: ResourceSilo = ResourceSilo()
|
||||||
obj.GUID = PlanetSideGUID(1)
|
obj.GUID = PlanetSideGUID(1)
|
||||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||||
|
|
@ -341,8 +340,8 @@ class ResourceSiloControlNoUpdateTest extends ActorTest {
|
||||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
||||||
bldg.GUID = PlanetSideGUID(6)
|
bldg.GUID = PlanetSideGUID(6)
|
||||||
obj.Owner = bldg
|
obj.Owner = bldg
|
||||||
val zoneEvents = TestProbe("zone-events")
|
val zoneEvents: TestProbe = TestProbe("zone-events")
|
||||||
val buildingEvents = TestProbe("building-events")
|
val buildingEvents: TestProbe = TestProbe("building-events")
|
||||||
zone.AvatarEvents = zoneEvents.ref
|
zone.AvatarEvents = zoneEvents.ref
|
||||||
bldg.Actor = buildingEvents.ref
|
bldg.Actor = buildingEvents.ref
|
||||||
obj.Actor ! Service.Startup()
|
obj.Actor ! Service.Startup()
|
||||||
|
|
@ -371,7 +370,9 @@ class ResourceSiloControlNoUpdateTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
object ResourceSiloTest {
|
object ResourceSiloTest {
|
||||||
val player = Player(
|
val player: Player = Player(
|
||||||
Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute).copy(stamina = 0)
|
Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute).copy(stamina = 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val fail: Boolean = false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import net.psforever.objects.vehicles.{Utility, UtilityType}
|
||||||
import net.psforever.objects.zones.{Zone, ZoneDeployableActor, ZoneMap}
|
import net.psforever.objects.zones.{Zone, ZoneDeployableActor, ZoneMap}
|
||||||
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
|
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
|
||||||
import net.psforever.packet.game._
|
import net.psforever.packet.game._
|
||||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
|
||||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
import net.psforever.types.{DriveState, PlanetSideGUID, Vector3}
|
import net.psforever.types.{DriveState, PlanetSideGUID, Vector3}
|
||||||
|
|
||||||
|
|
@ -253,7 +252,7 @@ class TelepadDeployableResponseFromRouterTest extends FreedContextActorTest {
|
||||||
val deploymentProbe = new TestProbe(system)
|
val deploymentProbe = new TestProbe(system)
|
||||||
router.Actor.tell(Deployment.TryDeploy(DriveState.Deploying), deploymentProbe.ref)
|
router.Actor.tell(Deployment.TryDeploy(DriveState.Deploying), deploymentProbe.ref)
|
||||||
eventsProbe.receiveN(10, 10.seconds) //flush all messages related to deployment
|
eventsProbe.receiveN(10, 10.seconds) //flush all messages related to deployment
|
||||||
deploymentProbe.receiveOne(2.seconds) //CanDeploy
|
deploymentProbe.receiveN(2, 10.seconds) //CanDeploy
|
||||||
deploymentProbe.expectNoMessage(2.seconds) //intentional delay
|
deploymentProbe.expectNoMessage(2.seconds) //intentional delay
|
||||||
assert(internal.Active, "link to router test - router internals not active when expected")
|
assert(internal.Active, "link to router test - router internals not active when expected")
|
||||||
assert(!telepad.Active, "link to router test - telepad active earlier than intended (2)")
|
assert(!telepad.Active, "link to router test - telepad active earlier than intended (2)")
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,17 @@ import net.psforever.objects.guid.NumberPoolHub
|
||||||
import net.psforever.objects.guid.source.MaxNumberSource
|
import net.psforever.objects.guid.source.MaxNumberSource
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
import net.psforever.objects.serverobject.CommonMessages
|
||||||
import net.psforever.objects.serverobject.environment._
|
import net.psforever.objects.serverobject.environment._
|
||||||
import net.psforever.objects.serverobject.environment.interaction.{EscapeFromEnvironment, InteractingWithEnvironment, RespondsToZoneEnvironment}
|
import net.psforever.objects.serverobject.environment.interaction.{InteractingWithEnvironment, RespondsToZoneEnvironment}
|
||||||
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
||||||
import net.psforever.objects.serverobject.mount.Mountable
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
import net.psforever.objects.sourcing.VehicleSource
|
import net.psforever.objects.sourcing.VehicleSource
|
||||||
import net.psforever.objects.vehicles.VehicleLockState
|
import net.psforever.objects.vehicles.VehicleLockState
|
||||||
import net.psforever.objects.vehicles.control.VehicleControl
|
import net.psforever.objects.vehicles.control.VehicleControl
|
||||||
|
import net.psforever.objects.vehicles.interaction.WithWater
|
||||||
import net.psforever.objects.vital.{ShieldCharge, SpawningActivity, Vitality}
|
import net.psforever.objects.vital.{ShieldCharge, SpawningActivity, Vitality}
|
||||||
import net.psforever.objects.zones.{Zone, ZoneMap}
|
import net.psforever.objects.zones.{Zone, ZoneMap}
|
||||||
import net.psforever.packet.game._
|
import net.psforever.packet.game._
|
||||||
import net.psforever.services.ServiceManager
|
import net.psforever.services.ServiceManager
|
||||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
|
||||||
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
|
|
||||||
|
|
@ -174,15 +174,17 @@ class VehicleControlPrepareForDeletionPassengerTest extends ActorTest {
|
||||||
//}
|
//}
|
||||||
|
|
||||||
class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActorTest {
|
class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActorTest {
|
||||||
val vehicleProbe = new TestProbe(system)
|
val eventsProbe = new TestProbe(system)
|
||||||
val catchall = new TestProbe(system)
|
val cargoProbe = new TestProbe(system)
|
||||||
val guid = new NumberPoolHub(new MaxNumberSource(10))
|
val guid = new NumberPoolHub(new MaxNumberSource(10))
|
||||||
ServiceManager.boot
|
ServiceManager.boot
|
||||||
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
GUID(guid)
|
GUID(guid)
|
||||||
|
|
||||||
override def SetupNumberPools(): Unit = {}
|
override def SetupNumberPools(): Unit = {}
|
||||||
override def VehicleEvents = vehicleProbe.ref
|
override def AvatarEvents = eventsProbe.ref
|
||||||
|
override def LocalEvents = eventsProbe.ref
|
||||||
|
override def VehicleEvents = eventsProbe.ref
|
||||||
}
|
}
|
||||||
zone.actor = system.spawn(ZoneActor(zone), "test-zone-actor")
|
zone.actor = system.spawn(ZoneActor(zone), "test-zone-actor")
|
||||||
// crappy workaround but without it the zone doesn't get initialized in time
|
// crappy workaround but without it the zone doesn't get initialized in time
|
||||||
|
|
@ -191,7 +193,6 @@ class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActor
|
||||||
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
||||||
vehicle.Faction = PlanetSideEmpire.TR
|
vehicle.Faction = PlanetSideEmpire.TR
|
||||||
vehicle.Zone = zone
|
vehicle.Zone = zone
|
||||||
val cargoProbe = new TestProbe(system)
|
|
||||||
vehicle.Actor = cargoProbe.ref
|
vehicle.Actor = cargoProbe.ref
|
||||||
val lodestar = Vehicle(GlobalDefinitions.lodestar)
|
val lodestar = Vehicle(GlobalDefinitions.lodestar)
|
||||||
lodestar.Faction = PlanetSideEmpire.TR
|
lodestar.Faction = PlanetSideEmpire.TR
|
||||||
|
|
@ -220,39 +221,45 @@ class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActor
|
||||||
"if with mounted cargo, eject it when marked for deconstruction" in {
|
"if with mounted cargo, eject it when marked for deconstruction" in {
|
||||||
lodestar.Actor ! Vehicle.Deconstruct()
|
lodestar.Actor ! Vehicle.Deconstruct()
|
||||||
|
|
||||||
val vehicle_msg = vehicleProbe.receiveN(6, 500 milliseconds)
|
val vehicleMsgs = eventsProbe.receiveN(6, 10.seconds)
|
||||||
vehicle_msg.head match {
|
val cargoMsgs = cargoProbe.receiveN(1, 1.seconds)
|
||||||
case VehicleServiceMessage("test", VehicleAction.KickPassenger(PlanetSideGUID(4), 4, true, PlanetSideGUID(2))) => ;
|
vehicleMsgs.head match {
|
||||||
|
case VehicleServiceMessage("test", VehicleAction.KickPassenger(PlanetSideGUID(4), 4, true, PlanetSideGUID(2))) => ()
|
||||||
case _ =>
|
case _ =>
|
||||||
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-1: ${vehicle_msg(5)}")
|
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-1: ${vehicleMsgs.head}")
|
||||||
}
|
}
|
||||||
assert(player2.VehicleSeated.isEmpty)
|
assert(player2.VehicleSeated.isEmpty)
|
||||||
assert(lodestar.Seats(0).occupant.isEmpty)
|
assert(lodestar.Seats(0).occupant.isEmpty)
|
||||||
//cargo dismounting messages
|
//cargo dismounting messages
|
||||||
vehicle_msg(1) match {
|
vehicleMsgs(1) match {
|
||||||
case VehicleServiceMessage(_, VehicleAction.SendResponse(_, PlanetsideAttributeMessage(PlanetSideGUID(1), 0, _))) => ;
|
case VehicleServiceMessage(_, VehicleAction.SendResponse(_, PlanetsideAttributeMessage(PlanetSideGUID(1), 0, _))) => ()
|
||||||
case _ =>
|
case _ =>
|
||||||
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-2: ${vehicle_msg.head}")
|
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-2: ${vehicleMsgs(1)}")
|
||||||
}
|
}
|
||||||
vehicle_msg(2) match {
|
vehicleMsgs(2) match {
|
||||||
case VehicleServiceMessage(_, VehicleAction.SendResponse(_, PlanetsideAttributeMessage(PlanetSideGUID(1), 68, _))) => ;
|
case VehicleServiceMessage(_, VehicleAction.SendResponse(_, PlanetsideAttributeMessage(PlanetSideGUID(1), 68, _))) => ()
|
||||||
case _ =>
|
case _ =>
|
||||||
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-3: ${vehicle_msg(1)}")
|
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-3: ${vehicleMsgs(2)}")
|
||||||
}
|
}
|
||||||
vehicle_msg(3) match {
|
vehicleMsgs(3) match {
|
||||||
case VehicleServiceMessage("test", VehicleAction.SendResponse(_, CargoMountPointStatusMessage(PlanetSideGUID(2), _, PlanetSideGUID(1), _, 1, CargoStatus.InProgress, 0))) => ;
|
case VehicleServiceMessage("test", VehicleAction.SendResponse(_, CargoMountPointStatusMessage(PlanetSideGUID(2), _, PlanetSideGUID(1), _, 1, CargoStatus.InProgress, 0))) => ;
|
||||||
case _ =>
|
case _ =>
|
||||||
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-4: ${vehicle_msg(2)}")
|
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-4: ${vehicleMsgs(3)}")
|
||||||
}
|
}
|
||||||
vehicle_msg(4) match {
|
vehicleMsgs(4) match {
|
||||||
case VehicleServiceMessage("test", VehicleAction.SendResponse(_, ObjectDetachMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _, _, _))) => ;
|
case VehicleServiceMessage("test", VehicleAction.SendResponse(_, ObjectDetachMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _, _, _))) => ()
|
||||||
case _ =>
|
case _ =>
|
||||||
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-5: ${vehicle_msg(3)}")
|
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-5: ${vehicleMsgs(4)}")
|
||||||
}
|
}
|
||||||
vehicle_msg(5) match {
|
vehicleMsgs(5) match {
|
||||||
case VehicleServiceMessage("test", VehicleAction.SendResponse(_, CargoMountPointStatusMessage(PlanetSideGUID(2), _, _, PlanetSideGUID(1), 1, CargoStatus.Empty, 0))) => ;
|
case VehicleServiceMessage("test", VehicleAction.SendResponse(_, CargoMountPointStatusMessage(PlanetSideGUID(2), _, _, PlanetSideGUID(1), 1, CargoStatus.Empty, 0))) => ()
|
||||||
case _ =>
|
case _ =>
|
||||||
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-6: ${vehicle_msg(4)}")
|
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-6: ${vehicleMsgs(5)}")
|
||||||
|
}
|
||||||
|
cargoMsgs.head match {
|
||||||
|
case Vehicle.Deconstruct(_) => ()
|
||||||
|
case _ =>
|
||||||
|
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-7: ${cargoMsgs.head}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -393,7 +400,7 @@ class VehicleControlMountingOwnedLockedDriverSeatTest extends ActorTest {
|
||||||
|
|
||||||
val player1 = Player(VehicleTest.avatar1)
|
val player1 = Player(VehicleTest.avatar1)
|
||||||
player1.GUID = PlanetSideGUID(1)
|
player1.GUID = PlanetSideGUID(1)
|
||||||
val player2 = Player(VehicleTest.avatar1)
|
val player2 = Player(VehicleTest.avatar1.copy(basic = VehicleTest.avatar1.basic.copy(faction = PlanetSideEmpire.NC)))
|
||||||
player2.GUID = PlanetSideGUID(2)
|
player2.GUID = PlanetSideGUID(2)
|
||||||
|
|
||||||
"Vehicle Control" should {
|
"Vehicle Control" should {
|
||||||
|
|
@ -578,67 +585,13 @@ class VehicleControlShieldsNotChargingTooEarlyTest extends ActorTest {
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
class VehicleControlInteractWithWaterPartialTest extends ActorTest {
|
class VehicleControlInteractWithWaterWadingTest extends ActorTest {
|
||||||
val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2
|
|
||||||
val player1 =
|
|
||||||
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute)) //guid=1
|
|
||||||
val playerProbe = TestProbe()
|
|
||||||
val guid = new NumberPoolHub(new MaxNumberSource(15))
|
|
||||||
val pool = Pool(EnvironmentAttribute.Water, DeepSquare(-1, 10, 10, 0, 0))
|
|
||||||
val zone = new Zone(
|
|
||||||
id = "test-zone",
|
|
||||||
new ZoneMap(name = "test-map") {
|
|
||||||
environment = List(pool)
|
|
||||||
},
|
|
||||||
zoneNumber = 0
|
|
||||||
) {
|
|
||||||
override def SetupNumberPools() = {}
|
|
||||||
GUID(guid)
|
|
||||||
override def LivePlayers = List(player1)
|
|
||||||
override def Vehicles = List(vehicle)
|
|
||||||
}
|
|
||||||
zone.blockMap.addTo(vehicle)
|
|
||||||
zone.blockMap.addTo(pool)
|
|
||||||
|
|
||||||
guid.register(player1, 1)
|
|
||||||
guid.register(vehicle, 2)
|
|
||||||
player1.Zone = zone
|
|
||||||
player1.Spawn()
|
|
||||||
vehicle.Zone = zone
|
|
||||||
vehicle.Faction = PlanetSideEmpire.TR
|
|
||||||
vehicle.Seats(0).mount(player1)
|
|
||||||
player1.VehicleSeated = vehicle.GUID
|
|
||||||
player1.Actor = playerProbe.ref
|
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-control")
|
|
||||||
|
|
||||||
"VehicleControl" should {
|
|
||||||
"causes disability when the vehicle drives too deep in water (check driver messaging)" in {
|
|
||||||
vehicle.Position = Vector3(5,5,-3) //right in the pool
|
|
||||||
vehicle.zoneInteractions() //trigger
|
|
||||||
|
|
||||||
val msg_drown = playerProbe.receiveOne(250 milliseconds)
|
|
||||||
assert(
|
|
||||||
msg_drown match {
|
|
||||||
case InteractingWithEnvironment(
|
|
||||||
p2,
|
|
||||||
Some(OxygenStateTarget(PlanetSideGUID(2), _, OxygenState.Suffocation, 100f))
|
|
||||||
) => (p2 eq pool)
|
|
||||||
case _ => false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class VehicleControlInteractWithWaterTest extends ActorTest {
|
|
||||||
val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2
|
|
||||||
val player1 =
|
|
||||||
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute)) //guid=1
|
|
||||||
val avatarProbe = TestProbe()
|
|
||||||
val playerProbe = TestProbe()
|
val playerProbe = TestProbe()
|
||||||
val vehicleProbe = TestProbe()
|
val vehicleProbe = TestProbe()
|
||||||
|
val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2
|
||||||
|
val player1 = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute)) //guid=1
|
||||||
val guid = new NumberPoolHub(new MaxNumberSource(15))
|
val guid = new NumberPoolHub(new MaxNumberSource(15))
|
||||||
val pool = Pool(EnvironmentAttribute.Water, DeepSquare(10, 10, 10, 0, 0))
|
val pool = Pool(EnvironmentAttribute.Water, DeepSquare(5, 2, 2, 0, 0))
|
||||||
val zone = new Zone(
|
val zone = new Zone(
|
||||||
id = "test-zone",
|
id = "test-zone",
|
||||||
new ZoneMap(name = "test-map") {
|
new ZoneMap(name = "test-map") {
|
||||||
|
|
@ -650,53 +603,48 @@ class VehicleControlInteractWithWaterTest extends ActorTest {
|
||||||
GUID(guid)
|
GUID(guid)
|
||||||
override def LivePlayers = List(player1)
|
override def LivePlayers = List(player1)
|
||||||
override def Vehicles = List(vehicle)
|
override def Vehicles = List(vehicle)
|
||||||
override def AvatarEvents = avatarProbe.ref
|
|
||||||
override def VehicleEvents = avatarProbe.ref
|
|
||||||
|
|
||||||
this.actor = new TestProbe(system).ref.toTyped[ZoneActor.Command]
|
|
||||||
}
|
}
|
||||||
zone.blockMap.addTo(vehicle)
|
zone.blockMap.addTo(vehicle)
|
||||||
zone.blockMap.addTo(pool)
|
zone.blockMap.addTo(pool)
|
||||||
|
|
||||||
guid.register(player1, 1)
|
guid.register(player1, 1)
|
||||||
guid.register(vehicle, 2)
|
guid.register(vehicle, 2)
|
||||||
guid.register(player1.avatar.locker, 5)
|
|
||||||
player1.Zone = zone
|
player1.Zone = zone
|
||||||
player1.Spawn()
|
player1.Spawn()
|
||||||
vehicle.Zone = zone
|
vehicle.Zone = zone
|
||||||
vehicle.Faction = PlanetSideEmpire.TR
|
vehicle.Faction = PlanetSideEmpire.TR
|
||||||
vehicle.Seats(0).mount(player1)
|
vehicle.Seats(0).mount(player1)
|
||||||
player1.VehicleSeated = vehicle.GUID
|
player1.VehicleSeated = vehicle.GUID
|
||||||
val (probe, avatarActor) = PlayerControlTest.DummyAvatar(system)
|
|
||||||
player1.Actor = playerProbe.ref
|
player1.Actor = playerProbe.ref
|
||||||
vehicle.Actor = vehicleProbe.ref
|
vehicle.Actor = vehicleProbe.ref
|
||||||
|
|
||||||
"VehicleControl" should {
|
"VehicleControl" should {
|
||||||
"causes disability when the vehicle drives too deep in water" in {
|
"report when the vehicle starts treading water" in {
|
||||||
vehicle.Position = Vector3(5,5,3) //right in the pool
|
vehicle.Position = Vector3(1, 1, 6)
|
||||||
vehicle.zoneInteractions() //trigger
|
vehicle.zoneInteractions()
|
||||||
|
vehicleProbe.expectNoMessage(2.seconds)
|
||||||
|
playerProbe.expectNoMessage()
|
||||||
|
|
||||||
val msg_drown = playerProbe.receiveOne(250 milliseconds)
|
vehicle.Position = Vector3(1, 1, 4f)
|
||||||
assert(msg_drown match {
|
vehicle.zoneInteractions()
|
||||||
case InteractingWithEnvironment(body, _) => body eq pool
|
val vehicleMsgs = vehicleProbe.receiveN(1, 5.seconds)
|
||||||
case _ => false
|
vehicleMsgs.head match {
|
||||||
})
|
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => ()
|
||||||
val msg_disable = vehicleProbe.receiveOne(10 seconds)
|
case _ =>
|
||||||
assert(msg_disable match {
|
assert(false, "")
|
||||||
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, VehicleControl.Disable(true)) => true
|
}
|
||||||
case _ => false
|
playerProbe.expectNoMessage()
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VehicleControlStopInteractWithWaterTest extends ActorTest {
|
class VehicleControlInteractWithWaterStartDrowningTest extends ActorTest {
|
||||||
val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2
|
|
||||||
val player1 =
|
|
||||||
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute)) //guid=1
|
|
||||||
val playerProbe = TestProbe()
|
val playerProbe = TestProbe()
|
||||||
|
val vehicleProbe = TestProbe()
|
||||||
|
val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2
|
||||||
|
val player1 = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute)) //guid=1
|
||||||
val guid = new NumberPoolHub(new MaxNumberSource(15))
|
val guid = new NumberPoolHub(new MaxNumberSource(15))
|
||||||
val pool = Pool(EnvironmentAttribute.Water, DeepSquare(-1, 10, 10, 0, 0))
|
val pool = Pool(EnvironmentAttribute.Water, DeepSquare(5, 2, 2, 0, 0))
|
||||||
val zone = new Zone(
|
val zone = new Zone(
|
||||||
id = "test-zone",
|
id = "test-zone",
|
||||||
new ZoneMap(name = "test-map") {
|
new ZoneMap(name = "test-map") {
|
||||||
|
|
@ -721,39 +669,290 @@ class VehicleControlStopInteractWithWaterTest extends ActorTest {
|
||||||
vehicle.Seats(0).mount(player1)
|
vehicle.Seats(0).mount(player1)
|
||||||
player1.VehicleSeated = vehicle.GUID
|
player1.VehicleSeated = vehicle.GUID
|
||||||
player1.Actor = playerProbe.ref
|
player1.Actor = playerProbe.ref
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-control")
|
vehicle.Actor = vehicleProbe.ref
|
||||||
|
|
||||||
"VehicleControl" should {
|
"VehicleControl" should {
|
||||||
"stop becoming disabled if the vehicle drives out of the water" in {
|
"report when the vehicle starts drowning" in {
|
||||||
vehicle.Position = Vector3(5,5,-3) //right in the pool
|
vehicle.Position = Vector3(1, 1, 6)
|
||||||
vehicle.zoneInteractions() //trigger
|
|
||||||
val msg_drown = playerProbe.receiveOne(250 milliseconds)
|
|
||||||
assert(
|
|
||||||
msg_drown match {
|
|
||||||
case InteractingWithEnvironment(
|
|
||||||
p2,
|
|
||||||
Some(OxygenStateTarget(PlanetSideGUID(2), _, OxygenState.Suffocation, 100f))
|
|
||||||
) => (p2 eq pool)
|
|
||||||
case _ => false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
vehicle.Position = Vector3.Zero //that's enough of that
|
|
||||||
vehicle.zoneInteractions()
|
vehicle.zoneInteractions()
|
||||||
val msg_recover = playerProbe.receiveOne(250 milliseconds)
|
vehicleProbe.expectNoMessage(2.seconds)
|
||||||
assert(
|
playerProbe.expectNoMessage()
|
||||||
msg_recover match {
|
|
||||||
case EscapeFromEnvironment(
|
vehicle.Position = Vector3(1, 1, 0f)
|
||||||
p2,
|
vehicle.zoneInteractions()
|
||||||
Some(OxygenStateTarget(PlanetSideGUID(2), _, OxygenState.Recovery, _))
|
val vehicleMsgs = vehicleProbe.receiveN(3, 5.seconds)
|
||||||
) => (p2 eq pool)
|
val playerMsgs = playerProbe.receiveN(1, 1.seconds)
|
||||||
case _ => false
|
vehicleMsgs.head match {
|
||||||
}
|
case RespondsToZoneEnvironment.StopTimer(WithWater.WaterAction) => ()
|
||||||
)
|
case _ =>
|
||||||
|
assert(false, "")
|
||||||
|
}
|
||||||
|
vehicleMsgs(1) match {
|
||||||
|
case RespondsToZoneEnvironment.Timer(WithWater.WaterAction, _, _, _) => ()
|
||||||
|
case _ =>
|
||||||
|
assert(false, "")
|
||||||
|
}
|
||||||
|
vehicleMsgs(2) match {
|
||||||
|
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => ()
|
||||||
|
case _ =>
|
||||||
|
assert(false, "")
|
||||||
|
}
|
||||||
|
playerMsgs.head match {
|
||||||
|
case InteractingWithEnvironment(somePool, Some(OxygenStateTarget(ValidPlanetSideGUID(2), _, OxygenState.Suffocation, 100.0f)))
|
||||||
|
if somePool eq pool => ()
|
||||||
|
case _ =>
|
||||||
|
assert(false, "")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//class VehicleControlInteractWithWaterStopDrowningTest extends ActorTest {
|
||||||
|
// val playerProbe = TestProbe()
|
||||||
|
// val vehicleProbe = TestProbe()
|
||||||
|
// val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2
|
||||||
|
// val player1 = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute)) //guid=1
|
||||||
|
// val guid = new NumberPoolHub(new MaxNumberSource(15))
|
||||||
|
// val pool = Pool(EnvironmentAttribute.Water, DeepSquare(5, 2, 2, 0, 0))
|
||||||
|
// val zone = new Zone(
|
||||||
|
// id = "test-zone",
|
||||||
|
// new ZoneMap(name = "test-map") {
|
||||||
|
// environment = List(pool)
|
||||||
|
// },
|
||||||
|
// zoneNumber = 0
|
||||||
|
// ) {
|
||||||
|
// override def SetupNumberPools() = {}
|
||||||
|
// GUID(guid)
|
||||||
|
// override def LivePlayers = List(player1)
|
||||||
|
// override def Vehicles = List(vehicle)
|
||||||
|
// }
|
||||||
|
// zone.blockMap.addTo(vehicle)
|
||||||
|
// zone.blockMap.addTo(pool)
|
||||||
|
//
|
||||||
|
// guid.register(player1, 1)
|
||||||
|
// guid.register(vehicle, 2)
|
||||||
|
// player1.Zone = zone
|
||||||
|
// player1.Spawn()
|
||||||
|
// vehicle.Zone = zone
|
||||||
|
// vehicle.Faction = PlanetSideEmpire.TR
|
||||||
|
// vehicle.Seats(0).mount(player1)
|
||||||
|
// player1.VehicleSeated = vehicle.GUID
|
||||||
|
// player1.Actor = playerProbe.ref
|
||||||
|
// vehicle.Actor = vehicleProbe.ref
|
||||||
|
//
|
||||||
|
// "VehicleControl" should {
|
||||||
|
// "report when the vehicle stops drowning" in {
|
||||||
|
// vehicle.Position = Vector3(1, 1, 6)
|
||||||
|
// vehicle.zoneInteractions()
|
||||||
|
// vehicleProbe.expectNoMessage(2.seconds)
|
||||||
|
// playerProbe.expectNoMessage()
|
||||||
|
//
|
||||||
|
// vehicle.Position = Vector3(1, 1, 0f)
|
||||||
|
// vehicle.zoneInteractions()
|
||||||
|
// val vehicleMsgs = vehicleProbe.receiveN(3, 5.seconds)
|
||||||
|
// val playerMsgs = playerProbe.receiveN(1, 1.seconds)
|
||||||
|
// vehicleMsgs.head match {
|
||||||
|
// case RespondsToZoneEnvironment.StopTimer(WithWater.WaterAction) => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
// vehicleMsgs(1) match {
|
||||||
|
// case RespondsToZoneEnvironment.Timer(WithWater.WaterAction, _, _, _) => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
// vehicleMsgs(2) match {
|
||||||
|
// case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
// playerMsgs.head match {
|
||||||
|
// case InteractingWithEnvironment(somePool, Some(OxygenStateTarget(ValidPlanetSideGUID(2), _, OxygenState.Suffocation, 100.0f)))
|
||||||
|
// if somePool eq pool => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// //escape drowning
|
||||||
|
// vehicle.Position = Vector3(1, 1, 4.7f)
|
||||||
|
// vehicle.zoneInteractions()
|
||||||
|
// val vehicleMsgs2 = vehicleProbe.receiveN(2, 5.seconds)
|
||||||
|
// val playerMsgs2 = playerProbe.receiveN(1, 1.seconds)
|
||||||
|
// vehicleMsgs2.head match {
|
||||||
|
// case RespondsToZoneEnvironment.StopTimer(WithWater.WaterAction) => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
// vehicleMsgs2(1) match {
|
||||||
|
// case RespondsToZoneEnvironment.Timer(WithWater.WaterAction, _, _, _) => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
// playerMsgs2.head match {
|
||||||
|
// case EscapeFromEnvironment(somePool, Some(OxygenStateTarget(ValidPlanetSideGUID(2), _, OxygenState.Recovery, _)))
|
||||||
|
// if somePool eq pool => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
class VehicleControlInteractWithWaterStopWadingTest extends ActorTest {
|
||||||
|
val playerProbe = TestProbe()
|
||||||
|
val vehicleProbe = TestProbe()
|
||||||
|
val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2
|
||||||
|
val player1 = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute)) //guid=1
|
||||||
|
val guid = new NumberPoolHub(new MaxNumberSource(15))
|
||||||
|
val pool = Pool(EnvironmentAttribute.Water, DeepSquare(5, 2, 2, 0, 0))
|
||||||
|
val zone = new Zone(
|
||||||
|
id = "test-zone",
|
||||||
|
new ZoneMap(name = "test-map") {
|
||||||
|
environment = List(pool)
|
||||||
|
},
|
||||||
|
zoneNumber = 0
|
||||||
|
) {
|
||||||
|
override def SetupNumberPools() = {}
|
||||||
|
GUID(guid)
|
||||||
|
override def LivePlayers = List(player1)
|
||||||
|
override def Vehicles = List(vehicle)
|
||||||
|
}
|
||||||
|
zone.blockMap.addTo(vehicle)
|
||||||
|
zone.blockMap.addTo(pool)
|
||||||
|
|
||||||
|
guid.register(player1, 1)
|
||||||
|
guid.register(vehicle, 2)
|
||||||
|
player1.Zone = zone
|
||||||
|
player1.Spawn()
|
||||||
|
vehicle.Zone = zone
|
||||||
|
vehicle.Faction = PlanetSideEmpire.TR
|
||||||
|
vehicle.Seats(0).mount(player1)
|
||||||
|
player1.VehicleSeated = vehicle.GUID
|
||||||
|
player1.Actor = playerProbe.ref
|
||||||
|
vehicle.Actor = vehicleProbe.ref
|
||||||
|
|
||||||
|
"VehicleControl" should {
|
||||||
|
"report when the vehicle stops wading" in {
|
||||||
|
vehicle.Position = Vector3(1, 1, 6)
|
||||||
|
vehicle.zoneInteractions()
|
||||||
|
vehicleProbe.expectNoMessage(2.seconds)
|
||||||
|
playerProbe.expectNoMessage()
|
||||||
|
|
||||||
|
vehicle.Position = Vector3(1, 1, 4f)
|
||||||
|
vehicle.zoneInteractions()
|
||||||
|
val vehicleMsgs = vehicleProbe.receiveN(1, 5.seconds)
|
||||||
|
playerProbe.expectNoMessage()
|
||||||
|
vehicleMsgs.head match {
|
||||||
|
case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => ()
|
||||||
|
case _ =>
|
||||||
|
assert(false, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
//stop wading
|
||||||
|
vehicle.Position = Vector3(1, 1, 6f)
|
||||||
|
vehicle.zoneInteractions()
|
||||||
|
val vehicleMsgs2 = vehicleProbe.receiveN(1, 5.seconds)
|
||||||
|
playerProbe.expectNoMessage()
|
||||||
|
vehicleMsgs2.head match {
|
||||||
|
case RespondsToZoneEnvironment.StopTimer(EnvironmentAttribute.Water) => ()
|
||||||
|
case _ =>
|
||||||
|
assert(false, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//class VehicleControlInteractWithWaterFullStopTest extends ActorTest {
|
||||||
|
// val playerProbe = TestProbe()
|
||||||
|
// val vehicleProbe = TestProbe()
|
||||||
|
// val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2
|
||||||
|
// val player1 = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute)) //guid=1
|
||||||
|
// val guid = new NumberPoolHub(new MaxNumberSource(15))
|
||||||
|
// val pool = Pool(EnvironmentAttribute.Water, DeepSquare(5, 2, 2, 0, 0))
|
||||||
|
// val zone = new Zone(
|
||||||
|
// id = "test-zone",
|
||||||
|
// new ZoneMap(name = "test-map") {
|
||||||
|
// environment = List(pool)
|
||||||
|
// },
|
||||||
|
// zoneNumber = 0
|
||||||
|
// ) {
|
||||||
|
// override def SetupNumberPools() = {}
|
||||||
|
// GUID(guid)
|
||||||
|
// override def LivePlayers = List(player1)
|
||||||
|
// override def Vehicles = List(vehicle)
|
||||||
|
// }
|
||||||
|
// zone.blockMap.addTo(vehicle)
|
||||||
|
// zone.blockMap.addTo(pool)
|
||||||
|
//
|
||||||
|
// guid.register(player1, 1)
|
||||||
|
// guid.register(vehicle, 2)
|
||||||
|
// player1.Zone = zone
|
||||||
|
// player1.Spawn()
|
||||||
|
// vehicle.Zone = zone
|
||||||
|
// vehicle.Faction = PlanetSideEmpire.TR
|
||||||
|
// vehicle.Seats(0).mount(player1)
|
||||||
|
// player1.VehicleSeated = vehicle.GUID
|
||||||
|
// player1.Actor = playerProbe.ref
|
||||||
|
// vehicle.Actor = vehicleProbe.ref
|
||||||
|
//
|
||||||
|
// "VehicleControl" should {
|
||||||
|
// "report when the vehicle stops interacting with water altogether" in {
|
||||||
|
// vehicle.Position = Vector3(1, 1, 6)
|
||||||
|
// vehicle.zoneInteractions()
|
||||||
|
// vehicleProbe.expectNoMessage(2.seconds)
|
||||||
|
// playerProbe.expectNoMessage()
|
||||||
|
// //wading and drowning
|
||||||
|
// vehicle.Position = Vector3(1, 1, 0f)
|
||||||
|
// vehicle.zoneInteractions()
|
||||||
|
// val vehicleMsgs = vehicleProbe.receiveN(3, 5.seconds)
|
||||||
|
// val playerMsgs = playerProbe.receiveN(1, 1.seconds)
|
||||||
|
// vehicleMsgs.head match {
|
||||||
|
// case RespondsToZoneEnvironment.StopTimer(WithWater.WaterAction) => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
// vehicleMsgs(1) match {
|
||||||
|
// case RespondsToZoneEnvironment.Timer(WithWater.WaterAction, _, _, _) => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
// vehicleMsgs(2) match {
|
||||||
|
// case RespondsToZoneEnvironment.Timer(EnvironmentAttribute.Water, _, _, _) => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
// playerMsgs.head match {
|
||||||
|
// case InteractingWithEnvironment(somePool, Some(OxygenStateTarget(ValidPlanetSideGUID(2), _, OxygenState.Suffocation, 100.0f)))
|
||||||
|
// if somePool eq pool => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// //escape drowning and wading
|
||||||
|
// vehicle.Position = Vector3(1, 1, 6f)
|
||||||
|
// vehicle.zoneInteractions()
|
||||||
|
// val vehicleMsgs2 = vehicleProbe.receiveN(2, 5.seconds)
|
||||||
|
// val playerMsgs2 = playerProbe.receiveN(1, 1.seconds)
|
||||||
|
// vehicleMsgs2.head match {
|
||||||
|
// case RespondsToZoneEnvironment.StopTimer(WithWater.WaterAction) => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
// vehicleMsgs2(1) match {
|
||||||
|
// case RespondsToZoneEnvironment.StopTimer(EnvironmentAttribute.Water) => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
// playerMsgs2.head match {
|
||||||
|
// case EscapeFromEnvironment(somePool, Some(OxygenStateTarget(ValidPlanetSideGUID(2), _, OxygenState.Recovery, _)))
|
||||||
|
// if somePool eq pool => ()
|
||||||
|
// case _ =>
|
||||||
|
// assert(false, "")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
class VehicleControlInteractWithLavaTest extends ActorTest {
|
class VehicleControlInteractWithLavaTest extends ActorTest {
|
||||||
val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2
|
val vehicle = Vehicle(GlobalDefinitions.fury) //guid=2
|
||||||
val player1 =
|
val player1 =
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue