Решения №11–13 (документ 01 комплекта): - №11: прогноз показывает точный шанс победы (BattleForecast.WinChancePermille) — перебор всех 101×101 равновероятных сочетаний удачи; в окне атаки «шанс победы 27%» - №12: сила считается точной дробью (BigInteger), удача — после всех модификаторов, округление одно и только для показа (3 пехоты против 1 кав. и 2 пех.: 13,00 вместо 12,96) - №13: потери — целая часть гарантирована, дробная — шанс ещё одной потери из отдельного потока случайности (своя соль на сторону и тип), воспроизводимо по номеру боя; одиночка-проигравший теперь может погибнуть - версия правил боя 3 (BattleRules, BattleConfig) Голод на момент боя (№9, документ 02 — офлайн в причинно-следственном порядке): - MarchManager спрашивает IPopulation.WasStarvingAt(время прихода войска) - перед боем, прошедшим в прошлом, просит Население досчитать время (публичный Tick); модуль Населения не менялся Формула потерь (№14) и раненые (№15) не тронуты — ждут чисел от команды. Тесты: шанс победы совпадает с 20 000 настоящих боёв (±2%), сила без промежуточного округления, округление потерь (одиночка гибнет ~50%, 1,5 → 1 или 2). Все 42 теста ModuleTests проходят вне Unity. Документы Battle, World, Core, README обновлены (только наши строки). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
68 lines
3.8 KiB
C#
68 lines
3.8 KiB
C#
using UnityEngine;
|
|
|
|
// ТАБЛИЦА БАЛАНСА БОЯ. Все числа боевой системы -- здесь, а не в коде модуля (ревью от 27.10.2026, п. 2.5).
|
|
//
|
|
// Ассет: Assets/Resources/BattleConfig.asset (выдели его в окне Project и меняй числа в Inspector,
|
|
// перекомпиляция не нужна; изменения действуют со следующего запуска игры). Создать заново:
|
|
// правый клик в Project -> Create -> Bogatyri -> Battle Config, имя файла -- BattleConfig, папка -- Resources.
|
|
//
|
|
// Модуль Боя таблицу не видит: App/GameModules переводит её в BattleRules.
|
|
// Сила воинов -- в GameData.Troops (рядом с ценой и временем обучения), здесь её нет.
|
|
// Числа -- стартовые для тестирования (план от 27.10.2026), утверждает команда.
|
|
[CreateAssetMenu(fileName = "BattleConfig", menuName = "Bogatyri/Battle Config")]
|
|
public class BattleConfig : ScriptableObject
|
|
{
|
|
[Tooltip("Версия баланса боя. Поменял числа -- подними версию: итог боя запоминает, по какой версии посчитан")]
|
|
public int version = 3;
|
|
|
|
[Tooltip("Контра, %: пехота > кавалерия > лучники > пехота. Взвешивается по доле нужного типа у врага")]
|
|
public int counterPercent = 25;
|
|
[Tooltip("Стены, %: усиление защитников замка и городов")]
|
|
public int wallsPercent = 20;
|
|
[Tooltip("Осадные при штурме стен, %")]
|
|
public int siegeVsWallsPercent = 50;
|
|
[Tooltip("Осадные в поле и в обороне, % (минус)")]
|
|
public int siegeInFieldPercent = -25;
|
|
[Tooltip("Потери проигравшего, % от каждого типа. Не окончательная формула")]
|
|
public int loserLossPercent = 50;
|
|
[Tooltip("Случайность каждой стороны: от -N% до +N%. 0 -- без случайности")]
|
|
public int randomPercent = 5;
|
|
|
|
[Tooltip("Голод: сколько силы остаётся, %. Утверждено 27.10.2026: -50% (остаётся 50). Проверяется на момент боя")]
|
|
public int famineStrengthPercent = 50;
|
|
[Tooltip("Усталость: сколько силы остаётся, %. Утверждено 27.10.2026: -20% (остаётся 80). Вместе с голодом -- 40%")]
|
|
public int fatigueStrengthPercent = 80;
|
|
|
|
static BattleConfig cached;
|
|
|
|
public static BattleConfig Load()
|
|
{
|
|
if (cached != null) return cached;
|
|
cached = Resources.Load<BattleConfig>("BattleConfig");
|
|
if (cached == null)
|
|
{
|
|
Debug.LogWarning("[БОЙ] Нет Assets/Resources/BattleConfig.asset -- берутся числа по умолчанию из BattleConfig.cs.");
|
|
cached = CreateInstance<BattleConfig>();
|
|
}
|
|
return cached;
|
|
}
|
|
|
|
// Правила для модуля Боя
|
|
public BattleRules ToRules(int[] unitPower)
|
|
{
|
|
return new BattleRules
|
|
{
|
|
Version = version,
|
|
UnitPower = unitPower,
|
|
CounterPercent = counterPercent,
|
|
WallsPercent = wallsPercent,
|
|
SiegeVsWallsPercent = siegeVsWallsPercent,
|
|
SiegeInFieldPercent = siegeInFieldPercent,
|
|
LoserLossPercent = loserLossPercent,
|
|
RandomPercent = Mathf.Max(0, randomPercent),
|
|
FamineStrengthPercent = Mathf.Clamp(famineStrengthPercent, 0, 100),
|
|
FatigueStrengthPercent = Mathf.Clamp(fatigueStrengthPercent, 0, 100)
|
|
};
|
|
}
|
|
}
|