diff --git a/Content.Client/Store/Ui/StoreBoundUserInterface.cs b/Content.Client/Store/Ui/StoreBoundUserInterface.cs
index 2301d11248..8ff5ff1ca8 100644
--- a/Content.Client/Store/Ui/StoreBoundUserInterface.cs
+++ b/Content.Client/Store/Ui/StoreBoundUserInterface.cs
@@ -53,11 +53,14 @@ public sealed class StoreBoundUserInterface : BoundUserInterface
_menu.UpdateBalance(msg.Balance);
_menu.PopulateStoreCategoryButtons(msg.Listings);
_menu.UpdateListing(msg.Listings.ToList());
+ _menu.SetFooterVisibility(msg.ShowFooter);
break;
case StoreInitializeState msg:
_windowName = msg.Name;
if (_menu != null && _menu.Window != null)
+ {
_menu.Window.Title = msg.Name;
+ }
break;
}
}
diff --git a/Content.Client/Store/Ui/StoreMenu.xaml b/Content.Client/Store/Ui/StoreMenu.xaml
index fbbf6c1343..824c153671 100644
--- a/Content.Client/Store/Ui/StoreMenu.xaml
+++ b/Content.Client/Store/Ui/StoreMenu.xaml
@@ -50,5 +50,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Store/Ui/StoreMenu.xaml.cs b/Content.Client/Store/Ui/StoreMenu.xaml.cs
index f39101ed16..a3f246badb 100644
--- a/Content.Client/Store/Ui/StoreMenu.xaml.cs
+++ b/Content.Client/Store/Ui/StoreMenu.xaml.cs
@@ -77,6 +77,11 @@ public sealed partial class StoreMenu : DefaultWindow
}
}
+ public void SetFooterVisibility(bool visible)
+ {
+ TraitorFooter.Visible = visible;
+ }
+
private void OnWithdrawButtonDown(BaseButton.ButtonEventArgs args)
{
// check if window is already open
diff --git a/Content.Server/Mind/Commands/RenameCommand.cs b/Content.Server/Mind/Commands/RenameCommand.cs
index 7efe3d9b4f..0f92ae7c29 100644
--- a/Content.Server/Mind/Commands/RenameCommand.cs
+++ b/Content.Server/Mind/Commands/RenameCommand.cs
@@ -82,11 +82,13 @@ public sealed class RenameCommand : IConsoleCommand
// PDAs
if (entSysMan.TryGetEntitySystem(out var pdaSystem))
{
- foreach (var pdaComponent in entMan.EntityQuery())
+ var query = entMan.EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var pda))
{
- if (pdaComponent.OwnerName != oldName)
- continue;
- pdaSystem.SetOwner(pdaComponent, name);
+ if (pda.OwnerName == oldName)
+ {
+ pdaSystem.SetOwner(uid, pda, name);
+ }
}
}
diff --git a/Content.Server/PDA/PDASystem.cs b/Content.Server/PDA/PDASystem.cs
index 8362142c83..92bacf95b7 100644
--- a/Content.Server/PDA/PDASystem.cs
+++ b/Content.Server/PDA/PDASystem.cs
@@ -6,6 +6,8 @@ using Content.Server.Light.EntitySystems;
using Content.Server.Light.Events;
using Content.Server.PDA.Ringer;
using Content.Server.Station.Systems;
+using Content.Server.Store.Components;
+using Content.Server.Store.Systems;
using Content.Server.UserInterface;
using Content.Shared.PDA;
using Robust.Server.GameObjects;
@@ -18,12 +20,13 @@ namespace Content.Server.PDA
{
public sealed class PDASystem : SharedPDASystem
{
+ [Dependency] private readonly CartridgeLoaderSystem _cartridgeLoader = default!;
+ [Dependency] private readonly InstrumentSystem _instrument = default!;
+ [Dependency] private readonly RingerSystem _ringer = default!;
+ [Dependency] private readonly StationSystem _station = default!;
+ [Dependency] private readonly StoreSystem _store = default!;
+ [Dependency] private readonly UserInterfaceSystem _ui = default!;
[Dependency] private readonly UnpoweredFlashlightSystem _unpoweredFlashlight = default!;
- [Dependency] private readonly RingerSystem _ringerSystem = default!;
- [Dependency] private readonly InstrumentSystem _instrumentSystem = default!;
- [Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
- [Dependency] private readonly StationSystem _stationSystem = default!;
- [Dependency] private readonly CartridgeLoaderSystem _cartridgeLoaderSystem = default!;
public override void Initialize()
{
@@ -40,43 +43,46 @@ namespace Content.Server.PDA
if (!TryComp(uid, out ServerUserInterfaceComponent? uiComponent))
return;
- UpdateStationName(pda);
+ UpdateStationName(uid, pda);
- if (_uiSystem.TryGetUi(uid, PDAUiKey.Key, out var ui, uiComponent))
+ if (_ui.TryGetUi(uid, PDAUiKey.Key, out var ui, uiComponent))
ui.OnReceiveMessage += (msg) => OnUIMessage(pda, msg);
}
protected override void OnItemInserted(EntityUid uid, PDAComponent pda, EntInsertedIntoContainerMessage args)
{
base.OnItemInserted(uid, pda, args);
- UpdatePDAUserInterface(pda);
+ UpdatePdaUi(uid, pda);
}
protected override void OnItemRemoved(EntityUid uid, PDAComponent pda, EntRemovedFromContainerMessage args)
{
base.OnItemRemoved(uid, pda, args);
- UpdatePDAUserInterface(pda);
+ UpdatePdaUi(uid, pda);
}
private void OnLightToggle(EntityUid uid, PDAComponent pda, LightToggleEvent args)
{
pda.FlashlightOn = args.IsOn;
- UpdatePDAUserInterface(pda);
+ UpdatePdaUi(uid, pda);
}
- public void SetOwner(PDAComponent pda, string ownerName)
+ public void SetOwner(EntityUid uid, PDAComponent pda, string ownerName)
{
pda.OwnerName = ownerName;
- UpdatePDAUserInterface(pda);
+ UpdatePdaUi(uid, pda);
}
private void OnGridChanged(EntityUid uid, PDAComponent pda, GridModifiedEvent args)
{
- UpdateStationName(pda);
- UpdatePDAUserInterface(pda);
+ UpdateStationName(uid, pda);
+ UpdatePdaUi(uid, pda);
}
- private void UpdatePDAUserInterface(PDAComponent pda)
+ ///
+ /// Send new UI state to clients, call if you modify something like uplink.
+ ///
+ public void UpdatePdaUi(EntityUid uid, PDAComponent pda)
{
var ownerInfo = new PDAIdInfoText
{
@@ -85,49 +91,62 @@ namespace Content.Server.PDA
JobTitle = pda.ContainedID?.JobTitle
};
- if (!_uiSystem.TryGetUi(pda.Owner, PDAUiKey.Key, out var ui))
+ if (!_ui.TryGetUi(uid, PDAUiKey.Key, out var ui))
return;
- var address = GetDeviceNetAddress(pda.Owner);
- var hasInstrument = HasComp(pda.Owner);
- var state = new PDAUpdateState(pda.FlashlightOn, pda.PenSlot.HasItem, ownerInfo, pda.StationName, false, hasInstrument, address);
+ var address = GetDeviceNetAddress(uid);
+ var hasInstrument = HasComp(uid);
+ var showUplink = HasComp(uid) && IsUnlocked(uid);
- _cartridgeLoaderSystem?.UpdateUiState(pda.Owner, state);
+ var state = new PDAUpdateState(pda.FlashlightOn, pda.PenSlot.HasItem, ownerInfo, pda.StationName, showUplink, hasInstrument, address);
+ _cartridgeLoader?.UpdateUiState(uid, state);
}
private void OnUIMessage(PDAComponent pda, ServerBoundUserInterfaceMessage msg)
{
- var pdaEnt = pda.Owner;
+ var uid = pda.Owner;
// todo: move this to entity events
switch (msg.Message)
{
case PDARequestUpdateInterfaceMessage _:
- UpdatePDAUserInterface(pda);
+ UpdatePdaUi(uid, pda);
break;
case PDAToggleFlashlightMessage _:
{
- if (EntityManager.TryGetComponent(pdaEnt, out UnpoweredFlashlightComponent? flashlight))
- _unpoweredFlashlight.ToggleLight(pdaEnt, flashlight);
+ if (TryComp(uid, out var flashlight))
+ _unpoweredFlashlight.ToggleLight(uid, flashlight);
break;
}
case PDAShowRingtoneMessage _:
{
- if (EntityManager.TryGetComponent(pdaEnt, out RingerComponent? ringer))
- _ringerSystem.ToggleRingerUI(ringer, msg.Session);
+ if (TryComp(uid, out var ringer))
+ _ringer.ToggleRingerUI(ringer, msg.Session);
break;
}
case PDAShowMusicMessage _:
{
- if (TryComp(pdaEnt, out InstrumentComponent? instrument))
- _instrumentSystem.ToggleInstrumentUi(pdaEnt, msg.Session, instrument);
+ if (TryComp(uid, out var instrument))
+ _instrument.ToggleInstrumentUi(uid, msg.Session, instrument);
+ break;
+ }
+ case PDAShowUplinkMessage _:
+ {
+ // check if its locked again to prevent malicious clients opening locked uplinks
+ if (TryComp(uid, out var store) && IsUnlocked(uid))
+ _store.ToggleUi(msg.Session.AttachedEntity!.Value, uid, store);
break;
}
}
}
- private void UpdateStationName(PDAComponent pda)
+ private bool IsUnlocked(EntityUid uid)
{
- var station = _stationSystem.GetOwningStation(pda.Owner);
+ return TryComp(uid, out var uplink) ? uplink.Unlocked : true;
+ }
+
+ private void UpdateStationName(EntityUid uid, PDAComponent pda)
+ {
+ var station = _station.GetOwningStation(uid);
pda.StationName = station is null ? null : Name(station.Value);
}
diff --git a/Content.Server/PDA/Ringer/RingerSystem.cs b/Content.Server/PDA/Ringer/RingerSystem.cs
index b0b56bc740..a75dcce74d 100644
--- a/Content.Server/PDA/Ringer/RingerSystem.cs
+++ b/Content.Server/PDA/Ringer/RingerSystem.cs
@@ -3,6 +3,8 @@ using Content.Server.Store.Systems;
using Content.Server.UserInterface;
using Content.Shared.PDA;
using Content.Shared.PDA.Ringer;
+using Content.Shared.Store;
+using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.Audio;
using Robust.Shared.Player;
@@ -14,8 +16,10 @@ namespace Content.Server.PDA.Ringer
{
public sealed class RingerSystem : SharedRingerSystem
{
+ [Dependency] private readonly PDASystem _pda = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly StoreSystem _store = default!;
+ [Dependency] private readonly UserInterfaceSystem _ui = default!;
public override void Initialize()
{
@@ -26,7 +30,7 @@ namespace Content.Server.PDA.Ringer
SubscribeLocalEvent(RandomizeUplinkCode);
// RingerBoundUserInterface Subscriptions
SubscribeLocalEvent(OnSetRingtone);
- SubscribeLocalEvent(OnSetUplinkRingtone);
+ SubscribeLocalEvent(OnSetUplinkRingtone);
SubscribeLocalEvent(RingerPlayRingtone);
SubscribeLocalEvent(UpdateRingerUserInterfaceDriver);
@@ -50,17 +54,28 @@ namespace Content.Server.PDA.Ringer
// Client sent us an updated ringtone so set it to that.
if (args.Ringtone.Length != RingtoneLength) return;
+ var ev = new BeforeRingtoneSetEvent(args.Ringtone);
+ RaiseLocalEvent(uid, ref ev);
+ if (ev.Handled)
+ return;
+
UpdateRingerRingtone(ringer, args.Ringtone);
}
- private void OnSetUplinkRingtone(EntityUid uid, RingerUplinkComponent uplink, RingerSetRingtoneMessage args)
+ private void OnSetUplinkRingtone(EntityUid uid, RingerUplinkComponent uplink, ref BeforeRingtoneSetEvent args)
{
- if (uplink.Code.SequenceEqual(args.Ringtone) &&
- args.Session.AttachedEntity != null &&
- TryComp(uid, out var store))
+ if (uplink.Code.SequenceEqual(args.Ringtone) && TryComp(uid, out var store))
{
- var user = args.Session.AttachedEntity.Value;
- _store.ToggleUi(args.Session.AttachedEntity.Value, uid, store);
+ uplink.Unlocked = !uplink.Unlocked;
+ if (TryComp(uid, out var pda))
+ _pda.UpdatePdaUi(uid, pda);
+
+ // can't keep store open after locking it
+ if (!uplink.Unlocked)
+ _ui.TryCloseAll(uid, StoreUiKey.Key);
+
+ // no saving the code to prevent meta click set on sus guys pda -> wewlad
+ args.Handled = true;
}
}
@@ -161,3 +176,6 @@ namespace Content.Server.PDA.Ringer
}
}
}
+
+[ByRefEvent]
+public record struct BeforeRingtoneSetEvent(Note[] Ringtone, bool Handled = false);
diff --git a/Content.Server/PDA/Ringer/RingerUplinkComponent.cs b/Content.Server/PDA/Ringer/RingerUplinkComponent.cs
index 138c48fb22..a446468ee1 100644
--- a/Content.Server/PDA/Ringer/RingerUplinkComponent.cs
+++ b/Content.Server/PDA/Ringer/RingerUplinkComponent.cs
@@ -10,9 +10,15 @@ namespace Content.Server.PDA.Ringer;
public sealed class RingerUplinkComponent : Component
{
///
- /// Notes to set ringtone to in order to open the uplink.
+ /// Notes to set ringtone to in order to lock or unlock the uplink.
/// Automatically initialized to random notes.
///
[DataField("code")]
public Note[] Code = new Note[RingerSystem.RingtoneLength];
+
+ ///
+ /// Whether to show the toggle uplink button in pda settings.
+ ///
+ [DataField("unlocked"), ViewVariables(VVAccess.ReadWrite)]
+ public bool Unlocked;
}
diff --git a/Content.Server/Station/Systems/StationSpawningSystem.cs b/Content.Server/Station/Systems/StationSpawningSystem.cs
index d8fece6575..fcd61ed066 100644
--- a/Content.Server/Station/Systems/StationSpawningSystem.cs
+++ b/Content.Server/Station/Systems/StationSpawningSystem.cs
@@ -231,7 +231,7 @@ public sealed class StationSpawningSystem : EntitySystem
_accessSystem.SetAccessToJob(cardId, jobPrototype, extendedAccess);
- _pdaSystem.SetOwner(pdaComponent, characterName);
+ _pdaSystem.SetOwner(idUid.Value, pdaComponent, characterName);
}
diff --git a/Content.Server/Store/Systems/StoreSystem.Ui.cs b/Content.Server/Store/Systems/StoreSystem.Ui.cs
index 2ad246c290..cde624ef72 100644
--- a/Content.Server/Store/Systems/StoreSystem.Ui.cs
+++ b/Content.Server/Store/Systems/StoreSystem.Ui.cs
@@ -1,5 +1,6 @@
using Content.Server.Actions;
using Content.Server.Administration.Logs;
+using Content.Server.PDA.Ringer;
using Content.Server.Stack;
using Content.Server.Store.Components;
using Content.Server.UserInterface;
@@ -49,6 +50,17 @@ public sealed partial class StoreSystem
UpdateUserInterface(user, storeEnt, component);
}
+ ///
+ /// Closes the store UI for everyone, if it's open
+ ///
+ public void CloseUi(EntityUid uid, StoreComponent? component = null)
+ {
+ if (!Resolve(uid, ref component))
+ return;
+
+ _ui.TryCloseAll(uid, StoreUiKey.Key);
+ }
+
///
/// Updates the user interface for a store and refreshes the listings
///
@@ -83,7 +95,9 @@ public sealed partial class StoreSystem
// TODO: if multiple users are supposed to be able to interact with a single BUI & see different
// stores/listings, this needs to use session specific BUI states.
- var state = new StoreUpdateState(component.LastAvailableListings, allCurrency);
+ // only tell operatives to lock their uplink if it can be locked
+ var showFooter = HasComp(store);
+ var state = new StoreUpdateState(component.LastAvailableListings, allCurrency, showFooter);
_ui.SetUiState(ui, state);
}
diff --git a/Content.Server/Store/Systems/StoreSystem.cs b/Content.Server/Store/Systems/StoreSystem.cs
index d596f6ac4c..e4a4410e22 100644
--- a/Content.Server/Store/Systems/StoreSystem.cs
+++ b/Content.Server/Store/Systems/StoreSystem.cs
@@ -1,4 +1,5 @@
using Content.Server.Mind.Components;
+using Content.Server.PDA.Ringer;
using Content.Server.Store.Components;
using Content.Server.UserInterface;
using Content.Shared.FixedPoint;
@@ -72,9 +73,9 @@ public sealed partial class StoreSystem : EntitySystem
if (args.Target == null || !TryComp(args.Target, out var store))
return;
- // require the store to be open before inserting currency
+ // if the store can be locked, it must be unlocked first before inserting currency
var user = args.User;
- if (!TryComp(user, out var actor) || !_ui.SessionHasOpenUi(uid, StoreUiKey.Key, actor.PlayerSession))
+ if (TryComp(args.Target, out var uplink) && !uplink.Unlocked)
return;
args.Handled = TryAddCurrency(GetCurrencyValue(uid, component), args.Target.Value, store);
@@ -183,6 +184,8 @@ public sealed partial class StoreSystem : EntitySystem
var ui = _ui.GetUiOrNull(uid, StoreUiKey.Key);
if (ui != null)
+ {
_ui.SetUiState(ui, new StoreInitializeState(preset.StoreName));
+ }
}
}
diff --git a/Content.Shared/Store/StoreUi.cs b/Content.Shared/Store/StoreUi.cs
index 6e3838d368..a142cf4e4f 100644
--- a/Content.Shared/Store/StoreUi.cs
+++ b/Content.Shared/Store/StoreUi.cs
@@ -16,10 +16,13 @@ public sealed class StoreUpdateState : BoundUserInterfaceState
public readonly Dictionary Balance;
- public StoreUpdateState(HashSet listings, Dictionary balance)
+ public readonly bool ShowFooter;
+
+ public StoreUpdateState(HashSet listings, Dictionary balance, bool showFooter)
{
Listings = listings;
Balance = balance;
+ ShowFooter = showFooter;
}
}
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 872636165b..5ce0d5be1f 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
@@ -53,7 +53,7 @@ traitor-role-codewords =
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!
+ Remember to lock it after, or the stations crew will easily open it too!
# don't need all the flavour text for character menu
traitor-role-codewords-short =
diff --git a/Resources/Locale/en-US/store/store.ftl b/Resources/Locale/en-US/store/store.ftl
index 96778ef47f..7af2b05533 100644
--- a/Resources/Locale/en-US/store/store.ftl
+++ b/Resources/Locale/en-US/store/store.ftl
@@ -2,5 +2,7 @@ store-ui-default-title = Store
store-ui-default-withdraw-text = Withdraw
store-ui-balance-display = {$currency}: {$amount}
store-ui-price-display = {$amount} {$currency}
+store-ui-traitor-flavor = Copyright (C) NT -30643
+store-ui-traitor-warning = Operatives must lock their uplinks after use to avoid detection.
-store-withdraw-button-ui = Withdraw {$currency}
\ No newline at end of file
+store-withdraw-button-ui = Withdraw {$currency}