Команда для отправки цели для станции (#21)

* Команда для отправки цели для станции

* Правки

(cherry picked from commit 93a79c4952e3a75c32ff5cc4d07df4018a9bf7db)
This commit is contained in:
BIGZi0348
2024-10-20 19:42:12 +03:00
committed by keslik
parent ee48b35f33
commit 5654c92678
11 changed files with 560 additions and 1 deletions

View File

@@ -135,6 +135,7 @@ namespace Content.Client.Entry
_prototypeManager.RegisterIgnore("wireLayout");
_prototypeManager.RegisterIgnore("alertLevels");
_prototypeManager.RegisterIgnore("nukeopsRole");
_prototypeManager.RegisterIgnore("stationGoal"); // WD ENGI EXCLUSIVE
_prototypeManager.RegisterIgnore("ghostRoleRaffleDecider");
//WD-EDIT

View File

@@ -0,0 +1,66 @@
using System.Linq;
using Content.Server.Administration;
using Content.Server.Commands;
using Content.Shared.Administration;
using Robust.Shared.Console;
using Robust.Shared.Prototypes;
namespace Content.Server._White._Engi.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 != 2)
{
shell.WriteError(Loc.GetString("shell-wrong-arguments-number"));
return;
}
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<IPrototypeManager>();
if (!prototypeManager.TryIndex<StationGoalPrototype>(protoId, out var proto))
{
shell.WriteError($"No station goal found with ID {protoId}!");
return;
}
var stationGoalPaper = IoCManager.Resolve<IEntityManager>().System<StationGoalPaperSystem>();
if (!stationGoalPaper.SendStationGoal(euid, protoId))
{
shell.WriteError("Station goal was not sent");
return;
}
}
public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
{
switch (args.Length)
{
case 1:
var stations = ContentCompletionHelper.StationIds(_entManager);
return CompletionResult.FromHintOptions(stations, "[StationId]");
case 2:
var options = IoCManager.Resolve<IPrototypeManager>()
.EnumeratePrototypes<StationGoalPrototype>()
.Select(p => new CompletionOption(p.ID));
return CompletionResult.FromHintOptions(options, Loc.GetString("send-station-goal-command-arg-id"));
}
return CompletionResult.Empty;
}
}
}

View File

@@ -0,0 +1,15 @@
using Robust.Shared.Prototypes;
namespace Content.Server._White._Engi.StationGoal
{
/// <summary>
/// WD ENGI EXCLUSIVE.
/// If attached to a station prototype, will send the station a random goal from the list.
/// </summary>
[RegisterComponent]
public sealed partial class StationGoalComponent : Component
{
[DataField]
public List<ProtoId<StationGoalPrototype>> Goals = new();
}
}

View File

@@ -0,0 +1,11 @@
namespace Content.Server._White._Engi.StationGoal
{
/// <summary>
/// WD ENGI EXCLUSIVE.
/// Paper with a written station goal in it.
/// </summary>
[RegisterComponent]
public sealed partial class StationGoalPaperComponent : Component
{
}
}

View File

@@ -0,0 +1,133 @@
using Content.Server.Fax;
using Content.Server.GameTicking.Events;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.Fax.Components;
using Content.Shared.Paper;
using Robust.Server.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Content.Server.RandomMetadata;
namespace Content.Server._White._Engi.StationGoal
{
/// <summary>
/// WD ENGI EXCLUSIVE.
/// System to spawn paper with station goal.
/// </summary>
public sealed class StationGoalPaperSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly FaxSystem _fax = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly RandomMetadataSystem _randomMeta = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStarting);
}
private void OnRoundStarting(RoundStartingEvent ev)
{
var playerCount = _playerManager.PlayerCount;
var query = EntityQueryEnumerator<StationGoalComponent>();
while (query.MoveNext(out var uid, out var station))
{
var tempGoals = new List<ProtoId<StationGoalPrototype>>(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;
}
if (selGoal is null)
return;
if (SendStationGoal(uid, selGoal))
{
Log.Info($"Goal {selGoal.ID} has been sent to station {MetaData(uid).EntityName}");
}
}
}
public bool SendStationGoal(EntityUid? ent, ProtoId<StationGoalPrototype> goal)
{
return SendStationGoal(ent, _proto.Index(goal));
}
/// <summary>
/// WD ENGI EXCLUSIVE.
/// Send a station goal on selected station to all faxes which are authorized to receive it.
/// </summary>
/// <returns>True if at least one fax received paper</returns>
public bool SendStationGoal(EntityUid? ent, StationGoalPrototype goal)
{
if (ent is null)
return false;
if (!TryComp<StationDataComponent>(ent, out var stationData))
return false;
var today = DateTime.Today.ToString("dd.MM");
var namesList = new List<string>
{
"names_first_male",
"names_last_male"
};
var operatorName = _randomMeta.GetRandomFromSegments(namesList, " ");
var faxContent = Loc.GetString("engi-station-goal-form",
("station", MetaData(ent.Value).EntityName),
("date", today),
("operator", operatorName),
("text", Loc.GetString(goal.Text)));
var printout = new FaxPrintout(
faxContent,
Loc.GetString("engi-station-goal-fax-paper-name"),
null,
null,
"paper_stamp-centcom",
new List<StampDisplayInfo>
{
new() { StampedName = Loc.GetString("stamp-component-stamped-name-centcom"), StampedColor = Color.FromHex("#006600") },
});
var wasSent = false;
var query = EntityQueryEnumerator<FaxMachineComponent>();
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)
{
_fax.Receive(faxUid, printout, null, fax);
foreach (var spawnEnt in goal.Spawns)
{
SpawnAtPosition(spawnEnt, Transform(faxUid).Coordinates);
}
wasSent = true;
}
}
return wasSent;
}
}
}

View File

@@ -0,0 +1,29 @@
using Robust.Shared.Prototypes;
namespace Content.Server._White._Engi.StationGoal
{
/// <summary>
/// WD ENGI EXCLUSIVE.
/// </summary>
[Serializable, Prototype("stationGoal")]
public sealed class StationGoalPrototype : IPrototype
{
[IdDataField]
public string ID { get; } = default!;
[DataField]
public string Text { get; set; } = string.Empty;
[DataField]
public int? MinPlayers;
[DataField]
public int? MaxPlayers;
/// <summary>
/// Goal may require certain items to complete. These items will appear near the receving fax machine at the start of the round.
/// </summary>
[DataField]
public List<EntProtoId> Spawns = new();
}
}

View File

@@ -59,6 +59,14 @@ public sealed partial class FaxMachineComponent : Component
[DataField]
public bool ReceiveNukeCodes { get; set; } = false;
/// <summary>
/// WD ENGI EXCLUSIVE.
/// Should that fax receive station goal info
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("receiveStationGoal")]
public bool ReceiveStationGoal { get; set; } = false;
/// <summary>
/// Sound to play when fax has been emagged
/// </summary>

View File

@@ -0,0 +1,226 @@
ent-StationGoalPaper = цель станции от Центком
.desc = Похоже у вас будет много работы.
engi-station-goal-fax-paper-name = цель станции от Центком
engi-station-goal-form = Постановление Центрального Командования
---------------------------------------------------------------------
Утверждение цели и задачи для станции { $station }
Центральным Командованием № 2562-CU-2
Дата: { $date }.2562 года
---------------------------------------------------------------------
Утвердить следующие цели для космической станции:
{ $text }
---------------------------------------------------------------------
1. Командование станции обязано строго следовать данной цели и заданию, а также предоставить все необходимые ресурсы и усилия для успешного выполнения миссии.
2. Право отменить данное постановление имеет исключительно Центральное Командование.
3. Сотрудникам станции запрещено покидать объект до момента выполнения цели. Исключение - станция находится в критическом состоянии и не является пригодной для жизни.
---------------------------------------------------------------------
Данное Постановление выписано:
И.Ф: { $operator }
Должность: Оператор Центрального Командования
Печать:
engi-station-goal-singularity = [bold]Постройка генератора, основанного на сингулярности.[/bold]
Все детали для цели должны быть заказаны или собраны на станции. Категорически запрещено использовать уже имеющиеся компоненты.
Для успешного выполнения цели необходимо сделать запуск сингулярности.
После окончания смены вся конструкция будет отсоединена от станции и транспортирована на другой объект.
engi-station-goal-solar-panels = [bold]Постройка сети солнечных панелей.[/bold]
Требования:
- Сеть должна состоять из минимум двух ветвей, расположенных на противоположных концах станции.
- Каждая ветвь должна состоять из минимум 36 солнечных панелей.
- Каждая ветвь должна иметь минимум два СМЭСа, несоединённых со станцией.
engi-station-goal-artifacts = [bold]Нахождение и исследование артефактов.[/bold]
Экипаж станции должен найти минимум три артефакта любым способом, отличным от покупки.
Сотрудники научного отдела должны изучить найденные артефакты и задокументировать их свойства.
В качестве документации могут быть приняты отчёты о каждом узле (печатаются на специальной консоли) и отдельный документ с описанием в доступной форме схемы артефакта.
Каждый документ должен быть подтверждён печатью научного руководителя или капитана. Артефакты с документацией должны быть доставлены на станцию центрального командования.
engi-station-goal-bank = [bold]Постройка орбитального хранилища с припасами и технологиями.[/bold]
Хранилище должно быть размещено в космосе, отдельно от основной станции, защищено от метеоритов и иметь автономное питание.
В хранилище должно быть минимум четыре ящика:
- ящик с продвинутыми медикаментами;
- ящик с запасами лучших семян;
- ящик-холодильник еды с высокой питательной ценностью;
- ящик с ценными, но не уникальными платами.
engi-station-goal-zoo = [bold]Улучшение рекреации персонала станции.[/bold]
Для этого инженерный отдел должен построить зоопарк с как минимум 3 (тремя) вольерами. На каждый вольер один вид. Каждый вольер должен быть обеспечен едой для конкретного вида и роботом-уборщиком. Площадь каждого вольера как минимум 16 м².
Животные должны быть заказаны в отделе снабжения.
engi-station-goal-mining-outpost = [bold]Постройка орбитального шахтёрского аванпоста.[/bold]
Аванпост должен быть размещен в космосе, отдельно от основной станции, защищён от метеоритов и иметь автономное питание, гравитацию и атмосферу.
Аванпост должен иметь как минимум две жилые комнаты с освещением и окнами. Оборудование для проведения работ: как минимум по две кирки, сумки для руды. Как минимум два шахтёрских скафандра.
На территории аванпоста должен быть склад для размещения добытого сырья и припасов: как минимум 500u (пятьсот единиц) пива в ящике-холодильнике для закусок. Как минимум по четыре набора медикаментов от механических повреждений.
engi-station-goal-tesla = [bold]Постройка генератора, основанного на Тесле.[/bold]
Все детали для цели должны быть заказаны или собраны на станции. Категорически запрещено использовать уже имеющиеся компоненты.
Для успешного выполнения цели необходимо сделать запуск теслы.
После окончания смены вся конструкция будет отсоединена от станции и транспортирована на другой объект.
engi-station-goal-security = [bold]Постройка и снабжение тренировочного комплекса для Службы Безопасности, с последующей проверкой состава.[/bold]
В будущем данная станция будет передислоцирована в сектор граничащий с небезопасным.
Задачей Инженерного отдела является постройка тренировочного комплекса, представляющего из себя полосу препятствий. Минимальное время на прохождение среднестатистического, подготовленного офицера, примерно 30 секунд.
Данная полоса должна включать в себя следующее:
- Змееобразные коридоры стекла.
- Различные препятствия для перелезания.
- Деревянную постройку с мишенями, имитирующую захват случайного отдела.
Инженерный отдел в праве строить и другие безопасные виды препятствий.
Задачей Медицинского отдела является изготовление партии таблеток Эфедрина, дозировкой 10u каждая, в минимальном количестве 10 шт, с последующей передачей на хранение в защищенном контейнере Смотрителю станции.
Задачей Службы Безопасности является проведение для каждого члена своего отдела тренировки на данной полосе с письменной фиксацией результатов. В результатах должно быть описано Имя и Фамилия сотрудника, а так же время за которое им была пройдена полоса. Лучшие сотрудники получат шанс на контракт о последующей работе на следующей смене данной станции. Результаты каждого сотрудника будет необходимо указать в отчете о состоянии цели.
engi-station-goal-shuttle-med = [bold]Постройка пилотируемого медицинского шаттла.[/bold]
Шаттл должен соответствовать следующим требованиям:
1. Обеспечен стабильным источником питания и резервной батареей СМЭС.
2. Уметь совершать следующие движения: крен, тангаж и рысканье.
3. Доступ к используемому оборудованию внутри отсеков не должен быть затруднён.
4. Иметь на борту химическую лабораторию с соответствующим оборудованием, рассчитанным минимум на одного сотрудника.
5. Иметь отсек для медицинских коек, рассчитанным минимум на десять человек.
6. Иметь на борту отсек с запасами медикаментов и провизии.
Справочная информация для неквалифицированного персонала:
Крен — вращательное движение.
Тангаж — поступательное движение "вперёд" и "назад".
Рысканье — поступательное движение "боком".
engi-station-goal-shuttle-sec = [bold]Постройка пилотируемого десантного шаттла.[/bold]
Шаттл должен соответствовать следующим требованиям:
1. Обеспечен стабильным источником питания и резервной батареей СМЭС.
2. Уметь совершать следующие движения: крен, тангаж и рысканье.
3. Доступ к используемому оборудованию внутри отсеков не должен быть затруднён.
4. Иметь на борту места и снаряжение как минимум на пять офицеров СБ.
Снаряжение для каждого офицера должно представлять из себя хотя бы один вид легального огнестрельного оружия, полученного не из арсенала, бронежилет, шлем, униформу.
5. Иметь на борту отсек с запасами медикаментов и провизии минимум на пять человек.
Справочная информация для неквалифицированного персонала:
Крен — вращательное движение.
Тангаж — поступательное движение "вперёд" и "назад".
Рысканье — поступательное движение "боком".
engi-station-goal-shuttle-rnd = [bold]Постройка пилотируемого исследовательского шаттла.[/bold]
Шаттл должен соответствовать следующим требованиям:
1. Обеспечен стабильным источником питания и резервной батареей СМЭС.
2. Уметь совершать следующие движения: крен, тангаж и рысканье.
3. Доступ к используемому оборудованию внутри отсеков не должен быть затруднён.
4. Иметь на борту следующие устройства и снаряжение: М.А.К.А.К. (x1), М.А.Р.Т.Ы.Х. (х2), синхронизатор аномалий (x1), магнитные сапоги (х2) и экспериментальный сосуд аномалии (х1), а также как минимум два скафандра EVA и два костюма радиационной защиты.
Справочная информация для неквалифицированного персонала:
Крен — вращательное движение.
Тангаж — поступательное движение "вперёд" и "назад".
Рысканье — поступательное движение "боком".
engi-station-goal-shuttle-srv = [bold]Постройка пилотируемого пассажирского шаттла.[/bold]
Шаттл должен соответствовать следующим требованиям:
1. Обеспечен стабильным источником питания и резервной батареей СМЭС.
2. Уметь совершать следующие движения: крен, тангаж и рысканье.
3. Доступ к используемому оборудованию внутри отсеков не должен быть затруднён.
4. Иметь на борту полностью обустроенный бар, в котором должен быть раздатчик безалкоголя, раздатчик алкоголя, бочка кваса, ящик барных принадлежностей, ящик пополнения раздатчика алкоголя, ящик пополнения раздатчика безалкоголя.
5. Иметь на борту обустроенную кухню, в которой должен быть ящик кухонных припасов и ящик кухонных принадлежностей. А также один гидропонный лоток и холодильник.
6. На борту должны быть приватные комнаты для комфортного проживания как минимум четверых человек.
7. На борту должен быть музыкальный автомат и ящик настольных игр.
Справочная информация для неквалифицированного персонала:
Крен — вращательное движение.
Тангаж — поступательное движение "вперёд" и "назад".
Рысканье — поступательное движение "боком".
engi-station-goal-shuttle-emergency = [bold]Постройка пилотируемого спасательного шаттла.[/bold]
Шаттл должен соответствовать следующим требованиям:
1. Обеспечен стабильным источником питания и резервной батареей СМЭС.
2. Уметь совершать следующие движения: крен, тангаж и рысканье.
3. Доступ к используемому оборудованию внутри отсеков не должен быть затруднён.
4. Иметь на борту ящик медицинских припасов, продвинутый аварийный набор, два ящика с наборами EVA, ящик стекла, два ящика стали, ящик пластали, ящик джетпаков, ящик ИРП.
Справочная информация для неквалифицированного персонала:
Крен — вращательное движение.
Тангаж — поступательное движение "вперёд" и "назад".
Рысканье — поступательное движение "боком".
engi-station-goal-theatre = [bold]Постройка театральной зоны.[/bold]
На данной станции пройдут переговоры с крупными компаниями для заключения партнёрских соглашений.
Театральная зона должна включать в себя:
1. Сцена с минимальным размером в 28м².
2. Минимальная вместимость зала в 21 персону.
3. Закулисье с различными нарядами, музыкальными инструментами, несколькими ящиками игрушек и мехом модели Х.О.Н.К.
4. Комнату или комнаты для четырех актеров. На каждого актера должно приходится по пять любых пирогов.
Материалы для клоунских скафандров вы можете получить из ящика театрального снаряжения.
В случае проведения тестового представления сервисный отдел станции будет вознагражден по прибытию на Станцию ЦК.
По окончании работ ЦК может прислать представителя для проведения тестового представления.
engi-station-goal-ai = [bold]Постройка автономного отсека ИИ.[/bold]
По окончанию строительства отсек должен быть отстыкован от станции и отправлен дрейфовать в космосе.
Требования:
1. Автономное питание на солнечных панелях или РИТЭГ, подключенные к СМЭС и Подстанции.
2. Иметь отсек для позитронного мозга.
3. Консоль сканера массы.
4. Два борга без позитронного мозга: инженерного и научного назначения.
5. Шлюз в отсек с командным доступом.
6. Сервер коммуникации и маршрутизатор проводных камер.
7. Снаружи отсек должен быть окружён контуром охлаждения.
Контур охлаждения должен представлять собой канал, шириной не менее одного метра, полностью заполненный любым газом, кроме обычной воздушной смеси, при температуре ниже -100 градусов по Цельсию и давлении как минимум в 3 раза превышающем атмосферное. Контур должен опоясывать не менее 80% модуля.
Рекомендуется предпринять дополнительные меры безопасности:
- Защиту от метеоритов.
- Сеть вокруг отсека под высоким напряжением.
engi-station-goal-botany = [bold]Постройка теплиц и выведение приспособленных к температуре растений.[/bold]
На станции или вблизи неё требуется построить три отсека с контролируемым климатом:
- Отсек с температурой 5 градусов Цельсия.
- Отсек с температурой 25 градусов Цельсия.
- Отсек с температурой 45 градусов Цельсия.
Каждый отсек необходимо снабдить минимум шестью гидропонными лотками и полным резервуаром с водой.
В каждом отсеке должно находится хотя бы одно растение, приспособленное к температуре отсека.
engi-station-goal-bunker = [bold]Приспособить станцию к мощным гиперэнергетическим потокам.[/bold]
Необходимо пристроить каждому отделу комнату, далее именуемой “бункер”, в которой экипаж станции мог бы укрыться от последствий гиперэнергетических потоков.
Требования к бункеру:
1. Минимальный размер 25м².
2. Укреплённые стены.
3. Вход через два непрозрачных шлюза с соответствующим отделу доступом.
4. От четырех кресел пилота.
5. Содержать базовые лекарства в виде таблеток со справкой о их назначении и наборы от механических повреждений.
6. Запасы провизии с расчетом на четыре человека, на срок от 72 часов.
7. Автономное питание и канистры с воздухом и кислородом.
8. Шкафчики со снаряжением для биологической и радиационной защиты. Так же аварийные скафандры EVA и костюм сапёра.
9. Интерком с общим ключом шифрования.

View File

@@ -1,3 +1,3 @@
send-station-goal-command-description = Отправляет выбранную цель станции на всех факсы способные её принять
send-station-goal-command-description = WD ENGI EXCLUSIVE. Отправляет выбранную цель станции на все факсы способные её принять
send-station-goal-command-help-text = Использование: { $command } <id-цели>
send-station-goal-command-arg-id = <ID цели>

View File

@@ -82,6 +82,7 @@
- type: FaxMachine
name: "Central Command"
notifyAdmins: true
receiveStationGoal: true # WD ENGI EXCLUSIVE
- type: entity
parent: FaxMachineBase
@@ -109,5 +110,6 @@
- type: FaxMachine
name: "Captain's Office"
receiveNukeCodes: true
receiveStationGoal: true # WD ENGI EXCLUSIVE
- type: StealTarget
stealGroup: FaxMachineCaptain

View File

@@ -0,0 +1,68 @@
# WD ENGI EXCLUSIVE
- type: stationGoal
id: Singularity
text: engi-station-goal-singularity
- type: stationGoal
id: SolarPanels
text: engi-station-goal-solar-panels
- type: stationGoal
id: Artifacts
text: engi-station-goal-artifacts
- type: stationGoal
id: Bank
text: engi-station-goal-bank
- type: stationGoal
id: Zoo
text: engi-station-goal-zoo
- type: stationGoal
id: MiningOutpost
text: engi-station-goal-mining-outpost
- type: stationGoal
id: Tesla
text: engi-station-goal-tesla
- type: stationGoal
id: SecurityTraining
text: engi-station-goal-security
- type: stationGoal
id: ShuttleMed
text: engi-station-goal-shuttle-med
- type: stationGoal
id: ShuttleSec
text: engi-station-goal-shuttle-sec
- type: stationGoal
id: ShuttleRnd
text: engi-station-goal-shuttle-rnd
- type: stationGoal
id: ShuttleSrv
text: engi-station-goal-shuttle-srv
- type: stationGoal
id: ShuttleEmergency
text: engi-station-goal-shuttle-emergency
- type: stationGoal
id: Theatre
text: engi-station-goal-theatre
- type: stationGoal
id: CellAI
text: engi-station-goal-ai
- type: stationGoal
id: Botany
text: engi-station-goal-botany
- type: stationGoal
id: Bunker
text: engi-station-goal-bunker