diff --git a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs index e005357f1f..9edfe80d20 100644 --- a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs @@ -1,12 +1,13 @@ using System.Linq; using Content.Server.Chat.Managers; +using Content.Server.NPC.Systems; using Content.Server.Objectives.Interfaces; +using Content.Server.PDA.Ringer; using Content.Server.Players; using Content.Server.Roles; +using Content.Server.Shuttles.Components; using Content.Server.Traitor; using Content.Server.Traitor.Uplink; -using Content.Server.NPC.Systems; -using Content.Server.Shuttles.Components; using Content.Shared.CCVar; using Content.Shared.Dataset; using Content.Shared.Preferences; @@ -18,8 +19,8 @@ using Robust.Shared.Configuration; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; -using Robust.Shared.Utility; using Robust.Shared.Timing; +using Robust.Shared.Utility; namespace Content.Server.GameTicking.Rules; @@ -249,14 +250,18 @@ public sealed class TraitorRuleSystem : GameRuleSystem if (mind.CurrentJob != null) startingBalance = Math.Max(startingBalance - mind.CurrentJob.Prototype.AntagAdvantage, 0); - if (!_uplink.AddUplink(mind.OwnedEntity!.Value, startingBalance)) + var pda = _uplink.FindUplinkTarget(mind.OwnedEntity!.Value); + if (pda == null || !_uplink.AddUplink(mind.OwnedEntity.Value, startingBalance)) return false; + // add the ringtone uplink and get its code for greeting + var code = AddComp(pda.Value).Code; + var antagPrototype = _prototypeManager.Index(TraitorPrototypeID); var traitorRole = new TraitorRole(mind, antagPrototype); mind.AddRole(traitorRole); Traitors.Add(traitorRole); - traitorRole.GreetTraitor(Codewords); + traitorRole.GreetTraitor(Codewords, code); _faction.RemoveFaction(entity, "NanoTrasen", false); _faction.AddFaction(entity, "Syndicate"); @@ -274,8 +279,9 @@ public sealed class TraitorRuleSystem : GameRuleSystem difficulty += objective.Difficulty; } - //give traitors their codewords to keep in their character info menu - traitorRole.Mind.Briefing = Loc.GetString("traitor-role-codewords", ("codewords", string.Join(", ", Codewords))); + //give traitors their codewords and uplink code to keep in their character info menu + traitorRole.Mind.Briefing = Loc.GetString("traitor-role-codewords-short", ("codewords", string.Join(", ", Codewords))) + + "\n" + Loc.GetString("traitor-role-uplink-code-short", ("code", string.Join("", code))); _audioSystem.PlayGlobal(_addedSound, Filter.Empty().AddPlayer(traitor), false, AudioParams.Default); return true; diff --git a/Content.Server/PDA/PDASystem.cs b/Content.Server/PDA/PDASystem.cs index fd8626cf74..8362142c83 100644 --- a/Content.Server/PDA/PDASystem.cs +++ b/Content.Server/PDA/PDASystem.cs @@ -5,8 +5,6 @@ using Content.Server.Light.Components; using Content.Server.Light.EntitySystems; using Content.Server.Light.Events; using Content.Server.PDA.Ringer; -using Content.Server.Store.Components; -using Content.Server.Store.Systems; using Content.Server.Station.Systems; using Content.Server.UserInterface; using Content.Shared.PDA; @@ -26,16 +24,12 @@ namespace Content.Server.PDA [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; [Dependency] private readonly StationSystem _stationSystem = default!; [Dependency] private readonly CartridgeLoaderSystem _cartridgeLoaderSystem = default!; - [Dependency] private readonly StoreSystem _storeSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnLightToggle); - SubscribeLocalEvent(AfterUIOpen); - SubscribeLocalEvent(OnUplinkInit); - SubscribeLocalEvent(OnUplinkRemoved); SubscribeLocalEvent(OnGridChanged); } @@ -76,16 +70,6 @@ namespace Content.Server.PDA UpdatePDAUserInterface(pda); } - private void OnUplinkInit(EntityUid uid, PDAComponent pda, ref StoreAddedEvent args) - { - UpdatePDAUserInterface(pda); - } - - private void OnUplinkRemoved(EntityUid uid, PDAComponent pda, ref StoreRemovedEvent args) - { - UpdatePDAUserInterface(pda); - } - private void OnGridChanged(EntityUid uid, PDAComponent pda, GridModifiedEvent args) { UpdateStationName(pda); @@ -109,25 +93,6 @@ namespace Content.Server.PDA var state = new PDAUpdateState(pda.FlashlightOn, pda.PenSlot.HasItem, ownerInfo, pda.StationName, false, hasInstrument, address); _cartridgeLoaderSystem?.UpdateUiState(pda.Owner, state); - - // TODO UPLINK RINGTONES/SECRETS This is just a janky placeholder way of hiding uplinks from non syndicate - // players. This should really use a sort of key-code entry system that selects an account which is not directly tied to - // a player entity. - - if (!TryComp(pda.Owner, out var storeComponent)) - return; - - var uplinkState = new PDAUpdateState(pda.FlashlightOn, pda.PenSlot.HasItem, ownerInfo, pda.StationName, true, hasInstrument, address); - - foreach (var session in ui.SubscribedSessions) - { - if (session.AttachedEntity is not { Valid: true } user) - continue; - - if (storeComponent.AccountOwner == user || (TryComp(session.AttachedEntity, out var mindcomp) && mindcomp.Mind != null && - mindcomp.Mind.HasRole())) - _cartridgeLoaderSystem?.UpdateUiState(pda.Owner, uplinkState, session); - } } private void OnUIMessage(PDAComponent pda, ServerBoundUserInterfaceMessage msg) @@ -145,14 +110,6 @@ namespace Content.Server.PDA _unpoweredFlashlight.ToggleLight(pdaEnt, flashlight); break; } - - case PDAShowUplinkMessage _: - { - if (msg.Session.AttachedEntity != null && - TryComp(pdaEnt, out var store)) - _storeSystem.ToggleUi(msg.Session.AttachedEntity.Value, pdaEnt, store); - break; - } case PDAShowRingtoneMessage _: { if (EntityManager.TryGetComponent(pdaEnt, out RingerComponent? ringer)) @@ -174,32 +131,6 @@ namespace Content.Server.PDA pda.StationName = station is null ? null : Name(station.Value); } - private void AfterUIOpen(EntityUid uid, PDAComponent pda, AfterActivatableUIOpenEvent args) - { - //TODO: this is awful - // A new user opened the UI --> Check if they are a traitor and should get a user specific UI state override. - if (!TryComp(pda.Owner, out var storeComp)) - return; - - if (storeComp.AccountOwner != args.User && - !(TryComp(args.User, out var mindcomp) && mindcomp.Mind != null && mindcomp.Mind.HasRole())) - return; - - if (!_uiSystem.TryGetUi(pda.Owner, PDAUiKey.Key, out var ui)) - return; - - var ownerInfo = new PDAIdInfoText - { - ActualOwnerName = pda.OwnerName, - IdOwner = pda.ContainedID?.FullName, - JobTitle = pda.ContainedID?.JobTitle - }; - - var state = new PDAUpdateState(pda.FlashlightOn, pda.PenSlot.HasItem, ownerInfo, pda.StationName, true, HasComp(pda.Owner), GetDeviceNetAddress(pda.Owner)); - - _cartridgeLoaderSystem?.UpdateUiState(uid, state, args.Session); - } - private string? GetDeviceNetAddress(EntityUid uid) { string? address = null; diff --git a/Content.Server/PDA/Ringer/RingerSystem.cs b/Content.Server/PDA/Ringer/RingerSystem.cs index eb5e38e5a8..b0b56bc740 100644 --- a/Content.Server/PDA/Ringer/RingerSystem.cs +++ b/Content.Server/PDA/Ringer/RingerSystem.cs @@ -1,17 +1,21 @@ +using Content.Server.Store.Components; +using Content.Server.Store.Systems; using Content.Server.UserInterface; -using Content.Shared.PDA.Ringer; -using Robust.Shared.Audio; -using Robust.Server.Player; -using Robust.Shared.Player; using Content.Shared.PDA; +using Content.Shared.PDA.Ringer; +using Robust.Server.Player; +using Robust.Shared.Audio; +using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Utility; +using System.Linq; namespace Content.Server.PDA.Ringer { public sealed class RingerSystem : SharedRingerSystem { [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly StoreSystem _store = default!; public override void Initialize() { @@ -19,10 +23,13 @@ namespace Content.Server.PDA.Ringer // General Event Subscriptions SubscribeLocalEvent(RandomizeRingtone); + SubscribeLocalEvent(RandomizeUplinkCode); // RingerBoundUserInterface Subscriptions SubscribeLocalEvent(OnSetRingtone); + SubscribeLocalEvent(OnSetUplinkRingtone); SubscribeLocalEvent(RingerPlayRingtone); SubscribeLocalEvent(UpdateRingerUserInterfaceDriver); + } //Event Functions @@ -46,7 +53,30 @@ namespace Content.Server.PDA.Ringer UpdateRingerRingtone(ringer, args.Ringtone); } + private void OnSetUplinkRingtone(EntityUid uid, RingerUplinkComponent uplink, RingerSetRingtoneMessage args) + { + if (uplink.Code.SequenceEqual(args.Ringtone) && + args.Session.AttachedEntity != null && + TryComp(uid, out var store)) + { + var user = args.Session.AttachedEntity.Value; + _store.ToggleUi(args.Session.AttachedEntity.Value, uid, store); + } + } + public void RandomizeRingtone(EntityUid uid, RingerComponent ringer, MapInitEvent args) + { + UpdateRingerRingtone(ringer, GenerateRingtone()); + } + + public void RandomizeUplinkCode(EntityUid uid, RingerUplinkComponent uplink, ComponentInit args) + { + uplink.Code = GenerateRingtone(); + } + + //Non Event Functions + + private Note[] GenerateRingtone() { // Default to using C pentatonic so it at least sounds not terrible. var notes = new[] @@ -65,12 +95,9 @@ namespace Content.Server.PDA.Ringer ringtone[i] = _random.Pick(notes); } - UpdateRingerRingtone(ringer, ringtone); - + return ringtone; } - //Non Event Functions - private bool UpdateRingerRingtone(RingerComponent ringer, Note[] ringtone) { // Assume validation has already happened. diff --git a/Content.Server/PDA/Ringer/RingerUplinkComponent.cs b/Content.Server/PDA/Ringer/RingerUplinkComponent.cs new file mode 100644 index 0000000000..138c48fb22 --- /dev/null +++ b/Content.Server/PDA/Ringer/RingerUplinkComponent.cs @@ -0,0 +1,18 @@ +using Content.Shared.PDA; + +namespace Content.Server.PDA.Ringer; + +/// +/// Opens the store ui when the ringstone is set to the secret code. +/// Traitors are told the code when greeted. +/// +[RegisterComponent, Access(typeof(RingerSystem))] +public sealed class RingerUplinkComponent : Component +{ + /// + /// Notes to set ringtone to in order to open the uplink. + /// Automatically initialized to random notes. + /// + [DataField("code")] + public Note[] Code = new Note[RingerSystem.RingtoneLength]; +} diff --git a/Content.Server/Traitor/TraitorRole.cs b/Content.Server/Traitor/TraitorRole.cs index 4e23122e7d..6717fcb4c6 100644 --- a/Content.Server/Traitor/TraitorRole.cs +++ b/Content.Server/Traitor/TraitorRole.cs @@ -1,5 +1,6 @@ using Content.Server.Chat.Managers; using Content.Server.Roles; +using Content.Shared.PDA; using Content.Shared.Roles; namespace Content.Server.Traitor @@ -18,13 +19,15 @@ namespace Content.Server.Traitor public override string Name { get; } public override bool Antagonist { get; } - public void GreetTraitor(string[] codewords) + public void GreetTraitor(string[] codewords, Note[] code) { if (Mind.TryGetSession(out var session)) { var chatMgr = IoCManager.Resolve(); + var entMgr = IoCManager.Resolve(); chatMgr.DispatchServerMessage(session, Loc.GetString("traitor-role-greeting")); - chatMgr.DispatchServerMessage(session, Loc.GetString("traitor-role-codewords", ("codewords", string.Join(", ",codewords)))); + chatMgr.DispatchServerMessage(session, Loc.GetString("traitor-role-codewords", ("codewords", string.Join(", ", codewords)))); + chatMgr.DispatchServerMessage(session, Loc.GetString("traitor-role-uplink-code", ("code", string.Join("", code)))); } } } diff --git a/Content.Server/Traitor/Uplink/UplinkSystem.cs b/Content.Server/Traitor/Uplink/UplinkSystem.cs index 956db85fcf..6d2f3cd20c 100644 --- a/Content.Server/Traitor/Uplink/UplinkSystem.cs +++ b/Content.Server/Traitor/Uplink/UplinkSystem.cs @@ -61,7 +61,11 @@ namespace Content.Server.Traitor.Uplink return true; } - private EntityUid? FindUplinkTarget(EntityUid user) + /// + /// Finds the entity that can hold an uplink for a user. + /// Usually this is a pda in their pda slot, but can also be in their hands. (but not pockets or inside bag, etc.) + /// + public EntityUid? FindUplinkTarget(EntityUid user) { // Try to find PDA in inventory if (_inventorySystem.TryGetContainerSlotEnumerator(user, out var containerSlotEnumerator)) diff --git a/Resources/Locale/en-US/game-ticking/game-presets/preset-traitor.ftl b/Resources/Locale/en-US/game-ticking/game-presets/preset-traitor.ftl index 44c4a3cc32..872636165b 100644 --- a/Resources/Locale/en-US/game-ticking/game-presets/preset-traitor.ftl +++ b/Resources/Locale/en-US/game-ticking/game-presets/preset-traitor.ftl @@ -51,3 +51,12 @@ traitor-role-codewords = {$codewords}. Codewords can be used in regular conversation to identify yourself discretely to other syndicate agents. Listen for them, and keep them secret. +traitor-role-uplink-code = + Set your ringtone to the notes {$code} to lock or unlock your uplink. + Remember to lock it and change it, or the stations crew will easily open it too! + +# don't need all the flavour text for character menu +traitor-role-codewords-short = + The codewords are: + {$codewords}. +traitor-role-uplink-code-short = Your uplink code is {$code}.