From cfbdfd9876e4b6cc302ae4814d62db0531a5bcf4 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 4 Nov 2026 15:13:02 +0100 Subject: [PATCH] =?UTF-8?q?=D0=95=D0=B4=D0=B0=20=D0=B2=D0=BE=D0=B8=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=B8=20=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=BF=D0=BE=20=D1=82=D0=B8=D0=BF=D0=B0=D0=BC=20(?= =?UTF-8?q?=D1=80=D0=B5=D1=88=D0=B5=D0=BD=D0=B8=D1=8F=2001.11,=20=D0=BF.?= =?UTF-8?q?=204):=200,15=20/=200,20=20/=200,15=20/=200,15,=20=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=8B=D0=B5=20--=20=D0=B4=D0=B0=D0=B6=D0=B5?= =?UTF-8?q?=20=D0=B2=20=D0=BE=D0=B6=D0=B8=D0=B4=D0=B0=D0=BD=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=B9=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IArmy.GetAllTroops; PopulationRules.FoodPerTroopTypePerHour (без таблицы -- как раньше); EconomyConfig.population.foodPerTroopTypePerHour. Co-Authored-By: Claude Opus 5.5 --- Assets/Resources/EconomyConfig.asset | 5 ++++ Assets/Scripts/App/EconomyConfig.cs | 5 +++- Assets/Scripts/App/GameModules.cs | 2 ++ Assets/Scripts/Modules/Army/ArmyService.cs | 9 ++++++ .../Modules/Core/Contracts/ModuleContracts.cs | 1 + .../Modules/Population/PopulationRules.cs | 4 +++ .../Modules/Population/PopulationService.cs | 13 +++++++- Assets/Scripts/Modules/Tests/ModuleTests.cs | 30 +++++++++++++++++++ Docs/Modules/Army.md | 1 + Docs/Modules/Population.md | 1 + Docs/Modules/README.md | 1 + 11 files changed, 70 insertions(+), 2 deletions(-) diff --git a/Assets/Resources/EconomyConfig.asset b/Assets/Resources/EconomyConfig.asset index 21f0383..8dfa34e 100644 --- a/Assets/Resources/EconomyConfig.asset +++ b/Assets/Resources/EconomyConfig.asset @@ -18,6 +18,11 @@ MonoBehaviour: startSoldiers: 30 foodPerCivilianPerHour: 0.1 foodPerSoldierPerHour: 0.2 + foodPerTroopTypePerHour: + - 0.15 + - 0.2 + - 0.15 + - 0.15 growthPerHour: 2.5 housingBase: 300 housingPerTownHallLevel: 50 diff --git a/Assets/Scripts/App/EconomyConfig.cs b/Assets/Scripts/App/EconomyConfig.cs index 9682259..f4fea3d 100644 --- a/Assets/Scripts/App/EconomyConfig.cs +++ b/Assets/Scripts/App/EconomyConfig.cs @@ -24,8 +24,11 @@ public class EconomyConfig : ScriptableObject [Tooltip("Еды в час на одного жителя")] public float foodPerCivilianPerHour = 0.1f; - [Tooltip("Еды в час на одного воина")] + [Tooltip("Еды в час на одного воина (и новобранца в Казармах), если норма по типам не задана")] public float foodPerSoldierPerHour = 0.2f; + [Tooltip("Еды в час на воина по типам: пехота, лучники, кавалерия, осадные. Решения 01.11, п. 4: 0,15 / 0,20 / 0,15 / 0,15. " + + "Раненые едят так же, даже ожидая койку. Пусто -- все по foodPerSoldierPerHour")] + public float[] foodPerTroopTypePerHour = { 0.15f, 0.2f, 0.15f, 0.15f }; [Tooltip("Прирост людей в час, если есть еда (документ: 2–3)")] public float growthPerHour = 2.5f; diff --git a/Assets/Scripts/App/GameModules.cs b/Assets/Scripts/App/GameModules.cs index c588a24..cf63015 100644 --- a/Assets/Scripts/App/GameModules.cs +++ b/Assets/Scripts/App/GameModules.cs @@ -209,6 +209,8 @@ public static class GameModules StartSoldiers = p.startSoldiers, FoodPerCivilianPerHour = p.foodPerCivilianPerHour, FoodPerSoldierPerHour = p.foodPerSoldierPerHour, + FoodPerTroopTypePerHour = p.foodPerTroopTypePerHour != null && p.foodPerTroopTypePerHour.Length > 0 + ? System.Array.ConvertAll(p.foodPerTroopTypePerHour, f => (double)f) : null, GrowthPerHour = p.growthPerHour, HousingBase = p.housingBase, HousingPerTownHallLevel = p.housingPerTownHallLevel, diff --git a/Assets/Scripts/Modules/Army/ArmyService.cs b/Assets/Scripts/Modules/Army/ArmyService.cs index fcdbd33..b3ea5c0 100644 --- a/Assets/Scripts/Modules/Army/ArmyService.cs +++ b/Assets/Scripts/Modules/Army/ArmyService.cs @@ -238,6 +238,15 @@ public sealed class ArmyService : IArmy, ISaveParticipant } } + public int GetAllTroops(int type) + { + if (type < 0 || type >= Types) return 0; + int n = troops[type] + woundedWaiting[type]; + foreach (var m in marches) n += m.units[type]; + foreach (var b in healing) if (b.type == type) n += b.count; + return n; + } + public int GetWoundedWaiting(int type) { return type >= 0 && type < Types ? woundedWaiting[type] : 0; diff --git a/Assets/Scripts/Modules/Core/Contracts/ModuleContracts.cs b/Assets/Scripts/Modules/Core/Contracts/ModuleContracts.cs index 6580fdf..bf4ddf5 100644 --- a/Assets/Scripts/Modules/Core/Contracts/ModuleContracts.cs +++ b/Assets/Scripts/Modules/Core/Contracts/ModuleContracts.cs @@ -150,6 +150,7 @@ public interface IArmy // Бой считает раненых, Армия хранит их и лечит, места -- от госпиталя (IHospital), цену лечения списывает Экономика. // Раненые -- люди: Население считает их вместе с воинами. Лишние раненые ждут места (ТЕСТ, решение Саши 01.11). int WoundedTotal { get; } // раненых всего: ждут места + лечатся + int GetAllTroops(int type); // все воины типа: в городе, в походах и раненые (для еды -- решения 01.11, п. 4) int GetWoundedWaiting(int type); // ждут места, по типам IReadOnlyList Healing { get; } // лечатся сейчас int HospitalBeds { get; } // мест в госпитале сейчас diff --git a/Assets/Scripts/Modules/Population/PopulationRules.cs b/Assets/Scripts/Modules/Population/PopulationRules.cs index 1201b7a..168a64c 100644 --- a/Assets/Scripts/Modules/Population/PopulationRules.cs +++ b/Assets/Scripts/Modules/Population/PopulationRules.cs @@ -12,6 +12,10 @@ public sealed class PopulationRules // Еда в час public double FoodPerCivilianPerHour = 0.1; public double FoodPerSoldierPerHour = 0.2; + // Еда воина по типам войск: пехота, лучники, кавалерия, осадные (решения по отчёту Саши, 01.11, п. 4: 0,15 / 0,20 / 0,15 / 0,15). + // Раненые едят полную норму своего типа, даже ожидая койку. null -- все воины едят FoodPerSoldierPerHour (как раньше). + // Новобранцы в Казармах -- по FoodPerSoldierPerHour (их норма не задана). + public double[] FoodPerTroopTypePerHour = null; // Прирост +2–3 человека в час, если есть еда public double GrowthPerHour = 2.5; diff --git a/Assets/Scripts/Modules/Population/PopulationService.cs b/Assets/Scripts/Modules/Population/PopulationService.cs index d9f2567..ae0e853 100644 --- a/Assets/Scripts/Modules/Population/PopulationService.cs +++ b/Assets/Scripts/Modules/Population/PopulationService.cs @@ -182,7 +182,18 @@ public sealed class PopulationService : IPopulation, ISaveParticipant double FoodPerHourExact(int soldiers) { // Обучающиеся в Казармах едят как воины - return civilians * rules.FoodPerCivilianPerHour + (soldiers + inTraining) * rules.FoodPerSoldierPerHour; + return civilians * rules.FoodPerCivilianPerHour + SoldiersFood(soldiers) + inTraining * rules.FoodPerSoldierPerHour; + } + + // Воины (в городе, в походах и раненые) едят по норме своего типа, если она задана (решения 01.11, п. 4) + double SoldiersFood(int soldiers) + { + var table = rules.FoodPerTroopTypePerHour; + if (table == null || table.Length == 0 || !GameServices.TryGet(out IArmy army)) return soldiers * rules.FoodPerSoldierPerHour; + double food = 0; + for (int t = 0; t < army.TypeCount; t++) + food += army.GetAllTroops(t) * (t < table.Length ? table[t] : rules.FoodPerSoldierPerHour); + return food; } public int GetWorkers(WorkJob job) diff --git a/Assets/Scripts/Modules/Tests/ModuleTests.cs b/Assets/Scripts/Modules/Tests/ModuleTests.cs index d8ab5fa..6ea7073 100644 --- a/Assets/Scripts/Modules/Tests/ModuleTests.cs +++ b/Assets/Scripts/Modules/Tests/ModuleTests.cs @@ -1949,4 +1949,34 @@ public class ModuleTests Assert.AreEqual(20, army.GetWoundedWaiting(0) + 10, "ещё 20 легли сразу после улучшения: ждут 10"); Assert.AreEqual(40, army.Healing[0].Count + army.Healing[1].Count); } + + // Решения 01.11, п. 4: воины и раненые едят по норме своего типа, раненые -- даже ожидая койку + [Test] + public void Population_FoodByTroopType_IncludesWounded() + { + var army = new ArmyService(2, new HospitalRules { TemporaryBeds = 0 }); // мест нет -- все раненые ждут + GameServices.Register(army); + GameServices.Register(new PopulationTests.FakeEconomy()); + GameServices.Register(new PopulationTests.FakeSettlement { TownHallLevel = 1 }); + var population = new PopulationService(new PopulationRules { FoodPerTroopTypePerHour = new[] { 0.15, 0.2, 0.15, 0.15 } }); + GameServices.Register(population); + double civilians = population.Civilians * 0.1; + + army.AddTroops(0, 20); // пехота 20 x 0,15 = 3 + army.AddTroops(1, 10); // лучники 10 x 0,20 = 2 + army.AddTroops(3, 4); // осадные 4 x 0,15 = 0,6 + Assert.AreEqual(civilians + 5.6, population.FoodPerHour, 0.001); + + army.TakeForMarch(1, 14); // в походе -- тоже едят + Assert.AreEqual(civilians + 5.6, population.FoodPerHour, 0.001, "поход не меняет еду"); + int[] sent = army.GetMarchUnits(1); + var wounded = new int[4]; + for (int t = 0; t < 4; t++) wounded[t] = sent[t] / 2; // половина ранена, остальные погибли + army.ReturnUnits(1, null, wounded, 0); + Assert.AreEqual(0, army.Healing.Count, "коек нет -- раненые ждут"); + double expected = 0; + for (int t = 0; t < 4; t++) expected += army.GetAllTroops(t) * new[] { 0.15, 0.2, 0.15, 0.15 }[t]; + Assert.AreEqual(civilians + expected, population.FoodPerHour, 0.001, "ждущие койку раненые едят полную норму"); + Assert.Less(expected, 5.6, "погибшие больше не едят"); + } } diff --git a/Docs/Modules/Army.md b/Docs/Modules/Army.md index ce38eb2..a59ba2b 100644 --- a/Docs/Modules/Army.md +++ b/Docs/Modules/Army.md @@ -148,6 +148,7 @@ healNext=<номер следующей группы лечения> | Дата | Кто | Что | | --- | --- | --- | +| 04.11.2026 | Claude | `IArmy.GetAllTroops(type)` — все воины типа: в городе, в походах и раненые (для еды по типам, решения 01.11, п. 4). | | 04.11.2026 | Claude | Решения по отчёту Саши от 01.11, п. 3: 5 временных мест до постройки госпиталя, цена лечения 1 / 1 / 2 / 3 золота за воина. | | 01.11.2026 | Claude | Здание «Госпиталь» в городе: уровни I–V, 20–60 мест, окно с ранеными и улучшением; места Армии — через `IHospital` (`HospitalBeds`). Без госпиталя мест нет (`temporaryBeds` = 0). Тест `Hospital_BedsFromBuilding_UpgradeFreesWaiting`. | | 01.11.2026 | Claude | Решения 31.10, п. 7: раненые и лечение у Армии — `WoundedTotal`, `Healing`, `HospitalBeds`, `ReturnUnits(…, woundedUnits, nowMs)`, `ProcessHealing`, `SoldiersHealedEvent`; места от `IHospital` (пока нет здания — `HospitalConfig.temporaryBeds`), лишние ждут, цена через Экономику (не утверждена). Сохранение `wounded=`, `heal=`. Тесты: места и сроки, однократность, люди в Населении, сохранение и цена. | diff --git a/Docs/Modules/Population.md b/Docs/Modules/Population.md index 35029f6..571dd0b 100644 --- a/Docs/Modules/Population.md +++ b/Docs/Modules/Population.md @@ -112,6 +112,7 @@ | Дата | Кто | Что | | --- | --- | --- | +| 04.11.2026 | Claude (Саша) | Решения по отчёту Саши от 01.11, п. 4: воины едят по норме типа — пехота 0,15, лучники 0,20, кавалерия 0,15, осадные 0,15 в час (`PopulationRules.FoodPerTroopTypePerHour`, `EconomyConfig.population.foodPerTroopTypePerHour`); раненые — полную норму своего типа, даже ожидая койку (`IArmy.GetAllTroops`). Новобранцы — по `foodPerSoldierPerHour`. Без таблицы — как раньше (тесты Населения не менялись). Час — тот же, что у остальной еды (переход еды на игровые часы — открытый вопрос). | | 01.11.2026 | Claude (Саша) | Раненые считаются людьми: `Soldiers` = в городе + в походах + `IArmy.WoundedTotal` (решения 31.10, п. 7). Погибшие уходят из людей, вылеченные не появляются заново. Еда раненых — как у воинов (нормы четырёх групп — открытый вопрос). | | 01.11.2026 | Claude (Саша) | Очередь обучения перенесена в Армию (решения 31.10, п. 8). Население по-прежнему отдаёт жителей (`TryRecruit`) и принимает новобранцев в воины (`CompleteTraining`) — его код не менялся, зовёт их теперь Армия. `RecruitsTrained` больше никто не вызывает. | | 31.10.2026 | Claude | `CompleteTraining`: новобранцы переходят в Армию одним действием с откатом, если Армия не приняла. Заказ обучения помечает, брали ли под него людей (`TrainingOrder.recruited`); старые заказы — по-старому. Интеграционные тесты с настоящей Армией: переход без потерь, отказ Армии, повтор, нет Армии, часть заказа. | diff --git a/Docs/Modules/README.md b/Docs/Modules/README.md index 909d336..b9700f9 100644 --- a/Docs/Modules/README.md +++ b/Docs/Modules/README.md @@ -105,6 +105,7 @@ EditMode-тесты: `Assets/Scripts/Modules/Tests/ModuleTests.cs`. Запуск | Дата | Кто | Что | | --- | --- | --- | +| 04.11.2026 | Claude | Еда воинов и раненых по типам (решения 01.11, п. 4). Обновлены Population, Army. | | 04.11.2026 | Claude | Карта мира в 2.5D на примитивах. Обновлены World, Intelligence. | | 04.11.2026 | Claude | 3D-поселение, этап I — прототип на примитивах (ТЗ от 04.11). Обновлён Settlement. | | 04.11.2026 | Claude | Решения по отчёту Саши от 01.11: потери сильной стороны до 2% при 10:1, 5 временных мест госпиталя, цена лечения 1 / 1 / 2 / 3 золота. Обновлены Battle, Army. |