squad-proto/CLAUDE.md
z.kirill 53187a7cdd Пункт UPGRADES выходил из игры; меню теперь проверяется (M26)
Жалоба была «крашится при открытии апгрейдов». Не крашилось: пункт
закрывал игру. В обработчике главного меню стоял `default: ui.quit`, а
экран улучшений добавили четвёртым пунктом — обработчик о нём просто не
узнал. Снаружи мгновенное закрытие окна неотличимо от падения.

Починка на две строки, но интереснее причина, по которой это прожило
четыре вехи: в проекте каждая механика меряется прогоном с кодом
возврата, а меню не проверял никто. Все инструменты смотрят на
СИМУЛЯЦИЮ.

Поэтому заведён --ui-check: проходит по всем пунктам меню и требует
одного — нажатие ВЕДЁТ КУДА-ТО, а из игры выходит ровно один пункт,
QUIT. Плюс проверяет, что кнопки экрана улучшений действительно покупают.
Окно при этом не открывается: UiActivate ничего из raylib не трогает.

Проверка сперва запущена на СЛОМАННОЙ сборке и дала код 1 с диагнозом
«пункт UPGRADES не делает ничего», и только после этого объявлена
рабочей. Проверка, которую не видели падающей, ещё ничего не проверяет.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 02:51:58 +03:00

133 lines
14 KiB
Markdown
Raw 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.

# 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) | оверлей F1F4, метрики, runtime-тюнинг, `--set` | отладка и балансировка |
| [docs/07-milestones.md](docs/07-milestones.md) | журнал вех M0M6: что сделано и чем проверено | история и статус |
| [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).