fish-station/Content.Client/_Sunrise/InteractionsPanel/InteractionsUIWindow.xaml.cs
2025-12-26 17:44:36 +03:00

1174 lines
38 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Linq;
using System.Numerics;
using Content.Client._Sunrise.InteractionsPanel.Models;
using Content.Shared._Sunrise.InteractionsPanel.Data.Components;
using Content.Shared._Sunrise.InteractionsPanel.Data.Prototypes;
using Content.Shared._Sunrise.InteractionsPanel.Data.UI;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client._Sunrise.InteractionsPanel;
[GenerateTypedNameReferences]
public sealed partial class InteractionsUIWindow : DefaultWindow
{
#region Dependencies
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly CustomInteractionService _customInteractionService = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] protected readonly ILocalizationManager Loc = default!;
private readonly SpriteSystem _spriteSystem;
#endregion
#region Color Scheme
private static readonly Color PrimaryColor = new Color(0, 212, 255); // #00d4ff
private static readonly Color SecondaryColor = new Color(184, 230, 255); // #b8e6ff
private static readonly Color BackgroundMedium = new Color(26, 35, 50); // #1a2332
private static readonly Color BackgroundLight = new Color(36, 51, 64); // #243340
private static readonly Color BackgroundHighlight = new Color(44, 68, 85); // #2c4455
private static readonly Color ErrorColor = new Color(255, 69, 58); // #ff453a
private static readonly Color SuccessColor = new Color(48, 209, 88); // #30d158
private static readonly Color TextMuted = new Color(142, 142, 147); // #8e8e93
private static readonly Color FavoriteColor = new Color(255, 214, 10); // #ffd60a
private static readonly Color FavoriteHoverColor = new Color(255, 180, 0); // #ffb400
#endregion
#region Properties
private InteractionsWindowBoundUserInterface? _owner;
private List<string>? _currentInteractionIds;
private string _searchText = string.Empty;
private string _customSearchText = string.Empty;
private Dictionary<Button, string> _buttonInteractions = new();
private HashSet<string> _customInteractionIds = new();
private readonly HashSet<string> _openCategories = new();
private readonly HashSet<string> _favoriteInteractions = new();
#endregion
#region Initialization
public InteractionsUIWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_spriteSystem = _entityManager.System<SpriteSystem>();
MainTabContainer.SetTabTitle(0, "Интеракции");
MainTabContainer.SetTabTitle(1, "Кастом");
MainTabContainer.SetTabTitle(2, "Настройки");
SearchInput.OnTextChanged += OnSearchTextChanged;
CustomInteractionSearchInput.OnTextChanged += OnCustomInteractionSearchTextChanged;
NewCustomInteractionButton.OnPressed += OnNewCustomInteractionPressed;
LoadSavedInteractions();
LoadOpenCategories();
LoadFavoriteInteractions();
InitializeSettings();
}
private void InitializeSettings()
{
var currentVisibility = _cfg.GetCVar(InteractionsCVars.EmoteVisibility);
var currentExpand = _cfg.GetCVar(InteractionsCVars.Expand);
EmoteVisibilityCheckBox.Pressed = currentVisibility;
HideTopPanelCheckBox.Pressed = currentExpand;
ApplySettingsButton.OnPressed += OnApplySettings;
TopUserInfoBox.Visible = !currentExpand;
}
private void OnApplySettings(BaseButton.ButtonEventArgs args)
{
var emoteVisible = EmoteVisibilityCheckBox.Pressed;
var expand = HideTopPanelCheckBox.Pressed;
SetEmoteVisibility(emoteVisible);
SetExpanded(expand);
}
private void OnSearchTextChanged(LineEdit.LineEditEventArgs args)
{
_searchText = args.Text.ToLowerInvariant();
if (_currentInteractionIds != null)
{
_buttonInteractions.Clear();
_customInteractionIds.Clear();
PopulateCategories(_currentInteractionIds);
}
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
UpdateButtonsState();
}
public override void Close()
{
_cfg.SetCVar(InteractionsCVars.WindowPosX, (int)Position.X);
_cfg.SetCVar(InteractionsCVars.WindowPosY, (int)Position.Y);
base.Close();
}
public void SavePos()
{
_cfg.SetCVar(InteractionsCVars.WindowPosX, (int)Position.X);
_cfg.SetCVar(InteractionsCVars.WindowPosY, (int)Position.Y);
_cfg.SaveToFile();
}
private bool IsInteractionOnCooldown(string interactionId)
{
var userEntity = _owner?.Owner ?? default;
if (!_entityManager.TryGetComponent<InteractionsComponent>(userEntity, out var component))
return false;
if (!component.InteractionCooldowns.TryGetValue(interactionId, out var endTime))
return false;
return _gameTiming.CurTime < endTime;
}
private void UpdateButtonsState()
{
var userEntity = _owner?.Owner ?? default;
if (!_entityManager.TryGetComponent<InteractionsComponent>(userEntity, out var component))
return;
foreach (var (button, interactionId) in _buttonInteractions)
{
var isCustom = _customInteractionIds.Contains(interactionId);
var interactionName = "Unknown";
if (!isCustom)
{
if (_prototypeManager.TryIndex<InteractionPrototype>(interactionId, out var prototype))
interactionName = Loc.GetString(prototype.Name);
else
continue;
}
else
{
var customInteraction = _customInteractionService.GetInteraction(interactionId);
if (customInteraction != null)
{
interactionName = customInteraction.Name;
}
}
var isOnCooldown = IsInteractionOnCooldown(interactionId);
button.Disabled = isOnCooldown;
if (isOnCooldown && component.InteractionCooldowns.TryGetValue(interactionId, out var endTime))
{
var remainingTime = endTime - _gameTiming.CurTime;
if (remainingTime > TimeSpan.Zero)
{
var seconds = (int)Math.Ceiling(remainingTime.TotalSeconds);
button.Text = $"{interactionName} ({seconds}с)";
}
}
else
{
button.Text = interactionName;
}
}
}
#endregion
#region State Management
public void UpdateState(NetEntity userEntity,
NetEntity targetEntity,
List<string> availableInteractionIds)
{
UpdateEntityInformation(userEntity, targetEntity);
_currentInteractionIds = availableInteractionIds;
_buttonInteractions.Clear();
_customInteractionIds.Clear();
PopulateCategories(availableInteractionIds);
}
private void UpdateEntityInformation(
NetEntity userEntity,
NetEntity targetEntity)
{
var selfTargeting = userEntity == targetEntity;
var nameUser = _entityManager.GetComponentOrNull<MetaDataComponent>(_entityManager.GetEntity(userEntity));
UserSpriteView.SetEntity(_entityManager.GetEntity(userEntity));
NameUser.Text = $"{nameUser?.EntityName}";
TargetContainer.Visible = !selfTargeting;
UserBoxShit.HorizontalAlignment = selfTargeting ? HAlignment.Center : HAlignment.Left;
if (!selfTargeting)
{
TargetSpriteView.SetEntity(_entityManager.GetEntity(targetEntity));
var nameTarget = _entityManager.GetComponentOrNull<MetaDataComponent>(_entityManager.GetEntity(targetEntity));
NameTarget.Text = $"{nameTarget?.EntityName}";
TargetSpriteView.InvalidateArrange();
TargetSpriteView.InvalidateMeasure();
}
}
#endregion
#region UI Population
private void PopulateCategories(List<string> interactionIds)
{
CategoriesContainer.DisposeAllChildren();
var customInteractions = _customInteractionService.GetInteractions();
if (!string.IsNullOrEmpty(_searchText))
{
customInteractions = customInteractions
.Where(i => i.Name.ToLowerInvariant().Contains(_searchText) ||
i.Description.ToLowerInvariant().Contains(_searchText))
.ToList();
}
var categorizedInteractions = new Dictionary<string, (string Name, List<object> Interactions)>();
var favoriteInteractions = new List<object>();
foreach (var id in interactionIds)
{
if (!_prototypeManager.TryIndex<InteractionPrototype>(id, out var interaction))
continue;
if (!string.IsNullOrEmpty(_searchText))
{
var interactionName = interaction.Name.ToLowerInvariant();
var interactionDesc = interaction.Description != null ? interaction.Description.ToLowerInvariant() : "";
if (!interactionName.Contains(_searchText) && !interactionDesc.Contains(_searchText))
continue;
}
if (_favoriteInteractions.Contains(interaction.ID))
{
favoriteInteractions.Add(interaction);
}
var categoryId = interaction.Category.ToString();
if (!_prototypeManager.TryIndex(interaction.Category, out InteractionCategoryPrototype? category))
continue;
if (!categorizedInteractions.TryGetValue(categoryId, out _))
{
var categoryName = Loc.GetString(category.Name);
categorizedInteractions[categoryId] = (categoryName, new List<object>());
}
if (!_favoriteInteractions.Contains(interaction.ID))
{
categorizedInteractions[categoryId].Interactions.Add(interaction);
}
}
foreach (var customInteraction in customInteractions)
{
var categoryId = customInteraction.CategoryId;
if (string.IsNullOrEmpty(categoryId) || !_prototypeManager.TryIndex<InteractionCategoryPrototype>(categoryId, out _))
continue;
if (_favoriteInteractions.Contains(customInteraction.Id))
{
favoriteInteractions.Add(customInteraction);
}
if (!categorizedInteractions.TryGetValue(categoryId, out _))
{
var category = _prototypeManager.Index<InteractionCategoryPrototype>(categoryId);
categorizedInteractions[categoryId] = (Loc.GetString(category.Name), new List<object>());
}
if (!_favoriteInteractions.Contains(customInteraction.Id))
{
categorizedInteractions[categoryId].Interactions.Add(customInteraction);
}
_customInteractionIds.Add(customInteraction.Id);
}
if (favoriteInteractions.Count > 0)
{
var sortedFavorites = favoriteInteractions
.OrderBy(i =>
{
return i switch
{
InteractionPrototype proto => proto.Name,
CustomInteraction custom => custom.Name,
_ => string.Empty
};
})
.ToList();
var favoritesCollapsible = CreateCategoryCollapsible("⭐ Избранные", sortedFavorites);
CategoriesContainer.AddChild(favoritesCollapsible);
}
if (categorizedInteractions.Count == 0 && favoriteInteractions.Count == 0)
{
var noResultsLabel = new Label
{
Text = "Ничего не найдено",
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
FontColorOverride = TextMuted,
Margin = new Thickness(0, 20, 0, 0)
};
CategoriesContainer.AddChild(noResultsLabel);
return;
}
var sortedCategories = categorizedInteractions
.OrderBy(kvp => kvp.Value.Name)
.ToList();
foreach (var (_, categoryData) in sortedCategories)
{
if (categoryData.Interactions.Count == 0)
continue;
var sortedInteractions = categoryData.Interactions
.OrderBy(i =>
{
return i switch
{
InteractionPrototype proto => proto.Name,
CustomInteraction custom => custom.Name,
_ => string.Empty
};
})
.ToList();
var collapsible = CreateCategoryCollapsible(categoryData.Name, sortedInteractions);
CategoriesContainer.AddChild(collapsible);
}
}
private Collapsible CreateCategoryCollapsible(string categoryName, List<object> interactions)
{
var heading = new CollapsibleHeading(categoryName)
{
ChevronMargin = new Thickness(6, 0, 10, 0),
MinHeight = 28,
Margin = new Thickness(0, 1, 0, 0)
};
heading.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = BackgroundMedium,
BorderColor = categoryName.StartsWith("⭐") ? FavoriteColor : PrimaryColor,
BorderThickness = new Thickness(0, 0, 0, 1)
};
var body = new CollapsibleBody
{
Margin = new Thickness(0, 0, 0, 0)
};
var collapsible = new Collapsible(heading, body);
heading.OnPressed += _ =>
{
collapsible.BodyVisible = !collapsible.BodyVisible;
if (collapsible.BodyVisible)
_openCategories.Add(categoryName);
else
_openCategories.Remove(categoryName);
SaveOpenCategories();
};
var interactionsContainer = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
HorizontalExpand = true,
Margin = new Thickness(0, 1, 0, 2),
};
foreach (var interaction in interactions)
{
BoxContainer buttonBox;
if (interaction is InteractionPrototype standardInteraction)
{
buttonBox = CreateInteractionButton(standardInteraction);
}
else if (interaction is CustomInteraction customInteraction)
{
buttonBox = CreateCustomInteractionButton(customInteraction);
}
else
{
continue;
}
interactionsContainer.AddChild(buttonBox);
}
body.AddChild(interactionsContainer);
collapsible.Margin = new Thickness(0, 0, 0, 2);
collapsible.BodyVisible = _openCategories.Contains(categoryName) || !string.IsNullOrEmpty(_searchText);
return collapsible;
}
private BoxContainer CreateInteractionButton(InteractionPrototype interaction)
{
var buttonBox = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
HorizontalExpand = true,
Margin = new Thickness(0, 1, 0, 0),
VerticalAlignment = VAlignment.Center
};
var isOnCooldown = IsInteractionOnCooldown(interaction.ID);
var button = new Button
{
Text = interaction.Name,
ToolTip = interaction.Description,
HorizontalExpand = true,
MinHeight = 40,
MaxHeight = 45,
StyleClasses = { StyleClass.ButtonSquare },
Disabled = isOnCooldown
};
if (interaction.Icon.HasValue && _prototypeManager.TryIndex(interaction.Icon.Value, out InteractionIconPrototype? iconProto))
{
var iconRect = new TextureRect
{
TextureScale = new Vector2(1.0f, 1.0f),
Stretch = TextureRect.StretchMode.KeepAspectCentered,
Texture = _spriteSystem.Frame0(iconProto.Icon),
HorizontalAlignment = HAlignment.Left,
VerticalAlignment = VAlignment.Center,
Margin = new Thickness(10, 0, 10, 0),
// MinSize = new Vector2(64, 64),
// MaxSize = new Vector2(64, 64)
};
button.AddChild(iconRect);
}
if (isOnCooldown)
{
button.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = new Color(BackgroundLight.R * 0.6f, BackgroundLight.G * 0.6f, BackgroundLight.B * 0.6f),
BorderColor = TextMuted,
BorderThickness = new Thickness(1)
};
}
else
{
button.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = BackgroundLight,
BorderColor = PrimaryColor,
BorderThickness = new Thickness(1)
};
}
_buttonInteractions[button] = interaction.ID;
if (isOnCooldown)
{
var userEntity = _owner?.Owner ?? default;
if (_entityManager.TryGetComponent<InteractionsComponent>(userEntity, out var component) &&
component.InteractionCooldowns.TryGetValue(interaction.ID, out var endTime))
{
var remainingTime = endTime - _gameTiming.CurTime;
if (remainingTime > TimeSpan.Zero)
{
var seconds = (int)Math.Ceiling(remainingTime.TotalSeconds);
button.Text = $"{interaction.Name} ({seconds}с)";
}
}
}
button.OnPressed += _ =>
{
ExecuteInteraction(interaction.ID, false);
};
buttonBox.AddChild(button);
var favoriteButton = new Button
{
MinSize = new Vector2(32, 45),
MaxSize = new Vector2(32, 45),
StyleClasses = { StyleClass.ButtonSquare },
Margin = new Thickness(2, 0, 0, 0),
VerticalAlignment = VAlignment.Center
};
var isFavorite = _favoriteInteractions.Contains(interaction.ID);
favoriteButton.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = isFavorite ? FavoriteColor : BackgroundLight,
BorderColor = isFavorite ? FavoriteColor : TextMuted,
BorderThickness = new Thickness(1)
};
var starIcon = new TextureRect
{
Texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/examine-star.png"))),
TextureScale = new Vector2(0.8f, 0.8f),
Stretch = TextureRect.StretchMode.KeepAspectCentered,
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
Modulate = isFavorite ? Color.White : TextMuted
};
favoriteButton.AddChild(starIcon);
favoriteButton.OnPressed += _ =>
{
ToggleFavorite(interaction.ID);
};
favoriteButton.OnMouseEntered += _ =>
{
favoriteButton.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = isFavorite ? FavoriteHoverColor : BackgroundHighlight,
BorderColor = isFavorite ? FavoriteHoverColor : PrimaryColor,
BorderThickness = new Thickness(1)
};
};
favoriteButton.OnMouseExited += _ =>
{
favoriteButton.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = isFavorite ? FavoriteColor : BackgroundLight,
BorderColor = isFavorite ? FavoriteColor : TextMuted,
BorderThickness = new Thickness(1)
};
};
buttonBox.AddChild(favoriteButton);
return buttonBox;
}
private BoxContainer CreateCustomInteractionButton(CustomInteraction interaction)
{
var buttonBox = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
HorizontalExpand = true,
Margin = new Thickness(0, 1, 0, 0),
VerticalAlignment = VAlignment.Center
};
var isOnCooldown = IsInteractionOnCooldown(interaction.Id);
var button = new Button
{
Text = interaction.Name,
ToolTip = interaction.Description,
HorizontalExpand = true,
MinHeight = 40,
MaxHeight = 45,
StyleClasses = { StyleClass.ButtonSquare },
Disabled = isOnCooldown,
};
if (!string.IsNullOrEmpty(interaction.IconId) &&
_prototypeManager.TryIndex<InteractionIconPrototype>(interaction.IconId, out var iconProto))
{
var iconRect = new TextureRect
{
TextureScale = new Vector2(1.0f, 1.0f),
Stretch = TextureRect.StretchMode.KeepAspectCentered,
Texture = _spriteSystem.Frame0(iconProto.Icon),
HorizontalAlignment = HAlignment.Left,
VerticalAlignment = VAlignment.Center,
Margin = new Thickness(10, 0, 10, 0),
// MinSize = new Vector2(64, 64),
// MaxSize = new Vector2(64, 64)
};
button.AddChild(iconRect);
}
if (isOnCooldown)
{
button.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = new Color(BackgroundLight.R * 0.6f, BackgroundLight.G * 0.6f, BackgroundLight.B * 0.6f),
BorderColor = TextMuted,
BorderThickness = new Thickness(1)
};
}
else
{
button.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = BackgroundLight,
BorderColor = SuccessColor,
BorderThickness = new Thickness(1)
};
}
_buttonInteractions[button] = interaction.Id;
if (isOnCooldown)
{
var userEntity = _owner?.Owner ?? default;
if (_entityManager.TryGetComponent<InteractionsComponent>(userEntity, out var component) &&
component.InteractionCooldowns.TryGetValue(interaction.Id, out var endTime))
{
var remainingTime = endTime - _gameTiming.CurTime;
if (remainingTime > TimeSpan.Zero)
{
var seconds = (int)Math.Ceiling(remainingTime.TotalSeconds);
button.Text = $"{interaction.Name} ({seconds}с)";
}
}
}
button.OnPressed += _ =>
{
ExecuteInteraction(interaction.Id, true);
};
buttonBox.AddChild(button);
var favoriteButton = new Button
{
MinSize = new Vector2(32, 44),
MaxSize = new Vector2(32, 44),
StyleClasses = { StyleClass.ButtonSquare },
Margin = new Thickness(2, 0, 0, 0),
VerticalAlignment = VAlignment.Center
};
var isFavorite = _favoriteInteractions.Contains(interaction.Id);
favoriteButton.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = isFavorite ? FavoriteColor : BackgroundLight,
BorderColor = isFavorite ? FavoriteColor : TextMuted,
BorderThickness = new Thickness(1)
};
var starIcon = new TextureRect
{
Texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/examine-star.png"))),
TextureScale = new Vector2(0.8f, 0.8f),
Stretch = TextureRect.StretchMode.KeepAspectCentered,
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
Modulate = isFavorite ? Color.White : TextMuted
};
favoriteButton.AddChild(starIcon);
favoriteButton.OnPressed += _ =>
{
ToggleFavorite(interaction.Id);
};
favoriteButton.OnMouseEntered += _ =>
{
favoriteButton.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = isFavorite ? FavoriteHoverColor : BackgroundHighlight,
BorderColor = isFavorite ? FavoriteHoverColor : PrimaryColor,
BorderThickness = new Thickness(1)
};
};
favoriteButton.OnMouseExited += _ =>
{
favoriteButton.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = isFavorite ? FavoriteColor : BackgroundLight,
BorderColor = isFavorite ? FavoriteColor : TextMuted,
BorderThickness = new Thickness(1)
};
};
buttonBox.AddChild(favoriteButton);
return buttonBox;
}
private void ExecuteInteraction(string interactionId, bool isCustom)
{
if (!isCustom)
{
_owner?.SendBoundUserInterfaceMessage(new InteractionMessage(interactionId));
}
else
{
var customInteraction = _customInteractionService.GetInteraction(interactionId);
if (customInteraction == null)
return;
var message = customInteraction.InteractionMessages.Count > 0
? _random.Pick(customInteraction.InteractionMessages)
: "взаимодействует с";
string? soundId = null;
if (customInteraction.SoundIds.Count > 0)
soundId = _random.Pick(customInteraction.SoundIds);
var customData = new CustomInteractionData(
message,
soundId,
customInteraction.SpawnsEffect,
customInteraction.EffectChance,
customInteraction.EntityEffectId,
customInteraction.Cooldown
);
_owner?.SendBoundUserInterfaceMessage(new InteractionMessage(interactionId, customData));
}
}
#endregion
#region Favorites
private void ToggleFavorite(string interactionId)
{
if (_favoriteInteractions.Contains(interactionId))
{
_favoriteInteractions.Remove(interactionId);
}
else
{
_favoriteInteractions.Add(interactionId);
}
SaveFavoriteInteractions();
if (_currentInteractionIds != null)
{
_buttonInteractions.Clear();
_customInteractionIds.Clear();
PopulateCategories(_currentInteractionIds);
}
}
private void SaveFavoriteInteractions()
{
var joined = string.Join(",", _favoriteInteractions);
_cfg.SetCVar(InteractionsCVars.FavoriteInteractions, joined);
_cfg.SaveToFile();
}
private void LoadFavoriteInteractions()
{
_favoriteInteractions.Clear();
var saved = _cfg.GetCVar(InteractionsCVars.FavoriteInteractions);
if (!string.IsNullOrEmpty(saved))
{
foreach (var interactionId in saved.Split(','))
{
if (!string.IsNullOrEmpty(interactionId))
{
_favoriteInteractions.Add(interactionId);
}
}
}
}
#endregion
#region API
public void SetOwner(InteractionsWindowBoundUserInterface owner)
{
_owner = owner;
}
#endregion
#region CFG
private void SetEmoteVisibility(bool visible)
{
_cfg.SetCVar(InteractionsCVars.EmoteVisibility, visible);
_cfg.SaveToFile();
}
private void SetExpanded(bool expand)
{
_cfg.SetCVar(InteractionsCVars.Expand, expand);
_cfg.SaveToFile();
TopUserInfoBox.Visible = !expand;
}
private void SaveOpenCategories()
{
var joined = string.Join(",", _openCategories);
_cfg.SetCVar(InteractionsCVars.OpenInteractionCategories, joined);
_cfg.SaveToFile();
}
private void LoadOpenCategories()
{
_openCategories.Clear();
var saved = _cfg.GetCVar(InteractionsCVars.OpenInteractionCategories);
if (!string.IsNullOrEmpty(saved))
{
foreach (var cat in saved.Split(','))
{
_openCategories.Add(cat);
}
}
}
#endregion
#region Custom
private void OnCustomInteractionSearchTextChanged(LineEdit.LineEditEventArgs args)
{
_customSearchText = args.Text.ToLowerInvariant();
LoadSavedInteractions();
}
private void OnNewCustomInteractionPressed(BaseButton.ButtonEventArgs args)
{
var editor = new CustomInteractionEditor();
editor.SetCloseCallback(saved =>
{
if (saved)
{
LoadSavedInteractions();
if (_currentInteractionIds != null)
{
_buttonInteractions.Clear();
_customInteractionIds.Clear();
PopulateCategories(_currentInteractionIds);
}
}
});
editor.OpenCentered();
}
private void LoadSavedInteractions()
{
SavedInteractionsContainer.DisposeAllChildren();
var interactions = _customInteractionService.GetInteractions();
if (!string.IsNullOrEmpty(_customSearchText))
{
interactions = interactions
.Where(i => i.Name.ToLowerInvariant().Contains(_customSearchText) ||
i.Description.ToLowerInvariant().Contains(_customSearchText))
.ToList();
}
if (interactions.Count == 0)
{
var emptyLabel = new Label
{
Text = string.IsNullOrEmpty(_customSearchText)
? "У вас нет сохраненных взаимодействий"
: "Ничего не найдено",
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
FontColorOverride = TextMuted,
Margin = new Thickness(0, 10, 0, 0)
};
SavedInteractionsContainer.AddChild(emptyLabel);
return;
}
foreach (var interaction in interactions)
{
SavedInteractionsContainer.AddChild(CreateSavedInteractionCard(interaction));
}
}
private Control CreateSavedInteractionCard(CustomInteraction interaction)
{
var card = new PanelContainer
{
Margin = new Thickness(0, 0, 0, 6)
};
card.PanelOverride = new StyleBoxFlat
{
BackgroundColor = BackgroundLight,
BorderColor = PrimaryColor,
BorderThickness = new Thickness(1)
};
var mainBox = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
Margin = new Thickness(6)
};
var headerBox = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
HorizontalExpand = true,
Margin = new Thickness(0, 0, 0, 4)
};
var titleLabel = new Label
{
Text = interaction.Name,
FontColorOverride = PrimaryColor,
HorizontalExpand = true
};
var editButton = new Button
{
Text = "Редактировать",
StyleClasses = { StyleClass.ButtonSquare },
Margin = new Thickness(0, 0, 4, 0)
};
editButton.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = BackgroundHighlight,
BorderColor = SuccessColor,
BorderThickness = new Thickness(1)
};
var deleteButton = new Button
{
Text = "Удалить",
StyleClasses = { StyleClass.ButtonSquare },
};
deleteButton.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = BackgroundHighlight,
BorderColor = ErrorColor,
BorderThickness = new Thickness(1)
};
editButton.OnPressed += _ => OnEditInteraction(interaction);
deleteButton.OnPressed += _ => OnDeleteInteraction(interaction);
headerBox.AddChild(titleLabel);
headerBox.AddChild(editButton);
headerBox.AddChild(deleteButton);
var descriptionLabel = new Label
{
Text = interaction.Description,
FontColorOverride = SecondaryColor,
Margin = new Thickness(0, 2, 0, 6)
};
var categoryBox = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
Margin = new Thickness(0, 2, 0, 0)
};
var categoryLabel = new Label
{
Text = $"Категория: {GetCategoryName(interaction.CategoryId)}",
FontColorOverride = new Color(208, 166, 92)
};
categoryBox.AddChild(categoryLabel);
mainBox.AddChild(headerBox);
mainBox.AddChild(descriptionLabel);
mainBox.AddChild(categoryBox);
card.AddChild(mainBox);
return card;
}
private string GetCategoryName(string categoryId)
{
if (string.IsNullOrEmpty(categoryId))
return "Не указана";
if (_prototypeManager.TryIndex<InteractionCategoryPrototype>(categoryId, out var category))
return Loc.GetString(category.Name);
return categoryId;
}
private void OnEditInteraction(CustomInteraction interaction)
{
var interactionCopy = new CustomInteraction
{
Id = interaction.Id,
Name = interaction.Name,
Description = interaction.Description,
IconId = interaction.IconId,
CategoryId = interaction.CategoryId,
InteractionMessages = new List<string>(interaction.InteractionMessages),
SoundIds = new List<string>(interaction.SoundIds),
SpawnsEffect = interaction.SpawnsEffect,
EffectChance = interaction.EffectChance,
EntityEffectId = interaction.EntityEffectId,
Cooldown = interaction.Cooldown
};
var editor = new CustomInteractionEditor(interactionCopy);
editor.SetCloseCallback((saved) =>
{
if (saved)
{
LoadSavedInteractions();
if (_currentInteractionIds != null)
{
_buttonInteractions.Clear();
_customInteractionIds.Clear();
PopulateCategories(_currentInteractionIds);
}
}
});
editor.OpenCentered();
}
private void OnDeleteInteraction(CustomInteraction interaction)
{
var confirmDialog = new DefaultWindow
{
Title = "Подтверждение",
MinSize = new Vector2(280, 140)
};
var dialogPanel = new PanelContainer
{
VerticalExpand = true,
HorizontalExpand = true
};
dialogPanel.PanelOverride = new StyleBoxFlat
{
BackgroundColor = BackgroundMedium
};
var dialogVBox = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
Margin = new Thickness(8),
VerticalExpand = true
};
var questionLabel = new Label
{
Text = $"Удалить '{interaction.Name}'?",
HorizontalExpand = true,
HorizontalAlignment = HAlignment.Center,
Margin = new Thickness(0, 0, 0, 12),
FontColorOverride = PrimaryColor
};
var buttonsBox = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Bottom,
VerticalExpand = true,
Margin = new Thickness(0, 6, 0, 0)
};
var cancelButton = new Button
{
Text = "Отмена",
StyleClasses = { StyleClass.ButtonSquare },
Margin = new Thickness(0, 0, 4, 0)
};
cancelButton.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = BackgroundLight,
BorderColor = SecondaryColor,
BorderThickness = new Thickness(1)
};
var confirmButton = new Button
{
Text = "Удалить",
StyleClasses = { StyleClass.ButtonSquare },
};
confirmButton.StyleBoxOverride = new StyleBoxFlat
{
BackgroundColor = BackgroundLight,
BorderColor = ErrorColor,
BorderThickness = new Thickness(1)
};
cancelButton.OnPressed += _ => confirmDialog.Close();
confirmButton.OnPressed += _ =>
{
_customInteractionService.RemoveInteraction(interaction.Id);
LoadSavedInteractions();
if (_currentInteractionIds != null)
{
_buttonInteractions.Clear();
_customInteractionIds.Clear();
PopulateCategories(_currentInteractionIds);
}
confirmDialog.Close();
};
buttonsBox.AddChild(cancelButton);
buttonsBox.AddChild(confirmButton);
dialogVBox.AddChild(questionLabel);
dialogVBox.AddChild(buttonsBox);
dialogPanel.AddChild(dialogVBox);
confirmDialog.AddChild(dialogPanel);
confirmDialog.OpenCentered();
}
#endregion
}