using TMPro; using UnityEngine; // Окно здания и рабочих (этап 3). Открывается тапом по зданию или кнопкой "Рабочие" в панели DEV. // - сверху: что это за здание, его уровень и кнопка "Улучшить" (больше мест и эффективность / больше лимит / больше жилья); // - ниже: все профессии с "−" и "+", сколько рабочих стоит, сколько мест и сколько добывается в час; // - внизу: "Свободно: N из M". // Окно -- только интерфейс: рабочих ставит модуль Населения, добычу считает модуль добычи. public static class BuildingWindow { static GameObject root; static GameObject focus; // здание, по которому тапнули (null -- просто список рабочих) public static void OnWorkplaceTapped(ResourceCollector building) { Open(building != null ? building.gameObject : null); } public static void OnStorageTapped(StorageBuilding building) { Open(building != null ? building.gameObject : null); } public static void Open(GameObject building) { // В режиме стройки тап -- это выбор участка, а не здания if (BuildModeController.Instance != null && BuildModeController.Instance.IsActive) return; focus = building; Rebuild(); } public static void Close() { if (root != null) Object.Destroy(root); root = null; focus = null; } static void Rebuild() { if (root != null) Object.Destroy(root); var card = UIKit.Modal(TitleFor(focus), out root); if (focus != null) BuildingSection(card, focus); WorkersSection(card); UIKit.Button(card, "Закрыть", UIKit.Theme.Gray, Close, -1, 80, 28); } static string TitleFor(GameObject building) { if (building == null) return "РАБОЧИЕ"; var id = building.GetComponent(); var leveled = building.GetComponent(); string name = id != null && !string.IsNullOrEmpty(id.buildingName) ? id.buildingName : building.name; return leveled != null ? $"{name.ToUpper()} — {leveled.Level} УР." : name.ToUpper(); } // ---------------- Здание: что даёт и улучшение ---------------- static void BuildingSection(RectTransform card, GameObject building) { var config = EconomyConfig.Load(); var rc = building.GetComponent(); var storage = building.GetComponent(); var leveled = building.GetComponent(); string info; if (rc != null && WorkJobs.TryFromResource(rc.resourceType, out WorkJob job) && GameModules.Production != null) { var p = GameModules.Production; info = $"Здание даёт {p.BuildingSlots(rc.level)} мест, норма ×{p.BuildingEfficiency(rc.level):0.##}.\n" + $"Всего мест «{WorkJobs.Name(job)}» в городе: {p.Slots(job)}."; } else if (rc != null && rc.IsHouse) { int perLevel = config.population.housingPerHouseLevel; string cap = GameServices.TryGet(out IPopulation pop) ? $"\nНаселение: {pop.Total} / {pop.HousingCap}" : ""; info = $"Дом: +{perLevel * rc.level} к пределу жилья (+{perLevel} за уровень).{cap}"; } else if (rc != null && rc.resourceType == ResourceType.Gems) { info = "Синий кристалл добывается в кристальных разломах на карте мира."; } else if (storage != null) { var s = config.storage; info = storage.kind == StorageBuilding.Kind.Warehouse ? $"Склад: +{s.perWarehouseLevel * storage.level:0} к лимиту дерева, камня, металла и золота." : $"Амбар: +{s.perGranaryLevel * storage.level:0} к лимиту еды."; } else info = ""; if (info.Length > 0) UIKit.Text(card, info, 26, UIKit.Theme.TextDim, TextAlignmentOptions.Center); if (leveled == null || (rc != null && rc.resourceType == ResourceType.Gems)) return; if (leveled.Level >= config.upgrade.maxLevel) { UIKit.Text(card, "Максимальный уровень", 26, UIKit.Theme.Gold, TextAlignmentOptions.Center); return; } var cost = config.UpgradeCost(leveled.Level); bool canPay = GameServices.TryGet(out IEconomy economy) && economy.CanAfford(cost); var b = UIKit.Button(card, $"Улучшить до {leveled.Level + 1} ур. ({CostText(cost)})", canPay ? UIKit.Theme.Green : UIKit.Theme.Gray, () => { if (!GameServices.TryGet(out IEconomy e) || !e.TrySpend(cost)) { UIKit.Toast("Не хватает ресурсов"); return; } leveled.Level = leveled.Level + 1; if (CitySync.Instance != null) CitySync.Instance.SyncNow(); UIKit.Toast($"Улучшено до {leveled.Level} уровня"); Rebuild(); }, -1, 80, 26); b.interactable = canPay; } static string CostText(ResourceAmount[] cost) { var parts = new string[cost.Length]; for (int i = 0; i < cost.Length; i++) parts[i] = $"{cost[i].Amount:0} {GameData.ResName(cost[i].Type).ToLower()}"; return string.Join(", ", parts); } // ---------------- Рабочие по профессиям ---------------- static void WorkersSection(RectTransform card) { if (!GameServices.TryGet(out IPopulation pop) || !GameServices.TryGet(out IProduction prod)) { UIKit.Text(card, "Модули Населения и добычи не подключены", 26, UIKit.Theme.Red, TextAlignmentOptions.Center); return; } for (int j = 0; j < WorkJobs.Count; j++) { var job = (WorkJob)j; int slots = prod.Slots(job); int workers = pop.GetWorkers(job); var row = UIKit.Row(card, 72, 8); string rate = slots > 0 ? $" +{prod.RatePerHour(WorkJobs.Resource(job)):0.#}/ч" : ""; var label = UIKit.Text(row, slots > 0 ? $"{WorkJobs.Name(job)}: {workers} / {slots}{rate}" : $"{WorkJobs.Name(job)}: нет зданий", 24, slots > 0 ? UIKit.Theme.Text : UIKit.Theme.TextDim); label.enableAutoSizing = true; label.fontSizeMin = 14; label.fontSizeMax = 24; UIKit.Size(label, -1, 72, 1); StepButton(row, "−5", job, -5, slots > 0 && workers > 0); StepButton(row, "−1", job, -1, slots > 0 && workers > 0); StepButton(row, "+1", job, +1, slots > 0 && workers < slots && pop.FreeWorkers > 0); StepButton(row, "+5", job, +5, slots > 0 && workers < slots && pop.FreeWorkers > 0); } UIKit.Text(card, $"Свободно: {pop.FreeWorkers} из {pop.Workforce} рабочих • остальные жители: {Mathf.Max(0, pop.Civilians - pop.Workforce)}", 24, UIKit.Theme.Gold, TextAlignmentOptions.Center); } static void StepButton(Transform row, string label, WorkJob job, int delta, bool enabled) { var b = UIKit.Button(row, label, delta > 0 ? UIKit.Theme.Blue : UIKit.Theme.Gray, () => { if (GameServices.TryGet(out IPopulation pop)) pop.SetWorkers(job, pop.GetWorkers(job) + delta); Rebuild(); }, 86, 64, 24); b.interactable = enabled; } }