Refactor how jobs are handed out (#5422)

* Completely refactor how job spawning works

* Remove remains of old system.

* Squash the final bug, cleanup.

* Attempt to fix tests

* Adjusts packed's round-start crew roster, re-enables a bunch of old roles.
Also adds the Central Command Official as a proper role.

* pretty up ui

* refactor StationSystem into the correct folder & namespace.

* remove a log, make sure the lobby gets updated if a new map is spontaneously added.

* re-add accidentally removed log

* We do a little logging

* we do a little resolving

* we do a little documenting

* Renamed OverflowJob to FallbackOverflowJob
Allows stations to configure their own roundstart overflow job list.

* narrator: it did not compile

* oops

* support having no overflow jobs

* filescope for consistency

* small fixes

* Bumps a few role counts for Packed, namely engis

* log moment

* E

* Update Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml

Co-authored-by: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com>

* Update Content.Server/Maps/GameMapPrototype.cs

Co-authored-by: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com>

* factored job logic, cleanup.

* e

* Address reviews

* Remove the concept of a "default" grid.
It has no future in our new multi-station world

* why was clickable using that in the first place

* fix bad evil bug that almost slipped through
also adds chemist

* rms obsolete things from chemist

* Adds a sanity fallback

* address reviews

* adds ability to set name

* fuck

* cleanup joingame
This commit is contained in:
Moony
2021-11-26 03:02:46 -06:00
committed by GitHub
parent dfb329d5db
commit ec68226e99
53 changed files with 1148 additions and 705 deletions

View File

@@ -2,9 +2,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Content.Client.GameTicking.Managers;
using Content.Client.HUD.UI;
using Content.Shared.Roles;
using Content.Shared.Station;
using Robust.Client.Console;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
@@ -25,10 +26,13 @@ namespace Content.Client.LateJoin
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
public event Action<string>? SelectedId;
public event Action<(StationId, string)> SelectedId;
private readonly Dictionary<string, JobButton> _jobButtons = new();
private readonly Dictionary<string, BoxContainer> _jobCategories = new();
private readonly Dictionary<StationId, Dictionary<string, JobButton>> _jobButtons = new();
private readonly Dictionary<StationId, Dictionary<string, BoxContainer>> _jobCategories = new();
private readonly List<ScrollContainer> _jobLists = new();
private readonly Control _base;
public LateJoinGui()
{
@@ -38,136 +42,203 @@ namespace Content.Client.LateJoin
var gameTicker = EntitySystem.Get<ClientGameTicker>();
Title = Loc.GetString("late-join-gui-title");
var jobList = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
var vBox = new BoxContainer
_base = new BoxContainer()
{
Orientation = LayoutOrientation.Vertical,
Children =
{
new ScrollContainer
{
VerticalExpand = true,
Children =
{
jobList
}
}
}
VerticalExpand = true,
Margin = new Thickness(0),
};
Contents.AddChild(vBox);
Contents.AddChild(_base);
var firstCategory = true;
RebuildUI();
foreach (var job in _prototypeManager.EnumeratePrototypes<JobPrototype>().OrderBy(j => j.Name))
{
foreach (var department in job.Departments)
{
if (!_jobCategories.TryGetValue(department, out var category))
{
category = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
Name = department,
ToolTip = Loc.GetString("late-join-gui-jobs-amount-in-department-tooltip",
("departmentName", department))
};
if (firstCategory)
{
firstCategory = false;
}
else
{
category.AddChild(new Control
{
MinSize = new Vector2(0, 23),
});
}
category.AddChild(new PanelContainer
{
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#464966")},
Children =
{
new Label
{
Text = Loc.GetString("late-join-gui-department-jobs-label", ("departmentName", department))
}
}
});
_jobCategories[department] = category;
jobList.AddChild(category);
}
var jobButton = new JobButton(job.ID);
var jobSelector = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
HorizontalExpand = true
};
var icon = new TextureRect
{
TextureScale = (2, 2),
Stretch = TextureRect.StretchMode.KeepCentered
};
if (job.Icon != null)
{
var specifier = new SpriteSpecifier.Rsi(new ResourcePath("/Textures/Interface/Misc/job_icons.rsi"), job.Icon);
icon.Texture = specifier.Frame0();
}
jobSelector.AddChild(icon);
var jobLabel = new Label
{
Text = job.Name
};
jobSelector.AddChild(jobLabel);
jobButton.AddChild(jobSelector);
category.AddChild(jobButton);
jobButton.OnPressed += _ =>
{
SelectedId?.Invoke(jobButton.JobId);
};
if (!gameTicker.JobsAvailable.Contains(job.ID))
{
jobButton.Disabled = true;
}
_jobButtons[job.ID] = jobButton;
}
}
SelectedId += jobId =>
SelectedId += x =>
{
var (station, jobId) = x;
Logger.InfoS("latejoin", $"Late joining as ID: {jobId}");
_consoleHost.ExecuteCommand($"joingame {CommandParsing.Escape(jobId)}");
_consoleHost.ExecuteCommand($"joingame {CommandParsing.Escape(jobId)} {station.Id}");
Close();
};
gameTicker.LobbyJobsAvailableUpdated += JobsAvailableUpdated;
}
private void JobsAvailableUpdated(IReadOnlyList<string> jobs)
private void RebuildUI()
{
foreach (var (id, button) in _jobButtons)
_base.RemoveAllChildren();
_jobLists.Clear();
_jobButtons.Clear();
_jobCategories.Clear();
var gameTicker = EntitySystem.Get<ClientGameTicker>();
foreach (var (id, name) in gameTicker.StationNames)
{
button.Disabled = !jobs.Contains(id);
var jobList = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
var collapseButton = new ContainerButton()
{
HorizontalAlignment = HAlignment.Right,
ToggleMode = true,
Children =
{
new TextureRect
{
StyleClasses = { OptionButton.StyleClassOptionTriangle },
Margin = new Thickness(8, 0),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
}
}
};
_base.AddChild(new StripeBack()
{
Children = {
new PanelContainer()
{
Children =
{
new Label()
{
StyleClasses = { "LabelBig" },
Text = $"NTSS {name}",
Align = Label.AlignMode.Center,
},
collapseButton
}
}
}
});
var jobListScroll = new ScrollContainer()
{
VerticalExpand = true,
Children = {jobList},
Visible = false,
};
if (_jobLists.Count == 0)
jobListScroll.Visible = true;
_jobLists.Add(jobListScroll);
_base.AddChild(jobListScroll);
collapseButton.OnToggled += _ =>
{
foreach (var section in _jobLists)
{
section.Visible = false;
}
jobListScroll.Visible = true;
};
var firstCategory = true;
foreach (var job in gameTicker.JobsAvailable[id].OrderBy(x => x.Key))
{
var prototype = _prototypeManager.Index<JobPrototype>(job.Key);
foreach (var department in prototype.Departments)
{
if (!_jobCategories.TryGetValue(id, out var _))
_jobCategories[id] = new Dictionary<string, BoxContainer>();
if (!_jobButtons.TryGetValue(id, out var _))
_jobButtons[id] = new Dictionary<string, JobButton>();
if (!_jobCategories[id].TryGetValue(department, out var category))
{
category = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
Name = department,
ToolTip = Loc.GetString("late-join-gui-jobs-amount-in-department-tooltip",
("departmentName", department))
};
if (firstCategory)
{
firstCategory = false;
}
else
{
category.AddChild(new Control
{
MinSize = new Vector2(0, 23),
});
}
category.AddChild(new PanelContainer
{
Children =
{
new Label
{
StyleClasses = { "LabelBig" },
Text = Loc.GetString("late-join-gui-department-jobs-label", ("departmentName", department))
}
}
});
_jobCategories[id][department] = category;
jobList.AddChild(category);
}
var jobButton = new JobButton(prototype.ID, job.Value);
var jobSelector = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
HorizontalExpand = true
};
var icon = new TextureRect
{
TextureScale = (2, 2),
Stretch = TextureRect.StretchMode.KeepCentered
};
if (prototype.Icon != null)
{
var specifier = new SpriteSpecifier.Rsi(new ResourcePath("/Textures/Interface/Misc/job_icons.rsi"), prototype.Icon);
icon.Texture = specifier.Frame0();
}
jobSelector.AddChild(icon);
var jobLabel = new Label
{
Text = job.Value >= 0 ?
Loc.GetString("late-join-gui-job-slot-capped", ("jobName", prototype.Name), ("amount", job.Value)) :
Loc.GetString("late-join-gui-job-slot-uncapped", ("jobName", prototype.Name))
};
jobSelector.AddChild(jobLabel);
jobButton.AddChild(jobSelector);
category.AddChild(jobButton);
jobButton.OnPressed += _ =>
{
SelectedId?.Invoke((id, jobButton.JobId));
};
if (job.Value == 0)
{
jobButton.Disabled = true;
}
_jobButtons[id][prototype.ID] = jobButton;
}
}
}
}
private void JobsAvailableUpdated(IReadOnlyDictionary<StationId, Dictionary<string, int>> _)
{
RebuildUI();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
@@ -184,10 +255,12 @@ namespace Content.Client.LateJoin
class JobButton : ContainerButton
{
public string JobId { get; }
public int Amount { get; }
public JobButton(string jobId)
public JobButton(string jobId, int amount)
{
JobId = jobId;
Amount = amount;
AddStyleClass(StyleClassButton);
}
}