ON_HIT поджигает цель, ON_KILL даёт рывок скорости стаками, ON_HURT
обжигает того, кто ударил, ON_DOWN даёт отряду ярость за павшего.
Отдельным тегом аффикса, то есть по тем же правилам, что и всё
остальное: платит по тиру, влезает в бюджет, катается и прививается.
СДЕЛАНО НЕ ТАК, КАК ПРЕДЛАГАЛ ДИЗАЙН. В docs/21-damage.md §4 стояло:
журнал боевых событий уже есть, вешайте триггеры на него. Звучит
правильно, и сделать так нельзя: sim/events.h это канал «симуляция ->
эффекты», односторонний по устройству, и в headless-прогонах его нет
вовсе. Начни правила боя его читать — игра станет вести себя по-разному
с окном и без, то есть --accept начнёт мерить не то, что меряет.
Триггеры срабатывают в месте урона. Опасение «два канала разойдутся»
снято иначе: второго канала никто и не завёл, есть четыре точки рядом с
тем уроном, который триггер обслуживает.
Четыре из девяти, и это не «пока»: каждый эффект обязан класть своё
число в уже существующий канал влияния. Крита в игре нет, площадного
урона нет, выдачи предметов на входе нет — заводить их ради строк
таблицы значит завести пять мёртвых веток. Причины выписаны в документе.
Три ограничителя проверяются числами в --descend:
триггеры: аффикс доехал да, ON_HIT поджёг стаков 1, откат 0.9 с
(за него наложено 0), ON_KILL стаков 1, скорость 1.06
рекурсия: за один шаг стаков прибавлялось максимум 1
Первая строка про проводку: аффикс с триггером легко сделать так, что он
лежит в предмете, показывается в подсказке и не делает ничего.
Проверка сперва брала targets[0] и проходила на descent по везению: на
hollow первым в пуле стоял ящик, а обстановка не горит и убийством не
считается. Теперь цель ищется по виду и ставится в свободную клетку с
прямой видимостью — иначе замеряется планировка этажа, а не триггеры.
Шаг симуляции 3.7 мкс из 16666. --accept PASS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
15 KiB
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 | оверлей F1–F4, метрики, runtime-тюнинг, --set |
отладка и балансировка |
| docs/07-milestones.md | журнал вех M0–M6: что сделано и чем проверено | история и статус |
| 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(спуск, эвакуация, круговой прогон профиля),squad_proto.exe --ui-check(пункты меню: каждый куда-то ведёт). - У кнопки тоже есть код возврата. Пункт UPGRADES четыре вехи закрывал игру
вместо открытия экрана: в обработчике стоял
default: quit, а новый пункт добавили четвёртым. Все прогоны меряли симуляцию, меню не проверял никто — теперь проверяет--ui-check, и новый экран обязан появиться в нём. - Унести можно только то, что на ВЫЖИВШИХ. Павший теряет своё, вайп теряет всё, достигнутая глубина не теряется никогда (17-extraction.md).
NUM_AGENTS— это вместимость, а не размер отряда. Сколько слотов занято, говоритSquad::roster, а занят ли конкретный —Agent::present. Правила боя читают толькоalive(пустой слот и павший для них одно), а рендер, HUD и профиль обязаны смотреть наpresent: иначе у одинокого оперативника вокруг появятся четыре чужих трупа (17-extraction.md).- Таймера в игре нет и не заводить. Фонарь тратит заряд за ПРОЙДЕННЫЙ ПУТЬ,
а не за время: стоять и думать бесплатно, дорого — обшарить этаж целиком.
Расход со
dtвместо пути — это таймер, и--descendего ловит (17-extraction.md). - Закон масштаба: угроза растёт квадратично, сила отряда — линейно с затуханием, разрыв закрывается ЗНАНИЕМ (стихии, реакции, порядок целей). Числа не должны спасать — иначе хоррор кончается на сороковом этаже (20-gdd.md).
- Предмет — это ЭКЗЕМПЛЯР, а не вид.
ItemInstanceнеявно приводится кItemId, и это удобно ровно до того места, где вещь копируют: присваивание вItemIdмолча теряет редкость и аффиксы. Подбор, перекладывание и запись профиля обязаны работать с экземпляром целиком (22-loot.md). - Материал добывается только в своей полосе. Био-ядра — с плотских этажей, крио — с мёрзлых, и это единственная причина возвращаться на средние глубины после рекорда. Протечка полос убивает весь контент, кроме последнего акта (22-loot.md).
- Журнал событий (
sim/events.h) правила боя НЕ читают. Это канал «симуляция → эффекты», и в headless его нет вовсе: начни от него зависеть — игра станет вести себя по-разному с окном и без. Триггеры срабатывают в месте урона, а не по журналу (21-damage.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.