From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Mon, 16 Oct 2023 21:51:58 +0000 (-0400) Subject: technology auto guidebook (#21029) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=fd994511a74bf58bf6f09bda61662b88a4f38f2d;p=space-station-14.git technology auto guidebook (#21029) * technology auto guidebook * boo-womp * boo-womp II --- diff --git a/Content.Client/Guidebook/Controls/GuideTechDisciplineEmbed.xaml b/Content.Client/Guidebook/Controls/GuideTechDisciplineEmbed.xaml new file mode 100644 index 0000000000..0878951af8 --- /dev/null +++ b/Content.Client/Guidebook/Controls/GuideTechDisciplineEmbed.xaml @@ -0,0 +1,4 @@ + + + diff --git a/Content.Client/Guidebook/Controls/GuideTechDisciplineEmbed.xaml.cs b/Content.Client/Guidebook/Controls/GuideTechDisciplineEmbed.xaml.cs new file mode 100644 index 0000000000..88d264cb05 --- /dev/null +++ b/Content.Client/Guidebook/Controls/GuideTechDisciplineEmbed.xaml.cs @@ -0,0 +1,60 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Content.Client.Guidebook.Richtext; +using Content.Shared.Research.Prototypes; +using JetBrains.Annotations; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Prototypes; + +namespace Content.Client.Guidebook.Controls; + +/// +/// Control for embedding all the technologies in a discipline into a guidebook. +/// +[UsedImplicitly, GenerateTypedNameReferences] +public sealed partial class GuideTechDisciplineEmbed : BoxContainer, IDocumentTag +{ + [Dependency] private readonly IPrototypeManager _prototype = default!; + + public GuideTechDisciplineEmbed() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + MouseFilter = MouseFilterMode.Stop; + } + + public GuideTechDisciplineEmbed(string group) : this() + { + var prototypes = _prototype.EnumeratePrototypes() + .Where(p => p.Discipline.Equals(group)).OrderBy(p => p.Tier).ThenBy(p => Loc.GetString(p.Name)); + foreach (var tech in prototypes) + { + var embed = new GuideTechnologyEmbed(tech); + DisciplineContainer.AddChild(embed); + } + } + + public bool TryParseTag(Dictionary args, [NotNullWhen(true)] out Control? control) + { + control = null; + if (!args.TryGetValue("Discipline", out var group)) + { + Logger.Error("Technology discipline embed tag is missing discipline argument"); + return false; + } + + var prototypes = _prototype.EnumeratePrototypes() + .Where(p => p.Discipline.Equals(group)).OrderBy(p => p.Tier).ThenBy(p => Loc.GetString(p.Name)); + foreach (var tech in prototypes) + { + var embed = new GuideTechnologyEmbed(tech); + DisciplineContainer.AddChild(embed); + } + + control = this; + return true; + } +} diff --git a/Content.Client/Guidebook/Controls/GuideTechnologyEmbed.xaml b/Content.Client/Guidebook/Controls/GuideTechnologyEmbed.xaml new file mode 100644 index 0000000000..6d96f19972 --- /dev/null +++ b/Content.Client/Guidebook/Controls/GuideTechnologyEmbed.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/Content.Client/Guidebook/Controls/GuideTechnologyEmbed.xaml.cs b/Content.Client/Guidebook/Controls/GuideTechnologyEmbed.xaml.cs new file mode 100644 index 0000000000..d61cc2d961 --- /dev/null +++ b/Content.Client/Guidebook/Controls/GuideTechnologyEmbed.xaml.cs @@ -0,0 +1,93 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Client.Guidebook.Richtext; +using Content.Client.Message; +using Content.Client.Research; +using Content.Client.UserInterface.ControlExtensions; +using Content.Shared.Research.Prototypes; +using JetBrains.Annotations; +using Robust.Client.AutoGenerated; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Prototypes; + +namespace Content.Client.Guidebook.Controls; + +/// +/// Control for embedding a research technology into a guidebook. +/// +[UsedImplicitly, GenerateTypedNameReferences] +public sealed partial class GuideTechnologyEmbed : BoxContainer, IDocumentTag, ISearchableControl +{ + [Dependency] private readonly IEntitySystemManager _systemManager = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; + + private readonly ResearchSystem _research; + private readonly SpriteSystem _sprite; + + public GuideTechnologyEmbed() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + _research = _systemManager.GetEntitySystem(); + _sprite = _systemManager.GetEntitySystem(); + MouseFilter = MouseFilterMode.Stop; + } + + public GuideTechnologyEmbed(string technology) : this() + { + GenerateControl(_prototype.Index(technology)); + } + + public GuideTechnologyEmbed(TechnologyPrototype technology) : this() + { + GenerateControl(technology); + } + + public bool CheckMatchesSearch(string query) + { + return this.ChildrenContainText(query); + } + + public void SetHiddenState(bool state, string query) + { + Visible = CheckMatchesSearch(query) ? state : !state; + } + + public bool TryParseTag(Dictionary args, [NotNullWhen(true)] out Control? control) + { + control = null; + if (!args.TryGetValue("Technology", out var id)) + { + Logger.Error("Technology embed tag is missing technology prototype argument"); + return false; + } + + if (!_prototype.TryIndex(id, out var technology)) + { + Logger.Error($"Specified technology prototype \"{id}\" is not a valid technology prototype"); + return false; + } + + GenerateControl(technology); + + control = this; + return true; + } + + private void GenerateControl(TechnologyPrototype technology) + { + var discipline = _prototype.Index(technology.Discipline); + + NameLabel.SetMarkup($"[bold]{Loc.GetString(technology.Name)}[/bold]"); + DescriptionLabel.SetMessage(_research.GetTechnologyDescription(technology, includePrereqs: true, disciplinePrototype: discipline)); + TechTexture.Texture = _sprite.Frame0(technology.Icon); + + DisciplineColorBackground.PanelOverride = new StyleBoxFlat + { + BackgroundColor = discipline.Color + }; + } +} diff --git a/Content.Client/Research/UI/MiniTechnologyCardControl.xaml.cs b/Content.Client/Research/UI/MiniTechnologyCardControl.xaml.cs index 8b1a583c24..5af1159c93 100644 --- a/Content.Client/Research/UI/MiniTechnologyCardControl.xaml.cs +++ b/Content.Client/Research/UI/MiniTechnologyCardControl.xaml.cs @@ -2,6 +2,7 @@ using Robust.Client.AutoGenerated; using Robust.Client.GameObjects; using Robust.Client.UserInterface; +using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Prototypes; using Robust.Shared.Utility; @@ -15,10 +16,13 @@ public sealed partial class MiniTechnologyCardControl : Control { RobustXamlLoader.Load(this); - var discipline = prototypeManager.Index(technology.Discipline); + var discipline = prototypeManager.Index(technology.Discipline); Background.ModulateSelfOverride = discipline.Color; Texture.Texture = spriteSys.Frame0(technology.Icon); NameLabel.SetMessage(Loc.GetString(technology.Name)); - Main.ToolTip = description.ToString(); + + var tooltip = new Tooltip(); + tooltip.SetMessage(description); + Main.TooltipSupplier = _ => tooltip; } } diff --git a/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs b/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs index c2b23f7341..a20509202f 100644 --- a/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs +++ b/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs @@ -27,7 +27,7 @@ public sealed partial class ResearchConsoleMenu : FancyWindow private readonly TechnologyDatabaseComponent? _technologyDatabase; private readonly ResearchSystem _research; private readonly SpriteSystem _sprite; - private readonly AccessReaderSystem _accessReader = default!; + private readonly AccessReaderSystem _accessReader; public readonly EntityUid Entity; @@ -55,7 +55,7 @@ public sealed partial class ResearchConsoleMenu : FancyWindow foreach (var tech in allTech) { - var mini = new MiniTechnologyCardControl(tech, _prototype, _sprite, GetTechnologyDescription(tech, false)); + var mini = new MiniTechnologyCardControl(tech, _prototype, _sprite, _research.GetTechnologyDescription(tech)); AvailableCardsContainer.AddChild(mini); } @@ -74,7 +74,7 @@ public sealed partial class ResearchConsoleMenu : FancyWindow foreach (var techId in _technologyDatabase.CurrentTechnologyCards) { var tech = _prototype.Index(techId); - var cardControl = new TechnologyCardControl(tech, _prototype, _sprite, GetTechnologyDescription(tech), state.Points, hasAccess); + var cardControl = new TechnologyCardControl(tech, _prototype, _sprite, _research.GetTechnologyDescription(tech, includeTier: false), state.Points, hasAccess); cardControl.OnPressed += () => OnTechnologyCardPressed?.Invoke(techId); TechnologyCardsContainer.AddChild(cardControl); } @@ -82,37 +82,11 @@ public sealed partial class ResearchConsoleMenu : FancyWindow foreach (var unlocked in _technologyDatabase.UnlockedTechnologies) { var tech = _prototype.Index(unlocked); - var cardControl = new MiniTechnologyCardControl(tech, _prototype, _sprite, GetTechnologyDescription(tech, false)); + var cardControl = new MiniTechnologyCardControl(tech, _prototype, _sprite, _research.GetTechnologyDescription(tech, false)); UnlockedCardsContainer.AddChild(cardControl); } } - public FormattedMessage GetTechnologyDescription(TechnologyPrototype technology, bool includeCost = true) - { - var description = new FormattedMessage(); - if (includeCost) - { - description.AddMarkup(Loc.GetString("research-console-cost", ("amount", technology.Cost))); - description.PushNewline(); - } - description.AddMarkup(Loc.GetString("research-console-unlocks-list-start")); - foreach (var recipe in technology.RecipeUnlocks) - { - var recipeProto = _prototype.Index(recipe); - description.PushNewline(); - description.AddMarkup(Loc.GetString("research-console-unlocks-list-entry", - ("name",recipeProto.Name))); - } - foreach (var generic in technology.GenericUnlocks) - { - description.PushNewline(); - description.AddMarkup(Loc.GetString("research-console-unlocks-list-entry-generic", - ("name", Loc.GetString(generic.UnlockDescription)))); - } - - return description; - } - public void UpdateInformationPanel(ResearchConsoleBoundInterfaceState state) { var amountMsg = new FormattedMessage(); diff --git a/Content.Server/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs b/Content.Server/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs index d886493e3f..176b2b68bc 100644 --- a/Content.Server/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs +++ b/Content.Server/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs @@ -72,7 +72,7 @@ public sealed class TechnologyDiskSystem : EntitySystem var tier = int.Parse(weightedRandom.Pick(_random)); //get a list of every distinct recipe in all the technologies. - var techs = new List(); + var techs = new List>(); foreach (var tech in _prototype.EnumeratePrototypes()) { if (tech.Tier != tier) diff --git a/Content.Shared/Research/Prototypes/TechnologyPrototype.cs b/Content.Shared/Research/Prototypes/TechnologyPrototype.cs index ec1ca029c7..38000677a1 100644 --- a/Content.Shared/Research/Prototypes/TechnologyPrototype.cs +++ b/Content.Shared/Research/Prototypes/TechnologyPrototype.cs @@ -1,6 +1,4 @@ using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; using Robust.Shared.Utility; namespace Content.Shared.Research.Prototypes; @@ -19,57 +17,57 @@ public sealed class TechnologyPrototype : IPrototype /// The name of the technology. /// Supports locale strings /// - [DataField("name", required: true)] - public string Name = string.Empty; + [DataField(required: true)] + public LocId Name = string.Empty; /// /// An icon used to visually represent the technology in UI. /// - [DataField("icon", required: true)] + [DataField(required: true)] public SpriteSpecifier Icon = default!; /// /// What research discipline this technology belongs to. /// - [DataField("discipline", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] - public string Discipline = default!; + [DataField(required: true)] + public ProtoId Discipline; /// /// What tier research is this? /// The tier governs how much lower-tier technology /// needs to be unlocked before this one. /// - [DataField("tier", required: true)] + [DataField(required: true)] public int Tier; /// /// Hidden tech is not ever available at the research console. /// - [DataField("hidden")] + [DataField] public bool Hidden; /// /// How much research is needed to unlock. /// - [DataField("cost")] + [DataField] public int Cost = 10000; /// /// A list of s that need to be unlocked in order to unlock this technology. /// - [DataField("technologyPrerequisites", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public IReadOnlyList TechnologyPrerequisites = new List(); + [DataField] + public List> TechnologyPrerequisites = new(); /// /// A list of s that are unlocked by this technology /// - [DataField("recipeUnlocks", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public IReadOnlyList RecipeUnlocks = new List(); + [DataField] + public List> RecipeUnlocks = new(); /// /// A list of non-standard effects that are done when this technology is unlocked. /// - [DataField("genericUnlocks")] + [DataField] public IReadOnlyList GenericUnlocks = new List(); } @@ -80,13 +78,13 @@ public partial record struct GenericUnlock() /// What event is raised when this is unlocked? /// Used for doing non-standard logic. /// - [DataField("purchaseEvent")] + [DataField] public object? PurchaseEvent = null; /// /// A player facing tooltip for what the unlock does. /// Supports locale strings. /// - [DataField("unlockDescription")] + [DataField] public string UnlockDescription = string.Empty; } diff --git a/Content.Shared/Research/Systems/SharedResearchSystem.cs b/Content.Shared/Research/Systems/SharedResearchSystem.cs index e0cc937b00..12f27d0b9c 100644 --- a/Content.Shared/Research/Systems/SharedResearchSystem.cs +++ b/Content.Shared/Research/Systems/SharedResearchSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Research.Components; using Content.Shared.Research.Prototypes; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using Robust.Shared.Utility; namespace Content.Shared.Research.Systems; @@ -40,7 +41,7 @@ public abstract class SharedResearchSystem : EntitySystem component.CurrentTechnologyCards.Add(selected.ID); } - Dirty(component); + Dirty(uid, component); } public List GetAvailableTechnologies(EntityUid uid, TechnologyDatabaseComponent? component = null) @@ -142,6 +143,59 @@ public abstract class SharedResearchSystem : EntitySystem return tier - 1; } + public FormattedMessage GetTechnologyDescription( + TechnologyPrototype technology, + bool includeCost = true, + bool includeTier = true, + bool includePrereqs = false, + TechDisciplinePrototype? disciplinePrototype = null) + { + var description = new FormattedMessage(); + if (includeTier) + { + disciplinePrototype ??= PrototypeManager.Index(technology.Discipline); + description.AddMarkup(Loc.GetString("research-console-tier-discipline-info", + ("tier", technology.Tier), ("color", disciplinePrototype.Color), ("discipline", Loc.GetString(disciplinePrototype.Name)))); + description.PushNewline(); + } + + if (includeCost) + { + description.AddMarkup(Loc.GetString("research-console-cost", ("amount", technology.Cost))); + description.PushNewline(); + } + + if (includePrereqs && technology.TechnologyPrerequisites.Any()) + { + description.AddMarkup(Loc.GetString("research-console-prereqs-list-start")); + foreach (var recipe in technology.TechnologyPrerequisites) + { + var techProto = PrototypeManager.Index(recipe); + description.PushNewline(); + description.AddMarkup(Loc.GetString("research-console-prereqs-list-entry", + ("text", Loc.GetString(techProto.Name)))); + } + description.PushNewline(); + } + + description.AddMarkup(Loc.GetString("research-console-unlocks-list-start")); + foreach (var recipe in technology.RecipeUnlocks) + { + var recipeProto = PrototypeManager.Index(recipe); + description.PushNewline(); + description.AddMarkup(Loc.GetString("research-console-unlocks-list-entry", + ("name",recipeProto.Name))); + } + foreach (var generic in technology.GenericUnlocks) + { + description.PushNewline(); + description.AddMarkup(Loc.GetString("research-console-unlocks-list-entry-generic", + ("text", Loc.GetString(generic.UnlockDescription)))); + } + + return description; + } + /// /// Returns whether a technology is unlocked on this database or not. /// diff --git a/Resources/Locale/en-US/guidebook/guides.ftl b/Resources/Locale/en-US/guidebook/guides.ftl index 9fc69839c0..8893db9b23 100644 --- a/Resources/Locale/en-US/guidebook/guides.ftl +++ b/Resources/Locale/en-US/guidebook/guides.ftl @@ -34,6 +34,7 @@ guide-entry-botanicals = Botanicals guide-entry-cloning = Cloning guide-entry-cryogenics = Cryogenics guide-entry-science = Science +guide-entry-technologies = Technologies guide-entry-anomalous-research = Anomalous Research guide-entry-scanners-and-vessels = Scanners and Vessels guide-entry-ape = A.P.E. diff --git a/Resources/Locale/en-US/research/components/research-console-component.ftl b/Resources/Locale/en-US/research/components/research-console-component.ftl index 1063e6ebcb..196983efcd 100644 --- a/Resources/Locale/en-US/research/components/research-console-component.ftl +++ b/Resources/Locale/en-US/research/components/research-console-component.ftl @@ -14,5 +14,7 @@ research-console-cost = Cost: [color=orchid]{$amount}[/color] research-console-unlocks-list-start = Unlocks: research-console-unlocks-list-entry = - [color=yellow]{$name}[/color] research-console-unlocks-list-entry-generic = - [color=green]{$text}[/color] +research-console-prereqs-list-start = Requires: +research-console-prereqs-list-entry = - [color=orchid]{$text}[/color] research-console-no-access-popup = No access! diff --git a/Resources/Prototypes/Guidebook/science.yml b/Resources/Prototypes/Guidebook/science.yml index d9a3d442b4..03840ec15e 100644 --- a/Resources/Prototypes/Guidebook/science.yml +++ b/Resources/Prototypes/Guidebook/science.yml @@ -3,11 +3,18 @@ name: guide-entry-science text: "/ServerInfo/Guidebook/Science/Science.xml" children: + - Technologies - AnomalousResearch - Xenoarchaeology - Robotics - MachineUpgrading +- type: guideEntry + id: Technologies + name: guide-entry-technologies + text: "/ServerInfo/Guidebook/Science/Technologies.xml" + filterEnabled: True + - type: guideEntry id: AnomalousResearch name: guide-entry-anomalous-research diff --git a/Resources/ServerInfo/Guidebook/Science/Science.xml b/Resources/ServerInfo/Guidebook/Science/Science.xml index a32112877f..c886daf4d5 100644 --- a/Resources/ServerInfo/Guidebook/Science/Science.xml +++ b/Resources/ServerInfo/Guidebook/Science/Science.xml @@ -10,7 +10,9 @@ Science, often called Research and Development, is a job made up of both generat The most important thing inside your department is the R&D server, which stores unlocked technologies, and the R&D computer, which allows you to unlock technologies. -Each technology costs [color=#a4885c]Research Points[/color] and unlocks recipes at lathes. Some technologies will also have prerequesites you have to unlock before you can research them. +Each technology costs [color=#a4885c]Research Points[/color] and unlocks recipes at lathes. Some technologies will also have prerequisites you have to unlock before you can research them. + +Information about the different technologies can be viewed [textlink="on the technology guidebook page" link="Technologies"]. ## Disciplines Technologies are spread over 5 different Disciplines: diff --git a/Resources/ServerInfo/Guidebook/Science/Technologies.xml b/Resources/ServerInfo/Guidebook/Science/Technologies.xml new file mode 100644 index 0000000000..7f0feaca42 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/Science/Technologies.xml @@ -0,0 +1,23 @@ + +# Technologies + +All technologies have a cost and a tier requirement in order to be researched. Unlocking them adds a variety of recipes that can be printed at various lathes. + +The different technologies and their respective discipline are listed below. + +## Industrial + + +## Biochemical + + +## Arsenal + + +## Experimental + + +## Civilian Services + + +