mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-04-28 15:25:22 +00:00
Buildings now have simple type distinctions to work using the known output of a SpawnRequestMessage packet. Support for cross-continental respawning (actually a failure case for being unable to spawn). Corpse tuning and testing.
This commit is contained in:
parent
20b7726653
commit
ddc2450541
52 changed files with 2491 additions and 711 deletions
|
|
@ -6,7 +6,7 @@ import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
|
|||
import net.psforever.objects.serverobject.locks.IFFLock
|
||||
import net.psforever.objects.serverobject.mblocker.Locker
|
||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, WarpGate}
|
||||
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, StructureType, WarpGate}
|
||||
import net.psforever.objects.serverobject.terminals.Terminal
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.types.Vector3
|
||||
|
|
@ -23,7 +23,7 @@ object Maps {
|
|||
val map5 = new ZoneMap("map05")
|
||||
|
||||
val map6 = new ZoneMap("map06") {
|
||||
LocalBuilding(2, FoundationBuilder(Building.Structure)) //Anguta
|
||||
LocalBuilding(2, FoundationBuilder(Building.Structure(StructureType.Facility, Vector3(3974.2344f, 4287.914f, 0)))) //Anguta
|
||||
LocalObject(222, Door.Constructor) //air term building, bay door
|
||||
LocalObject(370, Door.Constructor) //courtyard
|
||||
LocalObject(371, Door.Constructor) //courtyard
|
||||
|
|
@ -193,17 +193,17 @@ object Maps {
|
|||
TerminalToSpawnPad(224, 501)
|
||||
TerminalToSpawnPad(2419, 500)
|
||||
|
||||
LocalBuilding(38, FoundationBuilder(Building.Structure)) //Anguta, West Bunker
|
||||
LocalBuilding(38, FoundationBuilder(Building.Structure(StructureType.Bunker))) //Anguta, West Bunker
|
||||
LocalObject(362, Door.Constructor)
|
||||
ObjectToBuilding(362, 38)
|
||||
|
||||
LocalBuilding(42, FoundationBuilder(Building.Structure)) //Anguta, East Bunker(s)
|
||||
LocalBuilding(42, FoundationBuilder(Building.Structure(StructureType.Bunker))) //Anguta, East Bunker(s)
|
||||
LocalObject(407, Door.Constructor)
|
||||
LocalObject(408, Door.Constructor)
|
||||
ObjectToBuilding(407, 42)
|
||||
ObjectToBuilding(408, 42)
|
||||
|
||||
LocalBuilding(48, FoundationBuilder(Building.Structure)) //North Anguta Watchtower
|
||||
LocalBuilding(48, FoundationBuilder(Building.Structure(StructureType.Tower, Vector3(3864.2266f, 4518.0234f, 0)))) //North Anguta Watchtower
|
||||
LocalObject(364, Door.Constructor(Vector3(3871.9688f, 4509.992f, 269.65625f), Vector3(0f, 0f, 180f))) //s1
|
||||
LocalObject(365, Door.Constructor(Vector3(3871.9688f, 4509.992f, 279.57812f), Vector3(0f, 0f, 180f))) //s2
|
||||
LocalObject(366, Door.Constructor(Vector3(3871.9688f, 4509.992f, 299.57812f), Vector3(0f, 0f, 180f))) //s3
|
||||
|
|
@ -227,8 +227,8 @@ object Maps {
|
|||
LocalObject(1561, Terminal.Constructor(order_terminal))
|
||||
LocalObject(1562, Terminal.Constructor(order_terminal))
|
||||
LocalObject(1563, Terminal.Constructor(order_terminal))
|
||||
LocalObject(2138, SpawnTube.Constructor(Vector3(3870.9688f, 4505.7266f, 259.875f), Vector3(0, 0, 90)))
|
||||
LocalObject(2139, SpawnTube.Constructor(Vector3(3870.9688f, 4522.1562f, 259.875f), Vector3(0, 0, 90)))
|
||||
LocalObject(2138, SpawnTube.Constructor(respawn_tube_tower, Vector3(3870.9688f, 4505.7266f, 259.875f), Vector3(0, 0, 90)))
|
||||
LocalObject(2139, SpawnTube.Constructor(respawn_tube_tower, Vector3(3870.9688f, 4522.1562f, 259.875f), Vector3(0, 0, 90)))
|
||||
LocalObject(2315, Door.Constructor) //spawn tube door
|
||||
LocalObject(2316, Door.Constructor) //spawn tube door
|
||||
ObjectToBuilding(364, 48)
|
||||
|
|
@ -287,15 +287,13 @@ object Maps {
|
|||
LocalObject(1081, Terminal.Constructor(implant_terminal_interface)) //tube 520
|
||||
TerminalToInterface(520, 1081)
|
||||
|
||||
LocalBuilding(2, FoundationBuilder(Building.Structure)) //HART building C
|
||||
LocalBuilding(2, FoundationBuilder(Building.Structure(StructureType.Building))) //HART building C
|
||||
LocalObject(186, Terminal.Constructor(cert_terminal))
|
||||
LocalObject(187, Terminal.Constructor(cert_terminal))
|
||||
LocalObject(188, Terminal.Constructor(cert_terminal))
|
||||
LocalObject(362, Door.Constructor)
|
||||
LocalObject(370, Door.Constructor)
|
||||
LocalObject(371, Door.Constructor)
|
||||
LocalObject(372, Door.Constructor)
|
||||
LocalObject(373, Door.Constructor)
|
||||
LocalObject(374, Door.Constructor)
|
||||
LocalObject(375, Door.Constructor)
|
||||
LocalObject(394, Door.Constructor)
|
||||
|
|
@ -303,6 +301,8 @@ object Maps {
|
|||
LocalObject(396, Door.Constructor)
|
||||
LocalObject(397, Door.Constructor)
|
||||
LocalObject(398, Door.Constructor)
|
||||
LocalObject(462, Door.Constructor)
|
||||
LocalObject(463, Door.Constructor)
|
||||
LocalObject(522, ImplantTerminalMech.Constructor)
|
||||
LocalObject(523, ImplantTerminalMech.Constructor)
|
||||
LocalObject(524, ImplantTerminalMech.Constructor)
|
||||
|
|
@ -337,8 +337,6 @@ object Maps {
|
|||
ObjectToBuilding(362, 2)
|
||||
ObjectToBuilding(370, 2)
|
||||
ObjectToBuilding(371, 2)
|
||||
ObjectToBuilding(372, 2)
|
||||
ObjectToBuilding(373, 2)
|
||||
ObjectToBuilding(374, 2)
|
||||
ObjectToBuilding(375, 2)
|
||||
ObjectToBuilding(394, 2)
|
||||
|
|
@ -346,6 +344,8 @@ object Maps {
|
|||
ObjectToBuilding(396, 2)
|
||||
ObjectToBuilding(397, 2)
|
||||
ObjectToBuilding(398, 2)
|
||||
ObjectToBuilding(462, 2)
|
||||
ObjectToBuilding(463, 2)
|
||||
ObjectToBuilding(522, 2)
|
||||
ObjectToBuilding(523, 2)
|
||||
ObjectToBuilding(524, 2)
|
||||
|
|
@ -383,7 +383,7 @@ object Maps {
|
|||
TerminalToInterface(528, 1088)
|
||||
TerminalToInterface(529, 1089)
|
||||
|
||||
LocalBuilding(29, FoundationBuilder(Building.Structure)) //South Villa Gun Tower
|
||||
LocalBuilding(29, FoundationBuilder(Building.Structure(StructureType.Tower))) //South Villa Gun Tower
|
||||
LocalObject(330, Door.Constructor(Vector3(3979.9219f, 2592.0547f, 91.140625f), Vector3(0, 0, 180)))
|
||||
LocalObject(331, Door.Constructor(Vector3(3979.9219f, 2592.0547f, 111.140625f), Vector3(0, 0, 180)))
|
||||
LocalObject(332, Door.Constructor(Vector3(3979.9688f, 2608.0625f, 91.140625f), Vector3(0, 0, 0)))
|
||||
|
|
@ -405,7 +405,61 @@ object Maps {
|
|||
DoorToLock(332, 556)
|
||||
DoorToLock(333, 557)
|
||||
|
||||
LocalBuilding(51, FoundationBuilder(Building.Structure))
|
||||
LocalBuilding(42, FoundationBuilder(Building.Structure(StructureType.Building, Vector3(1, 0, 0)))) //spawn building south of HART C
|
||||
LocalObject(258, Door.Constructor) //spawn tube door
|
||||
LocalObject(259, Door.Constructor) //spawn tube door
|
||||
LocalObject(260, Door.Constructor) //spawn tube door
|
||||
LocalObject(261, Door.Constructor) //spawn tube door
|
||||
LocalObject(262, Door.Constructor) //spawn tube door
|
||||
LocalObject(263, Door.Constructor) //spawn tube door
|
||||
LocalObject(372, Door.Constructor) //entrance
|
||||
LocalObject(373, Door.Constructor) //entrance
|
||||
LocalObject(430, Door.Constructor) //vr door
|
||||
LocalObject(431, Door.Constructor) //vr door
|
||||
LocalObject(432, Door.Constructor) //vr door
|
||||
LocalObject(433, Door.Constructor) //vr door
|
||||
LocalObject(434, Door.Constructor) //vr door
|
||||
LocalObject(435, Door.Constructor) //vr door
|
||||
LocalObject(744, SpawnTube.Constructor(Vector3(3684.336f, 2709.0469f, 91.859375f), Vector3(0, 0, 180)))
|
||||
LocalObject(745, SpawnTube.Constructor(Vector3(3684.336f, 2713.2344f, 91.859375f), Vector3(0, 0, 0)))
|
||||
LocalObject(746, SpawnTube.Constructor(Vector3(3691.0703f, 2709.0469f, 91.859375f), Vector3(0, 0, 180)))
|
||||
LocalObject(747, SpawnTube.Constructor(Vector3(3691.0703f, 2713.2344f, 91.859375f), Vector3(0, 0, 0)))
|
||||
LocalObject(748, SpawnTube.Constructor(Vector3(3697.711f, 2709.0469f, 91.859375f), Vector3(0, 0, 180)))
|
||||
LocalObject(749, SpawnTube.Constructor(Vector3(3697.711f, 2713.2344f, 91.859375f), Vector3(0, 0, 0)))
|
||||
LocalObject(852, Terminal.Constructor(order_terminal)) //s. wall
|
||||
LocalObject(853, Terminal.Constructor(order_terminal)) //n. wall
|
||||
LocalObject(854, Terminal.Constructor(order_terminal)) //s. wall
|
||||
LocalObject(855, Terminal.Constructor(order_terminal)) //n. wall
|
||||
LocalObject(859, Terminal.Constructor(order_terminal)) //s. wall
|
||||
LocalObject(860, Terminal.Constructor(order_terminal)) //n. wall
|
||||
ObjectToBuilding(258, 42)
|
||||
ObjectToBuilding(259, 42)
|
||||
ObjectToBuilding(260, 42)
|
||||
ObjectToBuilding(261, 42)
|
||||
ObjectToBuilding(262, 42)
|
||||
ObjectToBuilding(263, 42)
|
||||
ObjectToBuilding(372, 42)
|
||||
ObjectToBuilding(373, 42)
|
||||
ObjectToBuilding(430, 42)
|
||||
ObjectToBuilding(431, 42)
|
||||
ObjectToBuilding(432, 42)
|
||||
ObjectToBuilding(433, 42)
|
||||
ObjectToBuilding(434, 42)
|
||||
ObjectToBuilding(435, 42)
|
||||
ObjectToBuilding(744, 42)
|
||||
ObjectToBuilding(745, 42)
|
||||
ObjectToBuilding(746, 42)
|
||||
ObjectToBuilding(747, 42)
|
||||
ObjectToBuilding(748, 42)
|
||||
ObjectToBuilding(749, 42)
|
||||
ObjectToBuilding(852, 42)
|
||||
ObjectToBuilding(853, 42)
|
||||
ObjectToBuilding(854, 42)
|
||||
ObjectToBuilding(855, 42)
|
||||
ObjectToBuilding(859, 42)
|
||||
ObjectToBuilding(860, 42)
|
||||
|
||||
LocalBuilding(51, FoundationBuilder(Building.Structure(StructureType.Platform))) //air terminal west of HART C
|
||||
LocalObject(304, Terminal.Constructor(dropship_vehicle_terminal))
|
||||
LocalObject(292,
|
||||
VehicleSpawnPad.Constructor(Vector3(3508.9844f, 2895.961f, 92.296875f), Vector3(0f, 0f, 270.0f))
|
||||
|
|
@ -414,7 +468,7 @@ object Maps {
|
|||
ObjectToBuilding(292, 51)
|
||||
TerminalToSpawnPad(304, 292)
|
||||
|
||||
LocalBuilding(77, FoundationBuilder(Building.Structure))
|
||||
LocalBuilding(77, FoundationBuilder(Building.Structure(StructureType.Platform))) //ground terminal west of HART C
|
||||
LocalObject(1063, Terminal.Constructor(ground_vehicle_terminal))
|
||||
LocalObject(706,
|
||||
VehicleSpawnPad.Constructor(Vector3(3506.0f, 2820.0f, 92.0f), Vector3(0f, 0f, 270.0f))
|
||||
|
|
@ -422,18 +476,6 @@ object Maps {
|
|||
ObjectToBuilding(1063, 77)
|
||||
ObjectToBuilding(706, 77)
|
||||
TerminalToSpawnPad(1063, 706)
|
||||
|
||||
//TODO check building id: these belong to a spawn building in HART C campus
|
||||
LocalObject(462, Door.Constructor)
|
||||
LocalObject(463, Door.Constructor)
|
||||
LocalObject(853, Terminal.Constructor(order_terminal))
|
||||
LocalObject(855, Terminal.Constructor(order_terminal))
|
||||
LocalObject(860, Terminal.Constructor(order_terminal))
|
||||
ObjectToBuilding(462, 2)
|
||||
ObjectToBuilding(463, 2)
|
||||
ObjectToBuilding(853, 2)
|
||||
ObjectToBuilding(855, 2)
|
||||
ObjectToBuilding(860, 2)
|
||||
}
|
||||
|
||||
val map14 = new ZoneMap("map13")
|
||||
|
|
|
|||
|
|
@ -25,10 +25,10 @@ import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
|
|||
import net.psforever.objects.serverobject.locks.IFFLock
|
||||
import net.psforever.objects.serverobject.mblocker.Locker
|
||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||
import net.psforever.objects.serverobject.terminals.{MatrixTerminalDefinition, SpawnTerminalDefinition, Terminal}
|
||||
import net.psforever.objects.serverobject.terminals.{MatrixTerminalDefinition, Terminal}
|
||||
import net.psforever.objects.serverobject.terminals.Terminal.TerminalMessage
|
||||
import net.psforever.objects.vehicles.{AccessPermissionGroup, Utility, VehicleLockState}
|
||||
import net.psforever.objects.serverobject.structures.{Building, WarpGate}
|
||||
import net.psforever.objects.serverobject.structures.{Building, StructureType, WarpGate}
|
||||
import net.psforever.objects.serverobject.terminals.Terminal
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.vehicles.{AccessPermissionGroup, VehicleLockState}
|
||||
|
|
@ -56,6 +56,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
var taskResolver : ActorRef = Actor.noSender
|
||||
var galaxy : ActorRef = Actor.noSender
|
||||
var continent : Zone = null
|
||||
var player : Player = null
|
||||
var avatar : Avatar = null
|
||||
var progressBarValue : Option[Float] = None
|
||||
var shooting : Option[PlanetSideGUID] = None
|
||||
var accessedContainer : Option[PlanetSideGameObject with Container] = None
|
||||
|
|
@ -66,9 +68,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
var clientKeepAlive : Cancellable = DefaultCancellable.obj
|
||||
var progressBarUpdate : Cancellable = DefaultCancellable.obj
|
||||
var reviveTimer : Cancellable = DefaultCancellable.obj
|
||||
|
||||
override def postStop() = {
|
||||
clientKeepAlive.cancel()
|
||||
clientKeepAlive.cancel
|
||||
progressBarUpdate.cancel
|
||||
reviveTimer.cancel
|
||||
localService ! Service.Leave()
|
||||
vehicleService ! Service.Leave()
|
||||
avatarService ! Service.Leave()
|
||||
|
|
@ -282,7 +287,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
case AvatarResponse.Release(tplayer) =>
|
||||
if(tplayer_guid != guid) {
|
||||
turnPlayerIntoCorpse(tplayer)
|
||||
TurnPlayerIntoCorpse(tplayer)
|
||||
}
|
||||
|
||||
case AvatarResponse.Reload(item_guid) =>
|
||||
|
|
@ -920,7 +925,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
continent.Transport ! Zone.SpawnVehicle(vehicle)
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.LoadVehicle(player_guid, vehicle, objedtId, vehicle_guid, vdata))
|
||||
sendResponse(PlanetsideAttributeMessage(vehicle_guid, 22, 1L)) //mount points off?
|
||||
sendResponse(PlanetsideAttributeMessage(vehicle_guid, 22, 1L)) //mount points off?
|
||||
sendResponse(PlanetsideAttributeMessage(vehicle_guid, 21, player_guid.guid)) //fte and ownership?
|
||||
//sendResponse(ObjectAttachMessage(vehicle_guid, player_guid, 0))
|
||||
vehicleService ! VehicleServiceMessage.UnscheduleDeconstruction(vehicle_guid) //cancel queue timeout delay
|
||||
|
|
@ -1002,6 +1006,64 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
log.info(s"$tplayer has left zone ${zone.Id}")
|
||||
}
|
||||
|
||||
case Zone.Lattice.SpawnPoint(zone_id, building, spawn_tube) =>
|
||||
log.info(s"Zone.Lattice.SpawnPoint: spawn point on $zone_id in ${building.Id} @ ${spawn_tube.GUID.guid} selected")
|
||||
reviveTimer.cancel
|
||||
val sameZone = zone_id == continent.Id
|
||||
val backpack = player.isBackpack
|
||||
val respawnTime : Long = if(sameZone) { 10 } else { 0 } //s
|
||||
val respawnTimeMillis = respawnTime * 1000 //ms
|
||||
sendResponse(AvatarDeadStateMessage(DeadState.RespawnTime, respawnTimeMillis, respawnTimeMillis, Vector3.Zero, 2, true))
|
||||
val tplayer = if(backpack) {
|
||||
RespawnClone(player) //new player
|
||||
}
|
||||
else {
|
||||
val player_guid = player.GUID
|
||||
sendResponse(ObjectDeleteMessage(player_guid, 4))
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid, 4))
|
||||
player //player is deconstructing self
|
||||
}
|
||||
|
||||
tplayer.Position = spawn_tube.Position
|
||||
tplayer.Orientation = spawn_tube.Orientation
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
val (target, msg) : (ActorRef, Any) = if(sameZone) {
|
||||
if(backpack) {
|
||||
//respawning from unregistered player
|
||||
(taskResolver, RegisterAvatar(tplayer))
|
||||
}
|
||||
else {
|
||||
//move existing player
|
||||
(self, PlayerLoaded(tplayer))
|
||||
}
|
||||
}
|
||||
else {
|
||||
continent.Population ! Zone.Population.Leave(avatar)
|
||||
val original = player
|
||||
//TODO check player orientation upon spawn not polluted
|
||||
if(backpack) {
|
||||
//unregister avatar locker + GiveWorld
|
||||
player = tplayer
|
||||
(taskResolver, TaskBeforeZoneChange(GUIDTask.UnregisterLocker(original.Locker)(continent.GUID), zone_id))
|
||||
}
|
||||
else {
|
||||
//unregister avatar whole + GiveWorld
|
||||
(taskResolver, TaskBeforeZoneChange(GUIDTask.UnregisterAvatar(original)(continent.GUID), zone_id))
|
||||
}
|
||||
}
|
||||
context.system.scheduler.scheduleOnce(respawnTime seconds, target, msg)
|
||||
|
||||
case Zone.Lattice.NoValidSpawnPoint(zone_number, None) =>
|
||||
log.warn(s"Zone.Lattice.SpawnPoint: zone $zone_number could not be accessed as requested")
|
||||
reviveTimer.cancel
|
||||
RequestSanctuaryZoneSpawn(player, zone_number)
|
||||
|
||||
case Zone.Lattice.NoValidSpawnPoint(zone_number, Some(spawn_group)) =>
|
||||
log.warn(s"Zone.Lattice.SpawnPoint: zone $zone_number has no available ${player.Faction} targets in spawn group $spawn_group")
|
||||
reviveTimer.cancel
|
||||
RequestSanctuaryZoneSpawn(player, zone_number)
|
||||
|
||||
case InterstellarCluster.ClientInitializationComplete() =>
|
||||
LivePlayerList.Add(sessionId, avatar)
|
||||
//PropertyOverrideMessage
|
||||
|
|
@ -1012,21 +1074,21 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
galaxy ! InterstellarCluster.GetWorld("z6")
|
||||
|
||||
case InterstellarCluster.GiveWorld(zoneId, zone) =>
|
||||
log.info(s"Zone $zoneId has been loaded")
|
||||
log.info(s"Zone $zoneId will now load")
|
||||
player.Continent = zoneId
|
||||
continent = zone
|
||||
continent.Population ! Zone.Population.Join(avatar)
|
||||
taskResolver ! RegisterNewAvatar(player)
|
||||
|
||||
case NewPlayerLoaded(tplayer) =>
|
||||
log.info(s"Player $tplayer has been loaded")
|
||||
log.info(s"Player ${tplayer.Name} has been loaded")
|
||||
player = tplayer
|
||||
//LoadMapMessage will cause the client to send back a BeginZoningMessage packet (see below)
|
||||
sendResponse(LoadMapMessage(continent.Map.Name, continent.Id, 40100,25,true,3770441820L))
|
||||
AvatarCreate() //important! the LoadMapMessage must be processed by the client before the avatar is created
|
||||
|
||||
case PlayerLoaded(tplayer) =>
|
||||
log.info(s"Player $tplayer has been loaded")
|
||||
log.info(s"Player ${tplayer.Name} will respawn")
|
||||
player = tplayer
|
||||
AvatarCreate()
|
||||
self ! SetCurrentAvatar(tplayer)
|
||||
|
|
@ -1034,22 +1096,25 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case PlayerFailedToLoad(tplayer) =>
|
||||
player.Continent match {
|
||||
case _ =>
|
||||
failWithError(s"$tplayer failed to load anywhere")
|
||||
failWithError(s"${tplayer.Name} failed to load anywhere")
|
||||
}
|
||||
|
||||
case SetCurrentAvatar(tplayer) =>
|
||||
player = tplayer
|
||||
val guid = tplayer.GUID
|
||||
sendResponse(SetCurrentAvatarMessage(guid,0,0))
|
||||
if(spectator) {
|
||||
sendResponse(ChatMsg(ChatMessageType.CMT_TOGGLESPECTATORMODE, false, "", "on", None))
|
||||
}
|
||||
|
||||
(0 until DetailedCharacterData.numberOfImplantSlots(tplayer.BEP)).foreach(slot => {
|
||||
sendResponse(AvatarImplantMessage(guid, ImplantAction.Initialization, slot, 1)) //init implant slot
|
||||
sendResponse(AvatarImplantMessage(guid, ImplantAction.Activation, slot, 0)) //deactivate implant
|
||||
//TODO: if this implant is Installed but does not have shortcut, add to a free slot or write over slot 61/62/63
|
||||
//TODO if this implant is Installed but does not have shortcut, add to a free slot or write over slot 61/62/63
|
||||
})
|
||||
|
||||
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 82, 0))
|
||||
//TODO: if Medkit does not have shortcut, add to a free slot or write over slot 64
|
||||
//TODO if Medkit does not have shortcut, add to a free slot or write over slot 64
|
||||
sendResponse(CreateShortcutMessage(guid, 1, 0, true, Shortcut.MEDKIT))
|
||||
sendResponse(ChangeShortcutBankMessage(guid, 0))
|
||||
//FavoritesMessage
|
||||
|
|
@ -1195,10 +1260,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
}
|
||||
|
||||
var player : Player = null
|
||||
var avatar : Avatar = null
|
||||
var spawnZones : Map[Int, Building] = null
|
||||
|
||||
def handleGamePkt(pkt : PlanetSideGamePacket) = pkt match {
|
||||
case ConnectToWorldRequestMessage(server, token, majorVersion, minorVersion, revision, buildDate, unk) =>
|
||||
val clientVersion = s"Client Version: $majorVersion.$minorVersion.$revision, $buildDate"
|
||||
|
|
@ -1272,7 +1333,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
//TODO check if can spawn on last continent/location from player?
|
||||
//TODO if yes, get continent guid accessors
|
||||
//TODO if no, get sanctuary guid accessors and reset the player's expectations
|
||||
//galaxy ! InterstellarCluster.GetWorld("z6")
|
||||
galaxy ! InterstellarCluster.RequestClientInitialization()
|
||||
case default =>
|
||||
log.error("Unsupported " + default + " in " + msg)
|
||||
|
|
@ -1283,18 +1343,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
case msg @ BeginZoningMessage() =>
|
||||
log.info("Reticulating splines ...")
|
||||
configZone(continent) //todo density
|
||||
configZone(continent)
|
||||
sendResponse(TimeOfDayMessage(1191182336))
|
||||
/** WIP */
|
||||
spawnZones = Map(
|
||||
7 -> continent.Building(2).get,
|
||||
6 -> continent.Building(48).get
|
||||
)
|
||||
|
||||
//custom
|
||||
sendResponse(ContinentalLockUpdateMessage(13, PlanetSideEmpire.VS)) // "The VS have captured the VS Sanctuary."
|
||||
sendResponse(ReplicationStreamMessage(5, Some(6), Vector(SquadListing()))) //clear squad list
|
||||
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 1))
|
||||
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 1)) //common
|
||||
(0 to 255).foreach(i => { sendResponse(SetEmpireMessage(PlanetSideGUID(i), PlanetSideEmpire.VS)) })
|
||||
|
||||
//render Equipment that was dropped into zone before the player arrived
|
||||
continent.EquipmentOnGround.foreach(item => {
|
||||
|
|
@ -1309,20 +1365,16 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
})
|
||||
//load active players in zone
|
||||
continent.LivePlayers.filterNot(_.GUID == player.GUID).foreach(char => {
|
||||
sendResponse(
|
||||
ObjectCreateMessage(ObjectClass.avatar, char.GUID, char.Definition.Packet.ConstructorData(char).get)
|
||||
)
|
||||
sendResponse(ObjectCreateMessage(ObjectClass.avatar, char.GUID, char.Definition.Packet.ConstructorData(char).get))
|
||||
})
|
||||
//load corpses in zone
|
||||
continent.Corpses.foreach( turnPlayerIntoCorpse(_) )
|
||||
continent.Corpses.foreach { TurnPlayerIntoCorpse }
|
||||
//load active vehicles in zone
|
||||
continent.Vehicles.foreach(vehicle => {
|
||||
val definition = vehicle.Definition
|
||||
sendResponse(
|
||||
ObjectCreateMessage(definition.ObjectId, vehicle.GUID, definition.Packet.ConstructorData(vehicle).get)
|
||||
)
|
||||
sendResponse(ObjectCreateMessage(definition.ObjectId, vehicle.GUID, definition.Packet.ConstructorData(vehicle).get))
|
||||
//seat vehicle occupants
|
||||
vehicle.Definition.MountPoints.values.foreach(seat_num => {
|
||||
definition.MountPoints.values.foreach(seat_num => {
|
||||
vehicle.Seat(seat_num).get.Occupant match {
|
||||
case Some(tplayer) =>
|
||||
if(tplayer.HasGUID) {
|
||||
|
|
@ -1339,14 +1391,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
continent.GUID(interface_guid) match {
|
||||
case Some(obj : Terminal) =>
|
||||
val objDef = obj.Definition
|
||||
val obj_uid = objDef.ObjectId
|
||||
val obj_data = objDef.Packet.ConstructorData(obj).get
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
obj_uid,
|
||||
ObjectClass.implant_terminal_interface,
|
||||
PlanetSideGUID(interface_guid),
|
||||
ObjectCreateMessageParent(parent_guid, 1),
|
||||
obj_data
|
||||
objDef.Packet.ConstructorData(obj).get
|
||||
)
|
||||
)
|
||||
case _ => ;
|
||||
|
|
@ -1444,36 +1494,35 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
case msg @ ReleaseAvatarRequestMessage() =>
|
||||
log.info(s"ReleaseAvatarRequest: ${player.GUID} on ${continent.Id} has released")
|
||||
//TODO is it easier to delete the player, then re-create them as a corpse?
|
||||
reviveTimer.cancel
|
||||
player.Release
|
||||
continent.Population ! Zone.Population.Release(avatar)
|
||||
continent.Population ! Zone.Corpse.Add(player)
|
||||
val knife = player.Slot(4).Equipment.get
|
||||
taskResolver ! RemoveEquipmentFromSlot(player, knife, 4)
|
||||
turnPlayerIntoCorpse(player)
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.Release(player, continent))
|
||||
sendResponse(AvatarDeadStateMessage(DeadState.Release, 0, 0, player.Position, 2, true))
|
||||
continent.Population ! Zone.Population.Release(avatar)
|
||||
player.VehicleSeated match {
|
||||
case None =>
|
||||
continent.Population ! Zone.Corpse.Add(player) //TODO move back out of this match case when changing below issue
|
||||
val knife = player.Slot(4).Equipment.get
|
||||
player.Slot(4).Equipment = None
|
||||
taskResolver ! RemoveEquipmentFromSlot(player, knife, 4)
|
||||
TurnPlayerIntoCorpse(player)
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.Release(player, continent))
|
||||
|
||||
case Some(_) =>
|
||||
//TODO we do not want to delete the player if he is seated in a vehicle when releasing
|
||||
//TODO it is necessary for now until we know how to juggle ownership properly
|
||||
val player_guid = player.GUID
|
||||
sendResponse(ObjectDeleteMessage(player_guid, 0))
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid, 0))
|
||||
self ! PacketCoding.CreateGamePacket(0, DismountVehicleMsg(player_guid, 0, true)) //let vehicle try to clean up its fields
|
||||
taskResolver ! GUIDTask.UnregisterPlayer(player)(continent.GUID)
|
||||
//sendResponse(ObjectDetachMessage(vehicle_guid, player.GUID, Vector3.Zero, 0, 0, 0))
|
||||
//sendResponse(PlayerStateShiftMessage(ShiftState(1, Vector3.Zero, 0)))
|
||||
}
|
||||
|
||||
case msg @ SpawnRequestMessage(u1, u2, u3, u4, u5) =>
|
||||
log.info(s"SpawnRequestMessage: $msg")
|
||||
spawnZones.get(u2.toInt) match {
|
||||
case Some(building) =>
|
||||
scala.util.Random.shuffle(building.Amenities.filter(_.isInstanceOf[SpawnTube])).headOption match { //TODO temporary shuffle
|
||||
case Some(tube) =>
|
||||
val tplayer = SpawnRequest(player) //new player
|
||||
tplayer.Position = tube.Position
|
||||
tplayer.Orientation = tube.Orientation
|
||||
log.info(s"SpawnRequestMessage: new player will spawn in ${building.Id} @ ${tube.GUID.guid}")
|
||||
sendResponse(AvatarDeadStateMessage(DeadState.RespawnTime, 10000, 10000, Vector3.Zero, 2, true))
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
context.system.scheduler.scheduleOnce(10 seconds, taskResolver, RegisterAvatar(tplayer))
|
||||
case None =>
|
||||
log.warn(s"SpawnRequestMessage: can not find a spawn point in this spawn group - $u2")
|
||||
}
|
||||
case None =>
|
||||
log.warn(s"SpawnRequestMessage: can not find somewhere to spawn on ${continent.Id}")
|
||||
}
|
||||
//TODO just focus on u5 and u2 for now
|
||||
galaxy ! Zone.Lattice.RequestSpawnPoint(u5.toInt, player, u2.toInt)
|
||||
|
||||
case msg @ SetChatFilterMessage(send_channel, origin, whitelist) =>
|
||||
log.info("SetChatFilters: " + msg)
|
||||
|
|
@ -1516,15 +1565,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
|
||||
if(messagetype == ChatMessageType.CMT_SUICIDE) {
|
||||
val player_guid = player.GUID
|
||||
val pos = player.Position
|
||||
player.Die
|
||||
sendResponse(PlanetsideAttributeMessage(player_guid, 0, 0))
|
||||
sendResponse(PlanetsideAttributeMessage(player_guid, 2, 0))
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 0, 0))
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 2, 0))
|
||||
sendResponse(DestroyMessage(player_guid, player_guid, PlanetSideGUID(0), pos)) //how many players get this message?
|
||||
sendResponse(AvatarDeadStateMessage(DeadState.Dead, 300000, 300000, pos, 2, true))
|
||||
KillPlayer(player)
|
||||
}
|
||||
|
||||
if(messagetype == ChatMessageType.CMT_DESTROY) {
|
||||
self ! PacketCoding.CreateGamePacket(0, RequestDestroyMessage(PlanetSideGUID(contents.toInt)))
|
||||
}
|
||||
|
||||
if (messagetype == ChatMessageType.CMT_VOICE) {
|
||||
|
|
@ -1853,7 +1898,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
// TODO: Make sure this is the correct response for all cases
|
||||
continent.GUID(object_guid) match {
|
||||
case Some(vehicle : Vehicle) =>
|
||||
if(player.VehicleOwned.contains(object_guid) && vehicle.Owner.contains(player.GUID)) {
|
||||
if((player.VehicleOwned.contains(object_guid) && vehicle.Owner.contains(player.GUID))
|
||||
|| (player.Faction == vehicle.Faction && (vehicle.Owner.isEmpty || vehicle.Health == 0))) {
|
||||
vehicleService ! VehicleServiceMessage.UnscheduleDeconstruction(object_guid)
|
||||
vehicleService ! VehicleServiceMessage.RequestDeleteVehicle(vehicle, continent)
|
||||
log.info(s"RequestDestroy: vehicle $object_guid")
|
||||
|
|
@ -2084,7 +2130,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
|
||||
case Some(obj : Terminal) =>
|
||||
if(obj.Definition.isInstanceOf[MatrixTerminalDefinition] || obj.Definition.isInstanceOf[SpawnTerminalDefinition]) {
|
||||
if(obj.Definition.isInstanceOf[MatrixTerminalDefinition]) {
|
||||
//TODO matrix spawn point; for now, just blindly bind to show work (and hope nothing breaks)
|
||||
sendResponse(BindPlayerMessage(1, "@ams", true, true, 0, 0, 0, obj.Position))
|
||||
}
|
||||
|
|
@ -2092,6 +2138,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
}
|
||||
|
||||
case Some(obj : SpawnTube) =>
|
||||
//deconstruction
|
||||
PlayerActionsToCancel()
|
||||
player.Release
|
||||
sendResponse(AvatarDeadStateMessage(DeadState.Release, 0, 0, player.Position, 2, true))
|
||||
continent.Population ! Zone.Population.Release(avatar)
|
||||
|
||||
case Some(obj : PlanetSideGameObject) =>
|
||||
if(itemType != 121) {
|
||||
sendResponse(UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
|
|
@ -2217,7 +2270,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
def dismountWarning(msg : String) : Unit = {
|
||||
log.warn(s"$msg; some vehicle might not know that a player is no longer sitting in it")
|
||||
}
|
||||
if(player.GUID == player_guid) {
|
||||
if(player.HasGUID && player.GUID == player_guid) {
|
||||
//normally disembarking from a seat
|
||||
player.VehicleSeated match {
|
||||
case Some(obj_guid) =>
|
||||
|
|
@ -2562,32 +2615,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
override def onFailure(ex : Throwable) : Unit = {
|
||||
localAnnounce ! PlayerFailedToLoad(localPlayer) //alerts WSA
|
||||
}
|
||||
}, List(RegisterLightweightAvatar(tplayer)(continent.GUID))
|
||||
}, List(GUIDTask.RegisterPlayer(tplayer)(continent.GUID))
|
||||
)
|
||||
}
|
||||
|
||||
//TODO temporary function for registering avatar without locker contents
|
||||
def RegisterLightweightAvatar(tplayer : Player)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
||||
import net.psforever.objects.LockerContainer
|
||||
import net.psforever.objects.inventory.InventoryItem
|
||||
val holsterTasks = tplayer.Holsters().filter(_.Equipment.isDefined).map(slot =>{
|
||||
GUIDTask.RegisterEquipment(slot.Equipment.get)(guid)
|
||||
}).toList
|
||||
val inventoryTasks = tplayer.Inventory.Items.map({ case((_ : Int, entry : InventoryItem)) => GUIDTask.RegisterEquipment(entry.obj)(guid)})
|
||||
TaskResolver.GiveTask(GUIDTask.RegisterObjectTask(tplayer)(guid).task, holsterTasks ++ inventoryTasks)
|
||||
}
|
||||
|
||||
//TODO temporary function for unregistering avatar without locker contents
|
||||
def UnregisterLightweightAvatar(tplayer : Player)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
||||
import net.psforever.objects.LockerContainer
|
||||
import net.psforever.objects.inventory.InventoryItem
|
||||
val holsterTasks = tplayer.Holsters().filter(_.Equipment.isDefined).map(slot =>{
|
||||
GUIDTask.UnregisterEquipment(slot.Equipment.get)(guid)
|
||||
}).toList
|
||||
val inventoryTasks = tplayer.Inventory.Items.map({ case((_ : Int, entry : InventoryItem)) => GUIDTask.UnregisterEquipment(entry.obj)(guid)})
|
||||
TaskResolver.GiveTask(GUIDTask.UnregisterObjectTask(tplayer)(guid).task, holsterTasks ++ inventoryTasks)
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct tasking that adds a completed and registered vehicle into the scene.
|
||||
* Use this function to renew the globally unique identifiers on a vehicle that has already been added to the scene once.
|
||||
|
|
@ -2739,6 +2770,22 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
)
|
||||
}
|
||||
|
||||
def TaskBeforeZoneChange(priorTask : TaskResolver.GiveTask, zoneId : String) : TaskResolver.GiveTask = {
|
||||
TaskResolver.GiveTask(
|
||||
new Task() {
|
||||
private val localService = galaxy
|
||||
private val localMsg = InterstellarCluster.GetWorld(zoneId)
|
||||
|
||||
override def isComplete : Task.Resolution.Value = Task.Resolution.Success
|
||||
|
||||
def Execute(resolver : ActorRef) : Unit = {
|
||||
localService ! localMsg
|
||||
resolver ! scala.util.Success(this)
|
||||
}
|
||||
}, List(priorTask)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* After a client has connected to the server, their account is used to generate a list of characters.
|
||||
* On the character selection screen, each of these characters is made to exist temporarily when one is selected.
|
||||
|
|
@ -3223,10 +3270,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
* @param building the building object
|
||||
*/
|
||||
def initBuilding(continentNumber : Int, buildingNumber : Int, building : Building) : Unit = {
|
||||
building match {
|
||||
case _ : WarpGate =>
|
||||
building.BuildingType match {
|
||||
case StructureType.WarpGate =>
|
||||
initGate(continentNumber, buildingNumber, building)
|
||||
case _ : Building =>
|
||||
case _ =>
|
||||
initFacility(continentNumber, buildingNumber, building)
|
||||
}
|
||||
}
|
||||
|
|
@ -3309,6 +3356,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(BroadcastWarpgateUpdateMessage(continentNumber, buildingNumber, false, false, true))
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the buildings and each specific amenity for that building in a given zone by sending the client packets.
|
||||
* These actions are performed during the loading of a zone.
|
||||
* @see `SetEmpireMessage`<br>
|
||||
* `PlanetsideAttributeMessage`<br>
|
||||
* `HackMessage`
|
||||
* @param zone the zone being loaded
|
||||
*/
|
||||
def configZone(zone : Zone) : Unit = {
|
||||
zone.Buildings.values.foreach(building => {
|
||||
sendResponse(SetEmpireMessage(PlanetSideGUID(building.ModelId), building.Faction))
|
||||
|
|
@ -3322,11 +3377,90 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
|
||||
/**
|
||||
* TODO write
|
||||
* The player has lost all his vitality and must be killed.<br>
|
||||
* <br>
|
||||
* Shift directly into a state of being dead on the client by setting health to zero points,
|
||||
* whereupon the player will perform a dramatic death animation.
|
||||
* Stamina is also set to zero points.
|
||||
* If the player was in a vehicle at the time of demise, special conditions apply and
|
||||
* the model must be manipulated so it behaves correctly.
|
||||
* Do not move or completely destroy the `Player` object as its coordinates of death will be important.<br>
|
||||
* <br>
|
||||
* A maximum revive waiting timer is started.
|
||||
* When this timer reaches zero, the avatar will attempt to spawn back on its faction-specific sanctuary continent.
|
||||
* @pararm tplayer the player to be killed
|
||||
*/
|
||||
def KillPlayer(tplayer : Player) : Unit = {
|
||||
val player_guid = tplayer.GUID
|
||||
val pos = tplayer.Position
|
||||
val respawnTimer = 300000 //milliseconds
|
||||
tplayer.Die
|
||||
sendResponse(PlanetsideAttributeMessage(player_guid, 0, 0))
|
||||
sendResponse(PlanetsideAttributeMessage(player_guid, 2, 0))
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 0, 0))
|
||||
sendResponse(DestroyMessage(player_guid, player_guid, PlanetSideGUID(0), pos)) //how many players get this message?
|
||||
sendResponse(AvatarDeadStateMessage(DeadState.Dead, respawnTimer, respawnTimer, pos, 2, true))
|
||||
if(tplayer.VehicleSeated.nonEmpty) {
|
||||
//make player invisible (if not, the cadaver sticks out the side in a seated position)
|
||||
sendResponse(PlanetsideAttributeMessage(player_guid, 29, 1))
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 29, 1))
|
||||
}
|
||||
PlayerActionsToCancel()
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
reviveTimer = context.system.scheduler.scheduleOnce(respawnTimer milliseconds, galaxy, Zone.Lattice.RequestSpawnPoint(Zones.SanctuaryZoneNumber(tplayer.Faction), tplayer, 7))
|
||||
}
|
||||
|
||||
/**
|
||||
* An event has occurred that would cause the player character to stop certain stateful activities.
|
||||
* These activities include shooting, hacking, accessing (a container), flying, and running.
|
||||
* Other players in the same zone must be made aware that the player has stopped as well.<br>
|
||||
* <br>
|
||||
* Things whose configuration should not be changed:<br>
|
||||
* - if the player is seated
|
||||
*/
|
||||
def PlayerActionsToCancel() : Unit = {
|
||||
progressBarUpdate.cancel
|
||||
progressBarValue = None
|
||||
accessedContainer match {
|
||||
case Some(obj : Vehicle) =>
|
||||
if(obj.AccessingTrunk.contains(player.GUID)) {
|
||||
obj.AccessingTrunk = None
|
||||
UnAccessContents(obj)
|
||||
}
|
||||
accessedContainer = None
|
||||
|
||||
case Some(_) =>
|
||||
accessedContainer = None
|
||||
|
||||
case None => ;
|
||||
}
|
||||
shooting match {
|
||||
case Some(guid) =>
|
||||
sendResponse(ChangeFireStateMessage_Stop(guid))
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, guid))
|
||||
shooting = None
|
||||
case None => ;
|
||||
}
|
||||
if(flying) {
|
||||
sendResponse(ChatMsg(ChatMessageType.CMT_FLY, false, "", "off", None))
|
||||
flying = false
|
||||
}
|
||||
if(speed > 1) {
|
||||
sendResponse(ChatMsg(ChatMessageType.CMT_SPEED, false, "", "1.000", None))
|
||||
speed = 1f
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A part of the process of spawning the player into the game world.
|
||||
* The function should work regardless of whether the player is alive or dead - it will make them alive.
|
||||
* It adds the `WSA`-current `Player` to the current zone and sends out the expected packets.
|
||||
*/
|
||||
def AvatarCreate() : Unit = {
|
||||
player.Spawn
|
||||
player.Health = 50
|
||||
player.Health = 50 //TODO temp
|
||||
val packet = player.Definition.Packet
|
||||
val dcdata = packet.DetailedConstructorData(player).get
|
||||
sendResponse(ObjectCreateDetailedMessage(ObjectClass.avatar, player.GUID, dcdata))
|
||||
|
|
@ -3335,11 +3469,16 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
log.debug(s"ObjectCreateDetailedMessage: $dcdata")
|
||||
}
|
||||
|
||||
def SpawnRequest(tplayer : Player) : Player = {
|
||||
/**
|
||||
* Produce a clone of the player that is equipped with the default infantry loadout.
|
||||
* The loadout is hardcoded.
|
||||
* The player is expected to be in a Standard Exo-Suit.
|
||||
* @param tplayer the original player
|
||||
* @return the duplication of the player, in Standard Exo-Suit and with default equipment loadout
|
||||
*/
|
||||
def RespawnClone(tplayer : Player) : Player = {
|
||||
val faction = tplayer.Faction
|
||||
val obj = Player.Respawn(tplayer)
|
||||
//obj.VehicleOwned = tplayer.VehicleOwned
|
||||
//obj.Continent = tplayer.Continent
|
||||
obj.Slot(0).Equipment = Tool(StandardPistol(faction))
|
||||
obj.Slot(2).Equipment = Tool(suppressor)
|
||||
obj.Slot(4).Equipment = Tool(StandardMelee(faction))
|
||||
|
|
@ -3352,13 +3491,38 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
obj
|
||||
}
|
||||
|
||||
def turnPlayerIntoCorpse(tplayer : Player) : Unit = {
|
||||
//sendResponse(PlanetsideAttributeMessage(tplayer.GUID, 6, 1))
|
||||
/**
|
||||
* Creates a player that has the characteristics of a corpse.
|
||||
* To the game, that is a backpack (or some pastry, festive graphical modification allowing).
|
||||
* @see `CorpseConverter.converter`
|
||||
* @param tplayer the player
|
||||
*/
|
||||
def TurnPlayerIntoCorpse(tplayer : Player) : Unit = {
|
||||
sendResponse(
|
||||
ObjectCreateDetailedMessage(ObjectClass.avatar, tplayer.GUID, CorpseConverter.converter.DetailedConstructorData(tplayer).get)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to tranfer to the player's faction-specific sanctuary continent.
|
||||
* If the server thinks the player is already on his sanctuary continent,
|
||||
* it will disconnect the player under the assumption that an error has occurred.
|
||||
* Eventually, this functionality should support better error-handling before it jumps to the conclusion:
|
||||
* "Disconnecting the client is the safest option."
|
||||
* @see `Zones.SanctuaryZoneNumber`
|
||||
* @param tplayer the player
|
||||
* @param currentZone the current cone number
|
||||
*/
|
||||
def RequestSanctuaryZoneSpawn(tplayer : Player, currentZone : Int) : Unit = {
|
||||
val sanctNumber = Zones.SanctuaryZoneNumber(tplayer.Faction)
|
||||
if(currentZone == sanctNumber) {
|
||||
sendResponse(DisconnectMessage("Player failed to load on faction's sanctuary continent. Please relog."))
|
||||
}
|
||||
else {
|
||||
galaxy ! Zone.Lattice.RequestSpawnPoint(sanctNumber, tplayer, 7)
|
||||
}
|
||||
}
|
||||
|
||||
def failWithError(error : String) = {
|
||||
log.error(error)
|
||||
sendResponse(ConnectionClose())
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
import akka.actor.ActorContext
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
|
||||
object Zones {
|
||||
val z1 = new Zone("z1", Maps.map1, 1)
|
||||
|
|
@ -86,4 +87,32 @@ object Zones {
|
|||
val i3 = new Zone("i3", Maps.map98, 31)
|
||||
|
||||
val i4 = new Zone("i4", Maps.map99, 32)
|
||||
|
||||
/**
|
||||
* Get the zone identifier name for the sanctuary continent of a given empire.
|
||||
* @param faction the empire
|
||||
* @return the zone id, with a blank string as an invalidating result
|
||||
*/
|
||||
def SanctuaryZoneId(faction : PlanetSideEmpire.Value) : String = {
|
||||
faction match {
|
||||
case PlanetSideEmpire.TR => "home1"
|
||||
case PlanetSideEmpire.NC => "home2"
|
||||
case PlanetSideEmpire.VS => "home3"
|
||||
case PlanetSideEmpire.NEUTRAL => "" //invalid, not black ops
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the zone number for the sanctuary continent of a given empire.
|
||||
* @param faction the empire
|
||||
* @return the zone number, within the sequence 1-32, and with 0 as an invalidating result
|
||||
*/
|
||||
def SanctuaryZoneNumber(faction : PlanetSideEmpire.Value) : Int = {
|
||||
faction match {
|
||||
case PlanetSideEmpire.TR => 11
|
||||
case PlanetSideEmpire.NC => 12
|
||||
case PlanetSideEmpire.VS => 13
|
||||
case PlanetSideEmpire.NEUTRAL => 0 //invalid, not black ops
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ class UndertakerActor extends Actor {
|
|||
override def onFailure(ex : Throwable): Unit = {
|
||||
localAnnounce ! UndertakerActor.FailureToWork(localCorpse, localZone, ex)
|
||||
}
|
||||
}, List(GUIDTask.UnregisterAvatar(corpse)(zone.GUID))
|
||||
}, List(GUIDTask.UnregisterPlayer(corpse)(zone.GUID))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue