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:
Leon Friedrich
2024-06-07 00:05:58 +12:00
committed by GitHub
parent 236d2e5337
commit e7f2ae52ab
24 changed files with 182 additions and 82 deletions

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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]);
}

View File

@@ -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;

View File

@@ -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 += _ =>

View File

@@ -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))
{

View File

@@ -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>

View File

@@ -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;

View File

@@ -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),

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -67,7 +67,6 @@ namespace Content.Server.Entry
factory.RegisterIgnore(IgnoredComponents.List);
prototypes.RegisterIgnore("parallax");
prototypes.RegisterIgnore("guideEntry");
ServerContentIoC.Register();

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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

View File

@@ -4,6 +4,7 @@
antagonist: true
setPreference: false
objective: roles-antag-space-ninja-objective
guides: [ SpaceNinja ]
#Ninja Gear
- type: startingGear

View File

@@ -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

View File

@@ -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

View File

@@ -4,6 +4,7 @@
antagonist: true
setPreference: true
objective: roles-antag-syndicate-agent-objective
guides: [ Traitors ]
# Syndicate Operative Outfit - Monkey
- type: startingGear

View File

@@ -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 ]