_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;
}
}
</BoxContainer>
</PanelContainer>
</BoxContainer>
+
+ <!-- Footer -->
+ <BoxContainer Orientation="Vertical" Name="TraitorFooter">
+ <PanelContainer StyleClasses="LowDivider" />
+ <BoxContainer Orientation="Horizontal" Margin="10 2 5 0" VerticalAlignment="Bottom">
+ <Label Text="{Loc 'store-ui-traitor-flavor'}" StyleClasses="WindowFooterText" />
+ <Label Text="{Loc 'store-ui-traitor-warning'}" StyleClasses="WindowFooterText"
+ HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 5 0" />
+ </BoxContainer>
+ </BoxContainer>
</BoxContainer>
</DefaultWindow>
}
}
+ public void SetFooterVisibility(bool visible)
+ {
+ TraitorFooter.Visible = visible;
+ }
+
private void OnWithdrawButtonDown(BaseButton.ButtonEventArgs args)
{
// check if window is already open
// PDAs
if (entSysMan.TryGetEntitySystem<PDASystem>(out var pdaSystem))
{
- foreach (var pdaComponent in entMan.EntityQuery<PDAComponent>())
+ var query = entMan.EntityQueryEnumerator<PDAComponent>();
+ 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);
+ }
}
}
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;
{
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()
{
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)
+ /// <summary>
+ /// Send new UI state to clients, call if you modify something like uplink.
+ /// </summary>
+ public void UpdatePdaUi(EntityUid uid, PDAComponent pda)
{
var ownerInfo = new PDAIdInfoText
{
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<InstrumentComponent>(pda.Owner);
- var state = new PDAUpdateState(pda.FlashlightOn, pda.PenSlot.HasItem, ownerInfo, pda.StationName, false, hasInstrument, address);
+ var address = GetDeviceNetAddress(uid);
+ var hasInstrument = HasComp<InstrumentComponent>(uid);
+ var showUplink = HasComp<StoreComponent>(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<UnpoweredFlashlightComponent>(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<RingerComponent>(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<InstrumentComponent>(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<StoreComponent>(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)
+ {
+ return TryComp<RingerUplinkComponent>(uid, out var uplink) ? uplink.Unlocked : true;
+ }
+
+ private void UpdateStationName(EntityUid uid, PDAComponent pda)
{
- var station = _stationSystem.GetOwningStation(pda.Owner);
+ var station = _station.GetOwningStation(uid);
pda.StationName = station is null ? null : Name(station.Value);
}
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;
{
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()
{
SubscribeLocalEvent<RingerUplinkComponent, ComponentInit>(RandomizeUplinkCode);
// RingerBoundUserInterface Subscriptions
SubscribeLocalEvent<RingerComponent, RingerSetRingtoneMessage>(OnSetRingtone);
- SubscribeLocalEvent<RingerUplinkComponent, RingerSetRingtoneMessage>(OnSetUplinkRingtone);
+ SubscribeLocalEvent<RingerUplinkComponent, BeforeRingtoneSetEvent>(OnSetUplinkRingtone);
SubscribeLocalEvent<RingerComponent, RingerPlayRingtoneMessage>(RingerPlayRingtone);
SubscribeLocalEvent<RingerComponent, RingerRequestUpdateInterfaceMessage>(UpdateRingerUserInterfaceDriver);
// 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<StoreComponent>(uid, out var store))
+ if (uplink.Code.SequenceEqual(args.Ringtone) && TryComp<StoreComponent>(uid, out var store))
{
- var user = args.Session.AttachedEntity.Value;
- _store.ToggleUi(args.Session.AttachedEntity.Value, uid, store);
+ uplink.Unlocked = !uplink.Unlocked;
+ if (TryComp<PDAComponent>(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;
}
}
}
}
}
+
+[ByRefEvent]
+public record struct BeforeRingtoneSetEvent(Note[] Ringtone, bool Handled = false);
public sealed class RingerUplinkComponent : Component
{
/// <summary>
- /// 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.
/// </summary>
[DataField("code")]
public Note[] Code = new Note[RingerSystem.RingtoneLength];
+
+ /// <summary>
+ /// Whether to show the toggle uplink button in pda settings.
+ /// </summary>
+ [DataField("unlocked"), ViewVariables(VVAccess.ReadWrite)]
+ public bool Unlocked;
}
_accessSystem.SetAccessToJob(cardId, jobPrototype, extendedAccess);
- _pdaSystem.SetOwner(pdaComponent, characterName);
+ _pdaSystem.SetOwner(idUid.Value, pdaComponent, characterName);
}
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;
UpdateUserInterface(user, storeEnt, component);
}
+ /// <summary>
+ /// Closes the store UI for everyone, if it's open
+ /// </summary>
+ public void CloseUi(EntityUid uid, StoreComponent? component = null)
+ {
+ if (!Resolve(uid, ref component))
+ return;
+
+ _ui.TryCloseAll(uid, StoreUiKey.Key);
+ }
+
/// <summary>
/// Updates the user interface for a store and refreshes the listings
/// </summary>
// 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<RingerUplinkComponent>(store);
+ var state = new StoreUpdateState(component.LastAvailableListings, allCurrency, showFooter);
_ui.SetUiState(ui, state);
}
using Content.Server.Mind.Components;
+using Content.Server.PDA.Ringer;
using Content.Server.Store.Components;
using Content.Server.UserInterface;
using Content.Shared.FixedPoint;
if (args.Target == null || !TryComp<StoreComponent>(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<ActorComponent>(user, out var actor) || !_ui.SessionHasOpenUi(uid, StoreUiKey.Key, actor.PlayerSession))
+ if (TryComp<RingerUplinkComponent>(args.Target, out var uplink) && !uplink.Unlocked)
return;
args.Handled = TryAddCurrency(GetCurrencyValue(uid, component), args.Target.Value, store);
var ui = _ui.GetUiOrNull(uid, StoreUiKey.Key);
if (ui != null)
+ {
_ui.SetUiState(ui, new StoreInitializeState(preset.StoreName));
+ }
}
}
public readonly Dictionary<string, FixedPoint2> Balance;
- public StoreUpdateState(HashSet<ListingData> listings, Dictionary<string, FixedPoint2> balance)
+ public readonly bool ShowFooter;
+
+ public StoreUpdateState(HashSet<ListingData> listings, Dictionary<string, FixedPoint2> balance, bool showFooter)
{
Listings = listings;
Balance = balance;
+ ShowFooter = showFooter;
}
}
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 =
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}