From d2ff5f85c360c6b86f48497b1e00c1a29f19f252 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Thu, 27 Jun 2024 13:03:04 +0300 Subject: [PATCH] Upgrade station goal system (#2338) Co-authored-by: Morb <14136326+Morb0@users.noreply.github.com> --- .../Corvax/StationGoal/StationGoalCommand.cs | 34 +++-- .../StationGoal/StationGoalComponent.cs | 14 ++ .../StationGoal/StationGoalPaperSystem.cs | 132 ++++++++++++------ .../StationGoal/StationGoalPrototype.cs | 16 ++- .../station-goal/station-goal-component.ftl | 58 ++++++-- .../Corvax/Entities/Stations/base.yml | 14 ++ .../Prototypes/Corvax/Objectives/goals.yml | 40 +++++- .../Entities/Stations/nanotrasen.yml | 1 + Resources/Prototypes/SS220/Maps/axioma.yml | 12 ++ Resources/Prototypes/SS220/Maps/eclipse.yml | 12 ++ .../Prototypes/SS220/Maps/frankenstein.yml | 12 ++ Resources/Prototypes/SS220/Maps/nox.yml | 12 ++ 12 files changed, 282 insertions(+), 75 deletions(-) create mode 100644 Content.Server/Corvax/StationGoal/StationGoalComponent.cs create mode 100644 Resources/Prototypes/Corvax/Entities/Stations/base.yml diff --git a/Content.Server/Corvax/StationGoal/StationGoalCommand.cs b/Content.Server/Corvax/StationGoal/StationGoalCommand.cs index 8f1c451dc9b8a5..6c0a3c58ab223b 100644 --- a/Content.Server/Corvax/StationGoal/StationGoalCommand.cs +++ b/Content.Server/Corvax/StationGoal/StationGoalCommand.cs @@ -1,5 +1,6 @@ using System.Linq; using Content.Server.Administration; +using Content.Server.Commands; using Content.Shared.Administration; using Robust.Shared.Console; using Robust.Shared.Prototypes; @@ -9,19 +10,27 @@ namespace Content.Server.Corvax.StationGoal [AdminCommand(AdminFlags.Fun)] public sealed class StationGoalCommand : IConsoleCommand { + [Dependency] private readonly IEntityManager _entManager = default!; + public string Command => "sendstationgoal"; public string Description => Loc.GetString("send-station-goal-command-description"); public string Help => Loc.GetString("send-station-goal-command-help-text", ("command", Command)); public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (args.Length != 1) + if (args.Length != 2) { - shell.WriteError(Loc.GetString("shell-need-exactly-one-argument")); + shell.WriteError(Loc.GetString("shell-wrong-arguments-number")); return; } - var protoId = args[0]; + if (!NetEntity.TryParse(args[0], out var euidNet) || !_entManager.TryGetEntity(euidNet, out var euid)) + { + shell.WriteError($"Failed to parse euid '{args[0]}'."); + return; + } + + var protoId = args[1]; var prototypeManager = IoCManager.Resolve(); if (!prototypeManager.TryIndex(protoId, out var proto)) { @@ -30,24 +39,27 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) } var stationGoalPaper = IoCManager.Resolve().System(); - if (!stationGoalPaper.SendStationGoal(proto)) + if (!stationGoalPaper.SendStationGoal(euid, protoId)) { shell.WriteError("Station goal was not sent"); return; } } - + public CompletionResult GetCompletion(IConsoleShell shell, string[] args) { - if (args.Length == 1) + switch (args.Length) { - var options = IoCManager.Resolve() - .EnumeratePrototypes() - .Select(p => new CompletionOption(p.ID)); + case 1: + var stations = ContentCompletionHelper.StationIds(_entManager); + return CompletionResult.FromHintOptions(stations, "[StationId]"); + case 2: + var options = IoCManager.Resolve() + .EnumeratePrototypes() + .Select(p => new CompletionOption(p.ID)); - return CompletionResult.FromHintOptions(options, Loc.GetString("send-station-goal-command-arg-id")); + return CompletionResult.FromHintOptions(options, Loc.GetString("send-station-goal-command-arg-id")); } - return CompletionResult.Empty; } } diff --git a/Content.Server/Corvax/StationGoal/StationGoalComponent.cs b/Content.Server/Corvax/StationGoal/StationGoalComponent.cs new file mode 100644 index 00000000000000..c822d33ea83c5f --- /dev/null +++ b/Content.Server/Corvax/StationGoal/StationGoalComponent.cs @@ -0,0 +1,14 @@ +using Robust.Shared.Prototypes; + +namespace Content.Server.Corvax.StationGoal +{ + /// + /// if attached to a station prototype, will send the station a random goal from the list + /// + [RegisterComponent] + public sealed partial class StationGoalComponent : Component + { + [DataField] + public List> Goals = new(); + } +} diff --git a/Content.Server/Corvax/StationGoal/StationGoalPaperSystem.cs b/Content.Server/Corvax/StationGoal/StationGoalPaperSystem.cs index 6c37ba4c6777cb..3a1a1a9fc88410 100644 --- a/Content.Server/Corvax/StationGoal/StationGoalPaperSystem.cs +++ b/Content.Server/Corvax/StationGoal/StationGoalPaperSystem.cs @@ -1,5 +1,8 @@ using System.Linq; using Content.Server.Fax; +using Content.Server.GameTicking.Events; +using Content.Server.Station.Components; +using Content.Server.Station.Systems; using Content.Server.Paper; using Content.Shared.Fax.Components; using Content.Shared.GameTicking; @@ -8,6 +11,7 @@ using Content.Shared.SS220.Photocopier; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using Robust.Server.Player; namespace Content.Server.Corvax.StationGoal { @@ -16,75 +20,111 @@ namespace Content.Server.Corvax.StationGoal /// public sealed class StationGoalPaperSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly FaxSystem _faxSystem = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly StationSystem _station = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnRoundStarted); + SubscribeLocalEvent(OnRoundStarting); } - private void OnRoundStarted(RoundStartedEvent ev) + private void OnRoundStarting(RoundStartingEvent ev) { - SendRandomGoal(); - } + var playerCount = _playerManager.PlayerCount; - public bool SendRandomGoal() - { - var availableGoals = _prototypeManager.EnumeratePrototypes().ToList(); - var goal = _random.Pick(availableGoals); - return SendStationGoal(goal); - } - public static string Random_planet_name() - { - var rand = new Random(); - string name = $"{(char)rand.Next(65, 90)}-"; + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var station)) + { + var tempGoals = new List>(station.Goals); + StationGoalPrototype? selGoal = null; + while (tempGoals.Count > 0) + { + var goalId = _random.Pick(tempGoals); + var goalProto = _proto.Index(goalId); + + if (playerCount > goalProto.MaxPlayers || + playerCount < goalProto.MinPlayers) + { + tempGoals.Remove(goalId); + continue; + } + + selGoal = goalProto; + break; + } - for (var i = 1; i <= 5; i++) - name += $"{rand.Next(0, 9)}{(i != 5 ? "-" : "")}"; + if (selGoal is null) + return; - return name; + if (SendStationGoal(uid, selGoal)) + { + Log.Info($"Goal {selGoal.ID} has been sent to station {MetaData(uid).EntityName}"); + } + } + } + + public bool SendStationGoal(EntityUid? ent, ProtoId goal) + { + return SendStationGoal(ent, _proto.Index(goal)); } /// - /// Send a station goal to all faxes which are authorized to receive it. + /// Send a station goal on selected station to all faxes which are authorized to receive it. /// /// True if at least one fax received paper - public bool SendStationGoal(StationGoalPrototype goal) + public bool SendStationGoal(EntityUid? ent, StationGoalPrototype goal) { - var faxes = EntityManager.EntityQueryEnumerator(); - var wasSent = false; - while (faxes.MoveNext(out var uid, out var fax)) - { - if (!fax.ReceiveStationGoal) continue; + if (ent is null) + return false; - var dataToCopy = new Dictionary(); - var paperDataToCopy = new PaperPhotocopiedData() - { - Content = Loc.GetString(goal.Text, ("rand_planet_name", Random_planet_name())), - StampState = "paper_stamp-centcom", - StampedBy = new List{ - new(){ - StampedName = Loc.GetString("stamp-component-stamped-name-centcom"), - StampedColor = Color.FromHex("#dca019") //SS220-CentcomFashion-Changed the stamp color - } + if (!TryComp(ent, out var stationData)) + return false; + + var dataToCopy = new Dictionary(); + var paperDataToCopy = new PaperPhotocopiedData() + { + Content = Loc.GetString(goal.Text, ("station", MetaData(ent.Value).EntityName)), + StampState = "paper_stamp-centcom", + StampedBy = [ + new() + { + StampedName = Loc.GetString("stamp-component-stamped-name-centcom"), + StampedColor = Color.FromHex("#dca019") //SS220-CentcomFashion-Changed the stamp color } - }; - dataToCopy.Add(typeof(PaperComponent), paperDataToCopy); + ] + }; + dataToCopy.Add(typeof(PaperComponent), paperDataToCopy); - var metaData = new PhotocopyableMetaData() - { - EntityName = Loc.GetString("station-goal-fax-paper-name"), - PrototypeId = "PaperNtFormCc" - }; + var metaData = new PhotocopyableMetaData() + { + EntityName = Loc.GetString("station-goal-fax-paper-name"), + PrototypeId = "PaperNtFormCc" + }; - var printout = new FaxPrintout(dataToCopy, metaData); - _faxSystem.Receive(uid, printout, null, fax); + var printout = new FaxPrintout(dataToCopy, metaData); - wasSent = true; - } + var wasSent = false; + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var faxUid, out var fax)) + { + if (!fax.ReceiveStationGoal) + continue; + var largestGrid = _station.GetLargestGrid(stationData); + var grid = Transform(faxUid).GridUid; + if (grid is not null && largestGrid == grid.Value) + { + _faxSystem.Receive(faxUid, printout, null, fax); + foreach (var spawnEnt in goal.Spawns) + { + SpawnAtPosition(spawnEnt, Transform(faxUid).Coordinates); + } + wasSent = true; + } + } return wasSent; } } diff --git a/Content.Server/Corvax/StationGoal/StationGoalPrototype.cs b/Content.Server/Corvax/StationGoal/StationGoalPrototype.cs index 79d945f5be6c40..758049e4344691 100644 --- a/Content.Server/Corvax/StationGoal/StationGoalPrototype.cs +++ b/Content.Server/Corvax/StationGoal/StationGoalPrototype.cs @@ -7,6 +7,20 @@ public sealed class StationGoalPrototype : IPrototype { [IdDataFieldAttribute] public string ID { get; } = default!; - [DataField("text")] public string Text { get; set; } = string.Empty; + [DataField] + public string Text { get; set; } = string.Empty; + + [DataField] + public int? MinPlayers; + + [DataField] + public int? MaxPlayers; + + /// + /// Goal may require certain items to complete. These items will appear near the receving fax machine at the start of the round. + /// TODO: They should be spun up at the tradepost instead of at the fax machine, but I'm too lazy to do that right now. Maybe in the future. + /// + [DataField] + public List Spawns = new(); } } diff --git a/Resources/Locale/ru-RU/corvax/station-goal/station-goal-component.ftl b/Resources/Locale/ru-RU/corvax/station-goal/station-goal-component.ftl index d1d35cb90fd35a..f856aaf6e54547 100644 --- a/Resources/Locale/ru-RU/corvax/station-goal/station-goal-component.ftl +++ b/Resources/Locale/ru-RU/corvax/station-goal/station-goal-component.ftl @@ -1,19 +1,22 @@ station-goal-fax-paper-name = Цель станции station-goal-shuttle = - Цель вашей смены - построить пилотируемый шаттл в космосе и обеспечить его всем необходимым для выживания. + Цель смены станции {$station} - постройка пилотируемого шаттла в космосе и обеспечение его всем необходимым для выживания. Чтобы её выполнить, отделу снабжения нужно заказать все необходимые ресурсы для инженерного и научного отделов. Инженерному отделу необходимо построить его, а научный отдел должен предоставить инженерному отделу и шаттлу всю необходимую экипировку. + station-goal-singularity = - Цель вашей смены - построить генератор, основанный на сверхмассивной Сингулярности. - Чтобы её выполнить, инженерному отделу понадобится построить сдерживающую клетку, для чего отделу снабжения потребуется заказать все необходимые материалы. + Цель смены станции {$station} - постройка генератора основанного на сверхмассивной Сингулярности. + Чтобы её выполнить, инженерному отделу понадобится построить сдерживающую клетку, отделу снабжения потребуется заказать все необходимые материалы. Сдерживающая клетка должна быть способна сдержать сингулярность третьего класса. + station-goal-solar-panels = - Цель вашей смены - организовать систему запасного питания для станции на основе солнечных панелей. - Для этого вам необходимо заказать все необходимые материалы в отделе снабжения и построить 2 новые ветки солнечных панелей силами инженерного отдела. - Так же требуется обеспечить изолированность производимой ими энергии в новые 3 СМЭСа не подключённые к общей сети станции. + Цель смены станции {$station} - организовать систему запасного питания для станции на основе солнечных панелей. + Для этого вам понадобится заказать все необходимые материалы в отделе снабжения и после построить 2 новые ветки солнечных панелей инженерным отделом. + А так же обеспечить изолированность производимой ими энергии в новые 3 СМЭСа не подключённые к общей сети станции. + station-goal-artifacts = - Цель вашей смены - обнаружить, исследовать и доставить космические артефакты. + Цель смены станции {$station} - обнаружение, исследование и доставка космических артефактов. Для её выполнения будет необходима работа утилизаторов для поиска и доставки артефактов с обломков вокруг станции. После доставки их необходимо передать в специальном контейнере отделу исследования для изучения и документирования их свойств. Необходимо доставить на шаттле эвакуации в специальных контейнерах как минимум 2 полностью изученных и задокументированных артефакта. @@ -24,16 +27,49 @@ station-goal-artifacts = - Примечания - ФИ и должность ответственного Документ должен быть удостоверен печатью научного руководителя. + station-goal-bank = - Цель вашей смены - постройка орбитального хранилища с припасами и технологиями. - Хранилище должно быть размещено в космосе отдельно от основной станции. Проследите за прочностью его конструкции, случайный метеорит не должен повредить его. + Цель смены станции {$station} - постройка орбитального хранилища с припасами и технологиями. + Хранилище должно быть размещено в космосе отдельно от основной станции, проследите за прочностью его конструкции, случайный метеорит не должен повредить его. В хранилище необходимо разместить 4 ящика: - ящик с продвинутыми медикаментами - ящик с запасами лучших семян - ящик-холодильник еды с высокой питательной ценностью - ящик с ценными, но не уникальными платами Проследите за сохранностью содержимого в хранилище до окончания смены. + station-goal-zoo = - Цель вашей смены - улучшить рекреацию персонала на станции. - Инженерному отделу необходимо построить зоопарк недалеко от дорматориев с как минимум трёмя вольерами разных видов животных, заказанных в отделе снабжения. + Цель смены станции {$station} - улучшение рекреации персонала на станции. + Инженерному отделу необходимо построить зоопарк в недалёкой доступности от дорматориев с как минимум тремя вольерами разных видов животных заказанных в отделе снабжения. Обеспечьте животных пищей, как минимум одним роботом уборщиком в каждый вольер и всем необходимым для жизни в зависимости от вида животного. + +station-goal-mining-outpost = + Цель смены станции {$station} - постройка орбитального шахтёрского аванпоста для добычи руды и ресурсов с астероидов. + Аванпост должен быть размещён в космосе отдельно от основной станции. + Проследите за прочностью его конструкции, случайный метеорит не должен повредить его. + Аванпост должен иметь следующее: + - автономный, бесперебойный источник электроэнергии + - генератор гравитации + - оборудование для проведения работ, в частности кирки, сумки для руды и 2 шахтёрских скафандра + - комнаты для проживания 2 человек, с атмосферой, освещением и окнами + - склад для добытых ресурсов и необходимых для жизни продуктов + - Минимум 500 единиц пива и ящик-холодильник закусок + - 4 набора медикаментов от механического урона + - 4 набора медикаментов от физического урона + Проследите за сохранностью аванпоста до окончания смены. + +station-goal-tesla = + Цель смены станции {$station} - постройка генератора основанного на высоковольтной Тесле. + Чтобы её выполнить инженерному отделу понадобится построить сдерживающую клетку, отделу снабжения потребуется заказать все необходимые материалы. + Сдерживающая клетка должна быть способна сдерживать теслу без риска разрушения эмиттеров. + +station-goal-frame-repair = + Цель вашей смены - завершить строительство станции {$station}, достроив каждому отделу помещения, необходимые для успешной работы. Также вам необходимо построить кухню и гидропонику для сервисного отдела, оружейную и место содержания заключенных для отдела Службы безопасности и обеспечить свободный проход пассажиров станции до отбытия, без необходимости выхода в открытый космос. + Для помощи в выполнении цели мы будет каждые 5 минут высылать вам припасы на специальной посадочной площадке в центре станции. + Слава НТ! + +station-goal-delta-xeno-repair = + Цель смены станции {$station} - восстановление заброшенного ксенобиологического сектора научного отдела. Вам необходимо полностью восстановить электропитание, атмос, привести внешний вид к изначальному состоянию, и поймать минимум трех слаймов любых форм в ксенобиологические клетки, для их изучения последующей сменой. + +station-goal-delta-ambusol = + Цель смены станции {$station} - восстановление заброшенного вирусологического сектора медицинского отдела. Вам необходимо полностью восстановить электропитание, атмос, привести внешний вид к изначальному состоянию, и в стерильных условиях вирусологии провести синтезацию 500u Амбузола, из предоставленных трех пилюль Ромерола. \ No newline at end of file diff --git a/Resources/Prototypes/Corvax/Entities/Stations/base.yml b/Resources/Prototypes/Corvax/Entities/Stations/base.yml new file mode 100644 index 00000000000000..8aaaf00b712a0e --- /dev/null +++ b/Resources/Prototypes/Corvax/Entities/Stations/base.yml @@ -0,0 +1,14 @@ +- type: entity + id: BaseStationGoal + abstract: true + components: + - type: StationGoal + goals: + - Shuttle + - Singularity + - SolarPanels + - Artifacts + - Bank + - Zoo + - MiningOutpost + - Tesla \ No newline at end of file diff --git a/Resources/Prototypes/Corvax/Objectives/goals.yml b/Resources/Prototypes/Corvax/Objectives/goals.yml index cd4bb9abee6ece..94b0ee07d9e6af 100644 --- a/Resources/Prototypes/Corvax/Objectives/goals.yml +++ b/Resources/Prototypes/Corvax/Objectives/goals.yml @@ -1,23 +1,51 @@ +# General goals + - type: stationGoal - id: StationGoalShuttle + id: Shuttle text: station-goal-shuttle - type: stationGoal - id: StationGoalSingularity + id: Singularity text: station-goal-singularity - type: stationGoal - id: StationGoalSolarPanels + id: SolarPanels text: station-goal-solar-panels - type: stationGoal - id: StationGoalArtifacts + id: Artifacts text: station-goal-artifacts - type: stationGoal - id: StationGoalBank + id: Bank text: station-goal-bank - type: stationGoal - id: StationGoalZoo + id: Zoo text: station-goal-zoo + +- type: stationGoal + id: MiningOutpost + text: station-goal-mining-outpost + +- type: stationGoal + id: Tesla + text: station-goal-tesla + +# Special goals + +- type: stationGoal + id: FrameRepair + text: station-goal-frame-repair + +- type: stationGoal + id: XenobiologyRepair + text: station-goal-delta-xeno-repair + +- type: stationGoal + id: VirusologyAmbusol + text: station-goal-delta-ambusol + spawns: + - PillRomerol + - PillRomerol + - PillRomerol \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Stations/nanotrasen.yml b/Resources/Prototypes/Entities/Stations/nanotrasen.yml index 7e650d536f224e..7323158e1d3c15 100644 --- a/Resources/Prototypes/Entities/Stations/nanotrasen.yml +++ b/Resources/Prototypes/Entities/Stations/nanotrasen.yml @@ -10,6 +10,7 @@ id: StandardNanotrasenStation parent: - BaseStation + - BaseStationGoal # Corvax - BaseStationNews - BaseStationCargo - BaseStationJobsSpawning diff --git a/Resources/Prototypes/SS220/Maps/axioma.yml b/Resources/Prototypes/SS220/Maps/axioma.yml index 4785a8082612bb..190fd17cd9dd26 100644 --- a/Resources/Prototypes/SS220/Maps/axioma.yml +++ b/Resources/Prototypes/SS220/Maps/axioma.yml @@ -69,6 +69,18 @@ Reporter: [ 2, 2 ] ServiceWorker: [ 2, 2 ] Lawyer: [ 2, 2 ] + - type: StationGoal + goals: + - Shuttle + - Singularity + - SolarPanels + - Artifacts + - Bank + - Zoo + - MiningOutpost + - Tesla + - XenobiologyRepair + - VirusologyAmbusol - type: entity id: AxiomaNanotrasenStation diff --git a/Resources/Prototypes/SS220/Maps/eclipse.yml b/Resources/Prototypes/SS220/Maps/eclipse.yml index 83fc3307459364..34c6cb12411a00 100644 --- a/Resources/Prototypes/SS220/Maps/eclipse.yml +++ b/Resources/Prototypes/SS220/Maps/eclipse.yml @@ -70,6 +70,18 @@ ServiceWorker: [ 2, 2 ] Lawyer: [ 2, 2 ] Zookeeper: [ 1, 1 ] + - type: StationGoal + goals: + - Shuttle + - Singularity + - SolarPanels + - Artifacts + - Bank + - Zoo + - MiningOutpost + - Tesla + - XenobiologyRepair + - VirusologyAmbusol - type: entity id: EclipseNanotrasenStation diff --git a/Resources/Prototypes/SS220/Maps/frankenstein.yml b/Resources/Prototypes/SS220/Maps/frankenstein.yml index d6f46a44d4bb8c..4de211f101b9a5 100644 --- a/Resources/Prototypes/SS220/Maps/frankenstein.yml +++ b/Resources/Prototypes/SS220/Maps/frankenstein.yml @@ -68,6 +68,18 @@ Mime: [ 1, 1 ] Musician: [ 2, 2 ] Reporter: [ 2, 2 ] + - type: StationGoal + goals: + - Shuttle + - Singularity + - SolarPanels + - Artifacts + - Bank + - Zoo + - MiningOutpost + - Tesla + - XenobiologyRepair + - VirusologyAmbusol - type: entity id: FrankensteinStation diff --git a/Resources/Prototypes/SS220/Maps/nox.yml b/Resources/Prototypes/SS220/Maps/nox.yml index dcefebdb71e8e3..5e658f4bbeacfd 100644 --- a/Resources/Prototypes/SS220/Maps/nox.yml +++ b/Resources/Prototypes/SS220/Maps/nox.yml @@ -69,6 +69,18 @@ Mime: [ 1, 1 ] Musician: [ 2, 2 ] Reporter: [ 2, 2 ] + - type: StationGoal + goals: + - Shuttle + - Singularity + - SolarPanels + - Artifacts + - Bank + - Zoo + - MiningOutpost + - Tesla + - XenobiologyRepair + - VirusologyAmbusol - type: entity id: NoxNanotrasenStation