Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Content.Client.ADT.CartridgeLoader.Cartridges;
using Content.Shared.ADT.CartridgeLoader.Cartridges;
using Content.Shared.ADT.NanoChat;
using JetBrains.Annotations;
using Robust.Client.UserInterface;

namespace Content.Client.ADT.NanoChat;

[UsedImplicitly]
public sealed class StationAiNanoChatBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
{
private StationAiNanoChatWindow? _window;

protected override void Open()
{
base.Open();

_window = this.CreateWindow<StationAiNanoChatWindow>();
_window.Fragment.OnMessageSent += OnMessageSent;
}

private void OnMessageSent(NanoChatUiMessageType type, uint? number, string? content, string? job)
{
SendMessage(new StationAiNanoChatUiMessage(type, number, content, job));
}

protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);

if (state is not NanoChatUiState nanoChatState || _window == null)
return;

_window.UpdateState(nanoChatState);
}

protected override void Dispose(bool disposing)
{
base.Dispose(disposing);

if (_window == null)
return;

_window.Fragment.OnMessageSent -= OnMessageSent;
_window.Dispose();
_window = null;
}
}
26 changes: 26 additions & 0 deletions Content.Client/ADT/NanoChat/StationAiNanoChatWindow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Numerics;
using Content.Client.ADT.CartridgeLoader.Cartridges;
using Content.Shared.ADT.CartridgeLoader.Cartridges;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;

namespace Content.Client.ADT.NanoChat;

public sealed class StationAiNanoChatWindow : DefaultWindow
{
public readonly NanoChatUiFragment Fragment;

public StationAiNanoChatWindow()
{
Title = Loc.GetString("station-ai-nanochat-window-title");
MinSize = new Vector2(600, 400);

Fragment = new NanoChatUiFragment();
Contents.AddChild(Fragment);
}

public void UpdateState(NanoChatUiState state)
{
Fragment.UpdateState(state);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using Content.Server.ADT.NanoChat;
using Content.Server.Administration.Logs;
using Content.Server.CartridgeLoader;
using Content.Server.Power.Components;
Expand All @@ -10,6 +11,7 @@
using Content.Shared.ADT.CartridgeLoader.Cartridges;
using Content.Shared.ADT.NanoChat;
using Content.Shared.PDA;
using Content.Shared.Radio;
using Content.Shared.Radio.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
Expand Down Expand Up @@ -259,7 +261,7 @@ private void HandleSendMessage(Entity<NanoChatCartridgeComponent> cartridge,
);

// Attempt delivery
var (deliveryFailed, recipients) = AttemptMessageDelivery(cartridge, msg.RecipientNumber.Value);
var (deliveryFailed, recipients) = AttemptMessageDeliveryInternal(cartridge, msg.RecipientNumber.Value, cartridge.Comp.RadioChannel);

// Update delivery status
message = message with { DeliveryFailed = deliveryFailed };
Expand Down Expand Up @@ -300,17 +302,19 @@ private bool EnsureRecipientExists(Entity<NanoChatCardComponent> card, uint reci
}

/// <summary>
/// Attempts to deliver a message to recipients.
/// Attempts to deliver a message to recipients, including cards held by a station AI.
/// </summary>
/// <param name="sender">The sending cartridge entity</param>
/// <param name="sender">The sending entity (cartridge or station AI)</param>
/// <param name="recipientNumber">The recipient's number</param>
/// <param name="channelId">The radio channel used for delivery</param>
/// <returns>Tuple containing delivery status and recipients if found.</returns>
private (bool failed, List<Entity<NanoChatCardComponent>> recipient) AttemptMessageDelivery(
Entity<NanoChatCartridgeComponent> sender,
uint recipientNumber)
public (bool failed, List<Entity<NanoChatCardComponent>> recipient) AttemptMessageDeliveryInternal(
EntityUid sender,
uint recipientNumber,
ProtoId<RadioChannelPrototype> channelId)
{
// First verify we can send from this device
var channel = _prototype.Index(sender.Comp.RadioChannel);
var channel = _prototype.Index(channelId);
var sendAttemptEvent = new RadioSendAttemptEvent(channel, sender);
RaiseLocalEvent(ref sendAttemptEvent);
if (sendAttemptEvent.Cancelled)
Expand All @@ -331,11 +335,14 @@ private bool EnsureRecipientExists(Entity<NanoChatCardComponent> card, uint reci
if (foundRecipients.Count == 0)
return (true, foundRecipients);

var senderStation = _station.GetOwningStation(sender);

// Now check if any of these cards can receive
var deliverableRecipients = new List<Entity<NanoChatCardComponent>>();
foreach (var recipient in foundRecipients)
{
// Find any cartridges that have this card
var foundCartridge = false;
var cartridgeQuery = EntityQueryEnumerator<NanoChatCartridgeComponent, ActiveRadioComponent>();
while (cartridgeQuery.MoveNext(out var receiverUid, out var receiverCart, out _))
{
Expand All @@ -344,7 +351,6 @@ private bool EnsureRecipientExists(Entity<NanoChatCardComponent> card, uint reci

// Check if devices are on same station/map
var recipientStation = _station.GetOwningStation(receiverUid);
var senderStation = _station.GetOwningStation(sender);

// Both entities must be on a station
if (recipientStation == null || senderStation == null)
Expand All @@ -366,8 +372,38 @@ private bool EnsureRecipientExists(Entity<NanoChatCardComponent> card, uint reci

// Found valid cartridge that can receive
deliverableRecipients.Add(recipient);
foundCartridge = true;
break; // Only need one valid cartridge per card
}

if (foundCartridge)
continue;

// Cards held by a station AI (e.g. in a core) can receive without a cartridge
if (!HasComp<StationAiNanoChatComponent>(recipient.Owner))
continue;

var aiRecipientStation = _station.GetOwningStation(recipient.Owner);

// Both entities must be on a station
if (aiRecipientStation == null || senderStation == null)
continue;

// Must be on same map/station unless long range allowed
if (!channel.LongRange && aiRecipientStation != senderStation)
continue;

// Needs telecomms
if (!HasActiveServer(senderStation.Value) || !HasActiveServer(aiRecipientStation.Value))
continue;

// Check if recipient can receive
var aiReceiveAttemptEv = new RadioReceiveAttemptEvent(channel, sender, recipient.Owner);
RaiseLocalEvent(ref aiReceiveAttemptEv);
if (aiReceiveAttemptEv.Cancelled)
continue;

deliverableRecipients.Add(recipient);
}

return (deliverableRecipients.Count == 0, deliverableRecipients);
Expand Down Expand Up @@ -397,7 +433,7 @@ private bool HasActiveServer(EntityUid station)
/// <param name="sender">The sender's card entity</param>
/// <param name="recipient">The recipient's card entity</param>
/// <param name="message">The <see cref="NanoChatMessage" /> to deliver</param>
private void DeliverMessageToRecipient(Entity<NanoChatCardComponent> sender,
public void DeliverMessageToRecipient(Entity<NanoChatCardComponent> sender,
Entity<NanoChatCardComponent> recipient,
NanoChatMessage message)
{
Expand Down Expand Up @@ -487,7 +523,7 @@ private void UpdateUIForAllCards()
/// <summary>
/// Gets the <see cref="NanoChatRecipient" /> for a given NanoChat number.
/// </summary>
private NanoChatRecipient? GetCardInfo(uint number)
public NanoChatRecipient? GetCardInfo(uint number)
{
// Find card with this number to get its info
var query = EntityQueryEnumerator<NanoChatCardComponent>();
Expand All @@ -504,6 +540,11 @@ private void UpdateUIForAllCards()
jobTitle = idCard.LocalizedJobTitle;
name = idCard.FullName ?? name;
}
else if (HasComp<StationAiNanoChatComponent>(uid))
{
name = Name(uid);
jobTitle = Loc.GetString("job-name-station-ai");
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return new NanoChatRecipient(number, name, jobTitle);
}
Expand Down
27 changes: 27 additions & 0 deletions Content.Server/ADT/NanoChat/StationAiNanoChatComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Content.Shared.Radio;
using Robust.Shared.Prototypes;

namespace Content.Server.ADT.NanoChat;

/// <summary>
/// Added to a station AI while it is held in a core (via the AiHeld prototype).
/// Marks its NanoChat card as deliverable without a PDA cartridge and grants the NanoChat action.
/// </summary>
[RegisterComponent]
public sealed partial class StationAiNanoChatComponent : Component
{
/// <summary>
/// The action that opens the NanoChat UI.
/// </summary>
[DataField("NanoChat")]
public EntProtoId Action = "ActionStationAiNanoChat";

[DataField, AutoNetworkedField]
public EntityUid? ActionEntity;

/// <summary>
/// The <see cref="RadioChannelPrototype" /> required to send or receive messages.
/// </summary>
[DataField]
public ProtoId<RadioChannelPrototype> RadioChannel = "Common";
}
Loading
Loading