feat: now when research is unlocked in console, approver of reasearch is radio-ed too (#31170)

* feat: now when research is unlocked in console, approver of reasearch is radio-ed too

* refactor: now most of events that require actor name to be radio-ed or logged use TryGetIdentityShortInfoEvent which is subscibed by id-card system and borg system (to work for both carbon and synthetic life-forms)

* refactor: moved TryGetIdentityShortInfoEvent on id card system to shared, fixed cargo cent-com-originated orders

* remove unused check

* refactor: decoupled systems from IdCardSystem (those that are not dependent on it anymore)

* refactor: removed unuseed usings

* feat: emagged cargo/research consoles wont radio messages on buy/research confirm anymore

---------

Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
This commit is contained in:
Fildrance
2024-09-03 16:01:38 +03:00
committed by GitHub
parent 894d4980f5
commit 6380a9adca
13 changed files with 141 additions and 50 deletions

View File

@@ -24,6 +24,7 @@ public sealed class IdCardSystem : SharedIdCardSystem
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<IdCardComponent, BeingMicrowavedEvent>(OnMicrowaved); SubscribeLocalEvent<IdCardComponent, BeingMicrowavedEvent>(OnMicrowaved);
} }

View File

@@ -8,6 +8,8 @@ using Content.Shared.Cargo.Components;
using Content.Shared.Cargo.Events; using Content.Shared.Cargo.Events;
using Content.Shared.Cargo.Prototypes; using Content.Shared.Cargo.Prototypes;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.Emag.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Paper; using Content.Shared.Paper;
using Robust.Shared.Map; using Robust.Shared.Map;
@@ -175,10 +177,6 @@ namespace Content.Server.Cargo.Systems
RaiseLocalEvent(ref ev); RaiseLocalEvent(ref ev);
ev.FulfillmentEntity ??= station.Value; ev.FulfillmentEntity ??= station.Value;
_idCardSystem.TryFindIdCard(player, out var idCard);
// ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
order.SetApproverData(idCard.Comp?.FullName, idCard.Comp?.JobTitle);
if (!ev.Handled) if (!ev.Handled)
{ {
ev.FulfillmentEntity = TryFulfillOrder((station.Value, stationData), order, orderDatabase); ev.FulfillmentEntity = TryFulfillOrder((station.Value, stationData), order, orderDatabase);
@@ -194,12 +192,20 @@ namespace Content.Server.Cargo.Systems
order.Approved = true; order.Approved = true;
_audio.PlayPvs(component.ConfirmSound, uid); _audio.PlayPvs(component.ConfirmSound, uid);
var message = Loc.GetString("cargo-console-unlock-approved-order-broadcast", if (!HasComp<EmaggedComponent>(uid))
("productName", Loc.GetString(order.ProductName)), {
("orderAmount", order.OrderQuantity), var tryGetIdentityShortInfoEvent = new TryGetIdentityShortInfoEvent(uid, player);
("approver", order.Approver ?? string.Empty), RaiseLocalEvent(tryGetIdentityShortInfoEvent);
("cost", cost)); order.SetApproverData(tryGetIdentityShortInfoEvent.Title);
_radio.SendRadioMessage(uid, message, component.AnnouncementChannel, uid, escapeMarkup: false);
var message = Loc.GetString("cargo-console-unlock-approved-order-broadcast",
("productName", Loc.GetString(order.ProductName)),
("orderAmount", order.OrderQuantity),
("approver", order.Approver ?? string.Empty),
("cost", cost));
_radio.SendRadioMessage(uid, message, component.AnnouncementChannel, uid, escapeMarkup: false);
}
ConsolePopup(args.Actor, Loc.GetString("cargo-console-trade-station", ("destination", MetaData(ev.FulfillmentEntity.Value).EntityName))); ConsolePopup(args.Actor, Loc.GetString("cargo-console-trade-station", ("destination", MetaData(ev.FulfillmentEntity.Value).EntityName)));
// Log order approval // Log order approval

View File

@@ -1,4 +1,3 @@
using Content.Server.Access.Systems;
using Content.Server.Cargo.Components; using Content.Server.Cargo.Components;
using Content.Server.DeviceLinking.Systems; using Content.Server.DeviceLinking.Systems;
using Content.Server.Popups; using Content.Server.Popups;
@@ -31,7 +30,6 @@ public sealed partial class CargoSystem : SharedCargoSystem
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!; [Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
[Dependency] private readonly DeviceLinkSystem _linker = default!; [Dependency] private readonly DeviceLinkSystem _linker = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly IdCardSystem _idCardSystem = default!;
[Dependency] private readonly ItemSlotsSystem _slots = default!; [Dependency] private readonly ItemSlotsSystem _slots = default!;
[Dependency] private readonly PaperSystem _paperSystem = default!; [Dependency] private readonly PaperSystem _paperSystem = default!;
[Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly PopupSystem _popup = default!;

View File

@@ -1,15 +1,11 @@
using System.Globalization;
using Content.Server.Access.Systems;
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.AlertLevel; using Content.Server.AlertLevel;
using Content.Server.Chat.Systems; using Content.Server.Chat.Systems;
using Content.Server.DeviceNetwork;
using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Components;
using Content.Server.DeviceNetwork.Systems; using Content.Server.DeviceNetwork.Systems;
using Content.Server.Interaction; using Content.Server.Interaction;
using Content.Server.Popups; using Content.Server.Popups;
using Content.Server.RoundEnd; using Content.Server.RoundEnd;
using Content.Server.Screens;
using Content.Server.Screens.Components; using Content.Server.Screens.Components;
using Content.Server.Shuttles.Systems; using Content.Server.Shuttles.Systems;
using Content.Server.Station.Systems; using Content.Server.Station.Systems;
@@ -21,8 +17,8 @@ using Content.Shared.Communications;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork;
using Content.Shared.Emag.Components; using Content.Shared.Emag.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.Silicons.Borgs.Components;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
@@ -35,7 +31,6 @@ namespace Content.Server.Communications
[Dependency] private readonly ChatSystem _chatSystem = default!; [Dependency] private readonly ChatSystem _chatSystem = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!; [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;
[Dependency] private readonly EmergencyShuttleSystem _emergency = default!; [Dependency] private readonly EmergencyShuttleSystem _emergency = default!;
[Dependency] private readonly IdCardSystem _idCardSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly RoundEndSystem _roundEndSystem = default!; [Dependency] private readonly RoundEndSystem _roundEndSystem = default!;
[Dependency] private readonly StationSystem _stationSystem = default!; [Dependency] private readonly StationSystem _stationSystem = default!;
@@ -251,17 +246,9 @@ namespace Content.Server.Communications
return; return;
} }
// User has an id var tryGetIdentityShortInfoEvent = new TryGetIdentityShortInfoEvent(uid, mob);
if (_idCardSystem.TryFindIdCard(mob, out var id)) RaiseLocalEvent(tryGetIdentityShortInfoEvent);
{ author = tryGetIdentityShortInfoEvent.Title;
author = $"{id.Comp.FullName} ({CultureInfo.CurrentCulture.TextInfo.ToTitleCase(id.Comp.JobTitle ?? string.Empty)})".Trim();
}
// User does not have an id and is a borg, so use the borg's name
if (HasComp<BorgChassisComponent>(mob))
{
author = Name(mob).Trim();
}
} }
comp.AnnouncementCooldownRemaining = comp.Delay; comp.AnnouncementCooldownRemaining = comp.Delay;

View File

@@ -10,7 +10,6 @@ using Content.Shared.CriminalRecords.Systems;
using Content.Shared.Security; using Content.Shared.Security;
using Content.Shared.StationRecords; using Content.Shared.StationRecords;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Player;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Content.Shared.IdentityManagement; using Content.Shared.IdentityManagement;
using Content.Shared.Security.Components; using Content.Shared.Security.Components;
@@ -26,7 +25,6 @@ public sealed class CriminalRecordsConsoleSystem : SharedCriminalRecordsConsoleS
[Dependency] private readonly CriminalRecordsSystem _criminalRecords = default!; [Dependency] private readonly CriminalRecordsSystem _criminalRecords = default!;
[Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly RadioSystem _radio = default!; [Dependency] private readonly RadioSystem _radio = default!;
[Dependency] private readonly SharedIdCardSystem _idCard = default!;
[Dependency] private readonly StationRecordsSystem _records = default!; [Dependency] private readonly StationRecordsSystem _records = default!;
[Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!;
@@ -108,8 +106,13 @@ public sealed class CriminalRecordsConsoleSystem : SharedCriminalRecordsConsoleS
var name = _records.RecordName(key.Value); var name = _records.RecordName(key.Value);
var officer = Loc.GetString("criminal-records-console-unknown-officer"); var officer = Loc.GetString("criminal-records-console-unknown-officer");
if (_idCard.TryFindIdCard(mob.Value, out var id) && id.Comp.FullName is { } fullName)
officer = fullName; var tryGetIdentityShortInfoEvent = new TryGetIdentityShortInfoEvent(null, mob.Value);
RaiseLocalEvent(tryGetIdentityShortInfoEvent);
if (tryGetIdentityShortInfoEvent.Title != null)
{
officer = tryGetIdentityShortInfoEvent.Title;
}
(string, object)[] args; (string, object)[] args;
if (reason != null) if (reason != null)

View File

@@ -1,5 +1,4 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Content.Server.Access.Systems;
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.CartridgeLoader; using Content.Server.CartridgeLoader;
using Content.Server.CartridgeLoader.Cartridges; using Content.Server.CartridgeLoader.Cartridges;
@@ -19,6 +18,7 @@ using Content.Shared.MassMedia.Systems;
using Content.Shared.Popups; using Content.Shared.Popups;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Audio.Systems; using Robust.Shared.Audio.Systems;
using Content.Shared.IdentityManagement;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Server.MassMedia.Systems; namespace Content.Server.MassMedia.Systems;
@@ -35,7 +35,7 @@ public sealed class NewsSystem : SharedNewsSystem
[Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly GameTicker _ticker = default!; [Dependency] private readonly GameTicker _ticker = default!;
[Dependency] private readonly IdCardSystem _idCardSystem = default!; [Dependency] private readonly AccessReaderSystem _accessReader = default!;
[Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IChatManager _chatManager = default!;
public override void Initialize() public override void Initialize()
@@ -140,9 +140,9 @@ public sealed class NewsSystem : SharedNewsSystem
ent.Comp.PublishEnabled = false; ent.Comp.PublishEnabled = false;
ent.Comp.NextPublish = _timing.CurTime + TimeSpan.FromSeconds(ent.Comp.PublishCooldown); ent.Comp.NextPublish = _timing.CurTime + TimeSpan.FromSeconds(ent.Comp.PublishCooldown);
string? authorName = null; var tryGetIdentityShortInfoEvent = new TryGetIdentityShortInfoEvent(ent, msg.Actor);
if (_idCardSystem.TryFindIdCard(msg.Actor, out var idCard)) RaiseLocalEvent(tryGetIdentityShortInfoEvent);
authorName = idCard.Comp.FullName; string? authorName = tryGetIdentityShortInfoEvent.Title;
var title = msg.Title.Trim(); var title = msg.Title.Trim();
var content = msg.Content.Trim(); var content = msg.Content.Trim();

View File

@@ -2,6 +2,8 @@ using Content.Server.Power.EntitySystems;
using Content.Server.Research.Components; using Content.Server.Research.Components;
using Content.Shared.UserInterface; using Content.Shared.UserInterface;
using Content.Shared.Access.Components; using Content.Shared.Access.Components;
using Content.Shared.Emag.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Research.Components; using Content.Shared.Research.Components;
using Content.Shared.Research.Prototypes; using Content.Shared.Research.Prototypes;
@@ -37,10 +39,20 @@ public sealed partial class ResearchSystem
if (!UnlockTechnology(uid, args.Id, act)) if (!UnlockTechnology(uid, args.Id, act))
return; return;
var message = Loc.GetString("research-console-unlock-technology-radio-broadcast", if (!HasComp<EmaggedComponent>(uid))
("technology", Loc.GetString(technologyPrototype.Name)), {
("amount", technologyPrototype.Cost)); var getIdentityEvent = new TryGetIdentityShortInfoEvent(uid, act);
_radio.SendRadioMessage(uid, message, component.AnnouncementChannel, uid, escapeMarkup: false); RaiseLocalEvent(getIdentityEvent);
var message = Loc.GetString(
"research-console-unlock-technology-radio-broadcast",
("technology", Loc.GetString(technologyPrototype.Name)),
("amount", technologyPrototype.Cost),
("approver", getIdentityEvent.Title ?? string.Empty)
);
_radio.SendRadioMessage(uid, message, component.AnnouncementChannel, uid, escapeMarkup: false);
}
SyncClientWithServer(uid); SyncClientWithServer(uid);
UpdateConsoleInterface(uid, component); UpdateConsoleInterface(uid, component);
} }
@@ -87,4 +99,5 @@ public sealed partial class ResearchSystem
{ {
UpdateConsoleInterface(uid, component); UpdateConsoleInterface(uid, component);
} }
} }

View File

@@ -8,11 +8,11 @@ using Content.Shared.Hands.EntitySystems;
using Content.Shared.Inventory; using Content.Shared.Inventory;
using Content.Shared.NameIdentifier; using Content.Shared.NameIdentifier;
using Content.Shared.PDA; using Content.Shared.PDA;
using Content.Shared.Silicons.Borgs.Components;
using Content.Shared.StationRecords; using Content.Shared.StationRecords;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Content.Shared.GameTicking; using Content.Shared.GameTicking;
using Content.Shared.IdentityManagement;
using Robust.Shared.Collections; using Robust.Shared.Collections;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Timing; using Robust.Shared.Timing;
@@ -26,7 +26,6 @@ public sealed class AccessReaderSystem : EntitySystem
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly SharedGameTicker _gameTicker = default!; [Dependency] private readonly SharedGameTicker _gameTicker = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly SharedIdCardSystem _idCardSystem = default!;
[Dependency] private readonly SharedContainerSystem _containerSystem = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly SharedStationRecordsSystem _recordsSystem = default!; [Dependency] private readonly SharedStationRecordsSystem _recordsSystem = default!;
@@ -402,9 +401,12 @@ public sealed class AccessReaderSystem : EntitySystem
// TODO pass the ID card on IsAllowed() instead of using this expensive method // TODO pass the ID card on IsAllowed() instead of using this expensive method
// Set name if the accessor has a card and that card has a name and allows itself to be recorded // Set name if the accessor has a card and that card has a name and allows itself to be recorded
if (_idCardSystem.TryFindIdCard(accessor, out var idCard) var getIdentityShortInfoEvent = new TryGetIdentityShortInfoEvent(ent, accessor, true);
&& idCard.Comp is { BypassLogging: false, FullName: not null }) RaiseLocalEvent(getIdentityShortInfoEvent);
name = idCard.Comp.FullName; if (getIdentityShortInfoEvent.Title != null)
{
name = getIdentityShortInfoEvent.Title;
}
LogAccess(ent, name ?? Loc.GetString("access-reader-unknown-id")); LogAccess(ent, name ?? Loc.GetString("access-reader-unknown-id"));
} }

View File

@@ -1,7 +1,9 @@
using System.Globalization;
using Content.Shared.Access.Components; using Content.Shared.Access.Components;
using Content.Shared.Administration.Logs; using Content.Shared.Administration.Logs;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.Hands.Components; using Content.Shared.Hands.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Inventory; using Content.Shared.Inventory;
using Content.Shared.PDA; using Content.Shared.PDA;
using Content.Shared.Roles; using Content.Shared.Roles;
@@ -20,7 +22,9 @@ public abstract class SharedIdCardSystem : EntitySystem
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<IdCardComponent, MapInitEvent>(OnMapInit); SubscribeLocalEvent<IdCardComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<TryGetIdentityShortInfoEvent>(OnTryGetIdentityShortInfo);
} }
private void OnMapInit(EntityUid uid, IdCardComponent id, MapInitEvent args) private void OnMapInit(EntityUid uid, IdCardComponent id, MapInitEvent args)
@@ -28,6 +32,23 @@ public abstract class SharedIdCardSystem : EntitySystem
UpdateEntityName(uid, id); UpdateEntityName(uid, id);
} }
private void OnTryGetIdentityShortInfo(TryGetIdentityShortInfoEvent ev)
{
if (ev.Handled)
{
return;
}
string? title = null;
if (TryFindIdCard(ev.ForActor, out var idCard) && !(ev.RequestForAccessLogging && idCard.Comp.BypassLogging))
{
title = ExtractFullTitle(idCard);
}
ev.Title = title;
ev.Handled = true;
}
/// <summary> /// <summary>
/// Attempt to find an ID card on an entity. This will look in the entity itself, in the entity's hands, and /// Attempt to find an ID card on an entity. This will look in the entity itself, in the entity's hands, and
/// in the entity's inventory. /// in the entity's inventory.
@@ -214,4 +235,10 @@ public abstract class SharedIdCardSystem : EntitySystem
("jobSuffix", jobSuffix)); ("jobSuffix", jobSuffix));
_metaSystem.SetEntityName(uid, val); _metaSystem.SetEntityName(uid, val);
} }
private static string ExtractFullTitle(IdCardComponent idCardComponent)
{
return $"{idCardComponent.FullName} ({CultureInfo.CurrentCulture.TextInfo.ToTitleCase(idCardComponent.JobTitle ?? string.Empty)})"
.Trim();
}
} }

View File

@@ -63,6 +63,11 @@ namespace Content.Shared.Cargo
Reason = reason; Reason = reason;
} }
public void SetApproverData(string? approver)
{
Approver = approver;
}
public void SetApproverData(string? fullName, string? jobTitle) public void SetApproverData(string? fullName, string? jobTitle)
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();

View File

@@ -0,0 +1,32 @@
namespace Content.Shared.IdentityManagement;
/// <summary>
/// Event of attempt to collect actor full title - full name + job from id card for employee or entity name for borgs.
/// </summary>
public sealed class TryGetIdentityShortInfoEvent(EntityUid? whileInteractingWith, EntityUid forActor, bool forLogging = false) : HandledEntityEventArgs
{
/// <summary>
/// Full name of <see cref="ForActor"/>, with JobTitle.
/// Can be null if no system could find actor name / job.
/// </summary>
public string? Title;
/// <summary>
/// Entity for interacting with which title should be collected.
/// Could be used to black-out name of people when announcing actions
/// on e-magged devices.
/// </summary>
public readonly EntityUid? WhileInteractingWith = whileInteractingWith;
/// <summary>
/// Actor for whom title should be collected.
/// </summary>
public readonly EntityUid ForActor = forActor;
/// <summary>
/// Marker that title info was requested for access logging.
/// Is required as event handlers can determine, if they don't need
/// to place title info due to access logging restrictions.
/// </summary>
public readonly bool RequestForAccessLogging = forLogging;
}

View File

@@ -1,5 +1,5 @@
using Content.Shared.Access.Components;
using Content.Shared.Containers.ItemSlots; using Content.Shared.Containers.ItemSlots;
using Content.Shared.IdentityManagement;
using Content.Shared.Item.ItemToggle; using Content.Shared.Item.ItemToggle;
using Content.Shared.Movement.Components; using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems; using Content.Shared.Movement.Systems;
@@ -34,10 +34,27 @@ public abstract partial class SharedBorgSystem : EntitySystem
SubscribeLocalEvent<BorgChassisComponent, EntRemovedFromContainerMessage>(OnRemoved); SubscribeLocalEvent<BorgChassisComponent, EntRemovedFromContainerMessage>(OnRemoved);
SubscribeLocalEvent<BorgChassisComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers); SubscribeLocalEvent<BorgChassisComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
SubscribeLocalEvent<BorgChassisComponent, ActivatableUIOpenAttemptEvent>(OnUIOpenAttempt); SubscribeLocalEvent<BorgChassisComponent, ActivatableUIOpenAttemptEvent>(OnUIOpenAttempt);
SubscribeLocalEvent<TryGetIdentityShortInfoEvent>(OnTryGetIdentityShortInfo);
InitializeRelay(); InitializeRelay();
} }
private void OnTryGetIdentityShortInfo(TryGetIdentityShortInfoEvent args)
{
if (args.Handled)
{
return;
}
if (!HasComp<BorgChassisComponent>(args.ForActor))
{
return;
}
args.Title = Name(args.ForActor).Trim();
args.Handled = true;
}
private void OnItemSlotInsertAttempt(EntityUid uid, BorgChassisComponent component, ref ItemSlotInsertAttemptEvent args) private void OnItemSlotInsertAttempt(EntityUid uid, BorgChassisComponent component, ref ItemSlotInsertAttemptEvent args)
{ {
if (args.Cancelled) if (args.Cancelled)

View File

@@ -18,4 +18,4 @@ research-console-prereqs-list-start = Requires:
research-console-prereqs-list-entry = - [color=orchid]{$text}[/color] research-console-prereqs-list-entry = - [color=orchid]{$text}[/color]
research-console-no-access-popup = No access! research-console-no-access-popup = No access!
research-console-unlock-technology-radio-broadcast = Unlocked [bold]{$technology}[/bold] for [bold]{$amount}[/bold] research. research-console-unlock-technology-radio-broadcast = Unlocked [bold]{$technology}[/bold] for [bold]{$amount}[/bold] research by [bold]{$approver}[/bold].