Поселение: стройка по времени и строители, лимит зданий по Ратуше, перенос и снос, защита ресурсов; Терем богатыря; найм карточками

This commit is contained in:
2026-11-02 00:01:51 +03:00
parent 1b7da37c7e
commit d30fd34810
23 changed files with 1120 additions and 25 deletions
@@ -16,6 +16,11 @@ public static class SettlementModule
public float posX;
public float posY;
public int level;
// Стройка или улучшение, которое ещё идёт (01.11): 0 -- нет, 1 -- постройка, 2 -- улучшение
public int timerKind;
public long timerStartMs;
public long timerEndMs;
public int timerTargetLevel;
}
// Имена полей совпадают со старым save.json -- старые сохранения читаются без переделки
@@ -23,6 +28,10 @@ public static class SettlementModule
public class SettlementSaveData
{
public int townHallLevel = 1;
// Улучшение Ратуши, которое ещё идёт (01.11): timerEndMs 0 -- нет
public long townHallTimerStartMs;
public long townHallTimerEndMs;
public int townHallTimerTargetLevel;
public List<PlacedBuildingSaveEntry> placedBuildings = new List<PlacedBuildingSaveEntry>();
}
@@ -46,18 +55,34 @@ public static class SettlementModule
static SettlementSaveData CaptureScene()
{
var data = new SettlementSaveData();
if (TownHall.Instance != null) data.townHallLevel = TownHall.Instance.currentLevel;
if (TownHall.Instance != null)
{
data.townHallLevel = TownHall.Instance.currentLevel;
var thTimer = BuildTimer.Of(TownHall.Instance.gameObject);
if (thTimer != null && BuildTimer.All.Contains(thTimer))
{
data.townHallTimerStartMs = thTimer.startMs;
data.townHallTimerEndMs = thTimer.endMs;
data.townHallTimerTargetLevel = thTimer.targetLevel;
}
}
foreach (var placed in UnityEngine.Object.FindObjectsByType<PlacedBuildingId>(FindObjectsSortMode.None))
{
if (string.IsNullOrEmpty(placed.buildingName)) continue; // уже убрано, Destroy сработает в конце кадра
var leveled = placed.GetComponent<ILeveledBuilding>();
var timer = placed.GetComponent<BuildTimer>();
bool timerOn = timer != null && BuildTimer.All.Contains(timer);
data.placedBuildings.Add(new PlacedBuildingSaveEntry
{
buildingName = placed.buildingName,
posX = placed.transform.position.x,
posY = placed.transform.position.y,
level = leveled != null ? leveled.Level : 1
level = leveled != null ? leveled.Level : 1,
timerKind = timerOn ? (int)timer.kind : 0,
timerStartMs = timerOn ? timer.startMs : 0,
timerEndMs = timerOn ? timer.endMs : 0,
timerTargetLevel = timerOn ? timer.targetLevel : 0
});
}
return data;
@@ -74,7 +99,15 @@ public static class SettlementModule
EventBus.Publish(new SettlementRestoringEvent()); // например, Казармы должны попасть в список стройки
if (TownHall.Instance != null) TownHall.Instance.currentLevel = cached.townHallLevel;
if (TownHall.Instance != null)
{
TownHall.Instance.currentLevel = cached.townHallLevel;
var oldTimer = BuildTimer.Of(TownHall.Instance.gameObject);
if (oldTimer != null) oldTimer.Cancel();
if (cached.townHallTimerEndMs > 0)
BuildTimer.Begin(TownHall.Instance.gameObject, BuildTimer.Kind.Upgrade, cached.townHallTimerTargetLevel,
cached.townHallTimerStartMs, cached.townHallTimerEndMs);
}
// Сначала убираем уже заспавненные здания, чтобы не задвоить постройки
ClearPlacedBuildings();
@@ -98,6 +131,11 @@ public static class SettlementModule
var leveled = built.GetComponent<ILeveledBuilding>();
if (leveled != null) leveled.Level = entry.level;
// Стройка или улучшение продолжается (если время уже вышло -- закончится в первом же кадре)
if (entry.timerKind == (int)BuildTimer.Kind.Build || entry.timerKind == (int)BuildTimer.Kind.Upgrade)
BuildTimer.Begin(built, (BuildTimer.Kind)entry.timerKind, Mathf.Max(1, entry.timerTargetLevel),
entry.timerStartMs, entry.timerEndMs);
// Помечаем слот занятым, чтобы поверх нельзя было поставить ещё одно здание
BuildSlot slot = BuildManager.Instance.FindSlotAtPosition(pos);
if (slot != null)
@@ -124,6 +162,8 @@ public static class SettlementModule
link.linkedSlot = null;
}
e.buildingName = null; // чтобы сохранение в этом же кадре уже не видело здание
var timer = e.GetComponent<BuildTimer>();
if (timer != null) timer.Discard(); // строитель свободен сразу, а не в конце кадра
UnityEngine.Object.Destroy(e.gameObject);
}
}
@@ -167,7 +207,12 @@ public static class SettlementModule
if (!CityLoaded) return;
ClearPlacedBuildings();
if (TownHall.Instance != null) TownHall.Instance.currentLevel = 1;
if (TownHall.Instance != null)
{
TownHall.Instance.currentLevel = 1;
var thTimer = BuildTimer.Of(TownHall.Instance.gameObject);
if (thTimer != null) thTimer.Cancel();
}
appliedToBuildManager = BuildManager.Instance; // город уже в состоянии новой игры
EventBus.Publish(new TownHallLevelChangedEvent { Level = 1 });
}