Merge 9360526a3e into fd5b16abb3
This commit is contained in:
commit
8f1d5b2b11
|
|
@ -110,7 +110,7 @@ public sealed partial class DialogWindow : FancyWindow
|
|||
protected override void Opened()
|
||||
{
|
||||
base.Opened();
|
||||
|
||||
|
||||
// Grab keyboard focus for the first dialog entry
|
||||
_promptLines[0].Item2.GrabKeyboardFocus();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
<BoxContainer
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
HorizontalExpand="True"
|
||||
Orientation="Vertical"
|
||||
>
|
||||
<BoxContainer Orientation="Horizontal" VerticalExpand="True">
|
||||
<PanelContainer Margin="5" >
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxFlat BackgroundColor="#1B1B1B"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
|
||||
<BoxContainer Orientation="Vertical" SeparationOverride="5">
|
||||
<BoxContainer Orientation="Horizontal" >
|
||||
<Label Text="Issuer:" Margin="5"/>
|
||||
<LineEdit
|
||||
Name="ObjectiveIssuer"
|
||||
HorizontalExpand="True"
|
||||
Margin="5"
|
||||
/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="Title:" Margin="5"/>
|
||||
<LineEdit
|
||||
Name="ObjectiveTitle"
|
||||
HorizontalExpand="True"
|
||||
Margin="5"
|
||||
/>
|
||||
</BoxContainer>
|
||||
<customControls:HSeparator/>
|
||||
<Label Text="Description:" Margin="5"/>
|
||||
<TextEdit
|
||||
Name="ObjectiveDescription"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True"
|
||||
MinWidth="500"
|
||||
MinHeight="60"
|
||||
Margin="5"
|
||||
/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
|
||||
<BoxContainer Orientation="Vertical" Align="Center">
|
||||
<BoxContainer Align="Center">
|
||||
<PanelContainer>
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxFlat BackgroundColor="#1B1B1B"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
|
||||
<TextureButton Name="IconSelectButton" SetWidth="128" SetHeight="128" />
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" Align="Center" >
|
||||
<Button Name="ViewButton" Text="{Loc objective-editor-admin-ui-view}" StyleClasses="OpenRight" />
|
||||
<Button Name="ResetButton" Text="{Loc objective-editor-admin-ui-reset}" StyleClasses="OpenLeft"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
using Content.Client._DV.UserInterfaces.Controls;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client._DV.Objectives.Eui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class ObjectiveContainer : BoxContainer
|
||||
{
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IConsoleHost _console = default!;
|
||||
private readonly SpriteSystem _sprite;
|
||||
|
||||
private readonly SpritePickerWindow _spritePicker = new();
|
||||
|
||||
private ObjectiveUI? _objective = null;
|
||||
|
||||
public ObjectiveContainer()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
IoCManager.InjectDependencies(this);
|
||||
_sprite = _entityManager.System<SpriteSystem>();
|
||||
|
||||
_spritePicker.OnSpriteSelected += SetIcon;
|
||||
ObjectiveTitle.OnTextChanged += OnTitleChanged;
|
||||
ObjectiveIssuer.OnTextChanged += OnIssuerChanged;
|
||||
|
||||
ObjectiveDescription.OnTextChanged += OnDescriptionChanged;
|
||||
ObjectiveDescription.Placeholder = new Rope.Leaf(Loc.GetString("objective-editor-admin-ui-placeholder-description"));
|
||||
|
||||
ResetButton.OnPressed += _ => ResetObjective();
|
||||
ViewButton.OnPressed += _ => OnViewObjective();
|
||||
IconSelectButton.OnPressed += _ => OnOpenIconSelect();
|
||||
|
||||
ClearData();
|
||||
}
|
||||
|
||||
public bool HasChanges()
|
||||
{
|
||||
return _objective?.HasChanges ?? false;
|
||||
}
|
||||
|
||||
public void ClearData()
|
||||
{
|
||||
_objective = null;
|
||||
|
||||
ObjectiveIssuer.Editable = false;
|
||||
ObjectiveTitle.Editable = false;
|
||||
ObjectiveDescription.Editable = false;
|
||||
|
||||
ResetButton.Disabled = true;
|
||||
ViewButton.Disabled = true;
|
||||
IconSelectButton.Disabled = true;
|
||||
|
||||
ObjectiveIssuer.Text = "";
|
||||
ObjectiveTitle.Text = "";
|
||||
ObjectiveDescription.TextRope = new Rope.Leaf("");
|
||||
|
||||
IconSelectButton.TextureNormal = null;
|
||||
}
|
||||
|
||||
public void SetData(ObjectiveUI data)
|
||||
{
|
||||
_objective = data;
|
||||
|
||||
ObjectiveIssuer.Editable = true;
|
||||
ObjectiveTitle.Editable = true;
|
||||
ObjectiveDescription.Editable = true;
|
||||
|
||||
ResetButton.Disabled = false;
|
||||
ViewButton.Disabled = false;
|
||||
IconSelectButton.Disabled = false;
|
||||
|
||||
ObjectiveIssuer.Text = _objective.Issuer;
|
||||
ObjectiveTitle.Text = _objective.Title;
|
||||
ObjectiveDescription.TextRope = new Rope.Leaf(_objective.Description);
|
||||
|
||||
IconSelectButton.TextureNormal = _sprite.Frame0(data.Icon);
|
||||
}
|
||||
|
||||
public void ResetObjective()
|
||||
{
|
||||
if (_objective is null)
|
||||
return;
|
||||
|
||||
_objective.Reset();
|
||||
IconSelectButton.TextureNormal = _sprite.Frame0(_objective.Icon);
|
||||
}
|
||||
|
||||
private void OnTitleChanged(LineEdit.LineEditEventArgs args)
|
||||
{
|
||||
if (_objective is null)
|
||||
return;
|
||||
|
||||
_objective.Title = args.Text;
|
||||
}
|
||||
|
||||
private void OnIssuerChanged(LineEdit.LineEditEventArgs args)
|
||||
{
|
||||
if (_objective is null)
|
||||
return;
|
||||
|
||||
_objective.Issuer = args.Text;
|
||||
}
|
||||
|
||||
private void OnDescriptionChanged(TextEdit.TextEditEventArgs args)
|
||||
{
|
||||
if (_objective is null)
|
||||
return;
|
||||
|
||||
_objective.Description = Rope.Collapse(args.TextRope).Trim();
|
||||
}
|
||||
|
||||
private void OnOpenIconSelect()
|
||||
{
|
||||
if (_objective is null)
|
||||
return;
|
||||
|
||||
_spritePicker.OpenWithSprite(_objective.Icon);
|
||||
}
|
||||
|
||||
private void OnViewObjective()
|
||||
{
|
||||
if (_objective is null)
|
||||
return;
|
||||
|
||||
_console.ExecuteCommand($"vv {_objective.Entity}");
|
||||
}
|
||||
|
||||
private void SetIcon(SpriteSpecifier sprite)
|
||||
{
|
||||
if (_objective is null)
|
||||
return;
|
||||
|
||||
IconSelectButton.TextureNormal = _sprite.Frame0(sprite);
|
||||
_objective.Icon = sprite;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
using Content.Client.Eui;
|
||||
using Content.Shared._DV.Objectives.Eui;
|
||||
using Content.Shared.Eui;
|
||||
using Content.Shared.Mind;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._DV.Objectives.Eui;
|
||||
|
||||
public sealed class ObjectiveEditorEui : BaseEui
|
||||
{
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
private readonly ObjectiveEditorUi _editorUi;
|
||||
private Entity<MindComponent> _targetMind;
|
||||
|
||||
public ObjectiveEditorEui()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_editorUi = new ObjectiveEditorUi();
|
||||
_editorUi.SaveAction += SaveObjectives;
|
||||
_editorUi.CreateAction += CreateObjective;
|
||||
}
|
||||
|
||||
public override void Opened()
|
||||
{
|
||||
base.Opened();
|
||||
_editorUi.OpenCentered();
|
||||
}
|
||||
|
||||
public override void HandleState(EuiStateBase state)
|
||||
{
|
||||
if (state is not ObjectiveEditorEUIState s)
|
||||
return;
|
||||
|
||||
var mind = _entityManager.GetEntity(s.TargetMind);
|
||||
if (!_entityManager.TryGetComponent<MindComponent>(mind, out var comp))
|
||||
{
|
||||
// TODO: Log
|
||||
return;
|
||||
}
|
||||
|
||||
_targetMind = (mind, comp);
|
||||
|
||||
var name = comp.CharacterName ?? Loc.GetString("objective-editor-admin-ui-unknown-mind");
|
||||
_editorUi.SetEditorTitle(name, comp.RoleType, s.Subtype);
|
||||
_editorUi.SetObjectives(s.Objectives);
|
||||
}
|
||||
|
||||
public override void HandleMessage(EuiMessageBase msg)
|
||||
{
|
||||
base.HandleMessage(msg);
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
case ObjectiveEditorCreateResponse message:
|
||||
HandleCreateResponse(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCreateResponse(ObjectiveEditorCreateResponse response)
|
||||
{
|
||||
if (response.Data == null)
|
||||
{
|
||||
// TODO(Barry): Logging
|
||||
return;
|
||||
}
|
||||
|
||||
_editorUi.AddObjective(response.Data);
|
||||
}
|
||||
|
||||
private void SaveObjectives(bool silentSave)
|
||||
{
|
||||
SendMessage(new ObjectiveEditorSaveMessage(_editorUi.GetObjectives(), _entityManager.GetNetEntity(_targetMind), silentSave));
|
||||
}
|
||||
|
||||
private void CreateObjective(EntProtoId? proto)
|
||||
{
|
||||
SendMessage(new ObjectiveEditorCreateMessage(proto));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<controls:FancyWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
xmlns:obj="clr-namespace:Content.Client._DV.Objectives.Eui"
|
||||
Title="{Loc objective-editor-admin-ui-title}"
|
||||
MinSize="800 400"
|
||||
>
|
||||
<BoxContainer Orientation="Vertical" >
|
||||
<BoxContainer Orientation="Horizontal" Align="End">
|
||||
<CheckBox
|
||||
Name="SilentSave"
|
||||
Text="{Loc objective-editor-admin-ui-silent-save}"
|
||||
ToolTip="{Loc objective-editor-admin-ui-silent-save-tooltip}"
|
||||
Margin="5 0 5 0"/>
|
||||
<controls:ConfirmButton
|
||||
Name="ResetButton"
|
||||
Text="{Loc objective-editor-admin-ui-reset-all}"
|
||||
StyleClasses="OpenRight"
|
||||
ModulateSelfOverride="Red" />
|
||||
<controls:ConfirmButton
|
||||
Name="SaveButton"
|
||||
Text="{Loc objective-editor-admin-ui-save}"
|
||||
StyleClasses="OpenLeft"/>
|
||||
</BoxContainer>
|
||||
|
||||
<customControls:HSeparator Margin = "5"/>
|
||||
|
||||
<BoxContainer Orientation="Horizontal" VerticalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" MinWidth="200" Margin="5">
|
||||
<ItemList Name="ObjectiveList" VerticalExpand="True" HorizontalExpand="True" />
|
||||
<BoxContainer Orientation="Horizontal" >
|
||||
<Button Name="AddButton" Text="+" StyleClasses="OpenRight" />
|
||||
<controls:ConfirmButton Name="RemoveButton" Text="-" StyleClasses="OpenLeft" ModulateSelfOverride="Red"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
<obj:ObjectiveContainer Name="Container"/>
|
||||
</BoxContainer>
|
||||
|
||||
<customControls:HSeparator />
|
||||
<Label Text="{Loc objective-editor-admin-ui-check-note}" FontColorOverride="Red" Align="Center"/>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
using System.Linq;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared._DV.Objectives.Eui;
|
||||
using Content.Shared.Mind;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._DV.Objectives.Eui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class ObjectiveEditorUi : FancyWindow
|
||||
{
|
||||
private const int MaxTitleLength = 20;
|
||||
private const string ChangeMarker = "(*)";
|
||||
|
||||
private List<ObjectiveUI> _objectives = new();
|
||||
private ObjectiveUI? _selectedObjective = null;
|
||||
|
||||
public Action<bool>? SaveAction = null;
|
||||
public Action<EntProtoId?>? CreateAction = null;
|
||||
|
||||
public ObjectiveEditorUi()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
ResetButton.OnPressed += _ => OnResetObjectives();
|
||||
SaveButton.OnPressed += _ => SaveAction?.Invoke(SilentSave.Pressed);
|
||||
|
||||
AddButton.OnPressed += _ => OnAddObjective();
|
||||
RemoveButton.OnPressed += _ => OnDeleteObjective();
|
||||
|
||||
ObjectiveList.OnItemSelected += OnObjectiveSelected;
|
||||
ObjectiveList.OnItemDeselected += OnObjectiveDeselected;
|
||||
}
|
||||
|
||||
public List<ObjectiveData> GetObjectives()
|
||||
{
|
||||
return [.. _objectives.Where(x => !x.Deleted).Select(x => x.Current)];
|
||||
}
|
||||
|
||||
public void SetEditorTitle(
|
||||
string name,
|
||||
ProtoId<RoleTypePrototype>? role,
|
||||
LocId? subtype)
|
||||
{
|
||||
var roleText = role.HasValue ? role.Value.Id.ToString() : "N/A";
|
||||
if (subtype.HasValue)
|
||||
{
|
||||
roleText += string.Format(" - {0}", Loc.GetString(subtype));
|
||||
}
|
||||
|
||||
Title = Loc.GetString("objective-editor-admin-ui-title-filled", ("name", name), ("role", roleText));
|
||||
}
|
||||
|
||||
public void SetObjectives(List<ObjectiveData> objectives)
|
||||
{
|
||||
_objectives.Clear();
|
||||
_objectives = [.. objectives.Select(x => new ObjectiveUI(x))];
|
||||
|
||||
ObjectiveList.Clear();
|
||||
ObjectiveList.ClearSelected();
|
||||
|
||||
if (objectives.Count == 0)
|
||||
return; // Nothing to do
|
||||
|
||||
foreach (var objective in _objectives)
|
||||
{
|
||||
ObjectiveList.AddItem(GetShortTitle(objective.Title), metadata: objective);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddObjective(ObjectiveData objective)
|
||||
{
|
||||
var data = new ObjectiveUI(objective);
|
||||
_objectives.Add(data);
|
||||
ObjectiveList.AddItem(GetShortTitle(data.Title), metadata: data);
|
||||
}
|
||||
|
||||
private void OnObjectiveSelected(ItemList.ItemListSelectedEventArgs args)
|
||||
{
|
||||
var item = args.ItemList[args.ItemIndex];
|
||||
_selectedObjective = (ObjectiveUI)item.Metadata!;
|
||||
SetItemText(item, _selectedObjective);
|
||||
|
||||
Container.SetData(_selectedObjective);
|
||||
}
|
||||
private void OnObjectiveDeselected(ItemList.ItemListDeselectedEventArgs args)
|
||||
{
|
||||
var item = args.ItemList[args.ItemIndex];
|
||||
SetItemText(item, (ObjectiveUI)item.Metadata!);
|
||||
|
||||
_selectedObjective = null;
|
||||
Container.ClearData();
|
||||
}
|
||||
|
||||
private void SetItemText(ItemList.Item item, ObjectiveUI data)
|
||||
{
|
||||
var hasMarker = item.Text!.StartsWith(ChangeMarker);
|
||||
if (data.HasChanges && !hasMarker)
|
||||
{
|
||||
item.Text = string.Format("{0} {1}",
|
||||
ChangeMarker,
|
||||
GetShortTitle(data.Title)
|
||||
);
|
||||
}
|
||||
else if (!data.HasChanges && hasMarker)
|
||||
{
|
||||
item.Text = GetShortTitle(data.Title);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetShortTitle(string title)
|
||||
{
|
||||
var originalTitle = title;
|
||||
return title.Length <= MaxTitleLength
|
||||
? originalTitle
|
||||
: $"{originalTitle[..(MaxTitleLength - 3)]}...";
|
||||
}
|
||||
|
||||
private void OnResetObjectives()
|
||||
{
|
||||
Container.ResetObjective(); // Ensures that the Icon and whatever else is updated
|
||||
_objectives.ForEach(x => x.Reset());
|
||||
foreach (var item in ObjectiveList)
|
||||
{
|
||||
SetItemText(item, (ObjectiveUI)item.Metadata!);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAddObjective()
|
||||
{
|
||||
CreateAction?.Invoke(null);
|
||||
}
|
||||
|
||||
private void OnDeleteObjective()
|
||||
{
|
||||
var selected = ObjectiveList.GetSelected();
|
||||
if (!selected.Any())
|
||||
return; // Nothing selected, do nothing
|
||||
|
||||
// We're only removing this from the list of things, never deleting the objective from our
|
||||
// list in the case where a user needs to reset.
|
||||
|
||||
var item = selected.First();
|
||||
ObjectiveList.Remove(item);
|
||||
ObjectiveList.ClearSelected();
|
||||
|
||||
Container.ClearData();
|
||||
((ObjectiveUI)item.Metadata!).Deleted = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
using Content.Shared._DV.Objectives.Eui;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client._DV.Objectives.Eui;
|
||||
|
||||
// TODO(Barry): Think of a better name for this
|
||||
public sealed class ObjectiveUI(ObjectiveData data)
|
||||
{
|
||||
private readonly ObjectiveData _current = data;
|
||||
private readonly ObjectiveData _original = data.Clone();
|
||||
public bool HasChanges { get; private set; } = false;
|
||||
public ObjectiveData Current => _current;
|
||||
public bool Deleted = false;
|
||||
|
||||
public NetEntity Entity
|
||||
{
|
||||
get => _current.Entity;
|
||||
set
|
||||
{
|
||||
_current.Entity = value;
|
||||
HasChanges = true;
|
||||
}
|
||||
}
|
||||
public string Issuer
|
||||
{
|
||||
get => _current.Issuer;
|
||||
set
|
||||
{
|
||||
_current.Issuer = value;
|
||||
HasChanges = true;
|
||||
}
|
||||
}
|
||||
public string Title
|
||||
{
|
||||
get => _current.Info.Title;
|
||||
set
|
||||
{
|
||||
_current.Info.Title = value;
|
||||
HasChanges = true;
|
||||
}
|
||||
}
|
||||
public string Description
|
||||
{
|
||||
get => _current.Info.Description;
|
||||
set
|
||||
{
|
||||
_current.Info.Description = value;
|
||||
HasChanges = true;
|
||||
}
|
||||
}
|
||||
public SpriteSpecifier Icon
|
||||
{
|
||||
get => _current.Info.Icon;
|
||||
set
|
||||
{
|
||||
_current.Info.Icon = value;
|
||||
HasChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_current.CopyFrom(_original);
|
||||
HasChanges = false;
|
||||
Deleted = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<controls:FancyWindow
|
||||
Title="{Loc 'sprite-selector-ui-window-title'}"
|
||||
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls">
|
||||
|
||||
<BoxContainer MinWidth="300" MinHeight="200" Orientation="Vertical">
|
||||
<PanelContainer>
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxFlat BackgroundColor="#1B1B1B" />
|
||||
</PanelContainer.PanelOverride>
|
||||
|
||||
<TextureRect
|
||||
Name="PreviewTexture"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Center"
|
||||
Stretch="KeepAspectCentered"
|
||||
MinWidth="128"
|
||||
MinHeight="128"
|
||||
Margin="0 8 0 0"/>
|
||||
|
||||
</PanelContainer>
|
||||
|
||||
<TabContainer Name="TextureTypes">
|
||||
<BoxContainer Name="RSISelection" Orientation="Vertical">
|
||||
<LineEdit Name="RSIPath" />
|
||||
<OptionButton Name="RSIStates" />
|
||||
</BoxContainer>
|
||||
|
||||
<BoxContainer Name="TextureSelection" Orientation="Vertical">
|
||||
<LineEdit Name="TexturePath" />
|
||||
</BoxContainer>
|
||||
</TabContainer>
|
||||
|
||||
<Label Name="ErrorText" Visible="False" Align="Center" FontColorOverride="Red"/>
|
||||
|
||||
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center" Margin="5">
|
||||
<Button Name="OkButton" Text="{Loc 'sprite-selector-ui-ok'}"/>
|
||||
<Button Name="CancelButton" Text="{Loc 'sprite-selector-ui-cancel'}" ModulateSelfOverride="Red" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
using Content.Client.UserInterface.Controls;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client._DV.UserInterfaces.Controls;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class SpritePickerWindow : FancyWindow
|
||||
{
|
||||
private readonly SpriteSystem _sprite;
|
||||
private readonly IResourceCache _cache;
|
||||
|
||||
public Action<SpriteSpecifier>? OnSpriteSelected;
|
||||
private SpriteSpecifier _selectedSprite = SpriteSpecifier.Invalid;
|
||||
public SpritePickerWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
var entMan = IoCManager.Resolve<EntityManager>();
|
||||
_sprite = entMan.System<SpriteSystem>();
|
||||
_cache = IoCManager.Resolve<IResourceCache>();
|
||||
|
||||
TextureTypes.SetTabTitle(0, Loc.GetString("sprite-selector-ui-rsi-tab"));
|
||||
TextureTypes.SetTabTitle(1, Loc.GetString("sprite-selector-ui-texture-tab"));
|
||||
|
||||
RSIPath.OnTextChanged += OnRSIPathChanged;
|
||||
RSIPath.PlaceHolder = Loc.GetString("sprite-selector-ui-rsi-placeholder");
|
||||
RSIStates.OnItemSelected += OnRSIStateSelected;
|
||||
|
||||
TexturePath.OnTextChanged += OnTexturePathChanged;
|
||||
TexturePath.PlaceHolder = Loc.GetString("sprite-selector-ui-texture-placeholder");
|
||||
|
||||
OkButton.OnPressed += _ => OnConfirm();
|
||||
CancelButton.OnPressed += _ => Close();
|
||||
}
|
||||
|
||||
public void OpenWithSprite(SpriteSpecifier sprite)
|
||||
{
|
||||
ErrorText.Visible = false;
|
||||
|
||||
// Select the right tab
|
||||
if (sprite is SpriteSpecifier.Rsi rsi)
|
||||
{
|
||||
RSIPath.Text = rsi.RsiPath.CanonPath;
|
||||
SetAvailableStates(rsi.RsiPath, initialState: rsi.RsiState);
|
||||
|
||||
TexturePath.Text = "";
|
||||
}
|
||||
else if (sprite is SpriteSpecifier.Texture texture)
|
||||
{
|
||||
TexturePath.Text = texture.TexturePath.CanonPath;
|
||||
RSIPath.Text = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear everything as this was invalid
|
||||
TexturePath.Text = "";
|
||||
RSIPath.Text = "";
|
||||
}
|
||||
|
||||
OpenCentered();
|
||||
}
|
||||
|
||||
private void OnRSIPathChanged(LineEdit.LineEditEventArgs args)
|
||||
{
|
||||
if (!args.Text.EndsWith(".rsi"))
|
||||
return; // User might still be typing this out, don't bother validating just yet
|
||||
|
||||
SetAvailableStates(new ResPath(args.Text));
|
||||
}
|
||||
|
||||
private void OnRSIStateSelected(OptionButton.ItemSelectedEventArgs args)
|
||||
{
|
||||
RSIStates.SelectId(args.Id);
|
||||
|
||||
var state = (RSI.State)RSIStates.SelectedMetadata!;
|
||||
_selectedSprite = new SpriteSpecifier.Rsi(new ResPath(RSIPath.Text), state.StateId.Name!);
|
||||
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
private void SetAvailableStates(ResPath resPath, string? initialState = null)
|
||||
{
|
||||
// Textures/Sprites MUST be relative to the Texture root or else the cache won't find them.
|
||||
if (!resPath.TryRelativeTo(SpriteSpecifierSerializer.TextureRoot, out _))
|
||||
resPath = SpriteSpecifierSerializer.TextureRoot / resPath;
|
||||
|
||||
if (!_cache.TryGetResource<RSIResource>(resPath, out var rsi))
|
||||
{
|
||||
ErrorText.Visible = true;
|
||||
ErrorText.Text = Loc.GetString("sprite-selector-ui-rsi-not-found");
|
||||
return;
|
||||
}
|
||||
|
||||
ErrorText.Visible = false;
|
||||
RSIStates.Clear();
|
||||
|
||||
var initialSelection = 0;
|
||||
var i = 0;
|
||||
foreach (var state in rsi.RSI)
|
||||
{
|
||||
var name = state.StateId.Name!;
|
||||
RSIStates.AddItem(name, i);
|
||||
RSIStates.SetItemMetadata(i, state);
|
||||
|
||||
if (initialState != null && name == initialState)
|
||||
initialSelection = i;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (RSIStates.ChildCount == 0)
|
||||
return; // No states to show
|
||||
|
||||
|
||||
// Setup the icon to show something when the user swaps to it
|
||||
string rsiState;
|
||||
if (initialState == null)
|
||||
{
|
||||
// Select the first state available so it shows something to the user
|
||||
var firstState = (RSI.State)RSIStates.SelectedMetadata!;
|
||||
rsiState = firstState.StateId.Name!;
|
||||
}
|
||||
else
|
||||
{
|
||||
RSIStates.Select(initialSelection);
|
||||
rsiState = initialState;
|
||||
}
|
||||
|
||||
_selectedSprite = new SpriteSpecifier.Rsi(new ResPath(RSIPath.Text), rsiState);
|
||||
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
private void UpdatePreview()
|
||||
{
|
||||
PreviewTexture.Texture = _sprite.Frame0(_selectedSprite);
|
||||
}
|
||||
|
||||
private void OnTexturePathChanged(LineEdit.LineEditEventArgs args)
|
||||
{
|
||||
if (!args.Text.EndsWith(".png"))
|
||||
return; // User might still be typing this out, don't bother validating just yet
|
||||
|
||||
var resPath = new ResPath(args.Text);
|
||||
|
||||
if (!resPath.TryRelativeTo(SpriteSpecifierSerializer.TextureRoot, out _))
|
||||
resPath = SpriteSpecifierSerializer.TextureRoot / resPath;
|
||||
|
||||
if (!_cache.TryGetResource<TextureResource>(resPath, out var _))
|
||||
{
|
||||
ErrorText.Visible = true;
|
||||
ErrorText.Text = Loc.GetString("sprite-selector-ui-texture-not-found");
|
||||
return;
|
||||
}
|
||||
|
||||
ErrorText.Visible = false;
|
||||
|
||||
_selectedSprite = new SpriteSpecifier.Texture(resPath);
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
private void OnConfirm()
|
||||
{
|
||||
OnSpriteSelected?.Invoke(_selectedSprite);
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
|
@ -36,8 +36,6 @@ using Robust.Shared.Toolshed;
|
|||
using Robust.Shared.Utility;
|
||||
using System.Linq;
|
||||
using static Content.Shared.Configurable.ConfigurationComponent;
|
||||
using Content.Shared._Impstation.Thaven.Components; // DeltaV
|
||||
using Content.Server._Impstation.Thaven; // DeltaV
|
||||
|
||||
namespace Content.Server.Administration.Systems
|
||||
{
|
||||
|
|
@ -68,7 +66,6 @@ namespace Content.Server.Administration.Systems
|
|||
[Dependency] private readonly AdminFrozenSystem _freeze = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly SiliconLawSystem _siliconLawSystem = default!;
|
||||
[Dependency] private readonly ThavenMoodsSystem _moods = default!; // DeltaV
|
||||
|
||||
private readonly Dictionary<ICommonSession, List<EditSolutionsEui>> _openSolutionUis = new();
|
||||
|
||||
|
|
@ -403,26 +400,7 @@ namespace Content.Server.Administration.Systems
|
|||
});
|
||||
}
|
||||
|
||||
// Begin DeltaV Additions - thaven moods
|
||||
if (TryComp<ThavenMoodsComponent>(args.Target, out var moods))
|
||||
{
|
||||
args.Verbs.Add(new Verb()
|
||||
{
|
||||
Text = Loc.GetString("thaven-moods-ui-verb"),
|
||||
Category = VerbCategory.Admin,
|
||||
Act = () =>
|
||||
{
|
||||
var ui = new ThavenMoodsEui(_moods, EntityManager, _adminManager);
|
||||
if (!_playerManager.TryGetSessionByEntity(args.User, out var session))
|
||||
return;
|
||||
|
||||
_euiManager.OpenEui(ui, session);
|
||||
ui.UpdateMoods(moods, args.Target);
|
||||
},
|
||||
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Actions/actions_borg.rsi"), "state-laws"),
|
||||
});
|
||||
}
|
||||
// End DeltaV Additions
|
||||
AddDVAdminVerbs(args); // DeltaV - Extra admin verbs
|
||||
|
||||
// open camera
|
||||
args.Verbs.Add(new Verb()
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ public sealed class ObjectivesSystem : SharedObjectivesSystem
|
|||
}
|
||||
}
|
||||
|
||||
var successRate = totalObjectives > 0 ? (float) completedObjectives / totalObjectives : 0f;
|
||||
var successRate = totalObjectives > 0 ? (float)completedObjectives / totalObjectives : 0f;
|
||||
// Begin DeltaV Additions - custom objective response.
|
||||
if (TryComp<CustomObjectiveSummaryComponent>(mindId, out var customComp) &&
|
||||
customComp.ObjectiveSummary.Length <= _maxLengthSummaryLength)
|
||||
|
|
@ -352,6 +352,19 @@ public sealed class ObjectivesSystem : SharedObjectivesSystem
|
|||
.Select(p => p.ID)
|
||||
.Order();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the issuer for a given Objective
|
||||
/// </summary>
|
||||
/// <param name="objective">The objective to set the issuer for.</param>
|
||||
/// <param name="issuer">The new issuer of the objective.</param>
|
||||
public void SetIssuer(EntityUid objective, LocId issuer)
|
||||
{
|
||||
if (!TryComp<ObjectiveComponent>(objective, out var comp))
|
||||
return;
|
||||
|
||||
comp.Issuer = issuer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
using Content.Server._DV.Objectives.Eui;
|
||||
using Content.Server._Impstation.Thaven;
|
||||
using Content.Shared._Impstation.Thaven.Components;
|
||||
using Content.Server.Objectives;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Administration.Systems;
|
||||
|
||||
public sealed partial class AdminVerbSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ThavenMoodsSystem _moods = default!;
|
||||
private void AddDVAdminVerbs(GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (TryComp<ThavenMoodsComponent>(args.Target, out var moods))
|
||||
{
|
||||
args.Verbs.Add(new Verb()
|
||||
{
|
||||
Text = Loc.GetString("thaven-moods-ui-verb"),
|
||||
Category = VerbCategory.Admin,
|
||||
Act = () =>
|
||||
{
|
||||
var ui = new ThavenMoodsEui(_moods, EntityManager, _adminManager);
|
||||
if (!_playerManager.TryGetSessionByEntity(args.User, out var session))
|
||||
return;
|
||||
|
||||
_euiManager.OpenEui(ui, session);
|
||||
ui.UpdateMoods(moods, args.Target);
|
||||
},
|
||||
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Actions/actions_borg.rsi"), "state-laws"),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (_mindSystem.TryGetMind(args.Target, out var mindId, out var mindComp) &&
|
||||
mindComp.UserId != null)
|
||||
{
|
||||
args.Verbs.Add(new Verb()
|
||||
{
|
||||
Text = Loc.GetString("Edit Objectives"),
|
||||
Category = VerbCategory.Admin,
|
||||
Act = () =>
|
||||
{
|
||||
if (!_playerManager.TryGetSessionByEntity(args.User, out var session))
|
||||
return;
|
||||
|
||||
var ui = new ObjectiveEditorEui();
|
||||
_euiManager.OpenEui(ui, session);
|
||||
ui.UpdateObjectivesFor((mindId, mindComp));
|
||||
},
|
||||
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Actions/actions_borg.rsi"), "state-laws"),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
using Content.Server.Administration.Managers;
|
||||
|
||||
using Content.Server.EUI;
|
||||
using Content.Server.Mind;
|
||||
using Content.Server.Objectives;
|
||||
using Content.Shared.Objectives;
|
||||
using Content.Shared._DV.Objectives.Eui;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Eui;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Objectives.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
using System.Linq;
|
||||
using Content.Server.Popups;
|
||||
|
||||
namespace Content.Server._DV.Objectives.Eui;
|
||||
|
||||
public sealed class ObjectiveEditorEui : BaseEui
|
||||
{
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IAdminManager _adminManager = default!;
|
||||
|
||||
private readonly ObjectivesSystem _objectiveSystem = default!;
|
||||
private readonly MindSystem _mind = default!;
|
||||
private readonly MetaDataSystem _metadata = default!;
|
||||
private readonly PopupSystem _popup = default!;
|
||||
|
||||
private readonly ISawmill _sawmill = Logger.GetSawmill("objective-editor-eui"); // TODO(Barry): Actually need this or?
|
||||
|
||||
private readonly Dictionary<EntityUid, ObjectiveData> _objectives = [];
|
||||
private readonly EntProtoId _fallbackObjective = "EditorDefaultObjective";
|
||||
private readonly ObjectiveInfo _fallbackData = new ObjectiveInfo(
|
||||
"Title",
|
||||
"Description",
|
||||
new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Nano/cross.svg.png")),
|
||||
0f
|
||||
);
|
||||
|
||||
private Entity<MindComponent> _targetMind;
|
||||
|
||||
/// <summary>
|
||||
/// A list of temporary objective entities that have not yet been
|
||||
/// added to the target's mind.
|
||||
/// </summary>
|
||||
private List<EntityUid> _temporaryIds = [];
|
||||
|
||||
public ObjectiveEditorEui()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_objectiveSystem = _entityManager.System<ObjectivesSystem>();
|
||||
_mind = _entityManager.System<MindSystem>();
|
||||
_metadata = _entityManager.System<MetaDataSystem>();
|
||||
_popup = _entityManager.System<PopupSystem>();
|
||||
}
|
||||
|
||||
public override EuiStateBase GetNewState()
|
||||
{
|
||||
return new ObjectiveEditorEUIState(
|
||||
[.. _objectives.Values],
|
||||
_entityManager.GetNetEntity(_targetMind.Owner),
|
||||
_targetMind.Comp.Subtype);
|
||||
}
|
||||
|
||||
public override void Closed()
|
||||
{
|
||||
base.Closed();
|
||||
|
||||
ClearTempObjectives();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Grabs objectives for the specified mind and sets the UI state to reflect it.
|
||||
/// </summary>
|
||||
/// <param name="mind">The target mind to grab objectives for.</param>
|
||||
public void UpdateObjectivesFor(Entity<MindComponent> mind)
|
||||
{
|
||||
if (!IsAllowed())
|
||||
return;
|
||||
|
||||
_targetMind = mind;
|
||||
foreach (var objective in mind.Comp.Objectives)
|
||||
{
|
||||
_objectives.Add(objective, CreateObjectiveData(objective, mind));
|
||||
}
|
||||
|
||||
ClearTempObjectives();
|
||||
StateDirty();
|
||||
}
|
||||
|
||||
public override void HandleMessage(EuiMessageBase msg)
|
||||
{
|
||||
base.HandleMessage(msg);
|
||||
|
||||
if (!IsAllowed())
|
||||
return;
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
case ObjectiveEditorSaveMessage message:
|
||||
HandleSaveMessage(message);
|
||||
break;
|
||||
case ObjectiveEditorCreateMessage message:
|
||||
HandleCreateMessage(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle when a user on the client side wishes to save their current objective changes.
|
||||
/// </summary>
|
||||
/// <param name="message">The save message, which includes the new objectives.</param>
|
||||
private void HandleSaveMessage(ObjectiveEditorSaveMessage message)
|
||||
{
|
||||
var oldObjectives = _objectives.ShallowClone();
|
||||
_objectives.Clear(); // Clean up the previous set we knew about
|
||||
|
||||
foreach (var incomingObjective in message.Objectives)
|
||||
{
|
||||
var objEnt = _entityManager.GetEntity(incomingObjective.Entity);
|
||||
|
||||
EntityUid objective;
|
||||
if (oldObjectives.ContainsKey(objEnt))
|
||||
{
|
||||
// We can just update this entity, no need to add it to the mind either
|
||||
objective = objEnt;
|
||||
oldObjectives.Remove(objEnt); // Ensure it's not cleaned up
|
||||
}
|
||||
else if (_temporaryIds.Contains(objEnt))
|
||||
{
|
||||
objective = objEnt;
|
||||
_temporaryIds.Remove(objEnt); // Ensure it's not cleaned up
|
||||
_mind.AddObjective(_targetMind.Owner, _targetMind.Comp, objective);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Gotta make a new entity for it
|
||||
var newObjective = CreateObjective(incomingObjective.Proto);
|
||||
if (!newObjective.HasValue)
|
||||
continue; // TODO(Barry) Log an error
|
||||
objective = newObjective.Value;
|
||||
|
||||
// Ensure we add the new objective we've just created
|
||||
_mind.AddObjective(_targetMind.Owner, _targetMind.Comp, objective);
|
||||
}
|
||||
|
||||
var metadata = _entityManager.GetComponent<MetaDataComponent>(objective);
|
||||
|
||||
// Setup new Title/Description
|
||||
_metadata.SetEntityName(objective, incomingObjective.Info.Title, metadata: metadata);
|
||||
_metadata.SetEntityDescription(objective, incomingObjective.Info.Description, metadata: metadata);
|
||||
|
||||
// Now the issuer and Icon
|
||||
_objectiveSystem.SetIssuer(objective, incomingObjective.Issuer);
|
||||
_objectiveSystem.SetIcon(objective, incomingObjective.Info.Icon);
|
||||
|
||||
_objectives.Add(objective, CreateObjectiveData(objective, _targetMind));
|
||||
}
|
||||
|
||||
foreach (var old in oldObjectives.Keys)
|
||||
{
|
||||
_mind.TryRemoveObjective(_targetMind, _targetMind.Comp, old);
|
||||
}
|
||||
|
||||
ClearTempObjectives(); // Ensure all temporary objectives are cleared and deleted
|
||||
StateDirty(); // Ensure client is freshly updated with all the new Objective information
|
||||
|
||||
if (!message.Silent && _targetMind.Comp.CurrentEntity is EntityUid uid)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("objective-editor-admin-ui-notification"), uid, uid);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles when a user on the client side wants to create a whole new objective.
|
||||
/// The new objective entity will be stored temporarily until either the window closes,
|
||||
/// or the user performs a save.
|
||||
/// </summary>
|
||||
/// <param name="message">The create message, which may include a ProtoId to use.</param>
|
||||
private void HandleCreateMessage(ObjectiveEditorCreateMessage message)
|
||||
{
|
||||
var newObjective = CreateObjective(message.Proto);
|
||||
if (!newObjective.HasValue)
|
||||
return;
|
||||
|
||||
// N.b. The objective is not yet added to the mind.
|
||||
var data = CreateObjectiveData(newObjective.Value, _targetMind);
|
||||
_temporaryIds.Add(newObjective.Value);
|
||||
SendMessage(new ObjectiveEditorCreateResponse(data));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an ObjectiveData structure for the specified objective entity.
|
||||
/// </summary>
|
||||
/// <param name="objective">The objective entity.</param>
|
||||
/// <param name="mind">The mind the objective is bound to.</param>
|
||||
/// <param name="data">The output ObjectiveData structure.</param>
|
||||
private ObjectiveData CreateObjectiveData(
|
||||
EntityUid objective,
|
||||
Entity<MindComponent> mind)
|
||||
{
|
||||
var info = _objectiveSystem.GetInfo(objective, mind, mind.Comp);
|
||||
if (!info.HasValue)
|
||||
info = _fallbackData;
|
||||
|
||||
var metadata = _entityManager.GetComponent<MetaDataComponent>(objective);
|
||||
var issuer = _entityManager.GetComponent<ObjectiveComponent>(objective).LocIssuer;
|
||||
|
||||
return new ObjectiveData(
|
||||
_entityManager.GetNetEntity(objective),
|
||||
issuer,
|
||||
metadata.EntityPrototype?.ID,
|
||||
info.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all temporary objectives and queues them for deletion.
|
||||
/// </summary>
|
||||
private void ClearTempObjectives()
|
||||
{
|
||||
foreach (var ent in _temporaryIds)
|
||||
{
|
||||
_entityManager.QueueDeleteEntity(ent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new entity matching the specified Entity Prototype or a fallback, if that fails.
|
||||
/// </summary>
|
||||
/// <param name="prototype">The prototype to use, may be null.</param>
|
||||
/// <returns>The EntityUid of the new objective if successful, otherwise null.</returns>
|
||||
private EntityUid? CreateObjective(EntProtoId? prototype)
|
||||
{
|
||||
EntityUid? objective = null;
|
||||
if (prototype.HasValue)
|
||||
objective = _objectiveSystem.TryCreateObjective(_targetMind, _targetMind.Comp, prototype.Value);
|
||||
|
||||
if (!objective.HasValue)
|
||||
objective = _objectiveSystem.TryCreateObjective(_targetMind, _targetMind.Comp, _fallbackObjective);
|
||||
|
||||
return objective;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the current user is allowed to edit the objectives of any mind.
|
||||
/// </summary>
|
||||
/// <returns>True if allowed, otherwise False.</returns>
|
||||
private bool IsAllowed()
|
||||
{
|
||||
var adminData = _adminManager.GetAdminData(Player);
|
||||
if (adminData == null || !adminData.HasFlag(AdminFlags.Moderator))
|
||||
{
|
||||
_sawmill.Warning($"Player {Player.UserId} tried to open / use player objective editor UI without permission.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -366,6 +366,7 @@ public abstract partial class SharedMindSystem : EntitySystem
|
|||
mind.Objectives.Add(objective);
|
||||
}
|
||||
|
||||
// Begin DeltaV Additions - Additional RemoveObjective functions
|
||||
/// <summary>
|
||||
/// Removes an objective from this mind.
|
||||
/// </summary>
|
||||
|
|
@ -375,7 +376,16 @@ public abstract partial class SharedMindSystem : EntitySystem
|
|||
if (index < 0 || index >= mind.Objectives.Count)
|
||||
return false;
|
||||
|
||||
var objective = mind.Objectives[index];
|
||||
return TryRemoveObjective(mindId, mind, mind.Objectives[index]);
|
||||
}
|
||||
|
||||
/// Removes an objective from this mind.
|
||||
/// </summary>
|
||||
/// <returns>Returns true if the removal succeeded.</returns>
|
||||
public bool TryRemoveObjective(EntityUid mindId, MindComponent mind, EntityUid objective)
|
||||
{
|
||||
if (!mind.Objectives.Contains(objective))
|
||||
return false;
|
||||
|
||||
var title = Name(objective);
|
||||
_adminLogger.Add(LogType.Mind, LogImpact.Low, $"Objective {objective} ({title}) removed from the mind of {MindOwnerLoggingString(mind)}");
|
||||
|
|
@ -393,6 +403,7 @@ public abstract partial class SharedMindSystem : EntitySystem
|
|||
Del(objective);
|
||||
return true;
|
||||
}
|
||||
// End DeltaV Additions
|
||||
|
||||
public bool TryGetObjectiveComp<T>(EntityUid uid, [NotNullWhen(true)] out T? objective) where T : IComponent
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ public sealed partial class ObjectiveComponent : Component
|
|||
/// Organisation that issued this objective, used for grouping and as a header above common objectives.
|
||||
/// </summary>
|
||||
[DataField("issuer", required: true)]
|
||||
private LocId Issuer { get; set; }
|
||||
public LocId Issuer { get; set; } // DeltaV - Made public
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public string LocIssuer => Loc.GetString(Issuer);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
using Content.Shared.Objectives;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._DV.Objectives.Eui;
|
||||
|
||||
/// <summary>
|
||||
/// Bundle of data for objectives to display for editing.
|
||||
/// </summary>
|
||||
/// <param name="entity">The original objective entity.</param>
|
||||
/// <param name="issuer">The issuer for the objective.</param>
|
||||
/// <param name="proto">An optional prototype used to spawn the entity.</param>
|
||||
/// <param name="info">All other ObjectiveInfo for the entity.</param>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ObjectiveData(NetEntity entity, string issuer, EntProtoId? proto, ObjectiveInfo info)
|
||||
{
|
||||
public NetEntity Entity = entity;
|
||||
public string Issuer = issuer;
|
||||
public EntProtoId? Proto = proto;
|
||||
public ObjectiveInfo Info = info;
|
||||
|
||||
/// <summary>
|
||||
/// Provides a clone of the data.
|
||||
/// </summary>
|
||||
/// <returns>A full copy of the original data.</returns>
|
||||
public ObjectiveData Clone()
|
||||
{
|
||||
return (ObjectiveData)MemberwiseClone();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies data from another ObjectiveData.
|
||||
/// </summary>
|
||||
/// <param name="other">The other data to copy from.</param>
|
||||
public void CopyFrom(ObjectiveData other)
|
||||
{
|
||||
Entity = other.Entity;
|
||||
Issuer = other.Issuer;
|
||||
Proto = other.Proto;
|
||||
Info = other.Info;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
using Content.Shared.Eui;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._DV.Objectives.Eui;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ObjectiveEditorEUIState(
|
||||
List<ObjectiveData> objectives,
|
||||
NetEntity targetMind,
|
||||
LocId? subtype) : EuiStateBase
|
||||
{
|
||||
public List<ObjectiveData> Objectives { get; } = objectives;
|
||||
public NetEntity TargetMind { get; } = targetMind;
|
||||
|
||||
public LocId? Subtype = subtype;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ObjectiveEditorSaveMessage(
|
||||
List<ObjectiveData> objectives, NetEntity target, bool silent) : EuiMessageBase
|
||||
{
|
||||
public List<ObjectiveData> Objectives = objectives;
|
||||
public NetEntity Target = target;
|
||||
public bool Silent = silent;
|
||||
}
|
||||
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ObjectiveEditorCreateMessage(EntProtoId? proto = null) : EuiMessageBase
|
||||
{
|
||||
public EntProtoId? Proto = proto;
|
||||
}
|
||||
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ObjectiveEditorCreateResponse(ObjectiveData? data) : EuiMessageBase
|
||||
{
|
||||
public ObjectiveData? Data = data;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
objective-editor-admin-ui-title = Objectives Editor
|
||||
objective-editor-admin-ui-title-filled = Objectives Editor - {$name} | {$role}
|
||||
objective-editor-admin-ui-unknown-mind = Unknown
|
||||
objective-editor-admin-ui-new-objective = New
|
||||
objective-editor-admin-ui-save = Save
|
||||
|
||||
objective-editor-admin-ui-delete = Delete
|
||||
objective-editor-admin-ui-delete-all = Delete All
|
||||
|
||||
objective-editor-admin-ui-view = View
|
||||
|
||||
objective-editor-admin-ui-reset = Reset
|
||||
objective-editor-admin-ui-reset-all = Reset All
|
||||
|
||||
objective-editor-admin-ui-placeholder-issuer = New Issuer
|
||||
objective-editor-admin-ui-placeholder-title = New Title
|
||||
objective-editor-admin-ui-placeholder-description = New Description
|
||||
|
||||
objective-editor-admin-ui-check-note = The editor does NOT update the checks for an objective
|
||||
|
||||
objective-editor-admin-ui-silent-save = Silent Save
|
||||
objective-editor-admin-ui-silent-save-tooltip = Whether to show a popup to the user when their objectives change
|
||||
|
||||
objective-editor-admin-ui-notification = You feel new ideas enter your mind...
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
sprite-selector-ui-window-title = Sprite Selector
|
||||
sprite-selector-ui-ok = Ok
|
||||
sprite-selector-ui-cancel = Cancel
|
||||
|
||||
sprite-selector-ui-rsi-tab = RSI
|
||||
sprite-selector-ui-rsi-placeholder = /Textures/Tips/tippy.rsi
|
||||
sprite-selector-ui-rsi-not-found = Unable to find the specified RSI
|
||||
|
||||
sprite-selector-ui-texture-tab = Texture
|
||||
sprite-selector-ui-texture-placeholder = /Textures/Tips/tippy.rsi/down.png
|
||||
sprite-selector-ui-texture-not-found = Unable to find the specified texture
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
- type: entity
|
||||
parent: BaseObjective
|
||||
id: EditorDefaultObjective
|
||||
name: Default Title
|
||||
description: Default Description
|
||||
components:
|
||||
- type: Objective
|
||||
issuer: Default Issuer
|
||||
difficulty: 0
|
||||
icon: Interface/Nano/cross.svg.png
|
||||
- type: FreeObjective
|
||||
Loading…
Reference in New Issue