Files
MVP1/Assets/Scripts/App/BuildingWindow.cs
T

159 lines
7.8 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 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<PlacedBuildingId>();
var leveled = building.GetComponent<ILeveledBuilding>();
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<ResourceCollector>();
var storage = building.GetComponent<StorageBuilding>();
var leveled = building.GetComponent<ILeveledBuilding>();
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 ? $" <color=#9be29b>+{prod.RatePerHour(WorkJobs.Resource(job)):0.#}/ч</color>" : "";
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, $"Свободно: <b>{pop.FreeWorkers}</b> из {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;
}
}