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