Жалоба была «крашится при открытии апгрейдов». Не крашилось: пункт закрывал игру. В обработчике главного меню стоял `default: ui.quit`, а экран улучшений добавили четвёртым пунктом — обработчик о нём просто не узнал. Снаружи мгновенное закрытие окна неотличимо от падения. Починка на две строки, но интереснее причина, по которой это прожило четыре вехи: в проекте каждая механика меряется прогоном с кодом возврата, а меню не проверял никто. Все инструменты смотрят на СИМУЛЯЦИЮ. Поэтому заведён --ui-check: проходит по всем пунктам меню и требует одного — нажатие ВЕДЁТ КУДА-ТО, а из игры выходит ровно один пункт, QUIT. Плюс проверяет, что кнопки экрана улучшений действительно покупают. Окно при этом не открывается: UiActivate ничего из raylib не трогает. Проверка сперва запущена на СЛОМАННОЙ сборке и дала код 1 с диагнозом «пункт UPGRADES не делает ничего», и только после этого объявлена рабочей. Проверка, которую не видели падающей, ещё ничего не проверяет. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
133 lines
14 KiB
Markdown
133 lines
14 KiB
Markdown
# CLAUDE.md — оглавление
|
||
|
||
Этот файл — **только навигация**. Содержание живёт в `docs/`, по одному файлу на тему.
|
||
Читай нужный раздел, а не весь проект.
|
||
|
||
## Документация
|
||
|
||
| Файл | О чём | Когда открывать |
|
||
|---|---|---|
|
||
| [docs/00-overview.md](docs/00-overview.md) | что это за прототип, границы задачи | первое знакомство |
|
||
| [docs/01-build-and-run.md](docs/01-build-and-run.md) | сборка, запуск, управление, dev-режимы CLI | собрать и потыкать |
|
||
| [docs/02-architecture.md](docs/02-architecture.md) | карта модулей, порядок шага симуляции, правила зависимостей | перед любой правкой кода |
|
||
| [docs/03-rendering.md](docs/03-rendering.md) | софтверный фреймбуфер, изометрия, сортировка, спрайты | рендер, камера, спрайты |
|
||
| [docs/04-world.md](docs/04-world.md) | тайлмап, планировка уровня, DDA-рейкаст, коллизии, мишени | карта, LOS, коллизии |
|
||
| [docs/05-squad-ai.md](docs/05-squad-ai.md) | **ядро**: LaneClear, решатель огневых позиций, резерв линий, стрельба | поведение отряда |
|
||
| [docs/06-debug-and-tuning.md](docs/06-debug-and-tuning.md) | оверлей F1–F4, метрики, runtime-тюнинг, `--set` | отладка и балансировка |
|
||
| [docs/07-milestones.md](docs/07-milestones.md) | журнал вех M0–M6: что сделано и чем проверено | история и статус |
|
||
| [docs/08-decisions.md](docs/08-decisions.md) | отклонения от спека и почему, с замерами | «почему тут не как в ТЗ» |
|
||
| [docs/09-acceptance.md](docs/09-acceptance.md) | критерии приёмки (спек 11) и их текущие цифры | приёмка |
|
||
| [docs/10-atmosphere.md](docs/10-atmosphere.md) | **хоррор-слой**: свет, туман войны, трассеры, напряжение | картинка и атмосфера |
|
||
| [docs/11-melee.md](docs/11-melee.md) | **ближний бой**: сектор удара, три фазы, свой круг, дуга | клинки, классы оружия |
|
||
| [docs/12-assets.md](docs/12-assets.md) | **ассеты**: конвейер SpriteForge, манифесты, загрузчик, hot reload | добавить или пересобрать спрайт |
|
||
| [docs/13-combat.md](docs/13-combat.md) | **бой**: каталог оружия, твари, снаряжение, меню и HUD | оружие, враги, инвентарь, UI |
|
||
| [docs/14-monsters.md](docs/14-monsters.md) | **твари-ассеты**: Blender-риг на пять морфологий, листы, проверки | нарисовать или пересобрать тварь |
|
||
| [docs/15-engine-and-editor.md](docs/15-engine-and-editor.md) | **движок и редактор**: три цели сборки, каталог сущностей, формат комнат, генератор уровней | делать комнаты, менять генерацию, трогать границу движка |
|
||
| [docs/16-descent.md](docs/16-descent.md) | **спуск**: глубина как первичное понятие, бюджет опасности, лут, кривая сложности | менять сложность, добавлять тварей и лут |
|
||
| [docs/17-extraction.md](docs/17-extraction.md) | **экстракшен**: эвакуация, профиль и схрон, чекпоинты, что теряется | правила забега, снаряжение между вылазками |
|
||
| [docs/18-engine.md](docs/18-engine.md) | **Tile2D**: границы движка, проекции 2D, формат проекта, второй проект | трогать движок, заводить проект, добавлять вид отображения |
|
||
| [docs/19-agent.md](docs/19-agent.md) | **движок и ЛЛМ**: инструменты `--tool`, скиллы, терминал в редакторе | работать над проектом через claude/codex |
|
||
| [docs/20-gdd.md](docs/20-gdd.md) | **дизайн игры**: акты, петли, рост отряда, закон масштаба, 200 часов | что и зачем строим дальше |
|
||
| [docs/21-damage.md](docs/21-damage.md) | **урон**: семь стихий, статусы, реакции, формулы, триггеры | боевая математика |
|
||
| [docs/22-loot.md](docs/22-loot.md) | **добыча**: редкости, аффиксы, артефакты, зачарования, материалы | предметы и экономика |
|
||
| [docs/23-endgame.md](docs/23-endgame.md) | **лейтгейм**: Бездна, мутации, лидерборды, 262 ачивки | всё после сотого этажа |
|
||
|
||
## Быстрые факты
|
||
|
||
- Исходный спек: [SQUAD_PROTOTYPE_SPEC.md](SQUAD_PROTOTYPE_SPEC.md) — источник истины по правилам.
|
||
- Сборка: `cmake -S . -B build && cmake --build build --config Release`.
|
||
Целей три: `tile2d` (библиотека), `build/bin/squad_proto.exe` (игра),
|
||
`build/bin/tile2d_editor.exe` (редактор комнат).
|
||
- **Инструментов две группы, и делятся они по предмету**: `squad_proto --tool` —
|
||
баланс (урон, сопротивления, экономика), `tile2d_editor --tool` — содержимое
|
||
(комнаты, каталог, этажи). Редактор не линкуется с `sim/` и правил боя не
|
||
видит, поэтому смешать их нельзя.
|
||
- **Содержимое щупают инструментами, а не глазами**: `tile2d_editor --tool help`.
|
||
Правка делается файлами (комнаты и каталог — текст), последствия читаются
|
||
командой: `--tool validate`, `--tool floor`, `--tool map`
|
||
([19-agent.md](docs/19-agent.md)). Код возврата 1 = поломка.
|
||
- В редакторе снизу терминал (клавиша `` ` ``): те же инструменты, git, сборка и
|
||
запросы к `claude`/`codex` прямо оттуда. Открытый проект уходит потомкам
|
||
переменной `TILE2D_PROJECT`.
|
||
- Самопроверка: `squad_proto.exe --accept` печатает PASS/FAIL по всем измеримым критериям.
|
||
Содержимое проверяется отдельно: `tile2d_editor.exe --check` (комнаты и покрытие глубин),
|
||
`squad_proto.exe --descend 8` (спуск, эвакуация, круговой прогон профиля),
|
||
`squad_proto.exe --ui-check` (пункты меню: каждый куда-то ведёт).
|
||
- **У кнопки тоже есть код возврата.** Пункт UPGRADES четыре вехи закрывал игру
|
||
вместо открытия экрана: в обработчике стоял `default: quit`, а новый пункт
|
||
добавили четвёртым. Все прогоны меряли симуляцию, меню не проверял никто —
|
||
теперь проверяет `--ui-check`, и новый экран обязан появиться в нём.
|
||
- **Унести можно только то, что на ВЫЖИВШИХ.** Павший теряет своё, вайп теряет всё,
|
||
достигнутая глубина не теряется никогда ([17-extraction.md](docs/17-extraction.md)).
|
||
- **`NUM_AGENTS` — это вместимость, а не размер отряда.** Сколько слотов занято,
|
||
говорит `Squad::roster`, а занят ли конкретный — `Agent::present`. Правила боя
|
||
читают только `alive` (пустой слот и павший для них одно), а рендер, HUD и
|
||
профиль обязаны смотреть на `present`: иначе у одинокого оперативника вокруг
|
||
появятся четыре чужих трупа ([17-extraction.md](docs/17-extraction.md)).
|
||
- **Таймера в игре нет и не заводить.** Фонарь тратит заряд за ПРОЙДЕННЫЙ ПУТЬ,
|
||
а не за время: стоять и думать бесплатно, дорого — обшарить этаж целиком.
|
||
Расход со `dt` вместо пути — это таймер, и `--descend` его ловит
|
||
([17-extraction.md](docs/17-extraction.md)).
|
||
- **Закон масштаба:** угроза растёт квадратично, сила отряда — линейно с
|
||
затуханием, разрыв закрывается ЗНАНИЕМ (стихии, реакции, порядок целей).
|
||
Числа не должны спасать — иначе хоррор кончается на сороковом этаже
|
||
([20-gdd.md](docs/20-gdd.md)).
|
||
- **Предмет — это ЭКЗЕМПЛЯР, а не вид.** `ItemInstance` неявно приводится к
|
||
`ItemId`, и это удобно ровно до того места, где вещь копируют: присваивание в
|
||
`ItemId` молча теряет редкость и аффиксы. Подбор, перекладывание и запись
|
||
профиля обязаны работать с экземпляром целиком ([22-loot.md](docs/22-loot.md)).
|
||
- **Ни одного чистого улучшения.** Артефакт без цены становится обязательным, а
|
||
обязательный предмет — это вырезанный слот ([22-loot.md](docs/22-loot.md)).
|
||
- **Глубина — первичное понятие.** Вся кривая сложности живёт в одной функции
|
||
`DescribeFloor` ([engine/progression.h](engine/progression.h)); размазывать её
|
||
по генератору, каталогу и рендеру нельзя ([16-descent.md](docs/16-descent.md)).
|
||
- **Редактор линкуется только с движком.** Обращение из `editor/` к `sim/`,
|
||
`ai/` или `ui/` — ошибка сборки, и так задумано ([15-engine-and-editor.md](docs/15-engine-and-editor.md)).
|
||
Редактор принадлежит движку: он открывает любой проект (`--project <имя>`) и
|
||
ни одной игры по имени не знает.
|
||
- Тексты НА ЭКРАНЕ — латиницей: встроенный шрифт raylib кириллицы не знает и
|
||
рисует её вопросами. Комментарии и вывод в консоль остаются русскими.
|
||
- Числа игры — в [src/tuning.h](src/tuning.h), размеры движка — в
|
||
[engine/config.h](engine/config.h). Магических констант по коду быть не должно.
|
||
- `src/ai/` не знает про рендер, изометрию и ввод. Это правило не нарушать.
|
||
- Правило «не бить своих» одно на все классы оружия: у ствола это отрезок,
|
||
у клинка — сектор. Ослаблять его нельзя нигде.
|
||
- `RenderGame` принимает `const Game&` — эффекты физически не могут влиять на симуляцию.
|
||
- Приёмка меряется в ПЕСОЧНИЦЕ: `Game::combatMode` выключен, в мире мишени,
|
||
на бойцах нет снаряжения. Ломать это нельзя — иначе `--accept` меряет другое.
|
||
|
||
## Ассеты
|
||
|
||
Спрайты собирает внешний CLI **SpriteForge** (`C:\Users\uuu\Documents\spriteforge`).
|
||
Полный порядок работы — в [docs/12-assets.md](docs/12-assets.md), здесь только запреты:
|
||
|
||
- игра хранит манифесты `assets/manifests/`, исходники `assets/sources/` и
|
||
сгенерированный `generated/spriteforge_assets.h`; собранное лежит в
|
||
`build/sprites/` и в git не попадает;
|
||
- не открывать `build/sprites/*.sfa`, `.sfcache/`, сгенерированные PNG и
|
||
contact sheet: проверка только текстом — `sf list`, `sf describe`, `sf ascii`,
|
||
`sf validate`, `sf stats`;
|
||
- строковых ID ассетов в C++ нет — только константы `SF_ASSET_*`;
|
||
- не править репозиторий SpriteForge ради одной игровой сущности.
|
||
# Agent sprite production
|
||
|
||
For ANY request to create, change, replace, or add game art, follow `.claude/commands/sprite.md`
|
||
(the `/sprite` workflow) automatically even when the user did not type the slash command.
|
||
Never satisfy an art request with a one-off procedural runtime drawing.
|
||
|
||
When asked to create an agent, armor, or weapon sprite, use `/agent-sprite` and
|
||
`assets/agents/catalog.yaml`; do not draw a one-off procedural humanoid. Agent art is
|
||
an aligned paper-doll: body, armor and held weapon are separate 70x90, eight-direction
|
||
layers sharing one rig and pivot. Run `tools/build_agent_assets.ps1` after ingestion.
|
||
Start the game with `--sf-agents` (or `--sf`) to see the generated layers. Blender is
|
||
installed at `C:\Program Files\Blender Foundation\Blender 5.2\blender.exe`.
|
||
|
||
# Monster sprite production
|
||
|
||
Enemies do NOT go through the agent paper-doll. They have their own Blender-first
|
||
pipeline: `assets/monsters/catalog.yaml`, `tools/blender/monster_rig.py`,
|
||
`tools/monster_assets.py` (`monster-init`, `monster-render`, `monster-render-all`,
|
||
`validate`, `sync`). Five kinds, five distinct morphologies — never one humanoid
|
||
recoloured five times. Asset ids are `<kind>_<animation>`; renaming them breaks
|
||
`tools/asset_coverage.py`. Full rules in [docs/14-monsters.md](docs/14-monsters.md).
|