159 lines
7.8 KiB
C#
159 lines
7.8 KiB
C#
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;
|
|||
|
|
}
|
|||
|
|
}
|