forked from SpaceStation14-Shenanigans/Monolith
Ai Control Port (#3658)
This commit is contained in:
@@ -77,6 +77,16 @@ public sealed partial class RoboticsConsoleWindow : FancyWindow
|
||||
if (_selected is {} selected && !_cyborgs.ContainsKey(selected))
|
||||
_selected = null;
|
||||
|
||||
// Corvax-Next-AiRemoteControl-Start
|
||||
var isAiControllable = false;
|
||||
|
||||
if (_selected != null)
|
||||
{
|
||||
_cyborgs.TryGetValue(_selected, out var data);
|
||||
isAiControllable = data.IsAiControllable;
|
||||
}
|
||||
// Corvax-Next-AiRemoteControl-End
|
||||
|
||||
var hasCyborgs = _cyborgs.Count > 0;
|
||||
NoCyborgs.Visible = !hasCyborgs;
|
||||
CyborgsContainer.Visible = hasCyborgs;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-FileCopyrightText: 2025 GoobBot <uristmchands@proton.me>
|
||||
// SPDX-FileCopyrightText: 2025 ImHoks <imhokzzzz@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2025 KillanGenifer <killangenifer@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
using Content.Shared._CorvaxNext.Silicons.Borgs;
|
||||
|
||||
namespace Content.Client._CorvaxNext.Silicons.Borgs;
|
||||
|
||||
public sealed partial class AiRemoteControlSystem : SharedAiRemoteControlSystem
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<Control xmlns="https://spacestation14.io"
|
||||
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
Margin="0 0 0 10">
|
||||
<PanelContainer VerticalExpand="True" StyleClasses="BackgroundDark">
|
||||
<BoxContainer Orientation="Vertical"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True"
|
||||
Margin="5 5 5 5">
|
||||
<customControls:HSeparator Margin="0 5 0 5"/>
|
||||
<RichTextLabel Name="DeviceName"/>
|
||||
<BoxContainer Name="RemoteControlButtons" Orientation="Horizontal" HorizontalExpand="True" Margin="0 5 0 0">
|
||||
<Button Name="MoveButton" StyleClasses="chatSelectorOptionButton" Text="{Loc ai-remote-ui-menu-moveto}"/>
|
||||
<Control Margin="2 0 0 0"/>
|
||||
<Button Name="TakeControlButton" StyleClasses="chatSelectorOptionButton" Text="{Loc ai-remote-control}"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</Control>
|
||||
@@ -0,0 +1,39 @@
|
||||
// SPDX-FileCopyrightText: 2025 GoobBot <uristmchands@proton.me>
|
||||
// SPDX-FileCopyrightText: 2025 ImHoks <imhokzzzz@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2025 KillanGenifer <killangenifer@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Content.Shared._CorvaxNext.Silicons.Borgs.Components;
|
||||
|
||||
namespace Content.Client._CorvaxNext.Silicons.Laws.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class RemoteDeviceDisplay : Control
|
||||
{
|
||||
public event Action<RemoteDeviceActionEvent>? OnRemoteDeviceAction;
|
||||
|
||||
public RemoteDeviceDisplay(NetEntity netEntityUid, string displayName)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
DeviceName.SetMessage(displayName);
|
||||
|
||||
MoveButton.OnPressed += _ =>
|
||||
{
|
||||
OnRemoteDeviceAction?.Invoke(new RemoteDeviceActionEvent(
|
||||
RemoteDeviceActionEvent.RemoteDeviceActionType.MoveToDevice,
|
||||
netEntityUid));
|
||||
};
|
||||
|
||||
TakeControlButton.OnPressed += _ =>
|
||||
{
|
||||
OnRemoteDeviceAction?.Invoke(new RemoteDeviceActionEvent(
|
||||
RemoteDeviceActionEvent.RemoteDeviceActionType.TakeControl,
|
||||
netEntityUid));
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// SPDX-FileCopyrightText: 2025 GoobBot <uristmchands@proton.me>
|
||||
// SPDX-FileCopyrightText: 2025 ImHoks <imhokzzzz@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2025 KillanGenifer <killangenifer@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
using Content.Shared._CorvaxNext.Silicons.Borgs.Components;
|
||||
using Robust.Client.UserInterface;
|
||||
using static Content.Shared._CorvaxNext.Silicons.Borgs.Components.AiRemoteControllerComponent;
|
||||
|
||||
namespace Content.Client._CorvaxNext.Silicons.Laws.Ui;
|
||||
|
||||
public sealed class RemoteDevicesBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
private RemoteDevicesMenu? _menu;
|
||||
private EntityUid _owner;
|
||||
|
||||
public RemoteDevicesBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<RemoteDevicesMenu>();
|
||||
_menu.OnRemoteDeviceAction += SendAction;
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
if (state is not RemoteDevicesBuiState msg)
|
||||
return;
|
||||
|
||||
_menu?.Update(_owner, msg);
|
||||
}
|
||||
|
||||
public void SendAction(RemoteDeviceActionEvent action)
|
||||
{
|
||||
SendMessage(new RemoteDeviceActionMessage(action));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
Title="{Loc ai-remote-ui-menu-title}"
|
||||
MinSize="355 100"
|
||||
SetSize="355 415">
|
||||
<BoxContainer Orientation="Vertical"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True">
|
||||
<PanelContainer VerticalExpand="True" Margin="10 10 10 10">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#1B1B1E"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
<ScrollContainer
|
||||
HScrollEnabled="False"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True">
|
||||
<BoxContainer
|
||||
Name="RemoteDevicesDisplayContainer"
|
||||
Orientation="Vertical"
|
||||
VerticalExpand="True"
|
||||
Margin="10 10 10 0">
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-FileCopyrightText: 2025 GoobBot <uristmchands@proton.me>
|
||||
// SPDX-FileCopyrightText: 2025 ImHoks <imhokzzzz@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2025 KillanGenifer <killangenifer@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using FancyWindow = Content.Client.UserInterface.Controls.FancyWindow;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Content.Shared._CorvaxNext.Silicons.Borgs.Components;
|
||||
|
||||
namespace Content.Client._CorvaxNext.Silicons.Laws.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class RemoteDevicesMenu : FancyWindow
|
||||
{
|
||||
public event Action<RemoteDeviceActionEvent>? OnRemoteDeviceAction;
|
||||
|
||||
public RemoteDevicesMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public void Update(EntityUid uid, RemoteDevicesBuiState state)
|
||||
{
|
||||
RemoteDevicesDisplayContainer.Children.Clear();
|
||||
|
||||
if (state.DeviceList == null)
|
||||
return;
|
||||
|
||||
foreach (var device in state.DeviceList)
|
||||
{
|
||||
var control = new RemoteDeviceDisplay(device.NetEntityUid, device.DisplayName);
|
||||
|
||||
control.OnRemoteDeviceAction += action =>
|
||||
{
|
||||
OnRemoteDeviceAction?.Invoke(action);
|
||||
};
|
||||
|
||||
RemoteDevicesDisplayContainer.AddChild(control);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.Inventory;
|
||||
using Content.Server.Radio.Components;
|
||||
using Content.Shared._CorvaxNext.Silicons.Borgs.Components;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Silicons.Borgs;
|
||||
using Content.Shared.Silicons.Borgs.Components;
|
||||
@@ -28,6 +29,23 @@ public sealed class BorgSwitchableTypeSystem : SharedBorgSwitchableTypeSystem
|
||||
if (TryComp(ent, out ActiveRadioComponent? activeRadio))
|
||||
activeRadio.Channels = [.. radioChannels];
|
||||
|
||||
// Corvax-Next-AiRemoteControl-Start
|
||||
if (TryComp(ent, out AiRemoteControllerComponent? aiRemoteComp))
|
||||
{
|
||||
if (TryComp(aiRemoteComp.AiHolder, out IntrinsicRadioTransmitterComponent? stationAiTransmitter) && transmitter != null)
|
||||
{
|
||||
aiRemoteComp.PreviouslyTransmitterChannels = [.. radioChannels];
|
||||
transmitter.Channels = [.. stationAiTransmitter.Channels];
|
||||
}
|
||||
|
||||
if (TryComp(aiRemoteComp.AiHolder, out ActiveRadioComponent? stationAiActiveRadio) && activeRadio != null)
|
||||
{
|
||||
aiRemoteComp.PreviouslyActiveRadioChannels = [.. radioChannels];
|
||||
activeRadio.Channels = [.. stationAiActiveRadio.Channels];
|
||||
}
|
||||
}
|
||||
// Corvax-Next-AiRemoteControl-End
|
||||
|
||||
// Borg transponder for the robotics console
|
||||
if (TryComp(ent, out BorgTransponderComponent? transponder))
|
||||
{
|
||||
|
||||
@@ -6,7 +6,9 @@ using Content.Shared.Silicons.Borgs.Components;
|
||||
using Content.Shared.DeviceNetwork.Components;
|
||||
using Content.Shared.DeviceNetwork.Events;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared._CorvaxNext.Silicons.Borgs.Components; // Corvax-Next-AiRemoteControl
|
||||
|
||||
namespace Content.Server.Silicons.Borgs;
|
||||
|
||||
@@ -47,7 +49,8 @@ public sealed partial class BorgSystem
|
||||
charge,
|
||||
chassis.ModuleCount,
|
||||
hasBrain,
|
||||
canDisable);
|
||||
canDisable,
|
||||
HasComp<AiRemoteControllerComponent>(uid)); // Corvax-Next-AiRemoteControl
|
||||
|
||||
var payload = new NetworkPayload()
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Server.DeviceNetwork.Systems;
|
||||
using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.PowerCell;
|
||||
using Content.Shared._CorvaxNext.Silicons.Borgs.Components;
|
||||
using Content.Shared.UserInterface;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Access.Components;
|
||||
@@ -25,6 +26,8 @@ using Content.Shared.PowerCell.Components;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Silicons.Borgs;
|
||||
using Content.Shared.Silicons.Borgs.Components;
|
||||
using Content.Shared.Silicons.StationAi;
|
||||
using Content.Shared.StationAi;
|
||||
using Content.Shared.Throwing;
|
||||
using Content.Shared.Whitelist;
|
||||
using Content.Shared.Wires;
|
||||
@@ -144,6 +147,21 @@ public sealed partial class BorgSystem : SharedBorgSystem
|
||||
args.Handled = true;
|
||||
UpdateUI(uid, component);
|
||||
}
|
||||
|
||||
// Corvax-Next-AiRemoteControl-Start
|
||||
if (component.BrainEntity == null && HasComp<AiRemoteBrainComponent>(used) &&
|
||||
_whitelistSystem.IsWhitelistPassOrNull(component.BrainWhitelist, used))
|
||||
{
|
||||
EnsureComp<AiRemoteControllerComponent>(uid);
|
||||
_container.Insert(used, component.BrainContainer);
|
||||
_adminLog.Add(LogType.Action, LogImpact.Medium,
|
||||
$"{ToPrettyString(args.User):player} installed ai remote brain {ToPrettyString(used)} into borg {ToPrettyString(uid)}");
|
||||
args.Handled = true;
|
||||
BorgActivate(uid, component);
|
||||
|
||||
UpdateUI(uid, component);
|
||||
}
|
||||
// Corvax-Next-AiRemoteControl-End
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -178,6 +196,15 @@ public sealed partial class BorgSystem : SharedBorgSystem
|
||||
{
|
||||
_mind.TransferTo(mindId, args.Entity, mind: mind);
|
||||
}
|
||||
|
||||
// Corvax-Next-AiRemoteControl-Start
|
||||
if (HasComp<AiRemoteBrainComponent>(args.Entity))
|
||||
{
|
||||
BorgDeactivate(uid, component);
|
||||
RemComp<AiRemoteControllerComponent>(uid);
|
||||
RemComp<StationAiVisionComponent>(uid);
|
||||
}
|
||||
// Corvax-Next-AiRemoteControl-End
|
||||
}
|
||||
|
||||
private void OnMindAdded(EntityUid uid, BorgChassisComponent component, MindAddedMessage args)
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Server.Chat.Managers;
|
||||
using Content.Server.Radio.Components;
|
||||
using Content.Server.Roles;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared._CorvaxNext.Silicons.Borgs.Components; // Corvax-Next-AiRemoteControl
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Emag.Systems;
|
||||
@@ -13,6 +14,9 @@ using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Silicons.Laws;
|
||||
using Content.Shared.Silicons.Laws.Components;
|
||||
using Content.Shared.Silicons.StationAi; // Corvax-Next-AiRemoteControl
|
||||
using Content.Shared.Tag; // Corvax-Next-AiRemoteControl
|
||||
using Content.Shared.Wires;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
@@ -33,6 +37,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
|
||||
[Dependency] private readonly StationSystem _station = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
|
||||
[Dependency] private readonly EmagSystem _emag = default!;
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!; // Corvax-Next-AiRemoteControl
|
||||
[Dependency] private readonly IMapManager _map = default!; // Mono - Law update is grid-only now.
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -63,6 +68,12 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
|
||||
if (!TryComp<ActorComponent>(uid, out var actor))
|
||||
return;
|
||||
|
||||
// Corvax-Next-AiRemoteControl-Start
|
||||
if (HasComp<AiRemoteControllerComponent>(uid)
|
||||
|| _tagSystem.HasTag(uid, "StationAi")) // skip a law's notification for remotable and AI
|
||||
return;
|
||||
// Corvax-Next-AiRemoteControl-End
|
||||
|
||||
var msg = Loc.GetString("laws-notify");
|
||||
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", msg));
|
||||
_chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.Channel, colorOverride: Color.FromHex("#5ed7aa"));
|
||||
@@ -155,6 +166,11 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
|
||||
if (component.Lawset == null)
|
||||
component.Lawset = GetLawset(component.Laws);
|
||||
|
||||
// Corvax-Next-AiRemoteControl-Start
|
||||
if (HasComp<AiRemoteControllerComponent>(uid)) // You can't emag controllable entities
|
||||
return;
|
||||
// Corvax-Next-AiRemoteControl-End
|
||||
|
||||
// Show the silicon has been subverted.
|
||||
component.Subverted = true;
|
||||
|
||||
@@ -281,7 +297,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
|
||||
/// <summary>
|
||||
/// Set the laws of a silicon entity while notifying the player.
|
||||
/// </summary>
|
||||
public void SetLaws(List<SiliconLaw> newLaws, EntityUid target, SoundSpecifier? cue = null)
|
||||
public void SetLaws(List<SiliconLaw> newLaws, EntityUid target, SoundSpecifier? cue = null, bool silent = false) // AiRemoteControl - silent
|
||||
{
|
||||
if (!TryComp<SiliconLawProviderComponent>(target, out var component))
|
||||
return;
|
||||
@@ -290,7 +306,8 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
|
||||
component.Lawset = new SiliconLawset();
|
||||
|
||||
component.Lawset.Laws = newLaws;
|
||||
NotifyLawsChanged(target, cue);
|
||||
if (!silent) // AiRemoteControl - silent
|
||||
NotifyLawsChanged(target, cue);
|
||||
}
|
||||
|
||||
protected override void OnUpdaterInsert(Entity<SiliconLawUpdaterComponent> ent, ref EntInsertedIntoContainerMessage args)
|
||||
@@ -312,8 +329,16 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
|
||||
continue;
|
||||
|
||||
SetLaws(lawset, update, provider.LawUploadSound);
|
||||
// Mono edit end
|
||||
// Corvax-Next-AiRemoteControl-Start
|
||||
if (TryComp<StationAiHeldComponent>(update, out var stationAiHeldComp)
|
||||
&& stationAiHeldComp.CurrentConnectedEntity != null
|
||||
&& HasComp<SiliconLawProviderComponent>(stationAiHeldComp.CurrentConnectedEntity))
|
||||
{
|
||||
SetLaws(lawset, stationAiHeldComp.CurrentConnectedEntity.Value, provider.LawUploadSound);
|
||||
}
|
||||
// Corvax-Next-AiRemoteControl-End
|
||||
}
|
||||
// Mono edit end
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
// SPDX-FileCopyrightText: 2025 GoobBot <uristmchands@proton.me>
|
||||
// SPDX-FileCopyrightText: 2025 ImHoks <142083149+ImHoks@users.noreply.github.com>
|
||||
// SPDX-FileCopyrightText: 2025 ImHoks <imhokzzzz@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2025 KillanGenifer <killangenifer@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2025 gluesniffler <159397573+gluesniffler@users.noreply.github.com>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
using Content.Server.Radio.Components;
|
||||
using Content.Server.Silicons.Laws;
|
||||
using Content.Shared._CorvaxNext.Silicons.Borgs;
|
||||
using Content.Shared._CorvaxNext.Silicons.Borgs.Components;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Silicons.Laws.Components;
|
||||
using Content.Shared.Silicons.StationAi;
|
||||
using Content.Shared.StationAi;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Map; // Mono
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Player;
|
||||
using System.Threading.Tasks.Dataflow;
|
||||
|
||||
namespace Content.Server._CorvaxNext.Silicons.Borgs;
|
||||
|
||||
public sealed class AiRemoteControlSystem : SharedAiRemoteControlSystem
|
||||
{
|
||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||
[Dependency] private readonly SiliconLawSystem _lawSystem = default!;
|
||||
[Dependency] private readonly SharedStationAiSystem _stationAiSystem = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
|
||||
|
||||
[Dependency] private readonly IMapManager _map = default!; // Mono
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<AiRemoteControllerComponent, ReturnMindIntoAiEvent>(OnReturnMindIntoAi);
|
||||
SubscribeLocalEvent<AiRemoteControllerComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<AiRemoteControllerComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<AiRemoteControllerComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs);
|
||||
SubscribeLocalEvent<StationAiHeldComponent, AiRemoteControllerComponent.RemoteDeviceActionMessage>(OnUiRemoteAction);
|
||||
SubscribeLocalEvent<StationAiHeldComponent, ToggleRemoteDevicesScreenEvent>(OnToggleRemoteDevicesScreen);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<AiRemoteControllerComponent> entity, ref MapInitEvent args)
|
||||
{
|
||||
var visionComp = EnsureComp<StationAiVisionComponent>(entity.Owner);
|
||||
EntityUid? actionEnt = null;
|
||||
|
||||
_actions.AddAction(entity.Owner, ref actionEnt, entity.Comp.BackToAiAction);
|
||||
|
||||
if (actionEnt != null)
|
||||
entity.Comp.BackToAiActionEntity = actionEnt.Value;
|
||||
}
|
||||
|
||||
private void OnShutdown(Entity<AiRemoteControllerComponent> entity, ref ComponentShutdown args)
|
||||
{
|
||||
_actions.RemoveAction(entity.Owner, entity.Comp.BackToAiActionEntity);
|
||||
|
||||
var backArgs = new ReturnMindIntoAiEvent();
|
||||
backArgs.Performer = entity;
|
||||
|
||||
if (TryComp(entity, out IntrinsicRadioTransmitterComponent? transmitter)
|
||||
&& entity.Comp.PreviouslyTransmitterChannels != null)
|
||||
transmitter.Channels = [.. entity.Comp.PreviouslyTransmitterChannels];
|
||||
|
||||
if (TryComp(entity, out ActiveRadioComponent? activeRadio)
|
||||
&& entity.Comp.PreviouslyActiveRadioChannels != null)
|
||||
activeRadio.Channels = [.. entity.Comp.PreviouslyActiveRadioChannels];
|
||||
|
||||
ReturnMindIntoAi(entity);
|
||||
}
|
||||
|
||||
private void OnGetVerbs(Entity<AiRemoteControllerComponent> entity, ref GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
var user = args.User;
|
||||
|
||||
if (!TryComp<StationAiHeldComponent>(user, out var stationAiHeldComp))
|
||||
return;
|
||||
|
||||
var verb = new AlternativeVerb
|
||||
{
|
||||
Text = Loc.GetString("ai-remote-control"),
|
||||
Act = () => AiTakeControl(user, entity)
|
||||
};
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
private void OnReturnMindIntoAi(Entity<AiRemoteControllerComponent> entity, ref ReturnMindIntoAiEvent args) =>
|
||||
ReturnMindIntoAi(entity);
|
||||
|
||||
public void AiTakeControl(EntityUid ai, EntityUid entity)
|
||||
{
|
||||
if (!_mind.TryGetMind(ai, out var mindId, out var mind))
|
||||
return;
|
||||
|
||||
if (!TryComp<StationAiHeldComponent>(ai, out var stationAiHeldComp))
|
||||
return;
|
||||
|
||||
if (!TryComp<AiRemoteControllerComponent>(entity, out var aiRemoteComp))
|
||||
return;
|
||||
|
||||
if (!_map.TryFindGridAt(Transform(ai).MapPosition, out var grid, out var _) || Transform(entity).GridUid != grid)
|
||||
return; // Mono no controlling borgs outside the ai's grid.
|
||||
|
||||
if (TryComp(entity, out IntrinsicRadioTransmitterComponent? transmitter))
|
||||
{
|
||||
aiRemoteComp.PreviouslyTransmitterChannels = [.. transmitter.Channels];
|
||||
|
||||
if (TryComp(ai, out IntrinsicRadioTransmitterComponent? stationAiTransmitter))
|
||||
transmitter.Channels = [.. stationAiTransmitter.Channels];
|
||||
}
|
||||
|
||||
if (TryComp(entity, out ActiveRadioComponent? activeRadio))
|
||||
{
|
||||
aiRemoteComp.PreviouslyActiveRadioChannels = [.. activeRadio.Channels];
|
||||
|
||||
if (TryComp(ai, out ActiveRadioComponent? stationAiActiveRadio))
|
||||
activeRadio.Channels = [.. stationAiActiveRadio.Channels];
|
||||
}
|
||||
|
||||
_mind.ControlMob(ai, entity);
|
||||
aiRemoteComp.AiHolder = ai;
|
||||
aiRemoteComp.LinkedMind = mindId;
|
||||
|
||||
stationAiHeldComp.CurrentConnectedEntity = entity;
|
||||
|
||||
if (!_stationAiSystem.TryGetCore(ai, out var stationAiCore))
|
||||
return;
|
||||
|
||||
_stationAiSystem.SwitchRemoteEntityMode(stationAiCore, false);
|
||||
|
||||
RewriteLaws(ai, entity);
|
||||
}
|
||||
|
||||
private void OnToggleRemoteDevicesScreen(EntityUid uid, StationAiHeldComponent component, ToggleRemoteDevicesScreenEvent args)
|
||||
{
|
||||
if (args.Handled || !TryComp<ActorComponent>(uid, out var actor))
|
||||
return;
|
||||
args.Handled = true;
|
||||
|
||||
_userInterface.TryToggleUi(uid, RemoteDeviceUiKey.Key, actor.PlayerSession);
|
||||
|
||||
var aiGrid = Transform(uid).GridUid; // Mono
|
||||
var query = EntityManager.EntityQueryEnumerator<AiRemoteControllerComponent>();
|
||||
var remoteDevices = new List<RemoteDevicesData>();
|
||||
|
||||
while (query.MoveNext(out var queryUid, out var comp))
|
||||
{
|
||||
if (Transform(queryUid).GridUid != aiGrid)
|
||||
continue;
|
||||
var data = new RemoteDevicesData
|
||||
{
|
||||
NetEntityUid = GetNetEntity(queryUid),
|
||||
DisplayName = Comp<MetaDataComponent>(queryUid).EntityName
|
||||
};
|
||||
|
||||
remoteDevices.Add(data);
|
||||
}
|
||||
|
||||
var state = new RemoteDevicesBuiState(remoteDevices);
|
||||
_userInterface.SetUiState(uid, RemoteDeviceUiKey.Key, state);
|
||||
}
|
||||
|
||||
private void OnUiRemoteAction(EntityUid uid, StationAiHeldComponent component, AiRemoteControllerComponent.RemoteDeviceActionMessage msg)
|
||||
{
|
||||
if (msg.RemoteAction == null)
|
||||
return;
|
||||
|
||||
var target = GetEntity(msg.RemoteAction?.Target);
|
||||
|
||||
if (!HasComp<AiRemoteControllerComponent>(target))
|
||||
return;
|
||||
|
||||
switch (msg.RemoteAction?.ActionType)
|
||||
{
|
||||
case RemoteDeviceActionEvent.RemoteDeviceActionType.MoveToDevice:
|
||||
if (!_stationAiSystem.TryGetCore(uid, out var stationAiCore)
|
||||
|| stationAiCore.Comp?.RemoteEntity == null)
|
||||
return;
|
||||
_xformSystem.SetCoordinates(stationAiCore.Comp.RemoteEntity.Value, Transform(target.Value).Coordinates);
|
||||
break;
|
||||
|
||||
case RemoteDeviceActionEvent.RemoteDeviceActionType.TakeControl:
|
||||
AiTakeControl(uid, target.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void RewriteLaws(EntityUid from, EntityUid to)
|
||||
{
|
||||
if (!TryComp<SiliconLawProviderComponent>(from, out var fromLawsComp))
|
||||
return;
|
||||
|
||||
if (!TryComp<SiliconLawProviderComponent>(to, out var toLawsComp))
|
||||
return;
|
||||
|
||||
if (fromLawsComp.Lawset == null)
|
||||
return;
|
||||
|
||||
var fromLaws = _lawSystem.GetLaws(from);
|
||||
_lawSystem.SetLaws(fromLaws.Laws, to, silent: true);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -111,7 +111,12 @@ public partial record struct CyborgControlData
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||
public TimeSpan Timeout = TimeSpan.Zero;
|
||||
|
||||
public CyborgControlData(SpriteSpecifier? chassisSprite, string chassisName, string name, float charge, int moduleCount, bool hasBrain, bool canDisable)
|
||||
// Corvax-Next-AiRemoteControl-Start
|
||||
[DataField]
|
||||
public bool IsAiControllable;
|
||||
// Corvax-Next-AiRemoteControl-End
|
||||
|
||||
public CyborgControlData(SpriteSpecifier? chassisSprite, string chassisName, string name, float charge, int moduleCount, bool hasBrain, bool canDisable, bool isAiControllable) // Corvax-Next-AiRemoteControl
|
||||
{
|
||||
ChassisSprite = chassisSprite;
|
||||
ChassisName = chassisName;
|
||||
@@ -120,6 +125,7 @@ public partial record struct CyborgControlData
|
||||
ModuleCount = moduleCount;
|
||||
HasBrain = hasBrain;
|
||||
CanDisable = canDisable;
|
||||
IsAiControllable = isAiControllable; // Corvax-Next-AiRemoteControl
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Silicons.Laws.Components;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Wires;
|
||||
using Robust.Shared.Audio;
|
||||
using Content.Shared._CorvaxNext.Silicons.Borgs.Components;
|
||||
|
||||
namespace Content.Shared.Silicons.Laws;
|
||||
|
||||
@@ -35,6 +36,11 @@ public abstract partial class SharedSiliconLawSystem : EntitySystem
|
||||
if (_emag.CheckFlag(uid, EmagType.Interaction))
|
||||
return;
|
||||
|
||||
// Corvax-Next-AiRemoteControl-Start
|
||||
if (HasComp<AiRemoteControllerComponent>(uid))
|
||||
return;
|
||||
// Corvax-Next-AiRemoteControl-End
|
||||
|
||||
// prevent self-emagging
|
||||
if (uid == args.UserUid)
|
||||
{
|
||||
|
||||
@@ -28,6 +28,7 @@ using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared._CorvaxNext.Silicons.Borgs;
|
||||
|
||||
namespace Content.Shared.Silicons.StationAi;
|
||||
|
||||
@@ -57,6 +58,8 @@ public abstract partial class SharedStationAiSystem : EntitySystem
|
||||
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
|
||||
[Dependency] private readonly StationAiVisionSystem _vision = default!;
|
||||
|
||||
[Dependency] private readonly SharedAiRemoteControlSystem _remoteSystem = default!; // Corvax-Next-AiRemoteControl
|
||||
|
||||
// StationAiHeld is added to anything inside of an AI core.
|
||||
// StationAiHolder indicates it can hold an AI positronic brain (e.g. holocard / core).
|
||||
// StationAiCore holds functionality related to the core itself.
|
||||
@@ -231,6 +234,13 @@ public abstract partial class SharedStationAiSystem : EntitySystem
|
||||
// Try to insert our thing into them
|
||||
if (_slots.CanEject(ent.Owner, args.User, ent.Comp.Slot))
|
||||
{
|
||||
// Corvax-Next-AiRemoteControl-Start
|
||||
if (ent.Comp.Slot.Item != null
|
||||
&& TryComp<StationAiHeldComponent>(ent.Comp.Slot.Item, out var stationAiHeldComp))
|
||||
if (stationAiHeldComp.CurrentConnectedEntity != null)
|
||||
_remoteSystem.ReturnMindIntoAi(stationAiHeldComp.CurrentConnectedEntity.Value);
|
||||
// Corvax-Next-AiRemoteControl-End
|
||||
|
||||
if (!_slots.TryInsert(args.Args.Target.Value, targetHolder.Slot, ent.Comp.Slot.Item!.Value, args.User, excludeUserAudio: true))
|
||||
{
|
||||
return;
|
||||
@@ -289,6 +299,12 @@ public abstract partial class SharedStationAiSystem : EntitySystem
|
||||
AnnounceIntellicardUsage(held, intelliComp.WarningSound);
|
||||
}
|
||||
|
||||
// Corvax-Next-AiRemoteControl-Start
|
||||
if (TryComp<StationAiHeldComponent>(held, out var heldComp))
|
||||
if (heldComp.CurrentConnectedEntity != null)
|
||||
AnnounceIntellicardUsage(heldComp.CurrentConnectedEntity.Value, intelliComp.WarningSound);
|
||||
// Corvax-Next-AiRemoteControl-End
|
||||
|
||||
var doAfterArgs = new DoAfterArgs(EntityManager, args.User, cardHasAi ? intelliComp.UploadTime : intelliComp.DownloadTime, new IntellicardDoAfterEvent(), args.Target, ent.Owner)
|
||||
{
|
||||
BreakOnDamage = true,
|
||||
|
||||
@@ -6,4 +6,10 @@ namespace Content.Shared.Silicons.StationAi;
|
||||
/// Indicates this entity is currently held inside of a station AI core.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class StationAiHeldComponent : Component;
|
||||
// Corvax-Next-AiRemoteControl-Start
|
||||
public sealed partial class StationAiHeldComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityUid? CurrentConnectedEntity;
|
||||
}
|
||||
// Corvax-Next-AiRemoteControl-End
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-FileCopyrightText: 2025 GoobBot <uristmchands@proton.me>
|
||||
// SPDX-FileCopyrightText: 2025 ImHoks <imhokzzzz@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2025 KillanGenifer <killangenifer@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
namespace Content.Shared._CorvaxNext.Silicons.Borgs.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class AiRemoteBrainComponent : Component
|
||||
{
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
// SPDX-FileCopyrightText: 2025 GoobBot <uristmchands@proton.me>
|
||||
// SPDX-FileCopyrightText: 2025 ImHoks <imhokzzzz@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2025 KillanGenifer <killangenifer@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CorvaxNext.Silicons.Borgs.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class AiRemoteControllerComponent : Component
|
||||
{
|
||||
[DataField] public EntityUid? AiHolder;
|
||||
[DataField] public EntityUid? LinkedMind;
|
||||
|
||||
[DataField] public string[]? PreviouslyTransmitterChannels;
|
||||
[DataField] public string[]? PreviouslyActiveRadioChannels;
|
||||
|
||||
[DataField] public EntProtoId BackToAiAction = "ActionBackToAi";
|
||||
[DataField] public EntityUid? BackToAiActionEntity;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RemoteDeviceActionMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly RemoteDeviceActionEvent? RemoteAction;
|
||||
public RemoteDeviceActionMessage(RemoteDeviceActionEvent remoteDeviceAction)
|
||||
{
|
||||
RemoteAction = remoteDeviceAction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RemoteDeviceActionEvent : EntityEventArgs
|
||||
{
|
||||
public enum RemoteDeviceActionType
|
||||
{
|
||||
MoveToDevice,
|
||||
TakeControl
|
||||
}
|
||||
public RemoteDeviceActionType ActionType;
|
||||
public NetEntity Target;
|
||||
|
||||
public RemoteDeviceActionEvent(RemoteDeviceActionType actionType, NetEntity target)
|
||||
{
|
||||
ActionType = actionType;
|
||||
Target = target;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public record struct RemoteDevicesData()
|
||||
{
|
||||
public string DisplayName = string.Empty;
|
||||
public NetEntity NetEntityUid = NetEntity.Invalid;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RemoteDevicesBuiState : BoundUserInterfaceState
|
||||
{
|
||||
public List<RemoteDevicesData> DeviceList;
|
||||
|
||||
public RemoteDevicesBuiState(List<RemoteDevicesData> deviceList)
|
||||
{
|
||||
DeviceList = deviceList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// SPDX-FileCopyrightText: 2025 GoobBot <uristmchands@proton.me>
|
||||
// SPDX-FileCopyrightText: 2025 ImHoks <142083149+ImHoks@users.noreply.github.com>
|
||||
// SPDX-FileCopyrightText: 2025 ImHoks <imhokzzzz@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2025 KillanGenifer <killangenifer@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2025 gluesniffler <159397573+gluesniffler@users.noreply.github.com>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
using Content.Shared._CorvaxNext.Silicons.Borgs.Components;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Silicons.StationAi;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CorvaxNext.Silicons.Borgs;
|
||||
|
||||
public abstract class SharedAiRemoteControlSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedStationAiSystem _stationAiSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
}
|
||||
|
||||
public void ReturnMindIntoAi(EntityUid entity)
|
||||
{
|
||||
if (!TryComp<AiRemoteControllerComponent>(entity, out var remoteComp))
|
||||
return;
|
||||
|
||||
if (remoteComp?.AiHolder == null
|
||||
|| !_stationAiSystem.TryGetCore(remoteComp.AiHolder.Value, out var stationAiCore)
|
||||
|| stationAiCore.Comp?.RemoteEntity == null)
|
||||
return;
|
||||
|
||||
if (remoteComp.LinkedMind == null)
|
||||
return;
|
||||
|
||||
if (!TryComp<StationAiHeldComponent>(remoteComp.AiHolder.Value, out var stationAiHeldComp))
|
||||
return;
|
||||
|
||||
stationAiHeldComp.CurrentConnectedEntity = null;
|
||||
|
||||
_mind.TransferTo(remoteComp.LinkedMind.Value, remoteComp.AiHolder);
|
||||
|
||||
_stationAiSystem.SwitchRemoteEntityMode(stationAiCore, true);
|
||||
remoteComp.AiHolder = null;
|
||||
remoteComp.LinkedMind = null;
|
||||
|
||||
_xformSystem.SetCoordinates(stationAiCore.Comp.RemoteEntity.Value, Transform(entity).Coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class ReturnMindIntoAiEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class ToggleRemoteDevicesScreenEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum RemoteDeviceUiKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# UI
|
||||
ai-remote-ui-menu-title = Available devices
|
||||
ai-remote-ui-menu-moveto = Move to
|
||||
ai-remote-control = Take control
|
||||
@@ -38,6 +38,7 @@
|
||||
- ActionJumpToCore
|
||||
- ActionSurvCameraLights
|
||||
- ActionAIViewLaws
|
||||
- ActionOpenRemoteDevicesMenu # Corvax-Next-AiRemoteControl
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
enum.RadarConsoleUiKey.Key:
|
||||
@@ -50,6 +51,8 @@
|
||||
type: SiliconLawBoundUserInterface
|
||||
enum.CommunicationsConsoleUiKey.Key:
|
||||
type: CommunicationsConsoleBoundUserInterface
|
||||
enum.RemoteDeviceUiKey.Key: # Corvax-Next-AiRemoteControl
|
||||
type: RemoteDevicesBoundUserInterface
|
||||
- type: IntrinsicUI
|
||||
uis:
|
||||
enum.RadarConsoleUiKey.Key:
|
||||
@@ -116,6 +119,7 @@
|
||||
whitelist:
|
||||
tags:
|
||||
- StationAi
|
||||
- CanPilot # Mono
|
||||
- type: ContainerContainer
|
||||
containers:
|
||||
station_ai_mind_slot: !type:ContainerSlot
|
||||
@@ -508,6 +512,7 @@
|
||||
- HideContextMenu
|
||||
- StationAi
|
||||
- NoConsoleSound
|
||||
- CanPilot #Mono
|
||||
- type: StartingMindRole
|
||||
mindRole: "MindRoleSiliconBrain"
|
||||
silent: true
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
- PositronicBrain
|
||||
- SciFlash
|
||||
- CyborgEndoskeleton
|
||||
- AiRemoteBrain
|
||||
|
||||
- type: latheRecipePack
|
||||
id: BorgModulesStatic
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# SPDX-FileCopyrightText: 2025 GoobBot <uristmchands@proton.me>
|
||||
# SPDX-FileCopyrightText: 2025 KillanGenifer <killangenifer@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
- type: entity
|
||||
id: ActionBackToAi
|
||||
name: Back to Ai
|
||||
description: Sends your mind back to the core.
|
||||
components:
|
||||
- type: InstantAction
|
||||
checkConsciousness: false
|
||||
checkCanInteract: false
|
||||
priority: -9
|
||||
itemIconStyle: BigAction
|
||||
icon:
|
||||
sprite: Interface/Actions/actions_ai.rsi
|
||||
state: ai_core
|
||||
event: !type:ReturnMindIntoAiEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionOpenRemoteDevicesMenu
|
||||
name: Open list of remote devices
|
||||
description: Opens a menu with available remote devices.
|
||||
components:
|
||||
- type: InstantAction
|
||||
checkConsciousness: false
|
||||
checkCanInteract: false
|
||||
priority: -9
|
||||
itemIconStyle: BigAction
|
||||
event: !type:ToggleRemoteDevicesScreenEvent
|
||||
icon:
|
||||
sprite: Mobs/Silicon/chassis.rsi
|
||||
state: robot
|
||||
@@ -0,0 +1,20 @@
|
||||
# SPDX-FileCopyrightText: 2025 GoobBot <uristmchands@proton.me>
|
||||
# SPDX-FileCopyrightText: 2025 KillanGenifer <killangenifer@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: AiRemoteBrain
|
||||
name: "AI-Cyborg Network Device"
|
||||
description: Artificial Intelligence cyborg control board.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Misc/module.rsi
|
||||
state: boris
|
||||
- type: Examiner
|
||||
- type: AiRemoteBrain
|
||||
- type: Actions
|
||||
- type: Tag
|
||||
tags:
|
||||
- CannotSuicide
|
||||
@@ -1,3 +1,8 @@
|
||||
# SPDX-FileCopyrightText: 2025 GoobBot <uristmchands@proton.me>
|
||||
# SPDX-FileCopyrightText: 2025 ImHoks <imhokzzzz@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
- type: latheRecipe
|
||||
id: ModsuitChestplate
|
||||
result: ModsuitChestplate
|
||||
@@ -50,3 +55,14 @@
|
||||
materials:
|
||||
Glass: 550
|
||||
Plasma: 250
|
||||
|
||||
# AI
|
||||
- type: latheRecipe
|
||||
id: AiRemoteBrain
|
||||
result: AiRemoteBrain
|
||||
completetime: 4
|
||||
materials:
|
||||
Steel: 300
|
||||
Glass: 400
|
||||
Gold: 400
|
||||
Silver: 200
|
||||
|
||||
@@ -94,12 +94,15 @@
|
||||
- ActionJumpToCore
|
||||
- ActionSurvCameraLights
|
||||
- ActionAIViewLaws
|
||||
- ActionOpenRemoteDevicesMenu # Corvax-Next-AiRemoteControl
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
enum.RadarConsoleUiKey.Key:
|
||||
type: RadarConsoleBoundUserInterface
|
||||
enum.SiliconLawsUiKey.Key:
|
||||
type: SiliconLawBoundUserInterface
|
||||
enum.RemoteDeviceUiKey.Key: # Corvax-Next-AiRemoteControl
|
||||
type: RemoteDevicesBoundUserInterface
|
||||
- type: IntrinsicUI
|
||||
uis:
|
||||
enum.RadarConsoleUiKey.Key:
|
||||
@@ -115,9 +118,6 @@
|
||||
- sprite: Mobs/Silicon/station_ai.rsi
|
||||
state: default
|
||||
- type: ShowJobIcons
|
||||
- type: Tag
|
||||
tags:
|
||||
- CanPilot
|
||||
- type: AdvancedPilot # can use both gunnery and shuttle console even on capitals
|
||||
|
||||
- type: entity
|
||||
|
||||
Reference in New Issue
Block a user