# Боевая система Урон, потери, исход боя с учётом типов войск. Модуль только считает: кто победил и сколько погибло каждого типа. Кто идёт в бой и что делать с итогом, решают другие модули. - **Сборка:** `Bogatyri.Battle` (без Unity и без float — тот же код будет считать бои на сервере). - **Папка:** `Assets/Scripts/Modules/Battle`. - **Зависит от:** ядра. ## Контракт `IBattleSystem` `BattleOutcome Resolve(BattleRequest request)` | `BattleRequest` | Что это | | --- | --- | | `AttackerUnits`, `DefenderUnits` | Состав сторон по типам (`TroopType`: пехота, лучники, кавалерия, осадные). | | `Attackers`, `Defenders` | Число воинов, если состав не задан (`null`) — тогда все считаются пехотой. | | `DefenderFortified` | Защитники за стенами (город, замок). У лагерей разбойников стен нет — бой в поле. | | `AttackerBonusPercent`, `DefenderBonusPercent` | Бонусы сторон в процентах: герой, технологии, голод (минус). | | `BattleOutcome` | Что это | | --- | --- | | `Victory` | Победил атакующий. | | `AttackerPower`, `DefenderPower` | Сила сторон ×100 (целые числа): с контрами, стенами и бонусами. | | `AttackerLosses`, `DefenderLosses`, `Survivors` | Потери сторон и выжившие атакующие — всего. | | `AttackerSurvivorUnits`, `DefenderLossUnits` | То же по типам войск. | Регистрирует `App/GameModules`: силу воина каждого типа передаёт из `GameData.Troops` (4 / 5 / 9 / 16), чтобы числа были в одном месте. Мир получает модуль при создании симуляции, не через реестр — так симуляцию можно запустить на сервере. ## Правила Это **предложение**. Формула боя — открытый вопрос этапа 6 плана, команда должна её утвердить. Все числа — константы в начале `BattleSystem.cs`. | Правило | Значение | | --- | --- | | Сила стороны | Сумма по типам: воины × сила типа × (100% + контры + осадный бонус) × (100% + бонусы стороны). | | Контры, +25% | Пехота сильнее кавалерии, кавалерия сильнее лучников, лучники сильнее пехоты. Бонус взвешивается по составу врага: против армии, где кавалерии 20%, пехота получает +5%. | | Осадные | Против стен +50%, в поле −25%. | | Стены | Защитники за стенами сильнее на 20%. | | Исход | Побеждает тот, у кого сила больше; ничья — защитнику. | | Потери проигравшего | Половина каждого типа. | | Потери победителя | Половина × (сила проигравшего / сила победителя): чем ровнее бой, тем больше потерь, но не больше половины. | Примеры (замок Змея Горыныча, гарнизон 20: пехота 8, лучники 6, кавалерия 4, осадные 2, за стенами): | Атакующие | Сила | Исход | Вернутся | | --- | --- | --- | --- | | 30 пехоты | 126 против 155 | поражение | 15 | | 40 пехоты | 168 против 155 | победа | 22 | | 30 смешанных (12 / 8 / 6 / 4) | 248 против 154 | победа | — | Бой без состава (старые походы, `Attackers` и `Defenders` числами) считается так, будто все — пехота. Без стен 30 против 20 — по-прежнему победа и 20 вернувшихся. ## События Нет: исход возвращается вызвавшему модулю. ## Сохранение Нет данных. ## Решения и план - **Командный план и ревью от 27.10.2026** (`Bogatyri_Plan_razrabotki.docx`, `Bogatyri_Battle_Army_Review_27-10-2026.docx`): случайность ±5% каждой стороне (воспроизводимая), прогноз риска вместо точного итога, потери от соотношения сил, раненые и погибшие, голод −50%, усталость −20%, числа — в настройки. Делается на этапе 2 плана. - **Открыто: малые отряды и округление.** Потери округляются вниз по каждому типу, поэтому одиночный проигравший не гибнет никогда. Проверено 28.10.2026: | Бой | Исход | Потери атакующего | Потери защитника | | --- | --- | --- | --- | | 1 против 1 | ничья, защитнику | 0 | 0 | | 1 против 10 | поражение | 0 | 0 | | 10 против 1 | победа | 0 | 0 | Варианты: округлять потери проигравшего вверх; или воспроизводимая случайность для остатка (одиночка гибнет с шансом 50%). Решает команда, тест `Battle_EdgeCases_OutcomeAndArithmetic` правило не фиксирует. - **Утвердить формулу** (контры, стены, осадные, потери) или поправить числа в `BattleSystem.cs`. - **Бонус героя** пока не передаётся в поход: `GameProgress.ArmyBonus` и сила героя в слое приложения. Нужен способ передать их в `AttackerBonusPercent` — например, через новый контракт или поле похода. - **Решение команды от 19.10.2026:** при голоде сильные дебаффы на боевую эффективность, включая гарнизон и походы. Для этого есть `AttackerBonusPercent` / `DefenderBonusPercent` (минус), проценты — из `EconomyConfig`. Голод уже считает модуль Населения (`IsStarving`). - **Гарнизоны соседей** пока не уменьшаются после боя: соседи — заглушки до сервера. ## Журнал изменений | Дата | Кто | Что | | --- | --- | --- | | 28.10.2026 | Claude | Тест крайних случаев (ревью, п. 2.4): 1×1, 1×10, 10×1, 0×0, пустая сторона, смешанный состав, бонусы −100%, −500%, +100000%, бой числом. Проверяются исход и арифметика (нет отрицательных, выжившие + погибшие = ушедшие). Правило округления потерь — открытый вопрос. | | 27.10.2026 | Claude | Бой с типами войск: сила по типам из `GameData.Troops`, контры (пехота > кавалерия > лучники > пехота, +25%), стены +20%, осадные +50% против стен и −25% в поле, потери по типам. `BattleRequest` и `BattleOutcome` расширены, старый бой «числом» считается пехотой. Тесты: контры, стены, осадные, потери в пределах состава. | | 19.10.2026 | Claude | Модуль выделен: `BattleResolver` из `WorldSimulation.cs` стал `BattleSystem` с контрактом `IBattleSystem`; `BattleOutcome` перенесён в ядро. Правила не изменились. |