Files
MVP1/Docs/Modules/Battle.md
T
AlexanderandClaude Opus 5.5 eeb90b8cb6 Боевой цикл, этап 2 плана: таблица баланса боя, случайность ±5%, прогноз риска, полный итог боя
Числа боя (ревью 27.10.2026, п. 2.5):
- BattleRules (модуль Боя, без Unity) — все числа в одном месте, с версией
- таблица BattleConfig (Assets/Resources/BattleConfig.asset) — меняется в Inspector, App/GameModules переводит её в BattleRules
- сила воинов по-прежнему из GameData.Troops

Случайность (план 27.10.2026):
- каждой стороне от −5% до +5% (шаг 0,1%), из номера боя BattleRequest.Seed (SplitMix64)
- тот же номер с теми же войсками — всегда тот же итог; поход получает battleSeed при выступлении и хранит его

Прогноз:
- IBattleSystem.Forecast: «преимущество / исход неясен / высокий риск поражения», диапазоны силы и потерь
- окно атаки показывает прогноз риска вместо точного итога; окно итога боя — силы и удачу сторон

Итог боя (ревью, п. 2.3):
- для обеих сторон по типам: до боя, выжившие, погибшие, раненые (пока нули — доля не утверждена)
- номер боя, версия правил, удача сторон

Тесты: случайность воспроизводима и в пределах ±5%; прогноз не противоречит 300 боям с разными номерами;
итог сходится по типам у обеих сторон; правила из таблицы; тот же поход — тот же бой.
Все 37 тестов ModuleTests прогнаны вне Unity — проходят.

Открыто для команды (Battle.md): показывать ли шанс победы в процентах; порядок бонусов и случайности.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 19:03:14 +01:00

13 KiB
Raw Blame History

Боевая система

Урон, потери, исход боя с учётом типов войск. Модуль только считает: кто победил и сколько погибло каждого типа. Кто идёт в бой и что делать с итогом, решают другие модули.

  • Сборка: Bogatyri.Battle (без Unity и без float — тот же код будет считать бои на сервере).
  • Папка: Assets/Scripts/Modules/Battle.
  • Зависит от: ядра.

Контракт IBattleSystem

  • BattleOutcome Resolve(BattleRequest request) — бой.
  • BattleForecast Forecast(BattleRequest request) — прогноз до боя с учётом случайности. Итог конкретного боя не раскрывает.
BattleRequest Что это
AttackerUnits, DefenderUnits Состав сторон по типам (TroopType: пехота, лучники, кавалерия, осадные).
Attackers, Defenders Число воинов, если состав не задан (null) — тогда все считаются пехотой.
DefenderFortified Защитники за стенами (город, замок). У лагерей разбойников стен нет — бой в поле.
AttackerBonusPercent, DefenderBonusPercent Бонусы сторон в процентах: герой, технологии, голод (минус).
Seed Номер боя. Из него считается случайность сторон: тот же номер с теми же войсками — всегда тот же итог.
BattleOutcome Что это
Victory Победил атакующий.
BattleId, RulesVersion Номер боя (= Seed) и версия правил, по которой посчитан итог.
AttackerPower, DefenderPower Итоговая сила сторон ×100 (целые числа): с контрами, стенами, бонусами и случайностью.
AttackerLuckPermille, DefenderLuckPermille Выпавшая случайность сторон в десятых долях процента: +23 = +2,3%.
AttackerLosses, DefenderLosses, Survivors Выбывшие (погибшие + раненые) и выжившие атакующие — всего.
…UnitsBefore, …SurvivorUnits, …DeadUnits, …WoundedUnits По типам войск и для обеих сторон: до боя, выжившие, погибшие, раненые. По каждому типу: до = выжившие + погибшие + раненые. Раненых пока нет (нули): доля не утверждена.
DefenderLossUnits Выбывшие защитники по типам — для старого кода.
BattleForecast Что это
Chance Advantage — победа при любой случайности, Uncertain — решает случайность, HighRisk — поражение при любой случайности.
AttackerPowerMin/Max, DefenderPowerMin/Max Сила сторон при крайних значениях случайности.
AttackerLossesMin/Max Потери атакующего: от лучшего случая до худшего.

Регистрирует App/GameModules: числа боя — из таблицы BattleConfig, сила воина каждого типа — из GameData.Troops (4 / 5 / 9 / 16). Мир получает модуль при создании симуляции, не через реестр — так симуляцию можно запустить на сервере.

Правила

Числа — стартовые для тестирования (план от 27.10.2026). Все они в одном месте:

  • в игре — таблица Assets/Resources/BattleConfig.asset: выдели её в окне Project и меняй числа в Inspector, изменения действуют со следующего запуска. Скрипт таблицы — App/BattleConfig.cs;
  • в модуле — BattleRules.cs (значения по умолчанию для тестов и сервера). App/GameModules переводит таблицу в BattleRules;
  • сила воинов — в GameData.Troops, рядом с ценой и временем обучения;
  • поменял числа — подними version: итог боя запоминает версию правил (RulesVersion).
Правило Значение
Сила стороны Сумма по типам: воины × сила типа × (100% + контры + осадный бонус) × (100% + бонусы стороны).
Контры, +25% Пехота сильнее кавалерии, кавалерия сильнее лучников, лучники сильнее пехоты. Бонус взвешивается по составу врага: против армии, где кавалерии 20%, пехота получает +5%.
Осадные Против стен +50%, в поле −25%.
Стены Защитники за стенами сильнее на 20%.
Случайность, ±5% Каждой стороне от −5% до +5% (с шагом 0,1%), отдельно. Считается из номера боя (Seed, алгоритм SplitMix64) — одинаково на любой платформе. Применяется последней: после контр, стен и бонусов.
Исход Побеждает тот, у кого итоговая сила больше; ничья — защитнику.
Потери проигравшего Половина каждого типа.
Потери победителя Половина × (сила проигравшего / сила победителя): чем ровнее бой, тем больше потерь, но не больше половины.

Примеры (замок Змея Горыныча, гарнизон 20: пехота 8, лучники 6, кавалерия 4, осадные 2, за стенами):

Атакующие Сила Исход Вернутся
30 пехоты 126 против 155 поражение 15
40 пехоты 168 против 155 победа 22
30 смешанных (12 / 8 / 6 / 4) 248 против 154 победа —

Прогноз с учётом случайности (тот же замок, 10 000 боёв с разными номерами):

Атакующие Прогноз Сила Потери Побед на деле
30 пехоты высокий риск поражения 119–132 против 147–163 15 0%
36 пехоты исход неясен 143–158 против 147–163 16–18 27%
40 пехоты исход неясен 159–176 против 147–163 16–20 97%
45 пехоты преимущество 179–198 против 147–163 16–20 100%
30 смешанных (12 / 8 / 6 / 4) преимущество 235–260 против 146–162 7–9 100%

Бой без состава (старые походы, Attackers и Defenders числами) считается так, будто все — пехота. Без стен 30 против 20 — по-прежнему победа и 20 вернувшихся.

События

Нет: исход возвращается вызвавшему модулю.

Сохранение

Нет данных.

Решения и план

  • Сделано 28.10.2026 (этап 2 плана): числа — в таблицу BattleConfig с версией; итог боя симметричный для обеих сторон; случайность ±5% из номера боя; прогноз «преимущество / исход неясен / высокий риск поражения».
  • Открыто: прогноз. «Исход неясен» охватывает и 27%, и 97% побед (таблица выше). Показывать ли игроку шанс победы в процентах — решает команда (посчитать его можно точно).
  • Открыто: порядок бонусов и случайности. Сейчас случайность применяется последней, после бонусов стороны.
  • Номер боя в мультиплеере должен выдавать сервер: иначе клиент мог бы подбирать удачный.
  • Командный план и ревью от 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 плана: числа боя — в таблицу BattleConfig (Assets/Resources/BattleConfig.asset) и BattleRules с версией; случайность ±5% каждой стороне из BattleRequest.Seed; Forecast — прогноз риска; BattleOutcome симметричный: до боя, выжившие, погибшие, раненые (пока нули) по типам у обеих сторон, номер боя, версия правил, удача сторон. Тесты: случайность воспроизводима и в пределах ±5%, прогноз не противоречит бою, итог сходится по типам, правила из таблицы.
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 перенесён в ядро. Правила не изменились.