using System; using TMPro; using UnityEngine; using UnityEngine.UI; // Окно "Круг" (слой приложения): вступить, основать, состав, покинуть. // Сам Круг -- модуль Круга: только через контракт ICircle и события CircleJoinedEvent / CircleLeftEvent. // Документ: Docs/Modules/Circle.md // // Открыть: CircleWindow.Open() -- кнопка "Круг" внизу карты мира. public static class CircleWindow { const float ListHeight = 620f; static GameObject root; static ICircle Circle => GameServices.Get(); public static bool IsOpen => root != null; public static void Open() { Close(); RectTransform card = UIKit.Modal(Circle.IsInCircle ? Circle.Current.name : "Круг", out root); if (Circle.IsInCircle) BuildMyCircle(card); else BuildChooseCircle(card); var close = UIKit.Button(card, "Закрыть", UIKit.Theme.Gray, Close, -1, 90, 30); UIKit.Size(close, -1, 90); } public static void Close() { if (root != null) UnityEngine.Object.Destroy(root); root = null; } // ---------------- Игрок не в Круге ---------------- static void BuildChooseCircle(RectTransform card) { UIKit.Text(card, "Вы не состоите в Круге. Вступите в один из Кругов или основайте свой — " + "вместе проще брать крепости и держать территорию.", 28, UIKit.Theme.TextDim, TextAlignmentOptions.Center); UIKit.Button(card, "Основать свой Круг", UIKit.Theme.Gold, AskNameAndCreate, -1, 90, 30); var list = ScrollArea(card); foreach (var c in Circle.GetCircles()) { CircleInfo circle = c; bool full = circle.members.Count >= Circle.MaxMembers; var row = UIKit.Row(list, 100, 16, UIKit.Theme.Card, 14); UIKit.Icon(row, BannerColor(circle.name), circle.name.Substring(0, 1), 72); var info = UIKit.Card(row, new Color(0, 0, 0, 0), 0, 2); UIKit.Size(info, -1, -1, 1); UIKit.Text(info, circle.name, 30, UIKit.Theme.Text).fontStyle = FontStyles.Bold; UIKit.Text(info, $"Глава: {circle.LeaderName} • участников {circle.members.Count} / {Circle.MaxMembers}", 22, UIKit.Theme.TextDim); var join = UIKit.Button(row, full ? "Мест нет" : "Вступить", full ? UIKit.Theme.Gray : UIKit.Theme.Green, () => Join(circle), -1, 76, 26); UIKit.Size(join, 210, 76); join.interactable = !full; } } static void AskNameAndCreate() { UIKit.InputDialog("Название Круга", "", CircleService.MaxNameLength, name => { if (Circle.TryCreate(name, out string error)) { UIKit.Toast($"Круг «{name}» основан. Вы -- глава"); Open(); } else UIKit.Toast(error); }); } static void Join(CircleInfo circle) { if (Circle.TryJoin(circle.id, out string error)) { UIKit.Toast($"Вы вступили в Круг «{circle.name}»"); Open(); } else UIKit.Toast(error); } // ---------------- Игрок в Круге ---------------- static void BuildMyCircle(RectTransform card) { CircleInfo circle = Circle.Current; string role = Circle.IsLeader ? "Глава" : "Участник"; UIKit.Text(card, $"Ваша роль: {role} • участников {circle.members.Count} / {Circle.MaxMembers}", 28, UIKit.Theme.TextDim, TextAlignmentOptions.Center); var list = ScrollArea(card); foreach (var m in circle.members) { bool me = m.playerId == LocalPlayer.Id; var row = UIKit.Row(list, 80, 14, me ? new Color(0.24f, 0.24f, 0.3f) : UIKit.Theme.Card, 12); UIKit.Icon(row, BannerColor(m.name), m.name.Substring(0, 1), 56); var name = UIKit.Text(row, me ? m.name + " (вы)" : m.name, 28, me ? UIKit.Theme.Gold : UIKit.Theme.Text); UIKit.Size(name, -1, -1, 1); UIKit.Size(UIKit.Text(row, m.role == CircleRole.Leader ? "Глава" : "Участник", 24, m.role == CircleRole.Leader ? UIKit.Theme.Gold : UIKit.Theme.TextDim, TextAlignmentOptions.Right), 180); } string leaveText = circle.members.Count == 1 ? "Вы в Круге один -- если выйти, Круг будет распущен." : Circle.IsLeader ? "Главой станет старейший участник Круга." : "Вернуться можно в любой момент, если будут места."; UIKit.Button(card, "Покинуть Круг", UIKit.Theme.Red, () => UIKit.Confirm("Покинуть Круг?", leaveText, "Покинуть", () => { Circle.Leave(); UIKit.Toast("Вы покинули Круг"); Open(); }), -1, 90, 30); } // ---------------- Помощники ---------------- // Список фиксированной высоты: окно растягивается по содержимому, а Кругов может быть много static RectTransform ScrollArea(RectTransform card) { var holder = UIKit.Make("ListHolder", card); UIKit.Size(holder, -1, ListHeight); return UIKit.ScrollList(holder, out ScrollRect _, 10); } // Один и тот же Круг -- всегда один цвет (string.GetHashCode в Unity меняется между запусками) static Color BannerColor(string name) { Color[] colors = { new Color(0.15f, 0.35f, 0.75f), new Color(0.45f, 0.2f, 0.18f), new Color(0.7f, 0.15f, 0.15f), new Color(0.2f, 0.45f, 0.2f), new Color(0.75f, 0.5f, 0.1f), new Color(0.35f, 0.35f, 0.4f) }; int hash = 17; foreach (char ch in name) hash = hash * 31 + ch; return colors[(hash & int.MaxValue) % colors.Length]; } }