Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,20 @@ game {
force-rotation-immediately = false
}

virtual-training = {
# Enables VR Shooting Range targets, if you know the VR Shooting Range is not going to be used,
# you can disable target spawns to slightly reduce the server's baseline CPU and memory usage.
shooting-range-targets-enabled = true

# You can customize the list of VR Shooting Range bot names here.
# The default names are all names that were observed from the original servers.
male-bot-names = ["Aphtek", "Arrius", "Augustus", "Batezek", "Baulk", "Bayloon", "Bentar", "Braydon", "Brok", "Brutus", "Byatis", "Cantrip", "Doragon", "Elion", "Garbazhu", "GAxir", "Ghurmak", "Grailbait", "Graznack", "Gorabbus", "Gorganogan", "Hlanith", "Jitrick", "Julianus", "Knyan", "Lupus", "Marcus", "Morkardar", "Morungat", "Murch", "Nerick", "Nezcaro", "Plinius", "Prondus", "Publius", "Quillion", "Remus", "Secarr", "Shantak", "Shoggoth", "Shulogrem", "Taractus", "Tazok", "Thran", "Thremnir", "Urzican", "Zorach", "Yarblek", "Yith", "Yoth"]

female-bot-names = ["Agatz", "Aggan", "Arham", "Borador", "Brrt", "Cahh", "Ceth", "Chazor", "Cherik", "Corax", "Cyaegha", "Cykranosh", "Dentarg", "Drask", "Fathrd", "Ghorak", "Grogdish", "Grotta", "Gorman", "Hurrbrrmn", "Hrrd", "Ithak", "Julius", "Kephnes", "Kherek", "Korros", "Kraa", "Kradak", "Kryle", "Marcius", "Melderthra", "Minx", "Mnar", "Nanak", "Ngranek", "Nir", "Nyariathotep", "Sharagar", "Sharrak", "Shkar", "Ssaad", "Ssikz", "Tarach", "Tarkacho", "Tassadar", "Thraa", "Thurraz", "Tyr", "Utz", "Whea", "Yakkaz", "Yarak", "Zadrak"]

universal-bot-names = ["Bane", "Barzai", "BoacTreth", "Brazoragh", "Cicero", "Chamak", "Chrkss", "Cshsssh", "DylathLeen", "Gnomon", "GrizzleBok", "Hatheg", "Izch", "Jazzkkrt", "Mogor", "Myst", "Nero", "OothNarga", "Orrg", "Shadow", "TchoTcho", "Twilight", "Vthak", "Vulthoom", "Ychch", "Zar", "Zhar"]
}

saved-msg = {
# A brief delay to the @charsaved message, in seconds.
# Use this when the message should display very soon for any reason.
Expand Down
14 changes: 14 additions & 0 deletions src/main/resources/guid-pools/tzshnc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"Name": "environment",
"Start": 0,
"Max": 896,
"Selector": "specific"
},
{
"Name": "bots",
"Start": 1300,
"Max": 1600,
"Selector": "random"
}
]
14 changes: 14 additions & 0 deletions src/main/resources/guid-pools/tzshtr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"Name": "environment",
"Start": 0,
"Max": 896,
"Selector": "specific"
},
{
"Name": "bots",
"Start": 1300,
"Max": 1600,
"Selector": "random"
}
]
14 changes: 14 additions & 0 deletions src/main/resources/guid-pools/tzshvs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"Name": "environment",
"Start": 0,
"Max": 896,
"Selector": "specific"
},
{
"Name": "bots",
"Start": 1300,
"Max": 1600,
"Selector": "random"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import akka.actor.{ActorContext, ActorRef, typed}
import net.psforever.actors.session.AvatarActor
import net.psforever.actors.session.support.{GeneralFunctions, GeneralOperations, SessionData}
import net.psforever.objects.{Account, BoomerDeployable, BoomerTrigger, ConstructionItem, GlobalDefinitions, LivePlayerList, Player, SensorDeployable, ShieldGeneratorDeployable, SpecialEmp, TelepadDeployable, Tool, TrapDeployable, TurretDeployable, Vehicle}
import net.psforever.objects.avatar.{Avatar, PlayerControl}
import net.psforever.objects.avatar.{Avatar, AvatarBot, PlayerControl}
import net.psforever.objects.ballistics.Projectile
import net.psforever.objects.ce.Deployable
import net.psforever.objects.definition.{BasicDefinition, KitDefinition, SpecialExoSuitDefinition}
Expand Down Expand Up @@ -286,6 +286,8 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
ops.handleUseGeneralEntity(panel, equipment)
case Some(obj: Player) =>
ops.handleUsePlayer(obj, equipment, pkt)
case Some(obj: AvatarBot) =>
ops.handleUseBot(obj, equipment, pkt)
case Some(locker: Locker) =>
ops.handleUseLocker(locker, equipment, pkt)
case Some(gen: Generator) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import akka.actor.{ActorContext, ActorRef, typed}
import net.psforever.actors.session.{AvatarActor, SessionActor}
import net.psforever.actors.session.support.{GeneralFunctions, GeneralOperations, SessionData, SessionOutfitHandlers}
import net.psforever.objects.{Account, BoomerDeployable, BoomerTrigger, ConstructionItem, GlobalDefinitions, LivePlayerList, Player, SensorDeployable, ShieldGeneratorDeployable, SpecialEmp, TelepadDeployable, Tool, TrapDeployable, TurretDeployable, Vehicle}
import net.psforever.objects.avatar.{Avatar, PlayerControl, SpecialCarry}
import net.psforever.objects.avatar.{Avatar, AvatarBot, PlayerControl, SpecialCarry}
import net.psforever.objects.ballistics.Projectile
import net.psforever.objects.ce.{Deployable, DeployedItem}
import net.psforever.objects.definition.{BasicDefinition, KitDefinition, SpecialExoSuitDefinition}
Expand Down Expand Up @@ -356,6 +356,8 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
ops.handleUseGeneralEntity(panel, equipment)
case Some(obj: Player) =>
ops.handleUsePlayer(obj, equipment, pkt)
case Some(obj: AvatarBot) =>
ops.handleUseBot(obj, equipment, pkt)
case Some(locker: Locker) =>
ops.handleUseLocker(locker, equipment, pkt)
case Some(gen: Generator) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package net.psforever.actors.session.support

import akka.actor.{ActorContext, ActorRef, Cancellable, typed}
import net.psforever.objects.avatar.AvatarBot
import net.psforever.objects.serverobject.containable.Containable
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.serverobject.interior.Sidedness
Expand Down Expand Up @@ -393,9 +394,17 @@ class GeneralOperations(
0
}
Some(TargetInfo(player.GUID, health, armor))
case Some(bot: AvatarBot) =>
val health = bot.Health.toFloat / bot.MaxHealth
val armor = if (bot.MaxArmor > 0) {
bot.Armor.toFloat / bot.MaxArmor
} else {
0
}
Some(TargetInfo(bot.GUID, health, armor))
case _ =>
log.warn(
s"TargetingImplantRequest: the info that ${player.Name} requested for target ${x.target_guid} is not for a player"
s"TargetingImplantRequest: the info that ${player.Name} requested for target ${x.target_guid} is not for a player or bot"
)
None
}
Expand Down Expand Up @@ -1060,9 +1069,7 @@ class GeneralOperations(
}

def trainingGriefWarning(): Unit = {
//don't know the correct ChatMessageType for this one yet;
//it's supposed to use a pop-up that takes 5 seconds before you are allowed to close it, so disabled for now
//sendResponse(ChatMsg(ChatMessageType.CMT_QUIT, wideContents=true, "", "@TrainingGriefWarning", None))
sendResponse(GenericActionMessage(GenericAction.TrainingGriefWarning))
}

def noVoicedChat(pkt: PlanetSideGamePacket): Unit = {
Expand Down Expand Up @@ -1199,6 +1206,27 @@ class GeneralOperations(
}
}

def handleUseBot(obj: AvatarBot, equipment: Option[Equipment], msg: UseItemMessage): Unit = {
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_use")
if (msg.unk3) {
msg.object_id match {
case ObjectClass.avatar | ObjectClass.avatar_bot | ObjectClass.avatar_bot_agile | ObjectClass.avatar_bot_agile_no_weapon |
ObjectClass.avatar_bot_max | ObjectClass.avatar_bot_max_no_weapon | ObjectClass.avatar_bot_reinforced |
ObjectClass.avatar_bot_reinforced_no_weapon | ObjectClass.avatar_bot_standard | ObjectClass.avatar_bot_standard_no_weapon =>
equipment match {
case Some(tool: Tool) if tool.Definition == GlobalDefinitions.bank =>
obj.Actor ! CommonMessages.Use(player, equipment)

case Some(tool: Tool) if tool.Definition == GlobalDefinitions.medicalapplicator =>
obj.Actor ! CommonMessages.Use(player, equipment)
case _ => ()
}

case _ =>
}
}
}

def handleUseLocker(locker: Locker, equipment: Option[Equipment], msg: UseItemMessage): Unit = {
equipment match {
case Some(item) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,14 +422,25 @@ class SessionData(
if (obj.spectator && obj != player) {
administrativeKick(player)
} else {
if (obj.IsInVRZone && obj.Faction == player.Faction && obj.CharId != player.CharId) {
//don't do friendly-fire in VR zones
general.trainingGriefWarning()
if (obj.IsInVRZone && obj.Faction == player.Faction) {
//disable self-damage and friendly-fire in VR zones
if (obj.CharId != player.CharId) {
general.trainingGriefWarning()
}
} else {
obj.Actor ! Vitality.Damage(func)
}
}

case obj: AvatarBot if obj.CanDamage && obj.Actor != Default.Actor =>
log.info(s"${player.Name} is attacking ${obj.Name}")
if (obj.IsInVRZone && obj.Faction == player.Faction) {
//disable friendly-fire in VR zones
general.trainingGriefWarning()
} else {
obj.Actor ! Vitality.Damage(func)
}

case obj: Vehicle if obj.CanDamage =>
val name = player.Name
val ownerName = obj.OwnerName.getOrElse("someone")
Expand All @@ -438,17 +449,18 @@ class SessionData(
} else {
log.info(s"$name is attacking $ownerName's ${obj.Definition.Name}")
}
if (obj.IsInVRZone && obj.Faction == player.Faction && !ownerName.equals(name)) {
//don't do friendly-fire in VR zones
general.trainingGriefWarning()
if (obj.IsInVRZone && obj.Faction == player.Faction) {
//disable self-damage and friendly-fire in VR zones
if (!ownerName.equals(name)) {
general.trainingGriefWarning()
}
} else {
obj.Actor ! Vitality.Damage(func)
}

case obj: Amenity if obj.CanDamage =>
if (obj.IsInVRZone && obj.Faction == player.Faction) {
//don't do friendly-fire in VR zones
general.trainingGriefWarning()
//disable friendly-fire in VR zones
} else {
obj.Actor ! Vitality.Damage(func)
}
Expand All @@ -461,12 +473,7 @@ class SessionData(
} else {
log.info(s"$name is attacking $ownerName's ${obj.Definition.Name}")
}
if (obj.IsInVRZone && obj.Faction == player.Faction && !ownerName.equals(name)) {
//don't do friendly-fire in VR zones
general.trainingGriefWarning()
} else {
obj.Actor ! Vitality.Damage(func)
}
obj.Actor ! Vitality.Damage(func)

case _ => ()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ class WeaponAndProjectileOperations(
proxy.Position = hitPos
proxy.WhichSide = Sidedness.StrictlyBetweenSides
val radiusSquared = proxy.profile.LashRadius * proxy.profile.LashRadius
var availableTargets = sessionLogic.localSector.livePlayerList
var availableTargets = sessionLogic.localSector.livePlayerList ++ sessionLogic.localSector.botList
var unresolvedChainLashHits: Seq[VolumetricGeometry] = Seq(Point(hitPos))
var uniqueChainLashTargets: Seq[(PlanetSideGameObject with FactionAffinity with Vitality, Projectile)] = Seq()
while (unresolvedChainLashHits.nonEmpty) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,9 @@ class ZoningOperations(
.foreach { targetPlayer =>
sendResponse(PlanetsideAttributeMessage(targetPlayer.GUID, 1, 120))
}
//load active bots in zone
val bots = continent.BotAvatars
bots.foreach(bot => sendResponse(OCM.apply(bot)))
//load corpses in zone
continent.Corpses.foreach {
spawn.DepictPlayerAsCorpse
Expand Down Expand Up @@ -887,30 +890,18 @@ class ZoningOperations(
RequestSanctuaryZoneSpawn(player, player.Zone.Number)
// leveraging SetZone for now because the VR zones have no "proper" spawn points configured yet
case 17 =>
if (player.Zone.id != "tzshtr") {
context.self ! SessionActor.SetZone("tzshtr", vrShootingZoneSpawns.toArray.apply(rand.nextInt(vrShootingZoneSpawns.size)))
}
context.self ! SessionActor.SetZone("tzshtr", vrShootingZoneSpawns.toArray.apply(rand.nextInt(vrShootingZoneSpawns.size)))
case 18 =>
if (player.Zone.id != "tzshnc") {
context.self ! SessionActor.SetZone("tzshnc", vrShootingZoneSpawns.toArray.apply(rand.nextInt(vrShootingZoneSpawns.size)))
}
context.self ! SessionActor.SetZone("tzshnc", vrShootingZoneSpawns.toArray.apply(rand.nextInt(vrShootingZoneSpawns.size)))
case 19 =>
if (player.Zone.id != "tzshvs") {
context.self ! SessionActor.SetZone("tzshvs", vrShootingZoneSpawns.toArray.apply(rand.nextInt(vrShootingZoneSpawns.size)))
}
context.self ! SessionActor.SetZone("tzshvs", vrShootingZoneSpawns.toArray.apply(rand.nextInt(vrShootingZoneSpawns.size)))
case 20 =>
if (player.Zone.id != "tzdrtr") {
context.self ! SessionActor.SetZone("tzdrtr", vrDrivingAreaSpawns.toArray.apply(rand.nextInt(vrDrivingAreaSpawns.size)))
}
context.self ! SessionActor.SetZone("tzdrtr", vrDrivingAreaSpawns.toArray.apply(rand.nextInt(vrDrivingAreaSpawns.size)))
case 21 =>
if (player.Zone.id != "tzdrnc") {
context.self ! SessionActor.SetZone("tzdrnc", vrDrivingAreaSpawns.toArray.apply(rand.nextInt(vrDrivingAreaSpawns.size)))
}
context.self ! SessionActor.SetZone("tzdrnc", vrDrivingAreaSpawns.toArray.apply(rand.nextInt(vrDrivingAreaSpawns.size)))
case 22 =>
if (player.Zone.id != "tzdrvs") {
context.self ! SessionActor.SetZone("tzdrvs", vrDrivingAreaSpawns.toArray.apply(rand.nextInt(vrDrivingAreaSpawns.size)))
}
case _ =>
context.self ! SessionActor.SetZone("tzdrvs", vrDrivingAreaSpawns.toArray.apply(rand.nextInt(vrDrivingAreaSpawns.size)))
case _ =>
log.warn(s"Received TrainingZoneMessage that requests unexpected zone number ${pkt.zone.guid}?")
}
}
Expand Down Expand Up @@ -1280,9 +1271,11 @@ class ZoningOperations(
ICS.FindZone(_.id.equals(zoneId), context.self)
))
} else if (player.HasGUID) {
if (player.IsInVRZone && !zoneId.startsWith("tz")) {
// reset the player to default gear to prevent them from smuggling things out of VR
log.info(s"${player.Name} is exiting VR Training, resetting ${player.Sex.possessive} loadout")
if (zoneId.startsWith("tz") || player.IsInVRZone) {
// reset the players loadout when entering or exiting any VR Training zone
// this is to prevent both entering the VR Driving Area with an ExoSuit too heavy to drive,
// or smuggling special equipment out of the VR Shooting Range
log.info(s"${player.Name} is zoning to or from a VR Training zone, resetting ${player.Sex.possessive} loadout")
val newPlayer = Player.Respawn(player)
DefinitionUtil.applyDefaultLoadout(newPlayer)
session = session.copy(player = newPlayer)
Expand Down Expand Up @@ -3176,10 +3169,12 @@ class ZoningOperations(

case _ if player.HasGUID => // player is deconstructing self or instant action
val player_guid = player.GUID
sendResponse(ObjectDeleteMessage(player_guid, unk1=1))
// entering or exiting VR zones uses a fade-out effect for the player instead of the usual green cloud deconstruction effect
val effect = if (player.IsInVRZone || zoneId.startsWith("tz")) 2 else 1
sendResponse(ObjectDeleteMessage(player_guid, unk1=effect))
continent.AvatarEvents ! AvatarServiceMessage(
continent.id,
AvatarAction.ObjectDelete(player_guid, player_guid, unk=1)
AvatarAction.ObjectDelete(player_guid, player_guid, unk=effect)
)
InGameHistory.SpawnReconstructionActivity(player, toZoneNumber, betterSpawnPoint)
LoadZoneAsPlayerUsing(player, pos, ori, toSide, zoneId)
Expand Down
Loading
Loading