Give jobs & antags prototypes a guide field (#28614)
* Give jobs & antags prototypes a guide field * A * space Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> * Add todo * Fix merge errors --------- Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
using Content.Shared.Guidebook;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Guidebook.Components;
|
||||
|
||||
@@ -13,9 +14,8 @@ public sealed partial class GuideHelpComponent : Component
|
||||
/// What guides to include show when opening the guidebook. The first entry will be used to select the currently
|
||||
/// selected guidebook.
|
||||
/// </summary>
|
||||
[DataField("guides", customTypeSerializer: typeof(PrototypeIdListSerializer<GuideEntryPrototype>), required: true)]
|
||||
[ViewVariables]
|
||||
public List<string> Guides = new();
|
||||
[DataField(required: true)]
|
||||
public List<ProtoId<GuideEntryPrototype>> Guides = new();
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to automatically include the children of the given guides.
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Client.Guidebook.RichText;
|
||||
using Content.Client.UserInterface.ControlExtensions;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Client.UserInterface.Controls.FancyTree;
|
||||
using JetBrains.Annotations;
|
||||
using Content.Shared.Guidebook;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Guidebook.Controls;
|
||||
|
||||
@@ -19,7 +18,7 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
|
||||
[Dependency] private readonly IResourceManager _resourceManager = default!;
|
||||
[Dependency] private readonly DocumentParsingManager _parsingMan = default!;
|
||||
|
||||
private Dictionary<string, GuideEntry> _entries = new();
|
||||
private Dictionary<ProtoId<GuideEntryPrototype>, GuideEntry> _entries = new();
|
||||
|
||||
public GuidebookWindow()
|
||||
{
|
||||
@@ -69,10 +68,10 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
|
||||
}
|
||||
|
||||
public void UpdateGuides(
|
||||
Dictionary<string, GuideEntry> entries,
|
||||
List<string>? rootEntries = null,
|
||||
string? forceRoot = null,
|
||||
string? selected = null)
|
||||
Dictionary<ProtoId<GuideEntryPrototype>, GuideEntry> entries,
|
||||
List<ProtoId<GuideEntryPrototype>>? rootEntries = null,
|
||||
ProtoId<GuideEntryPrototype>? forceRoot = null,
|
||||
ProtoId<GuideEntryPrototype>? selected = null)
|
||||
{
|
||||
_entries = entries;
|
||||
RepopulateTree(rootEntries, forceRoot);
|
||||
@@ -98,11 +97,11 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<GuideEntry> GetSortedEntries(List<string>? rootEntries)
|
||||
private IEnumerable<GuideEntry> GetSortedEntries(List<ProtoId<GuideEntryPrototype>>? rootEntries)
|
||||
{
|
||||
if (rootEntries == null)
|
||||
{
|
||||
HashSet<string> entries = new(_entries.Keys);
|
||||
HashSet<ProtoId<GuideEntryPrototype>> entries = new(_entries.Keys);
|
||||
foreach (var entry in _entries.Values)
|
||||
{
|
||||
if (entry.Children.Count > 0)
|
||||
@@ -111,7 +110,7 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
|
||||
.Select(childId => _entries[childId])
|
||||
.OrderBy(childEntry => childEntry.Priority)
|
||||
.ThenBy(childEntry => Loc.GetString(childEntry.Name))
|
||||
.Select(childEntry => childEntry.Id)
|
||||
.Select(childEntry => new ProtoId<GuideEntryPrototype>(childEntry.Id))
|
||||
.ToList();
|
||||
|
||||
entry.Children = sortedChildren;
|
||||
@@ -127,13 +126,13 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
|
||||
.ThenBy(rootEntry => Loc.GetString(rootEntry.Name));
|
||||
}
|
||||
|
||||
private void RepopulateTree(List<string>? roots = null, string? forcedRoot = null)
|
||||
private void RepopulateTree(List<ProtoId<GuideEntryPrototype>>? roots = null, ProtoId<GuideEntryPrototype>? forcedRoot = null)
|
||||
{
|
||||
Tree.Clear();
|
||||
|
||||
HashSet<string> addedEntries = new();
|
||||
HashSet<ProtoId<GuideEntryPrototype>> addedEntries = new();
|
||||
|
||||
TreeItem? parent = forcedRoot == null ? null : AddEntry(forcedRoot, null, addedEntries);
|
||||
TreeItem? parent = forcedRoot == null ? null : AddEntry(forcedRoot.Value, null, addedEntries);
|
||||
foreach (var entry in GetSortedEntries(roots))
|
||||
{
|
||||
AddEntry(entry.Id, parent, addedEntries);
|
||||
@@ -141,13 +140,15 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
|
||||
Tree.SetAllExpanded(true);
|
||||
}
|
||||
|
||||
private TreeItem? AddEntry(string id, TreeItem? parent, HashSet<string> addedEntries)
|
||||
private TreeItem? AddEntry(ProtoId<GuideEntryPrototype> id, TreeItem? parent, HashSet<ProtoId<GuideEntryPrototype>> addedEntries)
|
||||
{
|
||||
if (!_entries.TryGetValue(id, out var entry))
|
||||
return null;
|
||||
|
||||
if (!addedEntries.Add(id))
|
||||
{
|
||||
// TODO GUIDEBOOK Maybe allow duplicate entries?
|
||||
// E.g., for adding medicine under both chemicals & the chemist job
|
||||
Logger.Error($"Adding duplicate guide entry: {id}");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using Content.Client.Guidebook.Richtext;
|
||||
using Content.Shared.Guidebook;
|
||||
using Pidgin;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.ContentPack;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Linq;
|
||||
using Content.Client.Guidebook.Components;
|
||||
using Content.Client.Light;
|
||||
using Content.Client.Verbs;
|
||||
using Content.Shared.Guidebook;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Light.Components;
|
||||
using Content.Shared.Speech;
|
||||
@@ -13,6 +14,7 @@ using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -31,7 +33,12 @@ public sealed class GuidebookSystem : EntitySystem
|
||||
[Dependency] private readonly SharedPointLightSystem _pointLightSystem = default!;
|
||||
[Dependency] private readonly TagSystem _tags = default!;
|
||||
|
||||
public event Action<List<string>, List<string>?, string?, bool, string?>? OnGuidebookOpen;
|
||||
public event Action<List<ProtoId<GuideEntryPrototype>>,
|
||||
List<ProtoId<GuideEntryPrototype>>?,
|
||||
ProtoId<GuideEntryPrototype>?,
|
||||
bool,
|
||||
ProtoId<GuideEntryPrototype>?>? OnGuidebookOpen;
|
||||
|
||||
public const string GuideEmbedTag = "GuideEmbeded";
|
||||
|
||||
private EntityUid _defaultUser;
|
||||
@@ -80,7 +87,7 @@ public sealed class GuidebookSystem : EntitySystem
|
||||
});
|
||||
}
|
||||
|
||||
public void OpenHelp(List<string> guides)
|
||||
public void OpenHelp(List<ProtoId<GuideEntryPrototype>> guides)
|
||||
{
|
||||
OnGuidebookOpen?.Invoke(guides, null, null, true, guides[0]);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Client.Guidebook;
|
||||
using Content.Client.Guidebook.RichText;
|
||||
using Content.Client.UserInterface.Systems.Info;
|
||||
using Content.Shared.Guidebook;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using Content.Client.Guidebook;
|
||||
using Content.Client.Humanoid;
|
||||
using Content.Client.Inventory;
|
||||
using Content.Client.Lobby.UI;
|
||||
@@ -41,6 +42,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
||||
[UISystemDependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
|
||||
[UISystemDependency] private readonly ClientInventorySystem _inventory = default!;
|
||||
[UISystemDependency] private readonly StationSpawningSystem _spawn = default!;
|
||||
[UISystemDependency] private readonly GuidebookSystem _guide = default!;
|
||||
|
||||
private CharacterSetupGui? _characterSetup;
|
||||
private HumanoidProfileEditor? _profileEditor;
|
||||
@@ -232,6 +234,8 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
||||
_requirements,
|
||||
_markings);
|
||||
|
||||
_profileEditor.OnOpenGuidebook += _guide.OpenHelp;
|
||||
|
||||
_characterSetup = new CharacterSetupGui(EntityManager, _prototypeManager, _resourceCache, _preferencesManager, _profileEditor);
|
||||
|
||||
_characterSetup.CloseButton.OnPressed += _ =>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Client.Guidebook;
|
||||
using Content.Client.Humanoid;
|
||||
using Content.Client.Lobby.UI.Loadouts;
|
||||
using Content.Client.Lobby.UI.Roles;
|
||||
@@ -12,13 +11,13 @@ using Content.Client.UserInterface.Systems.Guidebook;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Clothing;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Guidebook;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Preferences.Loadouts;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.StatusIcon;
|
||||
using Content.Shared.Traits;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
@@ -96,6 +95,8 @@ namespace Content.Client.Lobby.UI
|
||||
[ValidatePrototypeId<GuideEntryPrototype>]
|
||||
private const string DefaultSpeciesGuidebook = "Species";
|
||||
|
||||
public event Action<List<ProtoId<GuideEntryPrototype>>>? OnOpenGuidebook;
|
||||
|
||||
private ISawmill _sawmill;
|
||||
|
||||
public HumanoidProfileEditor(
|
||||
@@ -615,10 +616,11 @@ namespace Content.Client.Lobby.UI
|
||||
{
|
||||
Margin = new Thickness(3f, 3f, 3f, 0f),
|
||||
};
|
||||
selector.OnOpenGuidebook += OnOpenGuidebook;
|
||||
|
||||
var title = Loc.GetString(antag.Name);
|
||||
var description = Loc.GetString(antag.Objective);
|
||||
selector.Setup(items, title, 250, description);
|
||||
selector.Setup(items, title, 250, description, guides: antag.Guides);
|
||||
selector.Select(Profile?.AntagPreferences.Contains(antag.ID) == true ? 0 : 1);
|
||||
|
||||
if (!_requirements.CheckRoleTime(antag.Requirements, out var reason))
|
||||
@@ -753,6 +755,10 @@ namespace Content.Client.Lobby.UI
|
||||
|
||||
private void OnSpeciesInfoButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
// TODO GUIDEBOOK
|
||||
// make the species guide book a field on the species prototype.
|
||||
// I.e., do what jobs/antags do.
|
||||
|
||||
var guidebookController = UserInterfaceManager.GetUIController<GuidebookUIController>();
|
||||
var species = Profile?.Species ?? SharedHumanoidAppearanceSystem.DefaultSpecies;
|
||||
var page = DefaultSpeciesGuidebook;
|
||||
@@ -761,10 +767,10 @@ namespace Content.Client.Lobby.UI
|
||||
|
||||
if (_prototypeManager.TryIndex<GuideEntryPrototype>(DefaultSpeciesGuidebook, out var guideRoot))
|
||||
{
|
||||
var dict = new Dictionary<string, GuideEntry>();
|
||||
var dict = new Dictionary<ProtoId<GuideEntryPrototype>, GuideEntry>();
|
||||
dict.Add(DefaultSpeciesGuidebook, guideRoot);
|
||||
//TODO: Don't close the guidebook if its already open, just go to the correct page
|
||||
guidebookController.ToggleGuidebook(dict, includeChildren:true, selected: page);
|
||||
guidebookController.OpenGuidebook(dict, includeChildren:true, selected: page);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -859,6 +865,7 @@ namespace Content.Client.Lobby.UI
|
||||
{
|
||||
Margin = new Thickness(3f, 3f, 3f, 0f),
|
||||
};
|
||||
selector.OnOpenGuidebook += OnOpenGuidebook;
|
||||
|
||||
var icon = new TextureRect
|
||||
{
|
||||
@@ -867,7 +874,7 @@ namespace Content.Client.Lobby.UI
|
||||
};
|
||||
var jobIcon = _prototypeManager.Index(job.Icon);
|
||||
icon.Texture = jobIcon.Icon.Frame0();
|
||||
selector.Setup(items, job.LocalizedName, 200, job.LocalizedDescription, icon);
|
||||
selector.Setup(items, job.LocalizedName, 200, job.LocalizedDescription, icon, job.Guides);
|
||||
|
||||
if (!_requirements.IsAllowed(job, out var reason))
|
||||
{
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
<Label Name="TitleLabel"
|
||||
Margin="5 0"
|
||||
MouseFilter="Stop"/>
|
||||
|
||||
<!--21 was the height of OptionsContainer at the time that this button was added. So I am limiting the texture to 21x21-->
|
||||
<Control SetSize="21 21">
|
||||
<TextureButton Name="Help" StyleClasses="HelpButton"/>
|
||||
</Control>
|
||||
<BoxContainer Name="OptionsContainer"
|
||||
SetWidth="400"/>
|
||||
</BoxContainer>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Guidebook;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Lobby.UI.Roles;
|
||||
@@ -17,8 +19,10 @@ public sealed partial class RequirementsSelector : BoxContainer
|
||||
{
|
||||
private readonly RadioOptions<int> _options;
|
||||
private readonly StripeBack _lockStripe;
|
||||
private List<ProtoId<GuideEntryPrototype>>? _guides;
|
||||
|
||||
public event Action<int>? OnSelected;
|
||||
public event Action<List<ProtoId<GuideEntryPrototype>>>? OnOpenGuidebook;
|
||||
|
||||
public int Selected => _options.SelectedId;
|
||||
|
||||
@@ -60,18 +64,33 @@ public sealed partial class RequirementsSelector : BoxContainer
|
||||
requirementsLabel
|
||||
}
|
||||
};
|
||||
|
||||
Help.OnPressed += _ =>
|
||||
{
|
||||
if (_guides != null)
|
||||
OnOpenGuidebook?.Invoke(_guides);
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Actually adds the controls.
|
||||
/// </summary>
|
||||
public void Setup((string, int)[] items, string title, int titleSize, string? description, TextureRect? icon = null)
|
||||
public void Setup(
|
||||
(string, int)[] items,
|
||||
string title,
|
||||
int titleSize,
|
||||
string? description,
|
||||
TextureRect? icon = null,
|
||||
List<ProtoId<GuideEntryPrototype>>? guides = null)
|
||||
{
|
||||
foreach (var (text, value) in items)
|
||||
{
|
||||
_options.AddItem(Loc.GetString(text), value);
|
||||
}
|
||||
|
||||
Help.Visible = guides != null;
|
||||
_guides = guides;
|
||||
|
||||
TitleLabel.Text = title;
|
||||
TitleLabel.MinSize = new Vector2(titleSize, 0f);
|
||||
TitleLabel.ToolTip = description;
|
||||
|
||||
@@ -78,6 +78,8 @@ namespace Content.Client.Stylesheets
|
||||
public const string StyleClassLabelSmall = "LabelSmall";
|
||||
public const string StyleClassButtonBig = "ButtonBig";
|
||||
|
||||
public const string StyleClassButtonHelp = "HelpButton";
|
||||
|
||||
public const string StyleClassPopupMessageSmall = "PopupMessageSmall";
|
||||
public const string StyleClassPopupMessageSmallCaution = "PopupMessageSmallCaution";
|
||||
public const string StyleClassPopupMessageMedium = "PopupMessageMedium";
|
||||
@@ -1346,6 +1348,10 @@ namespace Content.Client.Stylesheets
|
||||
new StyleProperty(PanelContainer.StylePropertyPanel, new StyleBoxFlat { BackgroundColor = NanoGold, ContentMarginBottomOverride = 2, ContentMarginLeftOverride = 2}),
|
||||
}),
|
||||
|
||||
Element<TextureButton>()
|
||||
.Class(StyleClassButtonHelp)
|
||||
.Prop(TextureButton.StylePropertyTexture, resCache.GetTexture("/Textures/Interface/VerbIcons/information.svg.192dpi.png")),
|
||||
|
||||
// Labels ---
|
||||
Element<Label>().Class(StyleClassLabelBig)
|
||||
.Prop(Label.StylePropertyFont, notoSans16),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.Guidebook;
|
||||
using Content.Client.Guidebook.Components;
|
||||
using Content.Shared.Guidebook;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
@@ -32,8 +33,8 @@ namespace Content.Client.UserInterface.Controls
|
||||
set => WindowTitle.Text = value;
|
||||
}
|
||||
|
||||
private List<string>? _helpGuidebookIds;
|
||||
public List<string>? HelpGuidebookIds
|
||||
private List<ProtoId<GuideEntryPrototype>>? _helpGuidebookIds;
|
||||
public List<ProtoId<GuideEntryPrototype>>? HelpGuidebookIds
|
||||
{
|
||||
get => _helpGuidebookIds;
|
||||
set
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Client.Guidebook;
|
||||
using Content.Client.Guidebook.Controls;
|
||||
using Content.Client.Lobby;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Guidebook;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
@@ -74,12 +75,12 @@ public sealed class GuidebookUIController : UIController, IOnStateEntered<LobbyS
|
||||
|
||||
public void OnSystemLoaded(GuidebookSystem system)
|
||||
{
|
||||
_guidebookSystem.OnGuidebookOpen += ToggleGuidebook;
|
||||
_guidebookSystem.OnGuidebookOpen += OpenGuidebook;
|
||||
}
|
||||
|
||||
public void OnSystemUnloaded(GuidebookSystem system)
|
||||
{
|
||||
_guidebookSystem.OnGuidebookOpen -= ToggleGuidebook;
|
||||
_guidebookSystem.OnGuidebookOpen -= OpenGuidebook;
|
||||
}
|
||||
|
||||
internal void UnloadButton()
|
||||
@@ -103,6 +104,22 @@ public sealed class GuidebookUIController : UIController, IOnStateEntered<LobbyS
|
||||
ToggleGuidebook();
|
||||
}
|
||||
|
||||
public void ToggleGuidebook()
|
||||
{
|
||||
if (_guideWindow == null)
|
||||
return;
|
||||
|
||||
if (_guideWindow.IsOpen)
|
||||
{
|
||||
UIManager.ClickSound();
|
||||
_guideWindow.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
OpenGuidebook();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWindowClosed()
|
||||
{
|
||||
if (GuidebookButton != null)
|
||||
@@ -127,30 +144,23 @@ public sealed class GuidebookUIController : UIController, IOnStateEntered<LobbyS
|
||||
/// <param name="includeChildren">Whether or not to automatically include child entries. If false, this will ONLY
|
||||
/// show the specified entries</param>
|
||||
/// <param name="selected">The guide whose contents should be displayed when the guidebook is opened</param>
|
||||
public void ToggleGuidebook(
|
||||
Dictionary<string, GuideEntry>? guides = null,
|
||||
List<string>? rootEntries = null,
|
||||
string? forceRoot = null,
|
||||
public void OpenGuidebook(
|
||||
Dictionary<ProtoId<GuideEntryPrototype>, GuideEntry>? guides = null,
|
||||
List<ProtoId<GuideEntryPrototype>>? rootEntries = null,
|
||||
ProtoId<GuideEntryPrototype>? forceRoot = null,
|
||||
bool includeChildren = true,
|
||||
string? selected = null)
|
||||
ProtoId<GuideEntryPrototype>? selected = null)
|
||||
{
|
||||
if (_guideWindow == null)
|
||||
return;
|
||||
|
||||
if (_guideWindow.IsOpen)
|
||||
{
|
||||
UIManager.ClickSound();
|
||||
_guideWindow.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (GuidebookButton != null)
|
||||
GuidebookButton.SetClickPressed(!_guideWindow.IsOpen);
|
||||
|
||||
if (guides == null)
|
||||
{
|
||||
guides = _prototypeManager.EnumeratePrototypes<GuideEntryPrototype>()
|
||||
.ToDictionary(x => x.ID, x => (GuideEntry) x);
|
||||
.ToDictionary(x => new ProtoId<GuideEntryPrototype>(x.ID), x => (GuideEntry) x);
|
||||
}
|
||||
else if (includeChildren)
|
||||
{
|
||||
@@ -171,17 +181,17 @@ public sealed class GuidebookUIController : UIController, IOnStateEntered<LobbyS
|
||||
_guideWindow.OpenCenteredRight();
|
||||
}
|
||||
|
||||
public void ToggleGuidebook(
|
||||
List<string> guideList,
|
||||
List<string>? rootEntries = null,
|
||||
string? forceRoot = null,
|
||||
public void OpenGuidebook(
|
||||
List<ProtoId<GuideEntryPrototype>> guideList,
|
||||
List<ProtoId<GuideEntryPrototype>>? rootEntries = null,
|
||||
ProtoId<GuideEntryPrototype>? forceRoot = null,
|
||||
bool includeChildren = true,
|
||||
string? selected = null)
|
||||
ProtoId<GuideEntryPrototype>? selected = null)
|
||||
{
|
||||
Dictionary<string, GuideEntry> guides = new();
|
||||
Dictionary<ProtoId<GuideEntryPrototype>, GuideEntry> guides = new();
|
||||
foreach (var guideId in guideList)
|
||||
{
|
||||
if (!_prototypeManager.TryIndex<GuideEntryPrototype>(guideId, out var guide))
|
||||
if (!_prototypeManager.TryIndex(guideId, out var guide))
|
||||
{
|
||||
Logger.Error($"Encountered unknown guide prototype: {guideId}");
|
||||
continue;
|
||||
@@ -189,17 +199,29 @@ public sealed class GuidebookUIController : UIController, IOnStateEntered<LobbyS
|
||||
guides.Add(guideId, guide);
|
||||
}
|
||||
|
||||
ToggleGuidebook(guides, rootEntries, forceRoot, includeChildren, selected);
|
||||
OpenGuidebook(guides, rootEntries, forceRoot, includeChildren, selected);
|
||||
}
|
||||
|
||||
private void RecursivelyAddChildren(GuideEntry guide, Dictionary<string, GuideEntry> guides)
|
||||
public void CloseGuidebook()
|
||||
{
|
||||
if (_guideWindow == null)
|
||||
return;
|
||||
|
||||
if (_guideWindow.IsOpen)
|
||||
{
|
||||
UIManager.ClickSound();
|
||||
_guideWindow.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void RecursivelyAddChildren(GuideEntry guide, Dictionary<ProtoId<GuideEntryPrototype>, GuideEntry> guides)
|
||||
{
|
||||
foreach (var childId in guide.Children)
|
||||
{
|
||||
if (guides.ContainsKey(childId))
|
||||
continue;
|
||||
|
||||
if (!_prototypeManager.TryIndex<GuideEntryPrototype>(childId, out var child))
|
||||
if (!_prototypeManager.TryIndex(childId, out var child))
|
||||
{
|
||||
Logger.Error($"Encountered unknown guide prototype: {childId} as a child of {guide.Id}. If the child is not a prototype, it must be directly provided.");
|
||||
continue;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Globalization;
|
||||
using Content.Client.Gameplay;
|
||||
using Content.Client.Guidebook;
|
||||
using Content.Client.Info;
|
||||
using Content.Shared.Administration.Managers;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Guidebook;
|
||||
using Content.Shared.Info;
|
||||
using Robust.Client;
|
||||
using Robust.Client.Console;
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Client.Guidebook.Richtext;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Prototypes;
|
||||
using System.Linq;
|
||||
using Content.Shared.Guidebook;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Guidebook;
|
||||
|
||||
|
||||
@@ -67,7 +67,6 @@ namespace Content.Server.Entry
|
||||
factory.RegisterIgnore(IgnoredComponents.List);
|
||||
|
||||
prototypes.RegisterIgnore("parallax");
|
||||
prototypes.RegisterIgnore("guideEntry");
|
||||
|
||||
ServerContentIoC.Register();
|
||||
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Guidebook;
|
||||
namespace Content.Shared.Guidebook;
|
||||
|
||||
[Prototype("guideEntry")]
|
||||
public sealed partial class GuideEntryPrototype : GuideEntry, IPrototype
|
||||
{
|
||||
public string ID => Id;
|
||||
}
|
||||
|
||||
[Virtual]
|
||||
public class GuideEntry
|
||||
@@ -10,7 +15,7 @@ public class GuideEntry
|
||||
/// <summary>
|
||||
/// The file containing the contents of this guide.
|
||||
/// </summary>
|
||||
[DataField("text", required: true)] public ResPath Text = default!;
|
||||
[DataField(required: true)] public ResPath Text = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The unique id for this guide.
|
||||
@@ -21,28 +26,22 @@ public class GuideEntry
|
||||
/// <summary>
|
||||
/// The name of this guide. This gets localized.
|
||||
/// </summary>
|
||||
[DataField("name", required: true)] public string Name = default!;
|
||||
[DataField(required: true)] public string Name = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The "children" of this guide for when guides are shown in a tree / table of contents.
|
||||
/// </summary>
|
||||
[DataField("children", customTypeSerializer:typeof(PrototypeIdListSerializer<GuideEntryPrototype>))]
|
||||
public List<string> Children = new();
|
||||
[DataField]
|
||||
public List<ProtoId<GuideEntryPrototype>> Children = new();
|
||||
|
||||
/// <summary>
|
||||
/// Enable filtering of items.
|
||||
/// </summary>
|
||||
[DataField("filterEnabled")] public bool FilterEnabled = default!;
|
||||
[DataField] public bool FilterEnabled = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Priority for sorting top-level guides when shown in a tree / table of contents.
|
||||
/// If the guide is the child of some other guide, the order simply determined by the order of children in <see cref="Children"/>.
|
||||
/// </summary>
|
||||
[DataField("priority")] public int Priority = 0;
|
||||
}
|
||||
|
||||
[Prototype("guideEntry")]
|
||||
public sealed partial class GuideEntryPrototype : GuideEntry, IPrototype
|
||||
{
|
||||
public string ID => Id;
|
||||
[DataField] public int Priority = 0;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared.Guidebook;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
@@ -43,4 +44,11 @@ public sealed partial class AntagPrototype : IPrototype
|
||||
/// </summary>
|
||||
[DataField("requirements")]
|
||||
public HashSet<JobRequirement>? Requirements;
|
||||
|
||||
/// <summary>
|
||||
/// Optional list of guides associated with this antag. If the guides are opened, the first entry in this list
|
||||
/// will be used to select the currently selected guidebook.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<ProtoId<GuideEntryPrototype>>? Guides;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Guidebook;
|
||||
using Content.Shared.Players.PlayTimeTracking;
|
||||
using Content.Shared.StatusIcon;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -117,6 +118,13 @@ namespace Content.Shared.Roles
|
||||
|
||||
[DataField]
|
||||
public bool Whitelisted;
|
||||
|
||||
/// <summary>
|
||||
/// Optional list of guides associated with this role. If the guides are opened, the first entry in this list
|
||||
/// will be used to select the currently selected guidebook.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<ProtoId<GuideEntryPrototype>>? Guides;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
name: guide-entry-chemist
|
||||
text: "/ServerInfo/Guidebook/Medical/Chemist.xml"
|
||||
children:
|
||||
- Medicine
|
||||
# - Medicine
|
||||
# Duplicate guide entries are currently not supported
|
||||
# TODO GUIDEBOOK Maybe allow duplicate entries?
|
||||
- Botanicals
|
||||
- AdvancedBrute
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
antagonist: true
|
||||
setPreference: false
|
||||
objective: roles-antag-space-ninja-objective
|
||||
guides: [ SpaceNinja ]
|
||||
|
||||
#Ninja Gear
|
||||
- type: startingGear
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
requirements:
|
||||
- !type:OverallPlaytimeRequirement
|
||||
time: 18000 # 5h
|
||||
guides: [ NuclearOperatives ]
|
||||
|
||||
- type: antag
|
||||
id: NukeopsMedic
|
||||
@@ -20,6 +21,7 @@
|
||||
- !type:RoleTimeRequirement
|
||||
role: JobChemist
|
||||
time: 10800 # 3h
|
||||
guides: [ NuclearOperatives ]
|
||||
|
||||
- type: antag
|
||||
id: NukeopsCommander
|
||||
@@ -34,6 +36,7 @@
|
||||
department: Security
|
||||
time: 18000 # 5h
|
||||
# should be changed to nukie playtime when thats tracked (wyci)
|
||||
guides: [ NuclearOperatives ]
|
||||
|
||||
#Nuclear Operative Gear
|
||||
- type: startingGear
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
antagonist: true
|
||||
setPreference: true
|
||||
objective: roles-antag-rev-head-objective
|
||||
guides: [ Revolutionaries ]
|
||||
|
||||
- type: antag
|
||||
id: Rev
|
||||
@@ -11,6 +12,7 @@
|
||||
antagonist: true
|
||||
setPreference: false
|
||||
objective: roles-antag-rev-objective
|
||||
guides: [ Revolutionaries ]
|
||||
|
||||
- type: startingGear
|
||||
id: HeadRevGear
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
antagonist: true
|
||||
setPreference: true
|
||||
objective: roles-antag-syndicate-agent-objective
|
||||
guides: [ Traitors ]
|
||||
|
||||
# Syndicate Operative Outfit - Monkey
|
||||
- type: startingGear
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
antagonist: true
|
||||
setPreference: true
|
||||
objective: roles-antag-initial-infected-objective
|
||||
guides: [ Zombies ]
|
||||
|
||||
- type: antag
|
||||
id: Zombie
|
||||
@@ -11,3 +12,4 @@
|
||||
antagonist: true
|
||||
setPreference: false
|
||||
objective: roles-antag-zombie-objective
|
||||
guides: [ Zombies ]
|
||||
|
||||
Reference in New Issue
Block a user