Files
ss14-wl/Content.Client/UserInterface/Systems/Character/CharacterUIController.cs
Zekins adc7478264 Система навыков (#324)
* skills

* engine

* fix

* fixtests
2025-10-19 18:38:40 +03:00

333 lines
10 KiB
C#

using System.Linq;
using Content.Client._WL.Skills.Ui; // WL-Skills
using Content.Client._WL.DynamicText.UI; // WL-Chages
using Content.Client.CharacterInfo;
using Content.Client.Gameplay;
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Systems.Character.Controls;
using Content.Client.UserInterface.Systems.Character.Windows;
using Content.Client.UserInterface.Systems.Objectives.Controls;
using Content.Shared._WL.Skills; // WL-Skills
using Content.Shared._WL.Skills.Components; // WL-Skills
using Content.Shared.Input;
using Content.Shared.Mind;
using Content.Shared.Mind.Components;
using Content.Shared.Roles;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input.Binding;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using static Content.Client.CharacterInfo.CharacterInfoSystem;
using static Robust.Client.UserInterface.Controls.BaseButton;
namespace Content.Client.UserInterface.Systems.Character;
[UsedImplicitly]
public sealed class CharacterUIController : UIController, IOnStateEntered<GameplayState>, IOnStateExited<GameplayState>, IOnSystemChanged<CharacterInfoSystem>
{
[Dependency] private readonly IEntityManager _ent = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityNetworkManager _entityNetworkManager = default!; // WL-Skills
//WL-Changes-Start
[Dependency] private readonly DynamicTextUIController _dynamicText = default!;
//WL-Changes-end
[UISystemDependency] private readonly CharacterInfoSystem _characterInfo = default!;
[UISystemDependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<MindRoleTypeChangedEvent>(OnRoleTypeChanged);
}
private CharacterWindow? _window;
private SkillsWindow? _skillsWindow; // WL-Skills
private MenuButton? CharacterButton => UIManager.GetActiveUIWidgetOrNull<MenuBar.Widgets.GameTopMenuBar>()?.CharacterButton;
public void OnStateEntered(GameplayState state)
{
DebugTools.Assert(_window == null);
_window = UIManager.CreateWindow<CharacterWindow>();
LayoutContainer.SetAnchorPreset(_window, LayoutContainer.LayoutPreset.CenterTop);
_window.OnClose += DeactivateButton;
_window.OnOpen += ActivateButton;
//WL-Changes-Start
_window.SkillsButton.OnPressed += OnSkillsButtonPressed;
if (_player.LocalEntity.HasValue && _ent.HasComponent<SkillsComponent>(_player.LocalEntity))
_window.SkillsButton.Disabled = false;
_window.DynamicTextButton.OnPressed += _ =>
{
_dynamicText.OpenWindow();
};
//WL-Changes-End
CommandBinds.Builder
.Bind(ContentKeyFunctions.OpenCharacterMenu,
InputCmdHandler.FromDelegate(_ => ToggleWindow()))
.Register<CharacterUIController>();
}
public void OnStateExited(GameplayState state)
{
if (_window != null)
{
_window.Close();
_window = null;
}
CommandBinds.Unregister<CharacterUIController>();
}
public void OnSystemLoaded(CharacterInfoSystem system)
{
system.OnCharacterUpdate += CharacterUpdated;
_player.LocalPlayerDetached += CharacterDetached;
}
public void OnSystemUnloaded(CharacterInfoSystem system)
{
system.OnCharacterUpdate -= CharacterUpdated;
_player.LocalPlayerDetached -= CharacterDetached;
}
public void UnloadButton()
{
if (CharacterButton == null)
{
return;
}
CharacterButton.OnPressed -= CharacterButtonPressed;
}
public void LoadButton()
{
if (CharacterButton == null)
{
return;
}
CharacterButton.OnPressed += CharacterButtonPressed;
}
private void DeactivateButton()
{
if (CharacterButton == null)
{
return;
}
CharacterButton.Pressed = false;
}
private void ActivateButton()
{
if (CharacterButton == null)
{
return;
}
CharacterButton.Pressed = true;
}
private void CharacterUpdated(CharacterData data)
{
if (_window == null)
{
return;
}
var (entity, job, objectives, briefing, entityName) = data;
_window.SpriteView.SetEntity(entity);
UpdateRoleType();
_window.NameLabel.Text = entityName;
_window.SubText.Text = job;
_window.Objectives.RemoveAllChildren();
_window.ObjectivesLabel.Visible = objectives.Any();
foreach (var (groupId, conditions) in objectives)
{
var objectiveControl = new CharacterObjectiveControl
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
Modulate = Color.Gray
};
var objectiveText = new FormattedMessage();
objectiveText.TryAddMarkup(groupId, out _);
var objectiveLabel = new RichTextLabel
{
StyleClasses = { StyleNano.StyleClassTooltipActionTitle }
};
objectiveLabel.SetMessage(objectiveText);
objectiveControl.AddChild(objectiveLabel);
foreach (var condition in conditions)
{
var conditionControl = new ObjectiveConditionsControl();
conditionControl.ProgressTexture.Texture = _sprite.Frame0(condition.Icon);
conditionControl.ProgressTexture.Progress = condition.Progress;
var titleMessage = new FormattedMessage();
var descriptionMessage = new FormattedMessage();
titleMessage.AddText(condition.Title);
descriptionMessage.AddText(condition.Description);
conditionControl.Title.SetMessage(titleMessage);
conditionControl.Description.SetMessage(descriptionMessage);
objectiveControl.AddChild(conditionControl);
}
_window.Objectives.AddChild(objectiveControl);
}
if (briefing != null)
{
var briefingControl = new ObjectiveBriefingControl();
var text = new FormattedMessage();
text.PushColor(Color.Yellow);
text.AddText(briefing);
briefingControl.Label.SetMessage(text);
_window.Objectives.AddChild(briefingControl);
}
var controls = _characterInfo.GetCharacterInfoControls(entity);
foreach (var control in controls)
{
_window.Objectives.AddChild(control);
}
_window.RolePlaceholder.Visible = briefing == null && !controls.Any() && !objectives.Any();
}
private void OnRoleTypeChanged(MindRoleTypeChangedEvent ev, EntitySessionEventArgs _)
{
UpdateRoleType();
}
private void UpdateRoleType()
{
if (_window == null || !_window.IsOpen)
return;
if (!_ent.TryGetComponent<MindContainerComponent>(_player.LocalEntity, out var container)
|| container.Mind is null)
return;
if (!_ent.TryGetComponent<MindComponent>(container.Mind.Value, out var mind))
return;
if (!_prototypeManager.TryIndex(mind.RoleType, out var proto))
Log.Error($"Player '{_player.LocalSession}' has invalid Role Type '{mind.RoleType}'. Displaying default instead");
_window.RoleType.Text = Loc.GetString(proto?.Name ?? "role-type-crew-aligned-name");
_window.RoleType.FontColorOverride = proto?.Color ?? Color.White;
}
private void CharacterDetached(EntityUid uid)
{
CloseWindow();
}
private void CharacterButtonPressed(ButtonEventArgs args)
{
ToggleWindow();
}
private void CloseWindow()
{
_window?.Close();
}
private void ToggleWindow()
{
if (_window == null)
return;
CharacterButton?.SetClickPressed(!_window.IsOpen);
if (_window.IsOpen)
{
CloseWindow();
}
else
{
_characterInfo.RequestCharacterInfo();
_window.Open();
}
}
// WL-Skills-start
private void OnSkillsButtonPressed(ButtonEventArgs args)
{
OpenSkillsWindow();
}
private void OpenSkillsWindow()
{
if (_player.LocalEntity is not { } entity)
return;
if (_skillsWindow != null)
{
_skillsWindow.Close();
_skillsWindow = null;
}
var skillsSystem = _ent.System<SharedSkillsSystem>();
if (!_ent.TryGetComponent<SkillsComponent>(entity, out var skillsComp))
return;
var jobId = skillsComp.CurrentJob;
var defaultSkills = skillsSystem.GetDefaultSkillsForJob(jobId);
var totalPoints = skillsSystem.GetTotalPoints(entity, jobId, skillsComp);
var currentSkills = skillsComp.Skills.ToDictionary(
kvp => (byte)kvp.Key,
kvp => kvp.Value
);
var skillsWindow = new SkillsWindow(
jobId ?? "unknown",
currentSkills,
defaultSkills,
totalPoints,
true
);
_skillsWindow = skillsWindow;
skillsWindow.OnSkillChanged += (changedJobId, skillKey, newLevel) =>
{
if (_player.LocalEntity is not { } localEntity)
return;
var skillType = (SkillType)skillKey;
var ev = new SelectSkillPressedEvent(_ent.GetNetEntity(localEntity), skillType, newLevel, changedJobId);
_entityNetworkManager.SendSystemNetworkMessage(ev);
};
skillsWindow.OpenCentered();
}
// WL-Skills-end
}