diff --git a/Content.Client/Guidebook/Components/GuideHelpComponent.cs b/Content.Client/Guidebook/Components/GuideHelpComponent.cs index db19bb9dcc..bb1d30bbc1 100644 --- a/Content.Client/Guidebook/Components/GuideHelpComponent.cs +++ b/Content.Client/Guidebook/Components/GuideHelpComponent.cs @@ -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. /// - [DataField("guides", customTypeSerializer: typeof(PrototypeIdListSerializer), required: true)] - [ViewVariables] - public List Guides = new(); + [DataField(required: true)] + public List> Guides = new(); /// /// Whether or not to automatically include the children of the given guides. diff --git a/Content.Client/Guidebook/Controls/GuidebookWindow.xaml.cs b/Content.Client/Guidebook/Controls/GuidebookWindow.xaml.cs index 4776386c1d..3a67dca89d 100644 --- a/Content.Client/Guidebook/Controls/GuidebookWindow.xaml.cs +++ b/Content.Client/Guidebook/Controls/GuidebookWindow.xaml.cs @@ -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 _entries = new(); + private Dictionary, GuideEntry> _entries = new(); public GuidebookWindow() { @@ -69,10 +68,10 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler } public void UpdateGuides( - Dictionary entries, - List? rootEntries = null, - string? forceRoot = null, - string? selected = null) + Dictionary, GuideEntry> entries, + List>? rootEntries = null, + ProtoId? forceRoot = null, + ProtoId? selected = null) { _entries = entries; RepopulateTree(rootEntries, forceRoot); @@ -98,11 +97,11 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler } } - private IEnumerable GetSortedEntries(List? rootEntries) + private IEnumerable GetSortedEntries(List>? rootEntries) { if (rootEntries == null) { - HashSet entries = new(_entries.Keys); + HashSet> 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(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? roots = null, string? forcedRoot = null) + private void RepopulateTree(List>? roots = null, ProtoId? forcedRoot = null) { Tree.Clear(); - HashSet addedEntries = new(); + HashSet> 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 addedEntries) + private TreeItem? AddEntry(ProtoId id, TreeItem? parent, HashSet> 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; } diff --git a/Content.Client/Guidebook/DocumentParsingManager.cs b/Content.Client/Guidebook/DocumentParsingManager.cs index 9c9e569eb4..e8a0743b9e 100644 --- a/Content.Client/Guidebook/DocumentParsingManager.cs +++ b/Content.Client/Guidebook/DocumentParsingManager.cs @@ -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; diff --git a/Content.Client/Guidebook/GuidebookSystem.cs b/Content.Client/Guidebook/GuidebookSystem.cs index 86dcf76942..675a025d7a 100644 --- a/Content.Client/Guidebook/GuidebookSystem.cs +++ b/Content.Client/Guidebook/GuidebookSystem.cs @@ -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?, bool, string?>? OnGuidebookOpen; + public event Action>, + List>?, + ProtoId?, + bool, + ProtoId?>? OnGuidebookOpen; + public const string GuideEmbedTag = "GuideEmbeded"; private EntityUid _defaultUser; @@ -80,7 +87,7 @@ public sealed class GuidebookSystem : EntitySystem }); } - public void OpenHelp(List guides) + public void OpenHelp(List> guides) { OnGuidebookOpen?.Invoke(guides, null, null, true, guides[0]); } diff --git a/Content.Client/Info/RulesControl.xaml.cs b/Content.Client/Info/RulesControl.xaml.cs index 5e25907496..22a520d539 100644 --- a/Content.Client/Info/RulesControl.xaml.cs +++ b/Content.Client/Info/RulesControl.xaml.cs @@ -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; diff --git a/Content.Client/Lobby/LobbyUIController.cs b/Content.Client/Lobby/LobbyUIController.cs index 05b98606ab..aa66b7731d 100644 --- a/Content.Client/Lobby/LobbyUIController.cs +++ b/Content.Client/Lobby/LobbyUIController.cs @@ -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 diff --git a/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs index ac43fa11a8..1681cd93bd 100644 --- a/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs @@ -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] private const string DefaultSpeciesGuidebook = "Species"; + public event Action>>? 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(); var species = Profile?.Species ?? SharedHumanoidAppearanceSystem.DefaultSpecies; var page = DefaultSpeciesGuidebook; @@ -761,10 +767,10 @@ namespace Content.Client.Lobby.UI if (_prototypeManager.TryIndex(DefaultSpeciesGuidebook, out var guideRoot)) { - var dict = new Dictionary(); + var dict = new Dictionary, 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)) { diff --git a/Content.Client/Lobby/UI/Roles/RequirementsSelector.xaml b/Content.Client/Lobby/UI/Roles/RequirementsSelector.xaml index 88bf49b123..4cab5286c2 100644 --- a/Content.Client/Lobby/UI/Roles/RequirementsSelector.xaml +++ b/Content.Client/Lobby/UI/Roles/RequirementsSelector.xaml @@ -1,9 +1,14 @@ -