Station AI customizations (#34501)
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
@@ -0,0 +1,40 @@
|
|||||||
|
using Content.Shared.Silicons.StationAi;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Client.Silicons.StationAi;
|
||||||
|
|
||||||
|
public sealed class StationAiCustomizationBoundUserInterface : BoundUserInterface
|
||||||
|
{
|
||||||
|
private StationAiCustomizationMenu? _menu;
|
||||||
|
|
||||||
|
public StationAiCustomizationBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Open()
|
||||||
|
{
|
||||||
|
base.Open();
|
||||||
|
|
||||||
|
_menu = new StationAiCustomizationMenu(Owner);
|
||||||
|
_menu.OpenCentered();
|
||||||
|
_menu.OnClose += Close;
|
||||||
|
|
||||||
|
_menu.SendStationAiCustomizationMessageAction += SendStationAiCustomizationMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendStationAiCustomizationMessage(ProtoId<StationAiCustomizationGroupPrototype> groupProtoId, ProtoId<StationAiCustomizationPrototype> customizationProtoId)
|
||||||
|
{
|
||||||
|
SendPredictedMessage(new StationAiCustomizationMessage(groupProtoId, customizationProtoId));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
|
||||||
|
if (!disposing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_menu?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
|
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||||
|
SetSize="600 600"
|
||||||
|
MinSize="600 220">
|
||||||
|
<BoxContainer Orientation="Vertical" VerticalExpand="True">
|
||||||
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="10 5 10 -5">
|
||||||
|
<controls:StripeBack HorizontalExpand="True">
|
||||||
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
|
<Control SetWidth="200">
|
||||||
|
<Label Text="{Loc 'station-ai-customization-categories'}" Margin="0 5 0 5" HorizontalExpand="True" HorizontalAlignment="Center" />
|
||||||
|
</Control>
|
||||||
|
<Label Text="{Loc 'station-ai-customization-options'}" Margin="0 5 0 5" HorizontalExpand="True" HorizontalAlignment="Center"/>
|
||||||
|
</BoxContainer>
|
||||||
|
</controls:StripeBack>
|
||||||
|
</BoxContainer>
|
||||||
|
<VerticalTabContainer Name="CustomizationGroupsContainer"
|
||||||
|
VerticalExpand="True"
|
||||||
|
HorizontalExpand="True">
|
||||||
|
</VerticalTabContainer>
|
||||||
|
</BoxContainer>
|
||||||
|
</controls:FancyWindow>
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
using Content.Client.UserInterface.Controls;
|
||||||
|
using Content.Shared.Silicons.StationAi;
|
||||||
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace Content.Client.Silicons.StationAi;
|
||||||
|
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class StationAiCustomizationMenu : FancyWindow
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||||
|
|
||||||
|
private Dictionary<ProtoId<StationAiCustomizationGroupPrototype>, StationAiCustomizationGroupContainer> _groupContainers = new();
|
||||||
|
private Dictionary<ProtoId<StationAiCustomizationGroupPrototype>, ButtonGroup> _buttonGroups = new();
|
||||||
|
|
||||||
|
public event Action<ProtoId<StationAiCustomizationGroupPrototype>, ProtoId<StationAiCustomizationPrototype>>? SendStationAiCustomizationMessageAction;
|
||||||
|
|
||||||
|
private const float IconScale = 1.75f;
|
||||||
|
|
||||||
|
public StationAiCustomizationMenu(EntityUid owner)
|
||||||
|
{
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
|
||||||
|
var stationAiSystem = _entManager.System<SharedStationAiSystem>();
|
||||||
|
|
||||||
|
// Load customziation data
|
||||||
|
_entManager.TryGetComponent<StationAiCoreComponent>(owner, out var stationAiCore);
|
||||||
|
stationAiSystem.TryGetHeld((owner, stationAiCore), out var insertedAi);
|
||||||
|
_entManager.TryGetComponent<StationAiCustomizationComponent>(insertedAi, out var stationAiCustomization);
|
||||||
|
|
||||||
|
// Create UI entires for each group of customizations
|
||||||
|
var groupPrototypes = _protoManager.EnumeratePrototypes<StationAiCustomizationGroupPrototype>();
|
||||||
|
groupPrototypes = groupPrototypes.OrderBy(x => x.ID); // To ensure consistency in presentation
|
||||||
|
|
||||||
|
foreach (var groupPrototype in groupPrototypes)
|
||||||
|
{
|
||||||
|
StationAiCustomizationPrototype? selectedPrototype = null;
|
||||||
|
|
||||||
|
if (stationAiCustomization?.ProtoIds.TryGetValue(groupPrototype, out var selectedProtoId) == true)
|
||||||
|
_protoManager.TryIndex(selectedProtoId, out selectedPrototype);
|
||||||
|
|
||||||
|
_buttonGroups[groupPrototype] = new ButtonGroup();
|
||||||
|
_groupContainers[groupPrototype] = new StationAiCustomizationGroupContainer(groupPrototype, selectedPrototype, _buttonGroups[groupPrototype], this, _protoManager);
|
||||||
|
CustomizationGroupsContainer.AddTab(_groupContainers[groupPrototype], Loc.GetString(groupPrototype.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
Title = Loc.GetString("station-ai-customization-menu");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnSendStationAiCustomizationMessage
|
||||||
|
(ProtoId<StationAiCustomizationGroupPrototype> groupProtoId, ProtoId<StationAiCustomizationPrototype> customizationProtoId)
|
||||||
|
{
|
||||||
|
SendStationAiCustomizationMessageAction?.Invoke(groupProtoId, customizationProtoId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class StationAiCustomizationGroupContainer : BoxContainer
|
||||||
|
{
|
||||||
|
public StationAiCustomizationGroupContainer
|
||||||
|
(StationAiCustomizationGroupPrototype groupPrototype,
|
||||||
|
StationAiCustomizationPrototype? selectedPrototype,
|
||||||
|
ButtonGroup buttonGroup,
|
||||||
|
StationAiCustomizationMenu menu,
|
||||||
|
IPrototypeManager protoManager)
|
||||||
|
{
|
||||||
|
Orientation = LayoutOrientation.Vertical;
|
||||||
|
HorizontalExpand = true;
|
||||||
|
VerticalExpand = true;
|
||||||
|
|
||||||
|
// Create UI entries for all customization in the group
|
||||||
|
foreach (var protoId in groupPrototype.ProtoIds)
|
||||||
|
{
|
||||||
|
if (!protoManager.TryIndex(protoId, out var prototype))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var entry = new StationAiCustomizationEntryContainer(groupPrototype, prototype, buttonGroup, menu);
|
||||||
|
AddChild(entry);
|
||||||
|
|
||||||
|
if (prototype == selectedPrototype)
|
||||||
|
entry.SelectButton.Pressed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class StationAiCustomizationEntryContainer : BoxContainer
|
||||||
|
{
|
||||||
|
public ProtoId<StationAiCustomizationPrototype> ProtoId;
|
||||||
|
public Button SelectButton;
|
||||||
|
|
||||||
|
public StationAiCustomizationEntryContainer
|
||||||
|
(StationAiCustomizationGroupPrototype groupPrototype,
|
||||||
|
StationAiCustomizationPrototype prototype,
|
||||||
|
ButtonGroup buttonGroup,
|
||||||
|
StationAiCustomizationMenu menu)
|
||||||
|
{
|
||||||
|
ProtoId = prototype;
|
||||||
|
|
||||||
|
Orientation = LayoutOrientation.Horizontal;
|
||||||
|
HorizontalExpand = true;
|
||||||
|
|
||||||
|
// Create a selection button
|
||||||
|
SelectButton = new Button
|
||||||
|
{
|
||||||
|
Text = Loc.GetString(prototype.Name),
|
||||||
|
HorizontalExpand = true,
|
||||||
|
ToggleMode = true,
|
||||||
|
Group = buttonGroup,
|
||||||
|
};
|
||||||
|
|
||||||
|
SelectButton.OnPressed += args =>
|
||||||
|
{
|
||||||
|
menu.OnSendStationAiCustomizationMessage(groupPrototype, prototype);
|
||||||
|
};
|
||||||
|
|
||||||
|
AddChild(SelectButton);
|
||||||
|
|
||||||
|
// Creat a background for the preview
|
||||||
|
var background = new AnimatedTextureRect
|
||||||
|
{
|
||||||
|
HorizontalAlignment = HAlignment.Center,
|
||||||
|
VerticalAlignment = VAlignment.Center,
|
||||||
|
SetWidth = 56,
|
||||||
|
SetHeight = 56,
|
||||||
|
Margin = new Thickness(10f, 2f),
|
||||||
|
};
|
||||||
|
|
||||||
|
background.DisplayRect.TextureScale = new Vector2(IconScale, IconScale);
|
||||||
|
|
||||||
|
if (prototype.PreviewBackground != null)
|
||||||
|
{
|
||||||
|
background.SetFromSpriteSpecifier(prototype.PreviewBackground);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddChild(background);
|
||||||
|
|
||||||
|
// Create a preview icon
|
||||||
|
var icon = new AnimatedTextureRect
|
||||||
|
{
|
||||||
|
HorizontalAlignment = HAlignment.Center,
|
||||||
|
VerticalAlignment = VAlignment.Center,
|
||||||
|
SetWidth = 56,
|
||||||
|
SetHeight = 56,
|
||||||
|
};
|
||||||
|
|
||||||
|
icon.DisplayRect.TextureScale = new Vector2(IconScale, IconScale);
|
||||||
|
|
||||||
|
// Default RSI path/state
|
||||||
|
var rsiPath = prototype.LayerData.FirstOrNull()?.Value.RsiPath;
|
||||||
|
var rsiState = prototype.LayerData.FirstOrNull()?.Value.State;
|
||||||
|
|
||||||
|
// Specified RSI path/state
|
||||||
|
if (!string.IsNullOrEmpty(prototype.PreviewKey) && prototype.LayerData.TryGetValue(prototype.PreviewKey, out var layerData))
|
||||||
|
{
|
||||||
|
rsiPath = layerData.RsiPath;
|
||||||
|
rsiState = layerData.State;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update icon
|
||||||
|
if (rsiPath != null && rsiState != null)
|
||||||
|
{
|
||||||
|
var specifier = new SpriteSpecifier.Rsi(new ResPath(rsiPath), rsiState);
|
||||||
|
icon.SetFromSpriteSpecifier(specifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
background.AddChild(icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.Silicons.StationAi;
|
using Content.Shared.Silicons.StationAi;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
@@ -9,6 +10,7 @@ public sealed partial class StationAiSystem : SharedStationAiSystem
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IOverlayManager _overlayMgr = default!;
|
[Dependency] private readonly IOverlayManager _overlayMgr = default!;
|
||||||
[Dependency] private readonly IPlayerManager _player = default!;
|
[Dependency] private readonly IPlayerManager _player = default!;
|
||||||
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
|
|
||||||
private StationAiOverlay? _overlay;
|
private StationAiOverlay? _overlay;
|
||||||
|
|
||||||
@@ -22,6 +24,7 @@ public sealed partial class StationAiSystem : SharedStationAiSystem
|
|||||||
SubscribeLocalEvent<StationAiOverlayComponent, LocalPlayerDetachedEvent>(OnAiDetached);
|
SubscribeLocalEvent<StationAiOverlayComponent, LocalPlayerDetachedEvent>(OnAiDetached);
|
||||||
SubscribeLocalEvent<StationAiOverlayComponent, ComponentInit>(OnAiOverlayInit);
|
SubscribeLocalEvent<StationAiOverlayComponent, ComponentInit>(OnAiOverlayInit);
|
||||||
SubscribeLocalEvent<StationAiOverlayComponent, ComponentRemove>(OnAiOverlayRemove);
|
SubscribeLocalEvent<StationAiOverlayComponent, ComponentRemove>(OnAiOverlayRemove);
|
||||||
|
SubscribeLocalEvent<StationAiCoreComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAiOverlayInit(Entity<StationAiOverlayComponent> ent, ref ComponentInit args)
|
private void OnAiOverlayInit(Entity<StationAiOverlayComponent> ent, ref ComponentInit args)
|
||||||
@@ -72,6 +75,17 @@ public sealed partial class StationAiSystem : SharedStationAiSystem
|
|||||||
RemoveOverlay();
|
RemoveOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnAppearanceChange(Entity<StationAiCoreComponent> entity, ref AppearanceChangeEvent args)
|
||||||
|
{
|
||||||
|
if (args.Sprite == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_appearance.TryGetData<PrototypeLayerData>(entity.Owner, StationAiVisualState.Key, out var layerData, args.Component))
|
||||||
|
args.Sprite.LayerSetData(StationAiVisualState.Key, layerData);
|
||||||
|
|
||||||
|
args.Sprite.LayerSetVisible(StationAiVisualState.Key, layerData != null);
|
||||||
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
public override void Shutdown()
|
||||||
{
|
{
|
||||||
base.Shutdown();
|
base.Shutdown();
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ public sealed partial class HolographicAvatarComponent : Component
|
|||||||
/// The prototype sprite layer data for the hologram
|
/// The prototype sprite layer data for the hologram
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public PrototypeLayerData[] LayerData;
|
public PrototypeLayerData[]? LayerData = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
using Content.Shared.Holopad;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Shared.Silicons.StationAi;
|
||||||
|
|
||||||
|
public abstract partial class SharedStationAiSystem
|
||||||
|
{
|
||||||
|
private ProtoId<StationAiCustomizationGroupPrototype> _stationAiCoreCustomGroupProtoId = "StationAiCoreIconography";
|
||||||
|
private ProtoId<StationAiCustomizationGroupPrototype> _stationAiHologramCustomGroupProtoId = "StationAiHolograms";
|
||||||
|
|
||||||
|
private void InitializeCustomization()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<StationAiCoreComponent, StationAiCustomizationMessage>(OnStationAiCustomization);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStationAiCustomization(Entity<StationAiCoreComponent> entity, ref StationAiCustomizationMessage args)
|
||||||
|
{
|
||||||
|
if (!_protoManager.TryIndex(args.GroupProtoId, out var groupPrototype) || !_protoManager.TryIndex(args.CustomizationProtoId, out var customizationProto))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryGetHeld((entity, entity.Comp), out var held))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<StationAiCustomizationComponent>(held, out var stationAiCustomization))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (stationAiCustomization.ProtoIds.TryGetValue(args.GroupProtoId, out var protoId) && protoId == args.CustomizationProtoId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
stationAiCustomization.ProtoIds[args.GroupProtoId] = args.CustomizationProtoId;
|
||||||
|
|
||||||
|
Dirty(held, stationAiCustomization);
|
||||||
|
|
||||||
|
// Update hologram
|
||||||
|
if (groupPrototype.Category == StationAiCustomizationType.Hologram)
|
||||||
|
UpdateHolographicAvatar((held, stationAiCustomization));
|
||||||
|
|
||||||
|
// Update core iconography
|
||||||
|
if (groupPrototype.Category == StationAiCustomizationType.CoreIconography && TryComp<StationAiHolderComponent>(entity, out var stationAiHolder))
|
||||||
|
UpdateAppearance((entity, stationAiHolder));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateHolographicAvatar(Entity<StationAiCustomizationComponent> entity)
|
||||||
|
{
|
||||||
|
if (!TryComp<HolographicAvatarComponent>(entity, out var avatar))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!entity.Comp.ProtoIds.TryGetValue(_stationAiHologramCustomGroupProtoId, out var protoId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_protoManager.TryIndex(protoId, out var prototype))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!prototype.LayerData.TryGetValue(StationAiState.Hologram.ToString(), out var layerData))
|
||||||
|
return;
|
||||||
|
|
||||||
|
avatar.LayerData = [layerData];
|
||||||
|
Dirty(entity, avatar);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CustomizeAppearance(Entity<StationAiCoreComponent> entity, StationAiState state)
|
||||||
|
{
|
||||||
|
var stationAi = GetInsertedAI(entity);
|
||||||
|
|
||||||
|
if (stationAi == null)
|
||||||
|
{
|
||||||
|
_appearance.RemoveData(entity.Owner, StationAiVisualState.Key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryComp<StationAiCustomizationComponent>(stationAi, out var stationAiCustomization) ||
|
||||||
|
!stationAiCustomization.ProtoIds.TryGetValue(_stationAiCoreCustomGroupProtoId, out var protoId) ||
|
||||||
|
!_protoManager.TryIndex(protoId, out var prototype) ||
|
||||||
|
!prototype.LayerData.TryGetValue(state.ToString(), out var layerData))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This data is handled manually in the client StationAiSystem
|
||||||
|
_appearance.SetData(entity.Owner, StationAiVisualState.Key, layerData);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ using Robust.Shared.Prototypes;
|
|||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Shared.Silicons.StationAi;
|
namespace Content.Shared.Silicons.StationAi;
|
||||||
|
|
||||||
@@ -56,6 +57,7 @@ public abstract partial class SharedStationAiSystem : EntitySystem
|
|||||||
[Dependency] private readonly SharedTransformSystem _xforms = default!;
|
[Dependency] private readonly SharedTransformSystem _xforms = default!;
|
||||||
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
|
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
|
||||||
[Dependency] private readonly StationAiVisionSystem _vision = default!;
|
[Dependency] private readonly StationAiVisionSystem _vision = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||||
|
|
||||||
// StationAiHeld is added to anything inside of an AI core.
|
// StationAiHeld is added to anything inside of an AI core.
|
||||||
// StationAiHolder indicates it can hold an AI positronic brain (e.g. holocard / core).
|
// StationAiHolder indicates it can hold an AI positronic brain (e.g. holocard / core).
|
||||||
@@ -82,6 +84,7 @@ public abstract partial class SharedStationAiSystem : EntitySystem
|
|||||||
InitializeAirlock();
|
InitializeAirlock();
|
||||||
InitializeHeld();
|
InitializeHeld();
|
||||||
InitializeLight();
|
InitializeLight();
|
||||||
|
InitializeCustomization();
|
||||||
|
|
||||||
SubscribeLocalEvent<StationAiWhitelistComponent, BoundUserInterfaceCheckRangeEvent>(OnAiBuiCheck);
|
SubscribeLocalEvent<StationAiWhitelistComponent, BoundUserInterfaceCheckRangeEvent>(OnAiBuiCheck);
|
||||||
|
|
||||||
@@ -107,25 +110,35 @@ public abstract partial class SharedStationAiSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnCoreVerbs(Entity<StationAiCoreComponent> ent, ref GetVerbsEvent<Verb> args)
|
private void OnCoreVerbs(Entity<StationAiCoreComponent> ent, ref GetVerbsEvent<Verb> args)
|
||||||
{
|
{
|
||||||
if (!_admin.IsAdmin(args.User) ||
|
|
||||||
TryGetHeld((ent.Owner, ent.Comp), out _))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = args.User;
|
var user = args.User;
|
||||||
|
|
||||||
args.Verbs.Add(new Verb()
|
// Admin option to take over the station AI core
|
||||||
|
if (_admin.IsAdmin(args.User) &&
|
||||||
|
!TryGetHeld((ent.Owner, ent.Comp), out _))
|
||||||
{
|
{
|
||||||
Text = Loc.GetString("station-ai-takeover"),
|
args.Verbs.Add(new Verb()
|
||||||
Category = VerbCategory.Debug,
|
|
||||||
Act = () =>
|
|
||||||
{
|
{
|
||||||
var brain = SpawnInContainerOrDrop(DefaultAi, ent.Owner, StationAiCoreComponent.Container);
|
Text = Loc.GetString("station-ai-takeover"),
|
||||||
_mind.ControlMob(user, brain);
|
Category = VerbCategory.Debug,
|
||||||
},
|
Act = () =>
|
||||||
Impact = LogImpact.High,
|
{
|
||||||
});
|
var brain = SpawnInContainerOrDrop(DefaultAi, ent.Owner, StationAiCoreComponent.Container);
|
||||||
|
_mind.ControlMob(user, brain);
|
||||||
|
},
|
||||||
|
Impact = LogImpact.High,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option to open the station AI customization menu
|
||||||
|
if (TryGetHeld((ent, ent.Comp), out var insertedAi) && insertedAi == user)
|
||||||
|
{
|
||||||
|
args.Verbs.Add(new Verb()
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("station-ai-customization-menu"),
|
||||||
|
Act = () => _uiSystem.TryOpenUi(ent.Owner, StationAiCustomizationUiKey.Key, insertedAi),
|
||||||
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/emotes.svg.192dpi.png")),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAiAccessible(Entity<StationAiOverlayComponent> ent, ref AccessibleOverrideEvent args)
|
private void OnAiAccessible(Entity<StationAiOverlayComponent> ent, ref AccessibleOverrideEvent args)
|
||||||
@@ -494,14 +507,21 @@ public abstract partial class SharedStationAiSystem : EntitySystem
|
|||||||
if (!Resolve(entity.Owner, ref entity.Comp, false))
|
if (!Resolve(entity.Owner, ref entity.Comp, false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_containers.TryGetContainer(entity.Owner, StationAiHolderComponent.Container, out var container) ||
|
// Todo: when AIs can die, add a check to see if the AI is in the 'dead' state
|
||||||
container.Count == 0)
|
var state = StationAiState.Empty;
|
||||||
|
|
||||||
|
if (_containers.TryGetContainer(entity.Owner, StationAiHolderComponent.Container, out var container) && container.Count > 0)
|
||||||
|
state = StationAiState.Occupied;
|
||||||
|
|
||||||
|
// If the entity is a station AI core, attempt to customize its appearance
|
||||||
|
if (TryComp<StationAiCoreComponent>(entity, out var stationAiCore))
|
||||||
{
|
{
|
||||||
_appearance.SetData(entity.Owner, StationAiVisualState.Key, StationAiState.Empty);
|
CustomizeAppearance((entity, stationAiCore), state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_appearance.SetData(entity.Owner, StationAiVisualState.Key, StationAiState.Occupied);
|
// Otherwise let generic visualizers handle the appearance update
|
||||||
|
_appearance.SetData(entity.Owner, StationAiVisualState.Key, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void AnnounceIntellicardUsage(EntityUid uid, SoundSpecifier? cue = null) { }
|
public virtual void AnnounceIntellicardUsage(EntityUid uid, SoundSpecifier? cue = null) { }
|
||||||
@@ -550,17 +570,23 @@ public sealed partial class JumpToCoreEvent : InstantActionEvent
|
|||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed partial class IntellicardDoAfterEvent : SimpleDoAfterEvent;
|
public sealed partial class IntellicardDoAfterEvent : SimpleDoAfterEvent;
|
||||||
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public enum StationAiVisualState : byte
|
public enum StationAiVisualState : byte
|
||||||
{
|
{
|
||||||
Key,
|
Key,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum StationAiSpriteState : byte
|
||||||
|
{
|
||||||
|
Key,
|
||||||
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public enum StationAiState : byte
|
public enum StationAiState : byte
|
||||||
{
|
{
|
||||||
Empty,
|
Empty,
|
||||||
Occupied,
|
Occupied,
|
||||||
Dead,
|
Dead,
|
||||||
|
Hologram,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Silicons.StationAi;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds data for altering the appearance of station AIs.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
|
public sealed partial class StationAiCustomizationComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Dictionary of the prototype data used for customizing the appearance of the entity.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public Dictionary<ProtoId<StationAiCustomizationGroupPrototype>, ProtoId<StationAiCustomizationPrototype>> ProtoIds = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message sent to server that contains a station AI customization that the client has selected
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class StationAiCustomizationMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public readonly ProtoId<StationAiCustomizationGroupPrototype> GroupProtoId;
|
||||||
|
public readonly ProtoId<StationAiCustomizationPrototype> CustomizationProtoId;
|
||||||
|
|
||||||
|
public StationAiCustomizationMessage(ProtoId<StationAiCustomizationGroupPrototype> groupProtoId, ProtoId<StationAiCustomizationPrototype> customizationProtoId)
|
||||||
|
{
|
||||||
|
GroupProtoId = groupProtoId;
|
||||||
|
CustomizationProtoId = customizationProtoId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Key for opening the station AI customization UI
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum StationAiCustomizationUiKey : byte
|
||||||
|
{
|
||||||
|
Key,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The different catagories of station Ai customizations available
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum StationAiCustomizationType : byte
|
||||||
|
{
|
||||||
|
CoreIconography,
|
||||||
|
Hologram,
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Shared.Silicons.StationAi;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds data for customizing the appearance of station AIs.
|
||||||
|
/// </summary>
|
||||||
|
[Prototype]
|
||||||
|
public sealed partial class StationAiCustomizationGroupPrototype : IPrototype
|
||||||
|
{
|
||||||
|
[IdDataField]
|
||||||
|
public string ID { get; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The localized name of the customization.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true)]
|
||||||
|
public LocId Name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type of customization that is associated with this group.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public StationAiCustomizationType Category = StationAiCustomizationType.CoreIconography;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of prototypes associated with the customization group.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true)]
|
||||||
|
public List<ProtoId<StationAiCustomizationPrototype>> ProtoIds = new();
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared.Silicons.StationAi;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds data for customizing the appearance of station AIs.
|
||||||
|
/// </summary>
|
||||||
|
[Prototype]
|
||||||
|
public sealed partial class StationAiCustomizationPrototype : IPrototype, IInheritingPrototype
|
||||||
|
{
|
||||||
|
[IdDataField]
|
||||||
|
public string ID { get; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The (unlocalized) name of the customization.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true)]
|
||||||
|
public LocId Name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores the data which is used to modify the appearance of the station AI.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(required: true)]
|
||||||
|
public Dictionary<string, PrototypeLayerData> LayerData = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Key used to index the prototype layer data and extract a preview of the customization (for menus, etc)
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public string PreviewKey = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies a background to use for previewing the customization (for menus, etc)
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public SpriteSpecifier? PreviewBackground;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The prototype we inherit from.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
[ParentDataFieldAttribute(typeof(AbstractPrototypeIdArraySerializer<StationAiCustomizationPrototype>))]
|
||||||
|
public string[]? Parents { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies whether the prototype is abstract.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
[NeverPushInheritance]
|
||||||
|
[AbstractDataField]
|
||||||
|
public bool Abstract { get; }
|
||||||
|
}
|
||||||
@@ -22,3 +22,25 @@ toggle-light = Toggle light
|
|||||||
ai-device-not-responding = Device is not responding
|
ai-device-not-responding = Device is not responding
|
||||||
|
|
||||||
ai-consciousness-download-warning = Your consciousness is being downloaded.
|
ai-consciousness-download-warning = Your consciousness is being downloaded.
|
||||||
|
|
||||||
|
# UI
|
||||||
|
station-ai-customization-menu = AI customization
|
||||||
|
station-ai-customization-categories = Categories
|
||||||
|
station-ai-customization-options = Options (choice of one)
|
||||||
|
station-ai-customization-core = AI core displays
|
||||||
|
station-ai-customization-hologram = Holographic avatars
|
||||||
|
|
||||||
|
# Customizations
|
||||||
|
station-ai-icon-ai = Ghost in the machine
|
||||||
|
station-ai-icon-angel = Guardian angel
|
||||||
|
station-ai-icon-bliss = Simpler times
|
||||||
|
station-ai-icon-clown = Clownin' around
|
||||||
|
station-ai-icon-dorf = Adventure awaits
|
||||||
|
station-ai-icon-heartline = Lifeline
|
||||||
|
station-ai-icon-smiley = All smiles
|
||||||
|
|
||||||
|
station-ai-hologram-female = Female appearance
|
||||||
|
station-ai-hologram-male = Male appearance
|
||||||
|
station-ai-hologram-face = Disembodied head
|
||||||
|
station-ai-hologram-cat = Cat form
|
||||||
|
station-ai-hologram-dog = Corgi form
|
||||||
163
Resources/Prototypes/AppearanceCustomization/station_ai.yml
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
# Groups
|
||||||
|
- type: stationAiCustomizationGroup
|
||||||
|
id: StationAiCoreIconography
|
||||||
|
name: station-ai-customization-core
|
||||||
|
category: CoreIconography
|
||||||
|
protoIds:
|
||||||
|
- StationAiIconAi
|
||||||
|
- StationAiIconAngel
|
||||||
|
- StationAiIconBliss
|
||||||
|
- StationAiIconClown
|
||||||
|
- StationAiIconDorf
|
||||||
|
- StationAiIconHeartline
|
||||||
|
- StationAiIconSmiley
|
||||||
|
|
||||||
|
- type: stationAiCustomizationGroup
|
||||||
|
id: StationAiHolograms
|
||||||
|
name: station-ai-customization-hologram
|
||||||
|
category: Hologram
|
||||||
|
protoIds:
|
||||||
|
- StationAiHologramFemale
|
||||||
|
- StationAiHologramMale
|
||||||
|
- StationAiHologramFace
|
||||||
|
- StationAiHologramCat
|
||||||
|
- StationAiHologramDog
|
||||||
|
|
||||||
|
# Iconography
|
||||||
|
- type: stationAiCustomization
|
||||||
|
abstract: true
|
||||||
|
id: StationAiIconBase
|
||||||
|
previewKey: Occupied
|
||||||
|
previewBackground:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: base
|
||||||
|
|
||||||
|
- type: stationAiCustomization
|
||||||
|
parent: StationAiIconBase
|
||||||
|
id: StationAiIconAi
|
||||||
|
name: station-ai-icon-ai
|
||||||
|
layerData:
|
||||||
|
Occupied:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: ai
|
||||||
|
Dead:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: ai_dead
|
||||||
|
|
||||||
|
- type: stationAiCustomization
|
||||||
|
parent: StationAiIconBase
|
||||||
|
id: StationAiIconAngel
|
||||||
|
name: station-ai-icon-angel
|
||||||
|
layerData:
|
||||||
|
Occupied:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: ai_angel
|
||||||
|
Dead:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: ai_angel_dead
|
||||||
|
|
||||||
|
- type: stationAiCustomization
|
||||||
|
parent: StationAiIconBase
|
||||||
|
id: StationAiIconBliss
|
||||||
|
name: station-ai-icon-bliss
|
||||||
|
layerData:
|
||||||
|
Occupied:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: ai_bliss
|
||||||
|
Dead:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: ai_dead
|
||||||
|
|
||||||
|
- type: stationAiCustomization
|
||||||
|
parent: StationAiIconBase
|
||||||
|
id: StationAiIconClown
|
||||||
|
name: station-ai-icon-clown
|
||||||
|
layerData:
|
||||||
|
Occupied:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: ai_clown
|
||||||
|
Dead:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: ai_clown_dead
|
||||||
|
|
||||||
|
- type: stationAiCustomization
|
||||||
|
parent: StationAiIconBase
|
||||||
|
id: StationAiIconDorf
|
||||||
|
name: station-ai-icon-dorf
|
||||||
|
layerData:
|
||||||
|
Occupied:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: ai_dorf
|
||||||
|
Dead:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: ai_dead
|
||||||
|
|
||||||
|
- type: stationAiCustomization
|
||||||
|
parent: StationAiIconBase
|
||||||
|
id: StationAiIconHeartline
|
||||||
|
name: station-ai-icon-heartline
|
||||||
|
layerData:
|
||||||
|
Occupied:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: "ai_heartline"
|
||||||
|
Dead:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: "ai_heartline_dead"
|
||||||
|
|
||||||
|
- type: stationAiCustomization
|
||||||
|
parent: StationAiIconBase
|
||||||
|
id: StationAiIconSmiley
|
||||||
|
name: station-ai-icon-smiley
|
||||||
|
layerData:
|
||||||
|
Occupied:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: "ai_smiley"
|
||||||
|
Dead:
|
||||||
|
sprite: Mobs/Silicon/station_ai.rsi
|
||||||
|
state: "ai_dead"
|
||||||
|
|
||||||
|
# Holograms
|
||||||
|
- type: stationAiCustomization
|
||||||
|
id: StationAiHologramFemale
|
||||||
|
name: station-ai-hologram-female
|
||||||
|
previewKey: Hologram
|
||||||
|
layerData:
|
||||||
|
Hologram:
|
||||||
|
sprite: Mobs/Silicon/holograms.rsi
|
||||||
|
state: ai_female
|
||||||
|
|
||||||
|
- type: stationAiCustomization
|
||||||
|
id: StationAiHologramMale
|
||||||
|
name: station-ai-hologram-male
|
||||||
|
previewKey: Hologram
|
||||||
|
layerData:
|
||||||
|
Hologram:
|
||||||
|
sprite: Mobs/Silicon/holograms.rsi
|
||||||
|
state: ai_male
|
||||||
|
|
||||||
|
- type: stationAiCustomization
|
||||||
|
id: StationAiHologramFace
|
||||||
|
name: station-ai-hologram-face
|
||||||
|
previewKey: Hologram
|
||||||
|
layerData:
|
||||||
|
Hologram:
|
||||||
|
sprite: Mobs/Silicon/holograms.rsi
|
||||||
|
state: ai_face
|
||||||
|
|
||||||
|
- type: stationAiCustomization
|
||||||
|
id: StationAiHologramCat
|
||||||
|
name: station-ai-hologram-cat
|
||||||
|
previewKey: Hologram
|
||||||
|
layerData:
|
||||||
|
Hologram:
|
||||||
|
sprite: Mobs/Silicon/holograms.rsi
|
||||||
|
state: ai_cat
|
||||||
|
|
||||||
|
- type: stationAiCustomization
|
||||||
|
id: StationAiHologramDog
|
||||||
|
name: station-ai-hologram-dog
|
||||||
|
previewKey: Hologram
|
||||||
|
layerData:
|
||||||
|
Hologram:
|
||||||
|
sprite: Mobs/Silicon/holograms.rsi
|
||||||
|
state: ai_dog
|
||||||
@@ -70,10 +70,6 @@
|
|||||||
canShuttle: false
|
canShuttle: false
|
||||||
title: comms-console-announcement-title-station-ai
|
title: comms-console-announcement-title-station-ai
|
||||||
color: "#5ed7aa"
|
color: "#5ed7aa"
|
||||||
- type: HolographicAvatar
|
|
||||||
layerData:
|
|
||||||
- sprite: Mobs/Silicon/station_ai.rsi
|
|
||||||
state: default
|
|
||||||
- type: ShowJobIcons
|
- type: ShowJobIcons
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -202,8 +198,11 @@
|
|||||||
layers:
|
layers:
|
||||||
- state: base
|
- state: base
|
||||||
- state: ai_empty
|
- state: ai_empty
|
||||||
map: ["unshaded"]
|
|
||||||
shader: unshaded
|
shader: unshaded
|
||||||
|
- state: ai
|
||||||
|
map: ["enum.StationAiVisualState.Key"]
|
||||||
|
shader: unshaded
|
||||||
|
visible: false
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
- type: InteractionPopup
|
- type: InteractionPopup
|
||||||
interactSuccessString: petting-success-station-ai
|
interactSuccessString: petting-success-station-ai
|
||||||
@@ -211,12 +210,6 @@
|
|||||||
messagePerceivedByOthers: petting-success-station-ai-others # Otherwise AI cannot tell its being pet as It's just a brain inside of the core, not the core itself.
|
messagePerceivedByOthers: petting-success-station-ai-others # Otherwise AI cannot tell its being pet as It's just a brain inside of the core, not the core itself.
|
||||||
interactSuccessSound:
|
interactSuccessSound:
|
||||||
path: /Audio/Ambience/Objects/periodic_beep.ogg
|
path: /Audio/Ambience/Objects/periodic_beep.ogg
|
||||||
- type: GenericVisualizer
|
|
||||||
visuals:
|
|
||||||
enum.StationAiVisualState.Key:
|
|
||||||
unshaded:
|
|
||||||
Empty: { state: ai_empty }
|
|
||||||
Occupied: { state: ai }
|
|
||||||
- type: Telephone
|
- type: Telephone
|
||||||
compatibleRanges:
|
compatibleRanges:
|
||||||
- Grid
|
- Grid
|
||||||
@@ -230,10 +223,12 @@
|
|||||||
- type: StationAiWhitelist
|
- type: StationAiWhitelist
|
||||||
- type: UserInterface
|
- type: UserInterface
|
||||||
interfaces:
|
interfaces:
|
||||||
enum.HolopadUiKey.AiRequestWindow:
|
enum.HolopadUiKey.AiRequestWindow:
|
||||||
type: HolopadBoundUserInterface
|
type: HolopadBoundUserInterface
|
||||||
enum.HolopadUiKey.AiActionWindow:
|
enum.HolopadUiKey.AiActionWindow:
|
||||||
type: HolopadBoundUserInterface
|
type: HolopadBoundUserInterface
|
||||||
|
enum.StationAiCustomizationUiKey.Key:
|
||||||
|
type: StationAiCustomizationBoundUserInterface
|
||||||
|
|
||||||
# The job-ready version of an AI spawn.
|
# The job-ready version of an AI spawn.
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -244,12 +239,6 @@
|
|||||||
- type: ContainerSpawnPoint
|
- type: ContainerSpawnPoint
|
||||||
containerId: station_ai_mind_slot
|
containerId: station_ai_mind_slot
|
||||||
job: StationAi
|
job: StationAi
|
||||||
- type: Sprite
|
|
||||||
sprite: Mobs/Silicon/station_ai.rsi
|
|
||||||
layers:
|
|
||||||
- state: base
|
|
||||||
- state: ai
|
|
||||||
shader: unshaded
|
|
||||||
|
|
||||||
# The actual brain inside the core
|
# The actual brain inside the core
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -294,6 +283,14 @@
|
|||||||
- type: StartingMindRole
|
- type: StartingMindRole
|
||||||
mindRole: "MindRoleSiliconBrain"
|
mindRole: "MindRoleSiliconBrain"
|
||||||
silent: true
|
silent: true
|
||||||
|
- type: StationAiCustomization
|
||||||
|
protoIds:
|
||||||
|
StationAiCoreIconography: StationAiIconAi
|
||||||
|
StationAiHolograms: StationAiHologramFemale
|
||||||
|
- type: HolographicAvatar
|
||||||
|
layerData:
|
||||||
|
- sprite: Mobs/Silicon/holograms.rsi
|
||||||
|
state: ai_female
|
||||||
- type: NameIdentifier
|
- type: NameIdentifier
|
||||||
group: StationAi
|
group: StationAi
|
||||||
|
|
||||||
|
|||||||
BIN
Resources/Textures/Mobs/Silicon/holograms.rsi/ai_cat.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
Resources/Textures/Mobs/Silicon/holograms.rsi/ai_dog.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
Resources/Textures/Mobs/Silicon/holograms.rsi/ai_face.png
Normal file
|
After Width: | Height: | Size: 625 B |
BIN
Resources/Textures/Mobs/Silicon/holograms.rsi/ai_female.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
Resources/Textures/Mobs/Silicon/holograms.rsi/ai_male.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
38
Resources/Textures/Mobs/Silicon/holograms.rsi/meta.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"license": "CC-BY-SA-3.0",
|
||||||
|
"copyright": "Taken from vgstation at https://github.com/vgstation-coders/vgstation13/blob/e2923df112df8aa025846d0764697bad6506586a/icons/mob/AI.dmi - modified by chromiumboy.",
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "ai_female"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_male"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_face",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
2.3,
|
||||||
|
0.2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_cat",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.75,
|
||||||
|
0.75
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_dog"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_angel.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_angel_dead.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_bliss.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_clown.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_clown_dead.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_dorf.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_heartline.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
BIN
Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_smiley.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
@@ -1,61 +1,215 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"license": "CC-BY-SA-3.0",
|
"license": "CC-BY-SA-3.0",
|
||||||
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/blob/2a19963297f91efb452dbb5c1d4eb28a14776b0a/icons/mob/silicon/ai.dmi",
|
"copyright": "Taken from vgstation at https://github.com/vgstation-coders/vgstation13/blob/e2923df112df8aa025846d0764697bad6506586a/icons/mob/AI.dmi - modified by chromiumboy.",
|
||||||
"size": {
|
"size": {
|
||||||
"x": 32,
|
"x": 32,
|
||||||
"y": 32
|
"y": 32
|
||||||
},
|
|
||||||
"states": [
|
|
||||||
{
|
|
||||||
"name": "ai",
|
|
||||||
"delays": [
|
|
||||||
[
|
|
||||||
0.2,
|
|
||||||
0.2,
|
|
||||||
0.1,
|
|
||||||
0.2,
|
|
||||||
0.2,
|
|
||||||
0.2,
|
|
||||||
0.2,
|
|
||||||
0.2,
|
|
||||||
0.2,
|
|
||||||
0.2,
|
|
||||||
0.2,
|
|
||||||
0.2,
|
|
||||||
0.2,
|
|
||||||
0.2,
|
|
||||||
0.1
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
"states": [
|
||||||
"name": "ai_camera",
|
{
|
||||||
"delays": [
|
"name": "ai",
|
||||||
[
|
"delays": [
|
||||||
1.0,
|
[
|
||||||
1.0
|
0.2,
|
||||||
]
|
0.2,
|
||||||
]
|
0.1,
|
||||||
},
|
0.2,
|
||||||
{
|
0.2,
|
||||||
"name": "ai_dead"
|
0.2,
|
||||||
},
|
0.2,
|
||||||
{
|
0.2,
|
||||||
"name": "ai_empty",
|
0.2,
|
||||||
"delays": [
|
0.2,
|
||||||
[
|
0.2,
|
||||||
0.7,
|
0.2,
|
||||||
0.7
|
0.2,
|
||||||
]
|
0.2,
|
||||||
]
|
0.1
|
||||||
},
|
]
|
||||||
{
|
]
|
||||||
"name": "default",
|
},
|
||||||
"directions": 4
|
{
|
||||||
},
|
"name": "ai_angel",
|
||||||
{
|
"delays": [
|
||||||
"name": "base"
|
[
|
||||||
}
|
0.08,
|
||||||
]
|
0.08,
|
||||||
}
|
0.08,
|
||||||
|
0.08,
|
||||||
|
0.08,
|
||||||
|
0.08
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_angel_dead",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.00,
|
||||||
|
0.08,
|
||||||
|
0.50,
|
||||||
|
0.20
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_bliss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_clown",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_clown_dead",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_dorf",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_heartline",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_heartline_dead",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.15,
|
||||||
|
0.15,
|
||||||
|
0.15,
|
||||||
|
0.15,
|
||||||
|
0.15,
|
||||||
|
0.15,
|
||||||
|
0.15,
|
||||||
|
0.15,
|
||||||
|
0.15,
|
||||||
|
0.15,
|
||||||
|
0.15,
|
||||||
|
0.15,
|
||||||
|
0.15
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_smiley",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_camera",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
1.0,
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_dead"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ai_empty",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.7,
|
||||||
|
0.7
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "default",
|
||||||
|
"directions": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "base"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||