24 ресурсные точки по решениям 31.10 (п. 6): лес 8, камень 7, металл 5, золото 4; размеры 12/8/4

Число по ресурсу и размеру -- в WorldResourceConfig; новая точка -- того же размера;
старые сохранения дополняются до таблицы.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Alexander
2026-11-01 13:08:51 +01:00
co-authored by Claude Opus 5.5
parent 5c4ba98fef
commit 3a86eadc0b
6 changed files with 114 additions and 21 deletions
@@ -47,7 +47,16 @@ namespace Bogatyri.World
public long GameHourMs = 5 * 60 * 1000;
// Не задано регламентом -- ТЕСТ, решает команда:
public int PointsPerResource = 2; // сколько точек каждого ресурса одновременно на карте
// Сколько точек одновременно на карте: [ресурс][размер] (решения по 8 вопросам Саши, 31.10, п. 6, ТЕСТ).
// Всего 24: лес 8, камень 7, металл 5, золото 4; по размерам 12 малых, 8 средних, 4 крупных.
// Раскладка размеров по ресурсам документом не задана -- задаётся здесь (в игре -- WorldResourceConfig).
public int[][] Count =
{
new[] { 4, 3, 1 }, // лес 8
new[] { 4, 2, 1 }, // камень 7
new[] { 2, 2, 1 }, // металл 5
new[] { 2, 1, 1 } // золото 4
};
public int Spacing = 2200; // не ближе 2,2 клетки к другим точкам карты
public static ResourcePointRules Default => new ResourcePointRules();
@@ -112,24 +121,44 @@ namespace Bogatyri.World
return points.Find(p => p.id == id);
}
// Первые точки: по PointsPerResource каждого ресурса, появляются в момент первого расчёта мира
// Точки на карте по таблице Count. Первые -- в момент первого расчёта мира; после загрузки сохранения
// недостающие добавляются (старое сохранение с 8 точками дополнится до 24, лишние доживут свой срок)
void EnsureResourcePoints(long nowMs)
{
if (pointsInitialized) return;
if (pointsInitialized && !pointsTopUp) return;
pointsInitialized = true;
for (int kind = 0; kind < ResourcePointRules.Resources.Length; kind++)
for (int k = 0; k < pointRules.PointsPerResource; k++)
SpawnPoint(kind, nowMs);
pointsTopUp = false;
SpawnMissingPoints(nowMs);
}
// Новая точка того же ресурса в другом месте. Место и размер -- из seed и номера появления (одинаково на сервере)
ResourcePoint SpawnPoint(int kind, long nowMs)
private bool pointsTopUp;
// Сколько активных точек каждого ресурса и размера не хватает до таблицы -- столько и появляется
void SpawnMissingPoints(long nowMs)
{
for (int kind = 0; kind < ResourcePointRules.Resources.Length; kind++)
for (int size = 0; size < 3; size++)
{
int have = 0;
foreach (var p in points) if (p.active && p.kind == kind && p.size == size) have++;
for (int k = have; k < PointCount(kind, size); k++)
if (SpawnPoint(kind, size, nowMs) == null) return; // карта переполнена -- попробуем при следующем исчезновении
}
}
int PointCount(int kind, int size)
{
var c = pointRules.Count;
return c != null && kind < c.Length && c[kind] != null && size < c[kind].Length ? Math.Max(0, c[kind][size]) : 0;
}
// Новая точка этого ресурса и размера в другом месте. Место -- из seed и номера появления (одинаково на сервере)
ResourcePoint SpawnPoint(int kind, int size, long nowMs)
{
pointGeneration++;
var rng = new DeterministicRandom(pointSeed ^ 0x2F0E1D ^ pointGeneration * 7919);
if (!WorldMapLayout.TryFindFreeSpot(rng, nodes, out int x, out int y, pointRules.Spacing)) return null;
int size = rng.Range(0, 3); // размер равновероятно -- регламент не задаёт (ТЕСТ)
var p = new ResourcePoint
{
id = "res_" + nextPointId++,
@@ -162,13 +191,14 @@ namespace Bogatyri.World
};
}
// Точка истощена или исчезла: на её месте больше нечего собирать, новая появляется в другом месте
// Точка истощена или исчезла: на её месте больше нечего собирать, новая того же ресурса и размера
// появляется в другом месте (если таких точек теперь меньше, чем в таблице)
void RetirePoint(ResourcePoint p, long atMs)
{
if (!p.active) return;
p.active = false;
p.occupiedBy = 0;
SpawnPoint(p.kind, atMs);
SpawnMissingPoints(atMs);
}
// Исчезнувшие точки убираются с карты, когда к ним уже никто не идёт и с них никто не возвращается
@@ -275,6 +305,7 @@ namespace Bogatyri.World
nextPointId = state?.nextPointId ?? 1;
pointGeneration = state?.generation ?? 0;
pointsInitialized = state?.initialized ?? false;
pointsTopUp = true; // таблица могла измениться -- при следующем расчёте мира добавить недостающие
if (state?.points == null) return;
foreach (var p in state.points)
{