From 058e1b96e608faf43f92cca0ea66d00b9a040a64 Mon Sep 17 00:00:00 2001 From: PeccNeck <74548962+PeccNeck@users.noreply.github.com> Date: Fri, 12 Sep 2025 20:31:57 -0400 Subject: [PATCH 1/5] fix cartridge ordering --- .../Station/Systems/StationSpawningSystem.cs | 52 +++++++++++++++++-- .../Station/SharedStationSpawningSystem.cs | 12 +---- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/Content.Server/Station/Systems/StationSpawningSystem.cs b/Content.Server/Station/Systems/StationSpawningSystem.cs index 9726bc8fde39..5a824414df5c 100644 --- a/Content.Server/Station/Systems/StationSpawningSystem.cs +++ b/Content.Server/Station/Systems/StationSpawningSystem.cs @@ -184,6 +184,10 @@ public EntityUid SpawnPlayerMob( hasBalance = true; } + // Arrays to store all keys and cartridges + EntProtoId[] encryptionKeys = Array.Empty(); + EntProtoId[] pdaCartridges = Array.Empty(); + // Order loadout selections by the order they appear on the prototype. foreach (var group in loadout.SelectedLoadouts.OrderBy(x => roleProto!.Groups.FindIndex(e => e == x.Key))) { @@ -205,6 +209,7 @@ public EntityUid SpawnPlayerMob( { bankBalance -= int.Max(0, loadoutProto.Price); // Treat negatives as zero. EquipStartingGear(entity.Value, loadoutProto, raiseEvent: false); + StoreKeysAndCartridges(loadoutProto, ref encryptionKeys, ref pdaCartridges); equippedItems.Add(loadoutProto.ID); } } @@ -234,6 +239,7 @@ public EntityUid SpawnPlayerMob( } EquipStartingGear(entity.Value, loadoutProto, raiseEvent: false); + StoreKeysAndCartridges(loadoutProto, ref encryptionKeys, ref pdaCartridges); equippedItems.Add(fallback); // Minimum number of items equipped, no need to load more prototypes. if (equippedItems.Count >= groupPrototype.MinLimit) @@ -244,8 +250,19 @@ public EntityUid SpawnPlayerMob( // Frontier: do not re-equip roleLoadout, make sure we equip job startingGear, // and deduct loadout costs from a bank account if we have one. - if (prototype?.StartingGear is not null) - EquipStartingGear(entity.Value, prototype.StartingGear, raiseEvent: false); + PrototypeManager.TryIndex(prototype?.StartingGear, out var startingGear); + + if (startingGear is not null) + { + EquipStartingGear(entity.Value, startingGear, raiseEvent: false); + StoreKeysAndCartridges(startingGear, ref encryptionKeys, ref pdaCartridges); + } + + StartingGearPrototype loadablesGear = new(); + loadablesGear.EncryptionKeys = encryptionKeys.ToList(); + loadablesGear.Cartridges = pdaCartridges.ToList(); + + TryEquipKeysAndCartridges(entity.Value, loadablesGear); var bankComp = EnsureComp(entity.Value); @@ -322,7 +339,7 @@ public void SetPdaAndIdCardData(EntityUid entity, string characterName, JobProto #endregion Player spawning helpers - // Frontier: equip cartridges + // Frontier: store and equip encryption keys and cartridges protected override void EquipPdaCartridgesIfPossible(EntityUid entity, List pdaCartridges) { if (!InventorySystem.TryGetSlotEntity(entity, "id", out var slotEnt)) @@ -338,6 +355,7 @@ protected override void EquipPdaCartridgesIfPossible(EntityUid entity, List 0) + { + EquipEncryptionKeysIfPossible(entity, loadoutProto.EncryptionKeys); + } + + if (loadoutProto.Cartridges.Count > 0) + { + EquipPdaCartridgesIfPossible(entity, loadoutProto.Cartridges); + } + } + // End Frontier: store and equip encryption keys and cartridges } /// diff --git a/Content.Shared/Station/SharedStationSpawningSystem.cs b/Content.Shared/Station/SharedStationSpawningSystem.cs index babb983a1fb6..d4ce3067841b 100644 --- a/Content.Shared/Station/SharedStationSpawningSystem.cs +++ b/Content.Shared/Station/SharedStationSpawningSystem.cs @@ -230,17 +230,6 @@ public void EquipStartingGear(EntityUid entity, IEquipmentLoadout? startingGear, QueueDel(spawnedEntity); } } - - if (startingGear.EncryptionKeys.Count > 0) - { - EquipEncryptionKeysIfPossible(entity, startingGear.EncryptionKeys); - } - - // PDA cartridges must run on server, installation logic exists server-side. - if (_net.IsServer && startingGear.Cartridges.Count > 0) - { - EquipPdaCartridgesIfPossible(entity, startingGear.Cartridges); - } // End Frontier if (raiseEvent) @@ -302,6 +291,7 @@ protected void EquipEncryptionKeysIfPossible(EntityUid entity, List var coords = _xformSystem.GetMapCoordinates(entity); foreach (var entProto in encryptionKeys) { + Log.Debug($"Entity {entity} auto-inserting loadout encryption key {entProto} into headset {keyContainer}."); var spawnedEntity = Spawn(entProto, coords); if (!_container.Insert(spawnedEntity, keyContainer)) { From cd3c91e704365c704ea73b639f0c537c1de6e1df Mon Sep 17 00:00:00 2001 From: PeccNeck <74548962+PeccNeck@users.noreply.github.com> Date: Sun, 14 Sep 2025 00:08:11 -0400 Subject: [PATCH 2/5] loadouts make do betterer* (*maybe) --- .../Station/StationSpawningSystem.cs | 3 +- .../Station/Systems/StationSpawningSystem.cs | 123 +++++++++++++----- .../Station/SharedStationSpawningSystem.cs | 67 ---------- 3 files changed, 90 insertions(+), 103 deletions(-) diff --git a/Content.Client/Station/StationSpawningSystem.cs b/Content.Client/Station/StationSpawningSystem.cs index babd2855afd7..65da518d229b 100644 --- a/Content.Client/Station/StationSpawningSystem.cs +++ b/Content.Client/Station/StationSpawningSystem.cs @@ -1,9 +1,8 @@ using Content.Shared.Station; -using Robust.Shared.Prototypes; // Frontier namespace Content.Client.Station; public sealed class StationSpawningSystem : SharedStationSpawningSystem { - protected override void EquipPdaCartridgesIfPossible(EntityUid entity, List encryptionKeys) { } // Frontier: PDA equipment + } diff --git a/Content.Server/Station/Systems/StationSpawningSystem.cs b/Content.Server/Station/Systems/StationSpawningSystem.cs index 5a824414df5c..9b1a64d1d35c 100644 --- a/Content.Server/Station/Systems/StationSpawningSystem.cs +++ b/Content.Server/Station/Systems/StationSpawningSystem.cs @@ -30,6 +30,10 @@ using Content.Server.CartridgeLoader; // Frontier using Content.Shared.CartridgeLoader; // Frontier using Robust.Server.GameObjects; // Frontier +using Robust.Shared.Containers; // Frontier +using Content.Shared.Radio.Components; // Frontier +using Content.Shared.Implants; // Frontier +using Content.Shared.Implants.Components; // Frontier namespace Content.Server.Station.Systems; @@ -54,6 +58,8 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem [Dependency] private readonly BankSystem _bank = default!; // Frontier [Dependency] private readonly CartridgeLoaderSystem _cartridgeLoader = default!; // Frontier [Dependency] private readonly TransformSystem _xformSystem = default!; // Frontier + [Dependency] private readonly SharedContainerSystem _container = default!; // Frontier + [Dependency] private readonly SharedImplanterSystem _implanter = default!; // Frontier /// /// Attempts to spawn a player character onto the given station. @@ -184,9 +190,10 @@ public EntityUid SpawnPlayerMob( hasBalance = true; } - // Arrays to store all keys and cartridges - EntProtoId[] encryptionKeys = Array.Empty(); - EntProtoId[] pdaCartridges = Array.Empty(); + // Frontier: A final loadout applied at the end of everything else. + // Right now it's just being used for special auto-equips, + // but maybe it could be used in the future to equip all loadouts in a single pass? + StartingGearPrototype loadoutLast = new(); // Order loadout selections by the order they appear on the prototype. foreach (var group in loadout.SelectedLoadouts.OrderBy(x => roleProto!.Groups.FindIndex(e => e == x.Key))) @@ -209,7 +216,7 @@ public EntityUid SpawnPlayerMob( { bankBalance -= int.Max(0, loadoutProto.Price); // Treat negatives as zero. EquipStartingGear(entity.Value, loadoutProto, raiseEvent: false); - StoreKeysAndCartridges(loadoutProto, ref encryptionKeys, ref pdaCartridges); + CollectLoadout(loadoutProto, ref loadoutLast); equippedItems.Add(loadoutProto.ID); } } @@ -239,7 +246,7 @@ public EntityUid SpawnPlayerMob( } EquipStartingGear(entity.Value, loadoutProto, raiseEvent: false); - StoreKeysAndCartridges(loadoutProto, ref encryptionKeys, ref pdaCartridges); + CollectLoadout(loadoutProto, ref loadoutLast); equippedItems.Add(fallback); // Minimum number of items equipped, no need to load more prototypes. if (equippedItems.Count >= groupPrototype.MinLimit) @@ -255,14 +262,18 @@ public EntityUid SpawnPlayerMob( if (startingGear is not null) { EquipStartingGear(entity.Value, startingGear, raiseEvent: false); - StoreKeysAndCartridges(startingGear, ref encryptionKeys, ref pdaCartridges); + CollectLoadout(startingGear, ref loadoutLast); } - StartingGearPrototype loadablesGear = new(); - loadablesGear.EncryptionKeys = encryptionKeys.ToList(); - loadablesGear.Cartridges = pdaCartridges.ToList(); + // Frontier: Attempt auto-equip for implants, encryption keys, and PDA cartridges + if (loadoutLast.Implants.Count > 0) + EquipImplantsIfPossible(entity.Value, loadoutLast.Implants); - TryEquipKeysAndCartridges(entity.Value, loadablesGear); + if (loadoutLast.EncryptionKeys.Count > 0) + EquipEncryptionKeysIfPossible(entity.Value, loadoutLast.EncryptionKeys); + + if (loadoutLast.Cartridges.Count > 0) + EquipPdaCartridgesIfPossible(entity.Value, loadoutLast.Cartridges); var bankComp = EnsureComp(entity.Value); @@ -339,8 +350,45 @@ public void SetPdaAndIdCardData(EntityUid entity, string characterName, JobProto #endregion Player spawning helpers - // Frontier: store and equip encryption keys and cartridges - protected override void EquipPdaCartridgesIfPossible(EntityUid entity, List pdaCartridges) + // Frontier: extra loadout fields + /// + /// Function to equip an entity with encryption keys. + /// If not possible, will delete them. + /// + /// The entity to receive equipment. + /// The encryption key prototype IDs to equip. + private void EquipEncryptionKeysIfPossible(EntityUid entity, List encryptionKeys) + { + if (!InventorySystem.TryGetSlotEntity(entity, "ears", out var slotEnt)) + { + DebugTools.Assert(false, $"Entity {entity} has a non-empty encryption key loadout, but doesn't have a headset!"); + return; + } + if (!_container.TryGetContainer(slotEnt.Value, EncryptionKeyHolderComponent.KeyContainerName, out var keyContainer)) + { + DebugTools.Assert(false, $"Entity {entity} has a non-empty encryption key loadout, but their headset doesn't have an encryption key container!"); + return; + } + var coords = _xformSystem.GetMapCoordinates(entity); + foreach (var entProto in encryptionKeys) + { + Log.Debug($"Entity {entity} auto-inserting loadout encryption key {entProto} into headset {keyContainer}."); + var spawnedEntity = Spawn(entProto, coords); + if (!_container.Insert(spawnedEntity, keyContainer)) + { + QueueDel(spawnedEntity); + DebugTools.Assert(false, $"Entity {entity} could not insert their loadout encryption key {entProto} into their headset!"); + } + } + } + + /// + /// Function to equip an entity with PDA cartridges. + /// If not possible, will delete them. + /// + /// The entity to receive equipment. + /// The PDA cartridge prototype IDs to equip. + private void EquipPdaCartridgesIfPossible(EntityUid entity, List pdaCartridges) { if (!InventorySystem.TryGetSlotEntity(entity, "id", out var slotEnt)) { @@ -363,33 +411,40 @@ protected override void EquipPdaCartridgesIfPossible(EntityUid entity, List 0) + /// + /// Function to equip an entity with implants. + /// If not possible, will delete them. + /// + /// The entity to receive equipment. + /// The implant prototype IDs to equip. + private void EquipImplantsIfPossible(EntityUid entity, List implants) + { + var coords = _xformSystem.GetMapCoordinates(entity); + foreach (var entProto in implants) { - EquipEncryptionKeysIfPossible(entity, loadoutProto.EncryptionKeys); + var spawnedEntity = Spawn(entProto, coords); + if (TryComp(spawnedEntity, out var implanter)) + _implanter.Implant(entity, entity, spawnedEntity, implanter); + else + DebugTools.Assert(false, $"Entity has an implant for {entProto}, which doesn't have an implanter component!"); + QueueDel(spawnedEntity); } + } - if (loadoutProto.Cartridges.Count > 0) - { - EquipPdaCartridgesIfPossible(entity, loadoutProto.Cartridges); - } + /// + /// Function to collect and store encryption keys and cartridges. + /// Does not handle any equip logic. + /// + /// The loadout prototype to collect from. + /// Reference to the loadout to collect to. + private void CollectLoadout(IEquipmentLoadout loadoutProto, ref StartingGearPrototype collectorLoadout) + { + collectorLoadout.EncryptionKeys.AddRange(loadoutProto.EncryptionKeys); + collectorLoadout.Cartridges.AddRange(loadoutProto.Cartridges); + collectorLoadout.Implants.AddRange(loadoutProto.Implants); } - // End Frontier: store and equip encryption keys and cartridges + // End Frontier: extra loadout fields } /// diff --git a/Content.Shared/Station/SharedStationSpawningSystem.cs b/Content.Shared/Station/SharedStationSpawningSystem.cs index d4ce3067841b..3732d7b39a57 100644 --- a/Content.Shared/Station/SharedStationSpawningSystem.cs +++ b/Content.Shared/Station/SharedStationSpawningSystem.cs @@ -12,11 +12,6 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Utility; -using Content.Shared.Implants; // Frontier -using Content.Shared.Implants.Components; // Frontier -using Content.Shared.Radio.Components; // Frontier -using Robust.Shared.Containers; // Frontier -using Robust.Shared.Network; // Frontier namespace Content.Shared.Station; @@ -29,9 +24,6 @@ public abstract class SharedStationSpawningSystem : EntitySystem [Dependency] private readonly MetaDataSystem _metadata = default!; [Dependency] private readonly SharedStorageSystem _storage = default!; [Dependency] private readonly SharedTransformSystem _xformSystem = default!; - [Dependency] private readonly INetManager _net = default!; // Frontier - [Dependency] private readonly SharedContainerSystem _container = default!; // Frontier - [Dependency] private readonly SharedImplanterSystem _implanter = default!; // Frontier private EntityQuery _handsQuery; private EntityQuery _inventoryQuery; @@ -215,23 +207,6 @@ public void EquipStartingGear(EntityUid entity, IEquipmentLoadout? startingGear, } } - // Frontier: extra fields - // Implants must run on server, container initialization only runs on server, and lobby dummies don't work. - if (_net.IsServer && startingGear.Implants.Count > 0) - { - var coords = _xformSystem.GetMapCoordinates(entity); - foreach (var entProto in startingGear.Implants) - { - var spawnedEntity = Spawn(entProto, coords); - if (TryComp(spawnedEntity, out var implanter)) - _implanter.Implant(entity, entity, spawnedEntity, implanter); - else - DebugTools.Assert(false, $"Entity has an implant for {entProto}, which doesn't have an implanter component!"); - QueueDel(spawnedEntity); - } - } - // End Frontier - if (raiseEvent) { var ev = new StartingGearEquippedEvent(entity); @@ -268,46 +243,4 @@ public void EquipStartingGear(EntityUid entity, IEquipmentLoadout? startingGear, return null; } - - // Frontier: extra loadout fields - /// Function to equip an entity with encryption keys. - /// If not possible, will delete them. - /// Only called in practice server-side. - /// - /// The entity to receive equipment. - /// The encryption key prototype IDs to equip. - protected void EquipEncryptionKeysIfPossible(EntityUid entity, List encryptionKeys) - { - if (!InventorySystem.TryGetSlotEntity(entity, "ears", out var slotEnt)) - { - DebugTools.Assert(false, $"Entity {entity} has a non-empty encryption key loadout, but doesn't have a headset!"); - return; - } - if (!_container.TryGetContainer(slotEnt.Value, EncryptionKeyHolderComponent.KeyContainerName, out var keyContainer)) - { - DebugTools.Assert(false, $"Entity {entity} has a non-empty encryption key loadout, but their headset doesn't have an encryption key container!"); - return; - } - var coords = _xformSystem.GetMapCoordinates(entity); - foreach (var entProto in encryptionKeys) - { - Log.Debug($"Entity {entity} auto-inserting loadout encryption key {entProto} into headset {keyContainer}."); - var spawnedEntity = Spawn(entProto, coords); - if (!_container.Insert(spawnedEntity, keyContainer)) - { - QueueDel(spawnedEntity); - DebugTools.Assert(false, $"Entity {entity} could not insert their loadout encryption key {entProto} into their headset!"); - } - } - } - - /// - /// Function to equip an entity with PDA cartridges. - /// If not possible, will delete them. - /// Only called in practice server-side. - /// - /// The entity to receive equipment. - /// The PDA cartridge prototype IDs to equip. - protected abstract void EquipPdaCartridgesIfPossible(EntityUid entity, List encryptionKeys); - // End Frontier: extra loadout fields } From a3938086a87f587f0fc1f6508b0259985abe2e86 Mon Sep 17 00:00:00 2001 From: PeccNeck <74548962+PeccNeck@users.noreply.github.com> Date: Sun, 14 Sep 2025 15:01:42 -0400 Subject: [PATCH 3/5] tiny tweak --- Content.Server/Station/Systems/StationSpawningSystem.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Content.Server/Station/Systems/StationSpawningSystem.cs b/Content.Server/Station/Systems/StationSpawningSystem.cs index 9b1a64d1d35c..3a80b6da63e1 100644 --- a/Content.Server/Station/Systems/StationSpawningSystem.cs +++ b/Content.Server/Station/Systems/StationSpawningSystem.cs @@ -257,9 +257,7 @@ public EntityUid SpawnPlayerMob( // Frontier: do not re-equip roleLoadout, make sure we equip job startingGear, // and deduct loadout costs from a bank account if we have one. - PrototypeManager.TryIndex(prototype?.StartingGear, out var startingGear); - - if (startingGear is not null) + if (_prototypeManager.TryIndex(prototype?.StartingGear, out var startingGear)) { EquipStartingGear(entity.Value, startingGear, raiseEvent: false); CollectLoadout(startingGear, ref loadoutLast); From 13a6385ad3dd2adb69ea77505711353f7eb190a4 Mon Sep 17 00:00:00 2001 From: PeccNeck <74548962+PeccNeck@users.noreply.github.com> Date: Sun, 14 Sep 2025 17:58:16 -0400 Subject: [PATCH 4/5] more minor tweaks that will help later :) --- .../Station/Systems/StationSpawningSystem.cs | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/Content.Server/Station/Systems/StationSpawningSystem.cs b/Content.Server/Station/Systems/StationSpawningSystem.cs index 3a80b6da63e1..51e6f88f291c 100644 --- a/Content.Server/Station/Systems/StationSpawningSystem.cs +++ b/Content.Server/Station/Systems/StationSpawningSystem.cs @@ -193,7 +193,7 @@ public EntityUid SpawnPlayerMob( // Frontier: A final loadout applied at the end of everything else. // Right now it's just being used for special auto-equips, // but maybe it could be used in the future to equip all loadouts in a single pass? - StartingGearPrototype loadoutLast = new(); + LoadoutPrototype loadoutLast = new(); // Order loadout selections by the order they appear on the prototype. foreach (var group in loadout.SelectedLoadouts.OrderBy(x => roleProto!.Groups.FindIndex(e => e == x.Key))) @@ -264,14 +264,7 @@ public EntityUid SpawnPlayerMob( } // Frontier: Attempt auto-equip for implants, encryption keys, and PDA cartridges - if (loadoutLast.Implants.Count > 0) - EquipImplantsIfPossible(entity.Value, loadoutLast.Implants); - - if (loadoutLast.EncryptionKeys.Count > 0) - EquipEncryptionKeysIfPossible(entity.Value, loadoutLast.EncryptionKeys); - - if (loadoutLast.Cartridges.Count > 0) - EquipPdaCartridgesIfPossible(entity.Value, loadoutLast.Cartridges); + TryAutoEquipMisc(entity.Value, loadoutLast); var bankComp = EnsureComp(entity.Value); @@ -430,13 +423,25 @@ private void EquipImplantsIfPossible(EntityUid entity, List implants } } + public void TryAutoEquipMisc(EntityUid entity, LoadoutPrototype loadout) + { + if (loadout.Implants.Count > 0) + EquipImplantsIfPossible(entity, loadout.Implants); + + if (loadout.EncryptionKeys.Count > 0) + EquipEncryptionKeysIfPossible(entity, loadout.EncryptionKeys); + + if (loadout.Cartridges.Count > 0) + EquipPdaCartridgesIfPossible(entity, loadout.Cartridges); + } + /// /// Function to collect and store encryption keys and cartridges. /// Does not handle any equip logic. /// /// The loadout prototype to collect from. /// Reference to the loadout to collect to. - private void CollectLoadout(IEquipmentLoadout loadoutProto, ref StartingGearPrototype collectorLoadout) + private void CollectLoadout(IEquipmentLoadout loadoutProto, ref LoadoutPrototype collectorLoadout) { collectorLoadout.EncryptionKeys.AddRange(loadoutProto.EncryptionKeys); collectorLoadout.Cartridges.AddRange(loadoutProto.Cartridges); From a567b590eb5c2e02d8b623d253b261a9db8a7138 Mon Sep 17 00:00:00 2001 From: PeccNeck <74548962+PeccNeck@users.noreply.github.com> Date: Sun, 14 Sep 2025 18:29:05 -0400 Subject: [PATCH 5/5] greetings from greetings --- .../_NF/GameTicking/GameTicker.NFSpawning.cs | 16 ++++++++++++++++ Content.Shared/_NF/CCVar/NFCCVars.cs | 10 ++++++++-- .../Prototypes/_NF/Loadouts/misc_loadouts.yml | 4 ++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 Resources/Prototypes/_NF/Loadouts/misc_loadouts.yml diff --git a/Content.Server/_NF/GameTicking/GameTicker.NFSpawning.cs b/Content.Server/_NF/GameTicking/GameTicker.NFSpawning.cs index 6e827638f4cc..943d5b244001 100644 --- a/Content.Server/_NF/GameTicking/GameTicker.NFSpawning.cs +++ b/Content.Server/_NF/GameTicking/GameTicker.NFSpawning.cs @@ -1,5 +1,6 @@ using System.Numerics; using Content.Server.Players.PlayTimeTracking; +using Content.Shared.Preferences.Loadouts; using Content.Server.Radio.EntitySystems; using Content.Shared._NF.CCVar; using Content.Shared.Radio; @@ -18,12 +19,14 @@ public sealed partial class GameTicker private ProtoId _newPlayerRadioChannel = "Service"; private EntProtoId _greetingRadioSource = "GreetingRadioSource"; private EntityUid _greetingEntity = EntityUid.Invalid; + private LoadoutPrototype? _newPlayerLoadoutPrototype = null; public void NFInitialize() { Subs.CVar(_cfg, NFCCVars.NewPlayerRadioGreetingEnabled, e => _newPlayerGreetingEnabled = e, true); Subs.CVar(_cfg, NFCCVars.NewPlayerRadioGreetingMaxPlaytime, e => _newPlayerGreetingMaxTime = TimeSpan.FromMinutes(e), true); Subs.CVar(_cfg, NFCCVars.NewPlayerRadioGreetingChannel, SetChannel, true); + Subs.CVar(_cfg, NFCCVars.NewPlayerStarterLoadout, SetLoadout, true); } private void SetChannel(string channel) @@ -32,6 +35,11 @@ private void SetChannel(string channel) _newPlayerRadioChannel = channel; } + private void SetLoadout(string loadout) + { + _prototypeManager.TryIndex(loadout, out _newPlayerLoadoutPrototype); + } + private void NFRoundStarted() { _greetingEntity = Spawn(_greetingRadioSource, new MapCoordinates(Vector2.Zero, DefaultMap)); @@ -63,6 +71,14 @@ private void HandleGreetingMessage(ICommonSession session, EntityUid mob, Entity if (playtime < _newPlayerGreetingMaxTime) { + // Equip new player loadout if one is specified + // Ordered before the radio message so the new player can see it, thus communicating that it exists + if (_newPlayerLoadoutPrototype is not null) + { + _stationSpawning.EquipStartingGear(mob, _newPlayerLoadoutPrototype, false); + _stationSpawning.TryAutoEquipMisc(mob, _newPlayerLoadoutPrototype); + } + _radio.SendRadioMessage(_greetingEntity, Loc.GetString("latejoin-arrival-new-player-announcement", ("character", MetaData(mob).EntityName), ("station", station)), diff --git a/Content.Shared/_NF/CCVar/NFCCVars.cs b/Content.Shared/_NF/CCVar/NFCCVars.cs index df95aa68b1d6..06f8bb57f74f 100644 --- a/Content.Shared/_NF/CCVar/NFCCVars.cs +++ b/Content.Shared/_NF/CCVar/NFCCVars.cs @@ -279,11 +279,17 @@ public sealed class NFCCVars /// The maximum playtime, in minutes, for a new player radio message to be sent. /// public static readonly CVarDef NewPlayerRadioGreetingMaxPlaytime = - CVarDef.Create("nf14.greeting.max_playtime", 180, CVar.REPLICATED); // Three hours + CVarDef.Create("nf14.greeting.max_playtime", 600, CVar.REPLICATED); // Ten hours /// /// The channel the radio message should be sent off on. /// public static readonly CVarDef NewPlayerRadioGreetingChannel = - CVarDef.Create("nf14.greeting.channel", "Service", CVar.REPLICATED); + CVarDef.Create("nf14.greeting.channel", "Greeting", CVar.REPLICATED); + + /// + /// A starter loadout prototype given to new players. + /// + public static readonly CVarDef NewPlayerStarterLoadout = + CVarDef.Create("nf14.greeting.loadout", "NFGreenhornLoadout", CVar.REPLICATED); } diff --git a/Resources/Prototypes/_NF/Loadouts/misc_loadouts.yml b/Resources/Prototypes/_NF/Loadouts/misc_loadouts.yml new file mode 100644 index 000000000000..10076726130b --- /dev/null +++ b/Resources/Prototypes/_NF/Loadouts/misc_loadouts.yml @@ -0,0 +1,4 @@ +- type: loadout + id: NFGreenhornLoadout + encryptionKeys: + - EncryptionKeyGreeting