squad-proto/CLAUDE.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

13 KiB
Raw Blame History

CLAUDE.md — оглавление

Этот файл — только навигация. Содержание живёт в docs/, по одному файлу на тему. Читай нужный раздел, а не весь проект.

Документация

Файл О чём Когда открывать
docs/00-overview.md что это за прототип, границы задачи первое знакомство
docs/01-build-and-run.md сборка, запуск, управление, dev-режимы CLI собрать и потыкать
docs/02-architecture.md карта модулей, порядок шага симуляции, правила зависимостей перед любой правкой кода
docs/03-rendering.md софтверный фреймбуфер, изометрия, сортировка, спрайты рендер, камера, спрайты
docs/04-world.md тайлмап, планировка уровня, DDA-рейкаст, коллизии, мишени карта, LOS, коллизии
docs/05-squad-ai.md ядро: LaneClear, решатель огневых позиций, резерв линий, стрельба поведение отряда
docs/06-debug-and-tuning.md оверлей F1F4, метрики, runtime-тюнинг, --set отладка и балансировка
docs/07-milestones.md журнал вех M0M6: что сделано и чем проверено история и статус
docs/08-decisions.md отклонения от спека и почему, с замерами «почему тут не как в ТЗ»
docs/09-acceptance.md критерии приёмки (спек 11) и их текущие цифры приёмка
docs/10-atmosphere.md хоррор-слой: свет, туман войны, трассеры, напряжение картинка и атмосфера
docs/11-melee.md ближний бой: сектор удара, три фазы, свой круг, дуга клинки, классы оружия
docs/12-assets.md ассеты: конвейер SpriteForge, манифесты, загрузчик, hot reload добавить или пересобрать спрайт
docs/13-combat.md бой: каталог оружия, твари, снаряжение, меню и HUD оружие, враги, инвентарь, UI
docs/14-monsters.md твари-ассеты: Blender-риг на пять морфологий, листы, проверки нарисовать или пересобрать тварь
docs/15-engine-and-editor.md движок и редактор: три цели сборки, каталог сущностей, формат комнат, генератор уровней делать комнаты, менять генерацию, трогать границу движка
docs/16-descent.md спуск: глубина как первичное понятие, бюджет опасности, лут, кривая сложности менять сложность, добавлять тварей и лут
docs/17-extraction.md экстракшен: эвакуация, профиль и схрон, чекпоинты, что теряется правила забега, снаряжение между вылазками
docs/18-engine.md Tile2D: границы движка, проекции 2D, формат проекта, второй проект трогать движок, заводить проект, добавлять вид отображения
docs/19-agent.md движок и ЛЛМ: инструменты --tool, скиллы, терминал в редакторе работать над проектом через claude/codex
docs/20-gdd.md дизайн игры: акты, петли, рост отряда, закон масштаба, 200 часов что и зачем строим дальше
docs/21-damage.md урон: семь стихий, статусы, реакции, формулы, триггеры боевая математика
docs/22-loot.md добыча: редкости, аффиксы, артефакты, зачарования, материалы предметы и экономика
docs/23-endgame.md лейтгейм: Бездна, мутации, лидерборды, 262 ачивки всё после сотого этажа

Быстрые факты

  • Исходный спек: 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). Код возврата 1 = поломка.
  • В редакторе снизу терминал (клавиша `): те же инструменты, git, сборка и запросы к claude/codex прямо оттуда. Открытый проект уходит потомкам переменной TILE2D_PROJECT.
  • Самопроверка: squad_proto.exe --accept печатает PASS/FAIL по всем измеримым критериям. Содержимое проверяется отдельно: tile2d_editor.exe --check (комнаты и покрытие глубин), squad_proto.exe --descend 8 (спуск, эвакуация, круговой прогон профиля).
  • Унести можно только то, что на ВЫЖИВШИХ. Павший теряет своё, вайп теряет всё, достигнутая глубина не теряется никогда (17-extraction.md).
  • NUM_AGENTS — это вместимость, а не размер отряда. Сколько слотов занято, говорит Squad::roster, а занят ли конкретный — Agent::present. Правила боя читают только alive (пустой слот и павший для них одно), а рендер, HUD и профиль обязаны смотреть на present: иначе у одинокого оперативника вокруг появятся четыре чужих трупа (17-extraction.md).
  • Таймера в игре нет и не заводить. Фонарь тратит заряд за ПРОЙДЕННЫЙ ПУТЬ, а не за время: стоять и думать бесплатно, дорого — обшарить этаж целиком. Расход со dt вместо пути — это таймер, и --descend его ловит (17-extraction.md).
  • Закон масштаба: угроза растёт квадратично, сила отряда — линейно с затуханием, разрыв закрывается ЗНАНИЕМ (стихии, реакции, порядок целей). Числа не должны спасать — иначе хоррор кончается на сороковом этаже (20-gdd.md).
  • Ни одного чистого улучшения. Артефакт без цены становится обязательным, а обязательный предмет — это вырезанный слот (22-loot.md).
  • Глубина — первичное понятие. Вся кривая сложности живёт в одной функции DescribeFloor (engine/progression.h); размазывать её по генератору, каталогу и рендеру нельзя (16-descent.md).
  • Редактор линкуется только с движком. Обращение из editor/ к sim/, ai/ или ui/ — ошибка сборки, и так задумано (15-engine-and-editor.md). Редактор принадлежит движку: он открывает любой проект (--project <имя>) и ни одной игры по имени не знает.
  • Тексты НА ЭКРАНЕ — латиницей: встроенный шрифт raylib кириллицы не знает и рисует её вопросами. Комментарии и вывод в консоль остаются русскими.
  • Числа игры — в src/tuning.h, размеры движка — в engine/config.h. Магических констант по коду быть не должно.
  • src/ai/ не знает про рендер, изометрию и ввод. Это правило не нарушать.
  • Правило «не бить своих» одно на все классы оружия: у ствола это отрезок, у клинка — сектор. Ослаблять его нельзя нигде.
  • RenderGame принимает const Game& — эффекты физически не могут влиять на симуляцию.
  • Приёмка меряется в ПЕСОЧНИЦЕ: Game::combatMode выключен, в мире мишени, на бойцах нет снаряжения. Ломать это нельзя — иначе --accept меряет другое.

Ассеты

Спрайты собирает внешний CLI SpriteForge (C:\Users\uuu\Documents\spriteforge). Полный порядок работы — в 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.