Files
MVP1/Docs/Modules/Battle.md
T
AlexanderandClaude Opus 5.5 d9c0039bd2 Кривая потерь по регламенту 31.10 (решение №14)
Бой (модуль Battle):
- доля выбывших каждого типа — плавная функция соотношения итоговых сил (сильная / слабая)
  по опорным точкам регламента: 1:1 — 45% / 45%, 3:1 — 16% / 74%, 5:1 — 11% / 88% (ТЕСТ);
  между точками линейно, без порогов-переключателей; одинаково для PvE, PvP и Круга
- заменяет «проигравший теряет 50%, победитель до 50%»
- считается точной дробью, округление потерь — как прежде шансом (№13)
- за 5:1 — значения последней точки (рост разгрома дальше не задан — вопрос команде)

Таблица BattleConfig: точки кривой (lossRatioPermille, strongLossPermille, weakLossPermille)
вместо loserLossPercent; некорректная таблица — значения по умолчанию. Версия правил 4.

Раненых пока нет: все выбывшие — погибшие. Раненые (№15) — следующим шагом вместе с госпиталем,
нужен контракт с Населением (Валдемар), чтобы раненые учитывались среди людей города.

Тесты: опорные точки, симметрия, плавность и монотонность, кривая из таблицы и защита от ошибки;
тесты округления пересчитаны под кривую. Все 47 тестов ModuleTests проходят вне Unity.
Код Валдемара не менялся.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 15:54:37 +01:00

20 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 Бонусы сторон в процентах: герой, технологии, голод (минус).
AttackerConditions, DefenderConditions Состояния сторон (BattleCondition, флаги): Famine — голод, Fatigue — усталость.
Seed Номер боя. Из него считается случайность сторон: тот же номер с теми же войсками — всегда тот же итог.
BattleOutcome Что это
Victory Победил атакующий.
BattleId, RulesVersion Номер боя (= Seed) и версия правил, по которой посчитан итог.
AttackerPower, DefenderPower Итоговая сила сторон ×100 (целые числа): с контрами, стенами, бонусами и случайностью.
AttackerLuckPermille, DefenderLuckPermille Выпавшая случайность сторон в десятых долях процента: +23 = +2,3%.
AttackerConditionPercent, DefenderConditionPercent Сколько силы оставили состояния: 100 — без штрафов, 50 — голод, 40 — голод и усталость.
AttackerLosses, DefenderLosses, Survivors Выбывшие (погибшие + раненые) и выжившие атакующие — всего.
…UnitsBefore, …SurvivorUnits, …DeadUnits, …WoundedUnits По типам войск и для обеих сторон: до боя, выжившие, погибшие, раненые. По каждому типу: до = выжившие + погибшие + раненые. Раненых пока нет (нули): доля не утверждена.
DefenderLossUnits Выбывшие защитники по типам — для старого кода.
BattleForecast Что это
Chance Advantage — победа при любой случайности, Uncertain — решает случайность, HighRisk — поражение при любой случайности.
WinChancePermille Шанс победы нападающего в десятых долях процента (решение №11). Точный: перебираются все 101 × 101 равновероятных сочетаний удачи сторон.
AttackerPowerMin/Max, DefenderPowerMin/Max Сила сторон при крайних значениях случайности.
AttackerLossesMin/Max Потери атакующего: от лучшего случая до худшего, с учётом округления потерь (№13).

Регистрирует 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% Решение №12. Каждой стороне от −5% до +5% (с шагом 0,1%), отдельно. Считается из номера боя (Seed, алгоритм SplitMix64) — одинаково на любой платформе. Применяется после всех модификаторов. Не прокачивается.
Без промежуточного округления Решение №12. Сила считается точной дробью (BigInteger): контра по составу врага, бонусы, голод и удача не округляются по дороге. Округляется один раз — только число для показа. Пример: 3 пехоты против 1 кавалерии и 2 пехоты — сила 13,00 (раньше 12,96).
Голод, −50% Утверждено 27.10.2026. Сила голодной стороны ×50%. Проверяется на момент боя. Действует и на нападающих, и на защитников.
Усталость, −20% Утверждено 27.10.2026. Сила ×80%. Правило уже в модуле, но пока никто её не выставляет: не утверждено, как учитывать смешивание свежих и уставших войск.
Голод и усталость вместе Последовательно: 50% × 80% = 40% силы (а не 30%).
Порядок Контры и осадные → бонусы стороны → состояния (голод, усталость) → случайность.
Исход Побеждает тот, у кого итоговая сила больше; ничья — защитнику.
Потери (решение №14, регламент 31.10) Доля выбывших каждого типа зависит от соотношения итоговых сил (сильная / слабая). Опорные точки (ТЕСТ): 1:1 — 45% / 45%, 3:1 — 16% / 74%, 5:1 — 11% / 88%. Между точками — плавно (линейно по соотношению), без порогов. Одинаково для PvE, PvP и Круга. За 5:1 — как при 5:1. Точки — в BattleConfig (lossRatioPermille, strongLossPermille, weakLossPermille).
Округление потерь Решение №13. Целая часть гарантирована, дробная — шанс ещё одной потери. Бросок — из отдельного потока случайности (своя «соль» на сторону и тип войск, не пересекается с удачей), воспроизводим по номеру боя. Одиночка-проигравший (потеря 0,5) гибнет примерно в половине боёв; 3 проигравших (1,5) теряют 1 или 2.

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

Атакующие Исход Вернутся (в среднем) Враг теряет из 20
30 пехоты поражение 15,5 8,3
40 пехоты победа в 97% боёв 22,5 9,2
30 смешанных (12 / 8 / 6 / 4) победа 19,1 10,8
78 смешанных победа 67,7 16,4

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

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

Шанс проверен тестом Battle_WinChance_MatchesRealBattles: совпадает с долей побед в 20 000 настоящих боёв с точностью ±2%.

Бой без состава (старые походы, Attackers и Defenders числами) считается так, будто все — пехота. Без стен 30 против 20 (1,5:1) — победа, возвращаются 18–19.

События

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

Сохранение

Нет данных.

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

  • Сделано 28.10.2026 (этап 2 плана): числа — в таблицу BattleConfig с версией; итог боя симметричный для обеих сторон; случайность ±5% из номера боя; прогноз «преимущество / исход неясен / высокий риск поражения».

  • Решено комплектом 29.10.2026 и сделано 30.10.2026: шанс победы в прогнозе (№11), сила без промежуточного округления (№12), округление потерь шансом (№13), голод на момент боя по истории голода Населения.

  • Сделано 28.10.2026: голод в бою. Голод игрока берётся из модуля Населения (IPopulation.IsStarving) в момент боя. Пример: 40 пехоты берут замок Змея Горыныча (168 против 155), голодные — нет (84 против 155). Числа — famineStrengthPercent и fatigueStrengthPercent в BattleConfig (версия правил 2).

  • Голод в офлайн-бою: Население хранит историю голода (IPopulation.WasStarvingAt, 48 часов, точность — шаг расчёта 10 минут). Перед боем, прошедшим в прошлом, мир просит Население досчитать время, затем спрашивает голод на момент прихода войска.

  • Голод гарнизона пока не нужен: на город игрока никто не нападает. Правило защитника уже есть (DefenderConditions).

  • Порядок бонусов и случайности решён (№12): удача — после всех модификаторов.

  • Номер боя в мультиплеере должен выдавать сервер: иначе клиент мог бы подбирать удачный.

  • Командный план и ревью от 27.10.2026 (Bogatyri_Plan_razrabotki.docx, Bogatyri_Battle_Army_Review_27-10-2026.docx): случайность ±5% каждой стороне (воспроизводимая), прогноз риска вместо точного итога, потери от соотношения сил, раненые и погибшие, голод −50%, усталость −20%, числа — в настройки. Делается на этапе 2 плана.

  • Малые отряды решены (№13): одиночка-проигравший гибнет с шансом по дробной части потерь.

  • Сделано 31.10.2026: кривая потерь (№14) по опорным точкам регламента 31.10. Раненых пока нет: все выбывшие считаются погибшими.

  • Открыто: разгром дальше 5:1. Регламент даёт точки до 5:1; дальше доли держатся на 11% / 88%. Растёт ли разгром выше (например, до 100% при 10:1) — решает команда.

  • Следующий шаг — раненые (№15) вместе с госпиталем. Доля погибших среди выбывших (ТЕСТ регламента): уверенная победа ~20%, близкий бой ~30%, поражение 2:1 ~45%, разгром 5:1 ~70%. Чтобы раненые не «пропали» из людей города, их должно учитывать Население (Валдемар) — договориться о контракте до реализации.

  • Утвердить формулу (контры, стены, осадные, потери) или поправить числа в BattleSystem.cs.

  • Бонус героя пока не передаётся в поход: GameProgress.ArmyBonus и сила героя в слое приложения. Нужен способ передать их в AttackerBonusPercent — например, через новый контракт или поле похода.

  • Решение команды от 19.10.2026: при голоде сильные дебаффы на боевую эффективность, включая гарнизон и походы. Для этого есть AttackerBonusPercent / DefenderBonusPercent (минус), проценты — из EconomyConfig. Голод уже считает модуль Населения (IsStarving).

  • Гарнизоны соседей пока не уменьшаются после боя: соседи — заглушки до сервера.

Журнал изменений

Дата Кто Что
31.10.2026 Claude Кривая потерь (решение №14, регламент 31.10): доля выбывших от соотношения итоговых сил по опорным точкам 1:1 — 45% / 45%, 3:1 — 16% / 74%, 5:1 — 11% / 88%, между ними плавно; вместо «проигравший 50%». Точки в BattleConfig, неверная таблица — значения по умолчанию. Версия правил 4. Тест Battle_LossCurve_ControlPointsAndSmoothness; тесты округления пересчитаны под кривую.
30.10.2026 Claude Комплект требований 29.10, решения №11–13: точный шанс победы в прогнозе (BattleForecast.WinChancePermille); сила — точной дробью без промежуточного округления; потери — целая часть гарантирована, дробная — шанс из отдельного потока случайности. Версия правил 3. Тесты: шанс совпадает с настоящими боями, сила без округления, округление потерь.
28.10.2026 Claude Голод и усталость: BattleCondition (флаги), BattleRequest.AttackerConditions / DefenderConditions, BattleOutcome.…ConditionPercent; голод −50%, усталость −20%, вместе 40% (последовательно); числа в BattleConfig и BattleRules (версия 2). Тесты: штрафы, голод переворачивает бой у нападающего и у защитника, прогноз с голодом.
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 перенесён в ядро. Правила не изменились.