* keeye * random locks for demiplanes * blank keys, material keys * craft blank keys * key file * fix skill tree UIScaling * fix audio and sounds and prediction * delete crowbar, merge its into pickaxe * QoL key shaping * lock introdusing * QoL progress lockpicking * examinable lock * lock insert * mithril lockkpick * Update wall_dirt.yml
228 lines
8.0 KiB
C#
228 lines
8.0 KiB
C#
using System.Linq;
|
|
using System.Numerics;
|
|
using Content.Shared._CP14.Skill;
|
|
using Content.Shared._CP14.Skill.Components;
|
|
using Content.Shared._CP14.Skill.Prototypes;
|
|
using Content.Shared._CP14.Skill.Restrictions;
|
|
using Robust.Client.AutoGenerated;
|
|
using Robust.Client.Graphics;
|
|
using Robust.Client.UserInterface;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Client.UserInterface.XAML;
|
|
using Robust.Client.Utility;
|
|
using Robust.Shared.Input;
|
|
using Robust.Shared.Prototypes;
|
|
|
|
namespace Content.Client._CP14.Skill.Ui;
|
|
|
|
[GenerateTypedNameReferences]
|
|
public sealed partial class CP14SkillTreeGraphControl : BoxContainer
|
|
{
|
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
|
private readonly CP14SharedSkillSystem _skillSystem;
|
|
|
|
private Entity<CP14SkillStorageComponent>? _player;
|
|
|
|
private IEnumerable<CP14SkillPrototype> _allSkills;
|
|
|
|
private CP14SkillPrototype? _hoveredNode;
|
|
private CP14SkillPrototype? _selectedNode;
|
|
public CP14SkillTreePrototype? Tree;
|
|
|
|
private bool dragging = false;
|
|
private Vector2 _previousMousePosition = Vector2.Zero;
|
|
private Vector2 _globalOffset = new (60,60);
|
|
|
|
private const float GridSize = 25f;
|
|
|
|
public event Action<CP14SkillPrototype?>? OnNodeSelected;
|
|
public event Action<Vector2>? OnOffsetChanged;
|
|
|
|
public CP14SkillTreeGraphControl()
|
|
{
|
|
IoCManager.InjectDependencies(this);
|
|
RobustXamlLoader.Load(this);
|
|
|
|
_skillSystem = _entManager.System<CP14SharedSkillSystem>();
|
|
|
|
_allSkills = _proto.EnumeratePrototypes<CP14SkillPrototype>();
|
|
_proto.PrototypesReloaded += _ => _allSkills = _proto.EnumeratePrototypes<CP14SkillPrototype>().OrderBy(skill => _skillSystem.GetSkillName(skill)).ToList();
|
|
OnOffsetChanged?.Invoke(_globalOffset);
|
|
}
|
|
|
|
public void UpdateState(Entity<CP14SkillStorageComponent>? player)
|
|
{
|
|
_player = player;
|
|
OnOffsetChanged?.Invoke(_globalOffset);
|
|
}
|
|
|
|
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
|
|
{
|
|
base.KeyBindDown(args);
|
|
|
|
if (args.Handled)
|
|
return;
|
|
|
|
if (args.Function == EngineKeyFunctions.UIClick)
|
|
{
|
|
dragging = true;
|
|
|
|
if (_hoveredNode == null)
|
|
return;
|
|
|
|
OnNodeSelected?.Invoke(_hoveredNode);
|
|
UserInterfaceManager.ClickSound();
|
|
_selectedNode = _hoveredNode;
|
|
}
|
|
|
|
if (args.Function == EngineKeyFunctions.UIRightClick)
|
|
{
|
|
_globalOffset = new Vector2(60, 60); // Reset offset on right click
|
|
OnOffsetChanged?.Invoke(_globalOffset);
|
|
}
|
|
}
|
|
|
|
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
|
|
{
|
|
base.KeyBindUp(args);
|
|
|
|
if (args.Handled || args.Function != EngineKeyFunctions.UIClick)
|
|
return;
|
|
|
|
dragging = false;
|
|
}
|
|
|
|
protected override void ExitedTree()
|
|
{
|
|
base.ExitedTree();
|
|
|
|
OnNodeSelected?.Invoke(null);
|
|
}
|
|
|
|
protected override void Draw(DrawingHandleScreen handle)
|
|
{
|
|
base.Draw(handle);
|
|
|
|
_hoveredNode = null;
|
|
if (_player == null || Tree == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var cursor = (UserInterfaceManager.MousePositionScaled.Position * UIScale) - GlobalPixelPosition;
|
|
|
|
if (dragging)
|
|
{
|
|
var delta = cursor - _previousMousePosition;
|
|
_globalOffset += delta;
|
|
OnOffsetChanged?.Invoke(_globalOffset);
|
|
}
|
|
|
|
_previousMousePosition = cursor;
|
|
|
|
var playerSkills = _player.Value.Comp.LearnedSkills;
|
|
|
|
//Draw connection lines
|
|
foreach (var skill in _allSkills)
|
|
{
|
|
if (skill.Tree != Tree)
|
|
continue;
|
|
|
|
var fromPos = skill.SkillUiPosition * GridSize * UIScale + _globalOffset;
|
|
|
|
foreach (var req in skill.Restrictions)
|
|
{
|
|
switch (req)
|
|
{
|
|
case NeedPrerequisite prerequisite:
|
|
if (!_proto.TryIndex(prerequisite.Prerequisite, out var prerequisiteSkill))
|
|
continue;
|
|
|
|
if (prerequisiteSkill.Tree != Tree)
|
|
continue;
|
|
|
|
var learned = playerSkills.Contains(skill.ID);
|
|
|
|
var toPos = prerequisiteSkill.SkillUiPosition * GridSize * UIScale + _globalOffset;
|
|
var color = learned ? Color.White : Color.FromSrgb(new Color(0.7f, 0.7f, 0.7f));
|
|
handle.DrawLine(fromPos, toPos, color);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Draw skill icons over lines
|
|
foreach (var skill in _allSkills)
|
|
{
|
|
if (skill.Tree != Tree)
|
|
continue;
|
|
|
|
//TODO: Not optimized, recalculates every frame. Needs to be calculated on state update and cached.
|
|
var canBeLearned = _skillSystem.CanLearnSkill(_player.Value, skill, _player.Value.Comp);
|
|
var pos = skill.SkillUiPosition * GridSize * UIScale + _globalOffset;
|
|
|
|
// Base skill icon
|
|
var baseTexture = skill.Icon.Frame0();
|
|
var baseSize = new Vector2(baseTexture.Width, baseTexture.Height) * 1.5f * UIScale;
|
|
var baseQuad = new UIBox2(pos - baseSize / 2, pos + baseSize / 2);
|
|
|
|
var hovered = (cursor - pos).LengthSquared() <= (baseSize.X / 2) * (baseSize.X / 2);
|
|
|
|
// Frame
|
|
var frameTexture = Tree.FrameIcon.Frame0();
|
|
var frameSize = new Vector2(frameTexture.Width, frameTexture.Height) * 1.5f * UIScale;
|
|
var frameQuad = new UIBox2(pos - frameSize / 2, pos + frameSize / 2);
|
|
handle.DrawTextureRect(frameTexture, frameQuad, canBeLearned ? Color.White : Color.FromSrgb(new Color(0.7f, 0.7f, 0.7f)));
|
|
|
|
// Selected Skill
|
|
if (_selectedNode == skill)
|
|
{
|
|
var selectedTexture = Tree.SelectedIcon.Frame0();
|
|
var selectedSize = new Vector2(selectedTexture.Width, selectedTexture.Height) * 1.5f * UIScale;
|
|
var selectedQuad = new UIBox2(pos - selectedSize / 2, pos + selectedSize / 2);
|
|
handle.DrawTextureRect(selectedTexture, selectedQuad, Color.White);
|
|
}
|
|
|
|
// Hovered Skill
|
|
if (hovered)
|
|
{
|
|
_hoveredNode = skill;
|
|
var hoveredTexture = Tree.HoveredIcon.Frame0();
|
|
var hoveredSize = new Vector2(hoveredTexture.Width, hoveredTexture.Height) * 1.5f * UIScale;
|
|
var hoveredQuad = new UIBox2(pos - hoveredSize / 2, pos + hoveredSize / 2);
|
|
handle.DrawTextureRect(hoveredTexture, hoveredQuad, Color.White);
|
|
}
|
|
|
|
var learned = playerSkills.Contains(skill.ID);
|
|
var allowedToLearn = _skillSystem.AllowedToLearn(_player.Value, skill, _player.Value.Comp);
|
|
|
|
// Learned Skill
|
|
if (learned)
|
|
{
|
|
var learnedTexture = Tree.LearnedIcon.Frame0();
|
|
var learnedSize = new Vector2(learnedTexture.Width, learnedTexture.Height) * 1.5f * UIScale;
|
|
var learnedQuad = new UIBox2(pos - learnedSize / 2, pos + learnedSize / 2);
|
|
handle.DrawTextureRect(learnedTexture, learnedQuad, Color.White);
|
|
}
|
|
else if (canBeLearned)
|
|
{
|
|
var availableTexture = Tree.AvailableIcon.Frame0();
|
|
var availableSize = new Vector2(availableTexture.Width, availableTexture.Height) * 1.5f * UIScale;
|
|
var availableQuad = new UIBox2(pos - availableSize / 2, pos + availableSize / 2);
|
|
handle.DrawTextureRect(availableTexture, availableQuad, Color.White);
|
|
}
|
|
|
|
var iconColor = allowedToLearn switch
|
|
{
|
|
true when !learned => Color.FromSrgb(new Color(0.7f, 0.7f, 0.7f)),
|
|
false when !learned => Color.FromSrgb(new Color(0f, 0f, 0f)),
|
|
_ => Color.White
|
|
};
|
|
|
|
handle.DrawTextureRect(baseTexture, baseQuad, iconColor);
|
|
}
|
|
}
|
|
}
|