Содержимое двух проектов: DESCENT и HOLLOW

Игра стала проектом движка, и её содержимое переехало из assets/ в projects/.

  projects/descent  сама игра: восемь комнат, каталог из 28 сущностей,
                    изометрия, кривая спуска на сто этажей
  projects/hollow   второй проект: вид сверху, четыре комнаты, свой каталог,
                    короткая и злая кривая

Второй проект существует не для примера. Движок с одним проектом ничем не
отличается от игры с красиво названными каталогами, и проверить, что зашитых
знаний про DESCENT в движке не осталось, можно только вторым проектом
(docs/18-engine.md).

Он же сразу окупился: --check нашёл в комнате maw глухую камеру посередине —
ту же ошибку, что когда-то в storage. На сетке она выглядит нормально, но
точка спавна внутри недостижима, и этаж тихо становится легче.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
z.kirill 2026-08-13 21:06:28 +03:00
parent 8d35f4c2ec
commit f637a07d72
16 changed files with 465 additions and 0 deletions

View File

@ -0,0 +1,66 @@
# Каталог размещаемых сущностей — граница между движком и игрой.
#
# Редактор комнат читает ТОЛЬКО этот файл: он не знает, что такое SHAMBLER и
# чем тот бьёт, он знает id, класс, цвет, глубину и цену. Игра переводит id в
# свои EnemyKind и ItemId одной таблицей (src/sim/spawn_catalog.cpp).
#
# entity <id> ключ=значение ...
#
# class monster | prop | loot
# depth N — с этажа N и глубже
# N..M — с N по M включительно
# danger цена в бюджете опасности этажа. Не урон и не HP, а «сколько места
# в голове игрока эта тварь занимает». Бюджет — то, чем этаж
# отличается по СЛОЖНОСТИ, а не по числу тел
# tier качество предмета: этаж выдаёт свой тир и всё, что ниже
# color чем редактор рисует сущность, пока для неё нет спрайта
#
# Порядок ключей не важен, лишние ключи — ошибка, а не молчаливый пропуск.
# Порядок СТРОК важен: это порядок палитры в редакторе.
# --- твари -------------------------------------------------------------------
# Кривая простая и читается сверху вниз: первые этажи — бредущие и бегуны,
# дальше подключаются плевки, громилы и хваты. Верхняя граница у мелочи есть
# намеренно: на двадцатом этаже одиночный бредущий занимал бы место, которое
# должно достаться чему-то, чего игрок ещё не видел.
entity shambler class=monster depth=1 danger=1.0 radius=0.34 color=116,52,52 sprite=shambler_walk name=SHAMBLER
entity rusher class=monster depth=1 danger=1.3 radius=0.27 color=158,74,44 sprite=rusher_walk name=RUSHER
entity spitter class=monster depth=3 danger=2.0 radius=0.31 color=96,132,72 sprite=spitter_walk name=SPITTER
entity lurker class=monster depth=5 danger=2.6 radius=0.30 color=88,62,118 sprite=lurker_walk name=LURKER
entity brute class=monster depth=7 danger=4.5 radius=0.46 color=142,60,78 sprite=brute_walk name=BRUTE
# Мишень приёмки: не ходит и не бьёт. Опасности не несёт, поэтому и бюджета
# не тратит — ею ставят неподвижную цель, когда нужна именно цель.
entity dummy class=monster depth=1 danger=0.0 radius=0.34 color=120,44,44 sprite=- name=TARGET
# --- обстановка --------------------------------------------------------------
# Ломается, не отрастает обратно и не участвует в зачистке.
entity crate class=prop depth=1 radius=0.38 color=104,76,46 sprite=prop_crate name=CRATE
entity barrel class=prop depth=1 radius=0.33 color=92,84,58 sprite=prop_barrel name=BARREL
entity locker class=prop depth=2 radius=0.36 color=78,88,96 sprite=prop_locker name=LOCKER
# --- лут ---------------------------------------------------------------------
# Тир — это «с какой глубины вещь становится находкой». Нижние тиры с глубиной
# не исчезают: бинт нужен всегда, он просто перестаёт быть удачей.
entity ammo class=loot tier=0 depth=1 radius=0.22 color=200,176,96 sprite=item_icon_ammo name=AMMO
entity bandage class=loot tier=0 depth=1 radius=0.22 color=216,208,196 sprite=item_icon_bandage name=BANDAGE
entity pistol class=loot tier=0 depth=1 radius=0.24 color=190,180,168 sprite=item_icon_pistol name=PISTOL
entity knife class=loot tier=0 depth=1 radius=0.22 color=214,222,232 sprite=item_icon_knife name=KNIFE
entity jacket class=loot tier=0 depth=1 radius=0.26 color=122,112,96 sprite=item_icon_jacket name=JACKET
entity rifle class=loot tier=1 depth=2 radius=0.26 color=208,196,150 sprite=item_icon_rifle name=CARBINE
entity saber class=loot tier=1 depth=2 radius=0.26 color=200,212,228 sprite=item_icon_saber name=SABER
entity vest class=loot tier=1 depth=3 radius=0.26 color=108,118,108 sprite=item_icon_vest name=VEST
entity stimpack class=loot tier=1 depth=3 radius=0.22 color=130,220,170 sprite=item_icon_stimpack name=STIM
entity smg class=loot tier=2 depth=5 radius=0.26 color=176,200,220 sprite=item_icon_smg name=SMG
entity shotgun class=loot tier=2 depth=6 radius=0.28 color=214,158,104 sprite=item_icon_shotgun name=SHOTGUN
entity cleaver class=loot tier=2 depth=6 radius=0.28 color=196,174,160 sprite=item_icon_cleaver name=CLEAVER
entity spurs class=loot tier=2 depth=5 radius=0.22 color=198,184,120 sprite=item_icon_spurs name=SPURS
entity lantern class=loot tier=2 depth=4 radius=0.24 color=240,206,130 sprite=item_icon_lantern name=LANTERN
entity magnum class=loot tier=3 depth=9 radius=0.28 color=226,210,176 sprite=item_icon_magnum name=MAGNUM
entity bow class=loot tier=3 depth=10 radius=0.26 color=154,190,164 sprite=item_icon_bow name=BOW
entity plate class=loot tier=3 depth=9 radius=0.30 color=140,146,156 sprite=item_icon_plate name=PLATE
entity shroud class=loot tier=3 depth=11 radius=0.26 color=88,84,100 sprite=item_icon_shroud name=SHROUD
entity charm class=loot tier=3 depth=8 radius=0.22 color=196,130,190 sprite=item_icon_charm name=CHARM

View File

@ -0,0 +1,39 @@
# Descent — игра, ради которой писался Tile2D. Для движка это один из проектов,
# и ничего, кроме этого файла и содержимого рядом, он про неё не знает.
#
# Числа кривой раньше стояли прямо в engine/progression.cpp. Здесь они не ради
# «настраиваемости вообще»: кривую правят на ощупь и часто, и правка «сделать
# десятый этаж чуть злее» не должна означать пересборку движка.
name DESCENT
view iso
rooms rooms
catalog catalog/entities.txt
startdepth 1
# Опасность: база, линейный рост, квадратичный хвост.
# Чистая линейка читается как «то же самое, только больше»; чистая экспонента
# обрывает забег там, где игрок начал понимать правила.
danger 3.0 2.2 0.10
# Плотность точек спавна: прирост за этаж и упор. Выше упора все точки
# срабатывают всегда, то есть этажи становятся одинаковыми.
density 0.05 1.5
# Лут: сколько предметов на первом этаже, через сколько этажей +1 предмет,
# через сколько этажей +1 тир. Тир медленнее опасности намеренно — спуск обязан
# опережать снаряжение.
loot 2 4 3
# Обзор: сколько сжимается за этаж и ниже чего не опускается. Ниже упора это
# уже не «страшно», а «не видно, куда идти».
sight 0.035 0.60
# Опыт за этаж. Медленнее опасности: спускаться выгодно, но не настолько,
# чтобы прыгать через этажи стало единственной разумной игрой.
xp 0.15
# С какого этажа начинается каждая тема отделки: STEEL, RUST, FLESH, FROST.
# Последняя полоса открытая — дальше менять тему не на что.
themes 1 4 8 13

View File

@ -0,0 +1,27 @@
# Открытая арена с четырьмя опорами. Здесь работает решатель огневых позиций:
# места хватает, и отряд обязан разойтись по линиям, а не сбиться в кучу.
name arena
size 14 12
weight 3
theme 0
start 0
depth 1 0
tiles
####++####++##
#............#
#..##....##..#
#..##....##..#
#............#
+............+
+............+
#............#
#..##....##..#
#..##....##..#
#............#
####++####++##
spawn 4 4 0.90 shambler:4 rusher:3 spitter:2
spawn 9 4 0.85 shambler:4 rusher:3
spawn 4 7 0.85 shambler:3 rusher:2 brute:1
spawn 9 7 0.90 shambler:4 spitter:2
spawn 6 1 0.40 crate:2 barrel:1
spawn 7 10 0.40 crate:1 locker:1

View File

@ -0,0 +1,23 @@
# Казарма: ряды перегородок и один сквозной проход посередине. Твари выходят
# из-за переборок сбоку, а не в лоб, — строй приходится разворачивать на ходу.
name barracks
size 13 9
weight 2
theme 1
start 0
depth 2 0
tiles
#####+++#####
#...........#
#.##.##.##..#
#.##.##.##..#
+...........+
#.##.##.##..#
#.##.##.##..#
#...........#
#####+++#####
spawn 4 1 0.75 shambler:3 rusher:2
spawn 8 1 0.60 spitter:2 shambler:1
spawn 11 4 0.70 rusher:3 lurker:1
spawn 4 7 0.75 shambler:3 brute:1
spawn 1 4 0.45 crate:2 barrel:2

View File

@ -0,0 +1,26 @@
# Перекрёсток. Рукава шириной три тайла: правило «не стрелять сквозь своих»
# упирается в геометрию, и отряд вытягивается в колонну.
name corridor_x
size 13 13
weight 3
theme 0
start 0
depth 1 0
tiles
#####+++#####
#####...#####
#####...#####
#####...#####
#####...#####
+...........+
+...........+
+...........+
#####...#####
#####...#####
#####...#####
#####...#####
#####+++#####
spawn 6 2 0.60 rusher:3 lurker:1
spawn 6 10 0.60 rusher:3 lurker:1
spawn 2 6 0.50 shambler:2 spitter:1
spawn 10 6 0.50 shambler:2 spitter:1

View File

@ -0,0 +1,21 @@
# Стартовая: просторно, светло по планировке и почти пусто.
# Отряд обязан успеть собраться в строй до первой твари.
name hall_start
size 12 10
weight 2
theme 0
start 1
depth 1 0
tiles
#####++#####
#..........#
#..#....#..#
#..#....#..#
+..........+
+..........+
#..#....#..#
#..#....#..#
#..........#
#####++#####
spawn 2 2 0.50 crate:2 barrel:1
spawn 9 7 0.40 barrel:1 locker:1

View File

@ -0,0 +1,25 @@
# Гнездо: кольцевые перегородки и ядро посередине. Линий огня почти нет,
# зато клинку есть где работать — сектор упирается в стену, а не в союзника.
name nest
size 12 12
weight 2
theme 2
start 0
depth 4 0
tiles
#####++#####
#..........#
#.##....##.#
#.#......#.#
#.#..##..#.#
+....##....+
+....##....+
#.#..##..#.#
#.#......#.#
#.##....##.#
#..........#
#####++#####
spawn 5 1 0.85 shambler:3 brute:1
spawn 2 5 0.80 lurker:2 rusher:2
spawn 9 5 0.80 lurker:2 rusher:2
spawn 6 10 0.85 shambler:3 spitter:2

View File

@ -0,0 +1,28 @@
# Яма: колодец посередине с единственным входом снизу. Громилу в нём
# приходится разбирать вдвоём, а круг его удара достаёт обоих.
name pit
size 14 14
weight 2
theme 2
start 0
depth 6 0
tiles
######++######
#............#
#............#
#...######...#
#...#....#...#
+...#....#...+
+...#....#...+
+...#....#...+
+...#....#...+
#...#....#...#
#...##..##...#
#............#
#............#
######++######
spawn 6 6 0.95 brute:3 shambler:2
spawn 2 4 0.70 spitter:2 rusher:2
spawn 11 4 0.70 spitter:2 rusher:2
spawn 6 12 0.60 shambler:3 lurker:1
spawn 2 11 0.40 barrel:2 crate:1

View File

@ -0,0 +1,23 @@
# Склад: обстановки много, тварей мало. Место, где игрок узнаёт, что хлам
# ломается, — и тратит на это магазин, которого потом не хватит.
name storage
size 12 10
weight 2
theme 1
start 0
depth 1 0
tiles
####++######
#..........#
#.####.###.#
#.#......#.#
+.#......#.+
+.#......#.+
#.#......#.#
#.###.####.#
#..........#
######++####
spawn 4 4 0.90 crate:4 barrel:3 locker:2
spawn 7 4 0.85 crate:3 barrel:2
spawn 4 6 0.70 barrel:2 locker:2
spawn 1 1 0.45 shambler:2 lurker:1

View File

@ -0,0 +1,23 @@
# Схрон: тесная камера в камере. Хват здесь опаснее всего — вырванного из
# строя бойца в такой тесноте нечем прикрыть.
name vault
size 10 10
weight 1
theme 3
start 0
depth 8 0
tiles
###++#####
#........#
#.######.#
#.#....#.#
+.#....#.+
+.#....#.+
#.#....#.#
#.##..##.#
#........#
#####++###
spawn 4 4 0.90 lurker:3 brute:1
spawn 1 1 0.55 rusher:2 shambler:1
spawn 8 8 0.55 spitter:2
spawn 4 8 0.40 locker:2 crate:1

View File

@ -0,0 +1,34 @@
# Каталог HOLLOW. Формат тот же, что у DESCENT, — это формат ДВИЖКА.
#
# Набор другой и цены другие: здесь нет мишеней и почти нет обстановки, зато
# бегуны выходят с первого этажа, а громила — с четвёртого, а не с седьмого.
#
# id совпадают с DESCENT намеренно: игра переводит их в свои EnemyKind одной
# таблицей (src/sim/spawn_catalog.cpp), и id, которого в ней нет, не даст
# никого. Это граница ИГРЫ, а не движка.
# --- твари -------------------------------------------------------------------
entity rusher class=monster depth=1 danger=1.3 radius=0.27 color=158,74,44 sprite=rusher_walk name=RUSHER
entity shambler class=monster depth=1 danger=1.0 radius=0.34 color=116,52,52 sprite=shambler_walk name=SHAMBLER
entity lurker class=monster depth=2 danger=2.6 radius=0.30 color=88,62,118 sprite=lurker_walk name=LURKER
entity spitter class=monster depth=3 danger=2.0 radius=0.31 color=96,132,72 sprite=spitter_walk name=SPITTER
entity brute class=monster depth=4 danger=4.5 radius=0.46 color=142,60,78 sprite=brute_walk name=BRUTE
# --- обстановка --------------------------------------------------------------
entity barrel class=prop depth=1 radius=0.33 color=92,84,58 sprite=prop_barrel name=BARREL
# --- лут ---------------------------------------------------------------------
# Короткая лестница качества: четыре тира на шесть этажей вместо четырёх на
# двенадцать. Спуск здесь не успевает одеть отряд, и это замысел.
entity ammo class=loot tier=0 depth=1 radius=0.22 color=200,176,96 sprite=item_icon_ammo name=AMMO
entity bandage class=loot tier=0 depth=1 radius=0.22 color=216,208,196 sprite=item_icon_bandage name=BANDAGE
entity knife class=loot tier=0 depth=1 radius=0.22 color=214,222,232 sprite=item_icon_knife name=KNIFE
entity rifle class=loot tier=1 depth=2 radius=0.26 color=208,196,150 sprite=item_icon_rifle name=CARBINE
entity vest class=loot tier=1 depth=2 radius=0.26 color=108,118,108 sprite=item_icon_vest name=VEST
entity shotgun class=loot tier=2 depth=3 radius=0.28 color=214,158,104 sprite=item_icon_shotgun name=SHOTGUN
entity lantern class=loot tier=2 depth=3 radius=0.24 color=240,206,130 sprite=item_icon_lantern name=LANTERN
entity plate class=loot tier=3 depth=5 radius=0.30 color=140,146,156 sprite=item_icon_plate name=PLATE
entity cleaver class=loot tier=3 depth=5 radius=0.28 color=196,174,160 sprite=item_icon_cleaver name=CLEAVER

View File

@ -0,0 +1,40 @@
# HOLLOW — второй проект на том же движке.
#
# Он существует не «для примера»: движок с ОДНИМ проектом ничем не отличается
# от игры с красиво названными каталогами, и проверить, что зашитых знаний про
# DESCENT в движке не осталось, можно только вторым проектом.
#
# Поэтому он отличается всем, чем проект вообще может отличаться:
# * другой вид отображения — вид сверху вместо изометрии;
# * своя кривая: короче, злее, беднее на лут;
# * свой каталог и свои комнаты.
#
# Общее у него с DESCENT ровно одно — id сущностей. Это граница НЕ движка, а
# игры: squad_proto умеет превращать в тварей только те id, которые перечислены
# в src/sim/spawn_catalog.cpp. Движку всё равно, как они называются.
name HOLLOW
view topdown
rooms rooms
catalog catalog/entities.txt
startdepth 1
# Злее с первого шага и круче в росте: спуск короткий, до глубин DESCENT здесь
# никто не доживает.
danger 5.0 3.4 0.25
# Плотность добирает упор быстрее — тесные комнаты и так держат мало точек.
density 0.09 1.5
# Лут реже и растёт медленнее: находка обязана быть событием.
loot 1 6 4
# Темнеет быстрее и садится ниже: вид сверху показывает больше геометрии за
# раз, и прежний обзор сделал бы этаж читаемым насквозь.
sight 0.055 0.45
xp 0.20
# Полосы отделки сдвинуты: спуск короче, и на четвёртом этаже уже плоть.
themes 1 2 4 6

View File

@ -0,0 +1,19 @@
# Ряд камер. Ниши по бокам: в них удобно стоять и невозможно отступать.
name cells
size 13 9
weight 3
theme 0
depth 1 0
tiles
####+++++####
#...........#
#.#.#.#.#.#.#
+...........+
+...........+
+...........+
#.#.#.#.#.#.#
#...........#
####+++++####
spawn 2 1 0.65 rusher:3 shambler:2
spawn 10 7 0.65 rusher:3 shambler:2
spawn 6 4 0.40 bandage:2 knife:1 rifle:1

View File

@ -0,0 +1,27 @@
# Зев. Открытая арена с ядром посередине: единственное место в наборе, где
# отряд может встать кругом.
#
# У ядра ДВА прохода, север и юг. Глухая коробка посередине выглядит на сетке
# так же, но точка спавна внутри неё недостижима: тварь не дойдёт до отряда и
# не будет убита, и этаж тихо станет легче. Ровно это и ловит --check.
name maw
size 13 11
weight 2
theme 2
depth 3 0
tiles
#####+++#####
#...........#
#...........#
#...##.##...#
+...#...#...+
+...#...#...+
+...##.##...+
#...........#
#...........#
#...........#
#####+++#####
spawn 6 5 0.85 brute:3 lurker:2
spawn 1 1 0.60 spitter:2 rusher:2
spawn 11 9 0.60 spitter:2 rusher:2
spawn 11 1 0.45 shotgun:1 plate:1 cleaver:1

View File

@ -0,0 +1,20 @@
# Стартовая HOLLOW. Тесная и короткая: вид сверху показывает всю комнату
# сразу, и просторный зал первого этажа не оставил бы ничего на потом.
name mouth
size 11 9
weight 2
theme 0
start 1
depth 1 0
tiles
####+++####
#.........#
#..##.##..#
+.........+
+....#....+
+.........+
#..##.##..#
#.........#
####+++####
spawn 2 1 0.45 barrel:1
spawn 8 7 0.45 barrel:1

View File

@ -0,0 +1,24 @@
# Колодец. Узкий и длинный: строй здесь не развернуть, и это единственное,
# что комната делает.
name shaft
size 7 13
weight 2
theme 1
depth 2 0
tiles
##+++##
#.....#
#.....#
#.###.#
+.....+
+.....+
+.....+
+.....+
#.###.#
#.....#
#.....#
#.....#
##+++##
spawn 3 1 0.70 lurker:2 rusher:2
spawn 3 11 0.70 lurker:2 spitter:1
spawn 1 6 0.35 vest:1 lantern:1