squad-proto/docs/20-gdd.md
z.kirill ece906cbb3 Отряд растёт с одного оперативника до пяти (M24)
Игра начинается ОДНИМ человеком: тактический нож, слабый фонарь, куртка.
Остальные четверо нанимаются за опыт по кривой 600/2400/9600/38400 —
самая дорогая покупка в игре и намеренно. Одиночка с ножом это первое
впечатление, и продать второго бойца за одну вылазку значило бы выбросить
весь хоррор начала: вдвоём уже не страшно.

NUM_AGENTS осталась величиной времени сборки и означает теперь ВМЕСТИМОСТЬ,
а не размер отряда: делать её динамической это сотня мест ради числа,
которое всё равно упирается в пять. Занятость слота это Agent::present, и
он отличается от alive. Правила боя читают только alive — для них пустой
слот и павший одно, и это верно. Разница нужна там, где показывают
человека: у павшего есть тело на полу и перечёркнутая карточка, у пустого
слота нет ни того, ни другого.

Проверка в --descend меряет цепочку «в профиле -> на этаже» и потолок, а
главное — переживает ли одиночка первую схватку:

  отряд: в профиле 1 -> на этаже 1, после найма 2, цена 600, сверх потолка отказ
         одиночка с ножом на первом этаже: выжил, 100 -> 41, подошло 2, убил 2

Первая версия этой проверки не измеряла ничего: боец стоял минуту, к нему
не подошёл никто, и «выжил» было пустым словом. Теперь отряд ставится
рядом с тварью.

Попутно найдено и исправлено: Profile::Save три вехи не писала ни версию
формата, ни улучшения. Купленный запас патронов действовал до конца
запуска и молча пропадал при чтении, а профиль без версии читался как
формат 1. Круговой прогон этого не видел, потому что сверял три поля из
десяти и делал это на пустом профиле, где всё сходится само. Теперь он
сверяет поля списком и на набитом профиле.

Формат профиля 3: добавлена строка squad. Старый профиль играл впятером и
получает пятерых при миграции — отобрать их значило бы съесть отряд,
которого игрок не терял.

--accept PASS без изменений: без профиля отряд по-прежнему впятером.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 22:29:19 +03:00

272 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 20 — Дизайн игры: от одного исследователя до отряда думслееров
Это мастер-документ. Формулы урона и стихий — [21-damage.md](21-damage.md),
предметы и зачарования — [22-loot.md](22-loot.md), бесконечный лейт, лидерборды
и ачивки — [23-endgame.md](23-endgame.md).
Всё, что здесь написано, обязано ужиться с уже построенным: спуск и бюджет
опасности ([16-descent.md](16-descent.md)), экстракшен ([17-extraction.md](17-extraction.md)),
вес, боезапас и расходники, движок Tile2D ([18-engine.md](18-engine.md)).
Где новое ломает старое — сказано прямо.
## 1. Обещание игры
Первый экран: **один** оперативник-исследователь. Тактический нож, слабый
фонарь, костюм радиозащиты. Полупустая лаборатория, две вялых твари, свет
работает. Не страшно — и это НАМЕРЕННО: игроку показывают дно шкалы, чтобы
через сто этажей он мог оглянуться.
> Сделано в M24. С поправкой на то, что есть: костюма радиозащиты в игре нет —
> сопротивления пока только у тварей, поэтому одиночка выходит в куртке.
> Замерено: он переживает первую схватку и убивает двух тварей, оставаясь с 41
> здоровьем из 100 ([17-extraction.md](17-extraction.md)).
Последний экран, которого нет: пятеро в силовой броне идут сквозь Бездну,
поджигают, замораживают и расщепляют всё в радиусе, и всё равно однажды не
возвращаются.
Между этими двумя точками — 200 часов, и ни одной минуты, где сила решала бы
всё сама.
## 2. Закон масштаба — главное правило всей математики
> **Угроза растёт квадратично. Сила отряда — линейно с затуханием.
> Разрыв закрывается ЗНАНИЕМ, а не числами.**
Угроза этажа — это бюджет опасности, он уже квадратичный:
`T(d) = 3 + 2.2·(d1) + 0.10·(d1)²`.
Сила отряда `P` растёт от улучшений, снаряжения и артефактов, но каждый источник
имеет затухание (§6). Поэтому `T(d) / P` неизбежно растёт, и на каждой глубине
есть **стена** — этаж, где отряд перестаёт справляться.
Сдвинуть стену можно тремя способами, и только третий не имеет потолка:
| Способ | Даёт | Потолок |
|---|---|---|
| улучшения и снаряжение | +58 этажей за полный тир | есть, жёсткий |
| артефакты и зачарования | +36 этажей за сборку | есть, мягкий |
| **знание** — стихии, реакции, порядок целей, маршрут | ×1.53 к эффективной силе | **нет** |
Отсюда следуют все дальнейшие решения. Если бы числа закрывали разрыв, игра
перестала бы быть хоррором на сороковом этаже: страшно не там, где мало урона,
а там, где ты не понимаешь, что тебя убивает.
**Что ломается, если нарушить.** Дайте силе расти быстрее квадрата — и лейтгейм
превратится в покос травы, а лидерборд — в тест на терпение. Дайте угрозе расти
быстрее силы без канала знания — и стена станет непроходимой стеной, а не
задачей.
## 3. Акты и глубины
Шесть актов авторского содержимого, дальше — бесконечность.
| Акт | Глубины | Тема | Что вводится | Отряд |
|---|---|---|---|---|
| I. Лаборатория | 18 | STEEL | базовый бой, вес, патроны | 1 |
| II. Технические уровни | 920 | RUST | стихии INC/CRY, первые аффиксы, 2-й оперативник | 2 |
| III. Био-крыло | 2135 | FLESH | TOX, on-death эффекты, зачарования | 3 |
| IV. Криокамеры | 3652 | FROST | ARC, реакции, специализации | 4 |
| V. Реактор | 5372 | EMBER | RAD, аномалии, артефакты | 5 |
| VI. Провал | 73100 | VOID | VOID, залом, сборки-ключи | 5 |
| VII. Бездна | 101+ | ABYSS | мутации, сезоны, лидерборды | 5 |
Тем становится семь (сейчас четыре: `THEME_COUNT = 4` в `engine/theme.h`).
Полосы задаются проектом (`themes` в `project.txt`), поэтому это правка данных,
а не движка.
Каждый акт — это **новая причина умирать**, а не новый цвет стен. Акт без
собственной механики смерти вырезается.
## 4. Игровой цикл
Три петли, вложенные друг в друга. Каждая обязана давать ответ на вопрос
«зачем ещё раз».
### Петля этажа (38 минут)
Спуститься → разведать → решить, где драка неизбежна → собрать находки →
уйти на спуск или наверх. Решение одно и постоянное: **ещё этаж или назад**.
Его задают ресурсы (патроны, бинты, вес) и здоровье, а не таймер.
### Петля вылазки (2545 минут)
Чекпоинт → 512 этажей → эвакуация или вайп. Ставка: снаряжение на выживших.
Награда: добыча, опыт, материалы, продвижение рекорда.
### Петля мета (десятки часов)
Опыт → узлы улучшений. Материалы → крафт и зачарования. Артефакты → сборки.
Рекорд глубины → новые чекпоинты → доступ к более глубоким находкам.
```
┌──────────── этаж ────────────┐
спуск│ разведка → бой → находки │уход
└───────────┬──────────────────┘
↓ эвакуация
┌──────── вылазка ─────────────┐
│ опыт · материалы · артефакты │
└───────────┬──────────────────┘
↓ база
┌────────── мета ──────────────┐
│ узлы · крафт · сборка отряда │
└───────────┬──────────────────┘
↓ глубже
```
## 5. Двести часов: откуда цифра
Не «на глазок», а из бюджета времени.
| Величина | Значение |
|---|---|
| среднее время этажа | 4.5 мин (акт I — 2.5, акт VI — 7) |
| этажей за вылазку | 5 → 12 (растёт с глубиной чекпоинтов) |
| время вылазки с подготовкой | 28 → 48 мин |
| вылазок на продвижение одного чекпоинта (5 этажей) | 1 → 12 |
Вылазок на акт: I — 6, II — 22, III — 38, IV — 56, V — 74, VI — 96.
**Итого ≈ 292 вылазки × 40 мин ≈ 195 часов.**
Кривая «вылазок на чекпоинт» растёт линейно: `R(c) = 1 + 0.55·c`, где `c`
номер чекпоинта. Линейно, а не экспоненциально: экспонента даёт стену, за
которой игрок уходит, а не гриндит.
**Правило против гринда:** каждая вылазка обязана давать прогресс, даже
провальная. Вайп сохраняет рекорд глубины и половину материалов, найденных на
этажах глубже предыдущего рекорда (см. §7). Ноль прогресса за 40 минут — это
причина закрыть игру, а не мотивация.
## 6. Рост отряда
### 6.1. Оперативники
Начинаем с одного. Каждый следующий — событие, а не покупка.
| № | Класс | Где | Условие |
|---|---|---|---|
| 1 | **Исследователь** | старт | — |
| 2 | **Штурмовик** | D912 | капсула стазиса + 2 500 опыта |
| 3 | **Техник** | D2126 | капсула + 18 000 опыта + 3 био-ядра |
| 4 | **Егерь** | D3642 | капсула + 90 000 опыта + 5 крио-ядер |
| 5 | **Инквизитор** | D5360 | капсула + 400 000 опыта + артефакт |
Капсула — редкая находка в своей полосе глубин (шанс на этаж 6%, пити на 20-м
этаже полосы). Найти её можно только В ЭТОЙ полосе: пропустить акт и прийти за
пятым оперативником на десятом этаже нельзя.
Классы различаются НЕ статами, а поведением в бою — игра без ручных действий
(спек 5), и класс это то, как оперативник ведёт себя сам:
| Класс | Поведение | Слабость |
|---|---|---|
| Исследователь | держит дистанцию, первым замечает аномалии, +обзор | ломается в ближнем бою |
| Штурмовик | идёт первым, держит удар, ломает строй тварей | жрёт патроны и бинты |
| Техник | ставит турель/мину на стоянках, чинит броню между этажами | почти не бьёт сам |
| Егерь | бьёт по одиночным целям с дистанции, добивает раненых | бесполезен в толпе |
| Инквизитор | накладывает стихии по площади, запускает реакции | хрупкий, ест материалы |
Пятеро — потолок жёсткий: `NUM_AGENTS = 5` уже в коде, и это же потолок
читаемости строя. Шестой в клине не виден.
### 6.2. Дерево улучшений
Пять ветвей, в каждой 8 узлов, у каждого 5 уровней = **200 уровней узлов**.
| Ветвь | О чём | Пример узлов |
|---|---|---|
| Снабжение | патроны, вес, расходники | запас, переноска, ёмкость сумки, авто-бинт |
| Живучесть | HP, броня, сопротивления | живучесть, латание, сопротивление RAD |
| Огневая мощь | урон, крит, скорострельность | пробитие, крит, перезарядка |
| Стихии | элементы и реакции | сила стихии, длительность, сила реакций |
| Разведка | обзор, находки, аномалии | обзор, шанс редкого, чтение аномалий |
Существующие четыре улучшения (`Upgrade::AMMO/CARRY/SIGHT/VIGOR` в
`sim/profile.h`) становятся первым кольцом ветвей Снабжения и Живучести.
**Затухание — обязательное.** Уровень `L` узла даёт долю от максимума узла:
```
gain(L) = maxGain · (1 1 / (1 + 0.55·L))
```
L=1 → 35% максимума, L=2 → 52%, L=3 → 62%, L=4 → 69%, L=5 → 73%.
Пятый уровень стоит вчетверо дороже первого и даёт вчетверо меньше — и это
честно написано в подсказке узла.
**Цена уровня:** `cost(node, L) = base(node) · 2.15^L`, где `base` — от 150
(первое кольцо) до 12 000 (внешнее). Полное дерево ≈ **41 миллион опыта**.
### 6.3. Сходится ли экономика опыта
Опыт за этаж: `XP(d) = T(d) · 10 · (1 + 0.15·(d1))` — это уже работающая
формула (`xpPerDanger`, `xpScale`).
| Глубина | XP за этаж |
|---|---|
| 5 | 205 |
| 20 | 3 460 |
| 50 | 29 300 |
| 80 | 116 000 |
| 100 | 190 000 |
За 292 вылазки по 8 этажей средней глубины акта набегает ≈ **44 миллиона**.
Дерево стоит 41 — сходится с запасом 7% на переигрывание. Это не совпадение:
`base` узлов подобраны от этой суммы обратным счётом.
**Опыт зачисляется только за эвакуацию** — правило уже в коде (`FinishRun`).
Вайп теряет весь опыт вылазки, и это главный источник напряжения на выходе.
## 7. Что теряется и что остаётся
Дополняет правила экстракшена ([17-extraction.md](17-extraction.md)).
| | Эвакуация | Вайп |
|---|---|---|
| надетое на выживших | остаётся | — |
| надетое на павших | теряется | теряется |
| общая сумка | в схрон целиком | теряется |
| опыт вылазки | зачисляется | теряется |
| материалы | все | **половина того, что найдено глубже рекорда** |
| рекорд глубины | растёт | **растёт** |
| узлы, артефакты в схроне | остаются | остаются |
Половина материалов при вайпе — единственная поблажка во всей системе, и она
куплена конкретной ценой: без неё «пошёл проверить, что там на пять этажей
глубже» стоит сорок минут и не даёт ничего. Прогресс обязан идти даже из
провала, иначе разведка глубины перестаёт быть занятием.
## 8. Что должно измениться в коде
Не «когда-нибудь», а список того, что эта математика требует прямо сейчас.
| Что | Где | Объём |
|---|---|---|
| отряд переменного размера 1→5 | `sim/squad.*`, HUD, строй | средний |
| стихии и сопротивления | `sim/loadout.h`, `sim/target.*`, каталог | крупный |
| шина триггеров on-hit/on-kill | поверх `sim/events.h` — журнал УЖЕ есть | средний |
| аффиксы предметов | `sim/items.h` → предмет с рулонами | крупный |
| материалы и крафт | `sim/profile.h`, новый экран | средний |
| дерево узлов | `sim/profile.h` + экран | средний |
| темы FLESH.. VOID | данные проекта | мелкий |
| мутации тварей | `engine/catalog.*` + `sim/enemy.*` | средний |
**Порядок работ.** Стихии → триггеры → аффиксы → материалы → дерево → классы →
мутации. Каждый шаг — отдельная веха со своими проверками, как всё в этом
репозитории. Стихии первыми, потому что от них зависят и аффиксы, и мутации, и
половина ачивок.
## 9. Как это проверяется
Дизайн, который нельзя измерить, — это пожелание. Для каждого утверждения выше
есть или должен появиться инструмент ([19-agent.md](19-agent.md)):
| Утверждение | Чем меряется |
|---|---|
| угроза растёт квадратично | `--tool curve 1 120` |
| стена сдвигается на 58 этажей за тир | `--tool wall <сборка>` (новый) |
| TTK держится в коридоре | `--tool ttk <глубина>` (новый) |
| экономика опыта сходится | `--tool economy` (новый): доход против цены дерева |
| 200 часов | `--tool time` (новый): бюджет по актам из таблицы §5 |
| набор комнат тянет глубину | `--tool validate` (есть) |
Числа в этих документах — **вход** для инструментов, а не украшение. Расхождение
между таблицей и выводом инструмента означает, что неправ документ.