6
2025-11-07 12:32:48 +03:00

222 lines
8.4 KiB
C#

using System.Linq;
using Content.Client._NF.LateJoin.Interfaces;
using Content.Client._NF.LateJoin.ListItems;
using Content.Client.Lobby;
using Content.Client.Players.PlayTimeTracking;
using Content.Shared._NF.Shipyard.Prototypes;
using Content.Shared.GameTicking;
using Content.Shared.Preferences;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client._NF.LateJoin.Controls;
[GenerateTypedNameReferences]
public sealed partial class CrewPickerControl : PickerControl
{
[Dependency] private readonly ILocalizationManager _loc = default!;
[Dependency] private readonly IEntitySystemManager _entitySystem = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly JobRequirementsManager _jobReqs = default!;
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
private readonly SpriteSystem _spriteSystem;
private Dictionary<NetEntity, StationJobInformation> _lobbyJobs = new();
private CrewListItem.ViewState? _lastSelectedStation;
public Action<NetEntity, string>? OnJobJoined;
private bool _hideJoblessShips = true;
public CrewPickerControl()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_spriteSystem = _entitySystem.GetEntitySystem<SpriteSystem>();
HideJoblessShipsCheckbox.OnPressed += _ => ToggleHideJoblessShips();
HideJoblessShipsCheckbox.Pressed = _hideJoblessShips;
}
public override void UpdateUi(IReadOnlyDictionary<NetEntity, StationJobInformation> obj)
{
_lobbyJobs = new Dictionary<NetEntity, StationJobInformation>(obj);
StationItemList.RemoveAllChildren();
foreach (var stationViewState in BuildStationViewStateList(_lobbyJobs))
{
var item = new CrewListItem(stationViewState);
item.StationButton.OnPressed += _ => OnStationPressed(stationViewState);
StationItemList.AddChild(item);
// Update displayed information if we get a new state update.
if (_lastSelectedStation != null && stationViewState.StationEntity == _lastSelectedStation.StationEntity)
_lastSelectedStation = stationViewState;
}
// Build station jobs, the right section of the screen.
StationJobItemList.RemoveAllChildren();
if (_lastSelectedStation != null && obj.TryGetValue(_lastSelectedStation.StationEntity, out var stationInfo))
{
foreach (var jobViewState in BuildJobViewStateList(stationInfo))
{
var item = new JobListItem(jobViewState);
item.OnPressed += _ =>
{
OnJobJoined?.Invoke(_lastSelectedStation.StationEntity, jobViewState.JobId);
};
StationJobItemList.AddChild(item);
}
}
StationName.Text = _lastSelectedStation?.StationName ?? "";
StationDescription.SetMessage(BuildDescription(_lastSelectedStation));
}
private void ToggleHideJoblessShips()
{
_hideJoblessShips = HideJoblessShipsCheckbox.Pressed;
UpdateUi(_lobbyJobs);
}
private void OnStationPressed(CrewListItem.ViewState stationItemViewState)
{
_lastSelectedStation = stationItemViewState;
UpdateUi(_lobbyJobs);
}
private List<JobListItem.ViewState> BuildJobViewStateList(StationJobInformation jobInformation)
{
var viewStateList = new List<JobListItem.ViewState>();
foreach (var (jobPrototype, jobCount) in jobInformation.JobsAvailable)
{
if (_preferencesManager.Preferences?.SelectedCharacter is not HumanoidCharacterProfile profile)
{
continue;
}
var prototype = _prototypeManager.Index(jobPrototype);
var jobName = prototype.LocalizedName + jobCount.WrapJobCountInParentheses();
Texture? texture = null;
if (_prototypeManager.TryIndex(prototype.Icon, out var jobIcon))
{
texture = _spriteSystem.Frame0(jobIcon.Icon);
}
var buttonTooltip = "";
if (!_jobReqs.IsAllowed(prototype, profile, out var denyReason))
{
buttonTooltip = denyReason.ToString();
}
var isButtonDisabled = jobCount == 0 || !_jobReqs.IsAllowed(prototype, profile, out _);
var viewState = new JobListItem.ViewState(
jobId: jobPrototype,
jobName: jobName,
toolTip: buttonTooltip,
disabled: isButtonDisabled,
jobIcon: texture
);
viewStateList.Add(viewState);
}
return viewStateList;
}
/**
* Convert some raw dictionary data to a view state model that is more readable.
*
* @param obj Dictionary of station entities to job prototypes.
* @param stationNames Dictionary of station entities to station names.
* @return List of view states for each station.
*/
private List<CrewListItem.ViewState> BuildStationViewStateList(
IReadOnlyDictionary<NetEntity, StationJobInformation> obj)
{
var stationList = obj.Where(kvp => !kvp.Value.IsLateJoinStation).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
var viewStateList = new List<CrewListItem.ViewState>();
foreach (var (stationEntity, stationJobInformation) in stationList)
{
if (_hideJoblessShips
&& !stationJobInformation.JobsAvailable.Any(x => x.Value != 0))
{
continue;
}
var viewState = new CrewListItem.ViewState(
stationEntity,
stationJobInformation.GetStationNameWithJobCount(),
"", // No subtext currently.
stationJobInformation.VesselDisplayInformation?.VesselAdvertisement != null
? _loc.GetString(stationJobInformation.VesselDisplayInformation.VesselAdvertisement)
: "",
_lastSelectedStation?.StationEntity == stationEntity,
"", // No icons currently.
stationJobInformation?.VesselDisplayInformation?.Vessel
);
// Always select the first station in the list if none is selected yet.
// This is because otherwise the right side of the screen would then be a blank space.
if (_lastSelectedStation == null)
{
_lastSelectedStation = viewState;
viewState.Selected = true;
}
viewStateList.Add(viewState);
}
// Sort 0 to the end of the list in the order it is in the dictionary.
// Sort 1 first, 2 second, etc.
return viewStateList.ToList();
}
private FormattedMessage BuildDescription(CrewListItem.ViewState? state)
{
FormattedMessage msg = new();
if (state == null)
return msg;
if (_prototypeManager.TryIndex<VesselPrototype>(state.Vessel, out var proto))
{
msg.AddMarkupPermissive(Loc.GetString("frontier-lobby-crew-vessel", ("name", proto.Name)));
msg.PushNewline();
if (proto.Classes.Count > 0)
{
msg.AddMarkupPermissive(Loc.GetString("frontier-lobby-crew-class-prefix"));
// Assuming a comma-separated string is fine
var comma = false;
foreach (var protoClass in proto.Classes)
{
if (comma)
msg.AddMarkupPermissive(", ");
else
comma = true;
msg.AddMarkupOrThrow(Loc.GetString($"shipyard-console-class-{protoClass}"));
}
msg.PushNewline();
}
msg.AddMarkupPermissive(Loc.GetString("frontier-lobby-crew-size", ("size", Loc.GetString($"shipyard-console-category-{proto.Category}"))));
msg.PushNewline();
msg.PushNewline();
}
if (state.StationDescription != null)
{
msg.AddMarkupPermissive(Loc.GetString("frontier-lobby-crew-class-advertisement"));
msg.PushNewline();
msg.AddMarkupPermissive(state.StationDescription);
}
return msg;
}
}