402 lines
36 KiB
Markdown
402 lines
36 KiB
Markdown
# Люди: генерация, характеристики, просмотр
|
||
|
||
Договорённость на следующий срез, не текущий код.
|
||
Типы и карта: [`defs.md`](defs.md). Экран игрока: [`near-term.md`](near-term.md).
|
||
Потоки: [`runtime.md`](runtime.md). Проекты: [`projects.md`](projects.md).
|
||
|
||
Школа перестаёт быть пустой коробкой. Появляются ученики, работники и родители: у каждого имя,
|
||
тело, навыки, черты и нужды. **Ничего из этого пока ни на что не влияет** — люди не ходят, не
|
||
работают и не учатся. Срез отвечает на вопрос «кто в этой школе», а не «что они делают».
|
||
|
||
Тот же принцип, что и с картой: **код — системы, содержание — данные**. Новый навык, черта, цвет
|
||
волос или набор имён появляются файлом в `mods/<id>/defs/`, без пересборки.
|
||
|
||
## Откуда берётся состав
|
||
|
||
Карта уже знает вместимость. `ThingDef.PupilSlots × count` даёт ученические места в комнате,
|
||
`RoomDef.positions` — должности, которые комната открывает. Отдельного «числа учеников» в форме
|
||
создания **нет**: состав школы — следствие того, что построено.
|
||
|
||
| Что построено | Что появляется |
|
||
| --- | --- |
|
||
| Кабинет с 16 партами | Класс на 16 учеников |
|
||
| Кабинет директора | Должность директора и один работник |
|
||
| Спортзал | Должность физрука |
|
||
| Библиотека | Должность библиотекаря |
|
||
|
||
**Один кабинет — один класс.** Кабинет закреплён за классом, как в обычной школе: класс живёт в
|
||
своём кабинете, и вместимость кабинета есть размер класса. Хотите одиннадцать параллелей —
|
||
поставьте одиннадцать кабинетов. Это делает редактор карты осмысленным: игрок строит не декорации,
|
||
а штатное расписание.
|
||
|
||
**Ванильная карта дорабатывается до одиннадцати кабинетов**, по одному на параллель, чтобы школа
|
||
из коробки была полной. Сейчас их четыре.
|
||
|
||
### Класс — сущность ростера, а не поле карты
|
||
|
||
Параллель и литера — именно поля, а не разбор подписи комнаты. Подпись разбирать нельзя дважды:
|
||
кириллическая «А» и латинская «A» на глаз неразличимы (в нынешней ванильной карте кабинеты
|
||
подписаны латиницей — `1A`, `2B`), а в другой локали литеры вообще другие.
|
||
|
||
Но и в **карте** этим полям не место. Параллель растёт каждый год: 5Б становится 6Б, не переезжая
|
||
из кабинета. Раскладка же после создания школы неизменна — иначе файл карты пришлось бы
|
||
переписывать каждое игровое 1 сентября.
|
||
|
||
Поэтому класс — отдельная сущность ростера: параллель, литера, закреплённый кабинет. Кабинет
|
||
закреплён за классом на всё время его жизни; одиннадцатый выпускается — кабинет достаётся новому
|
||
первому. Раскладку по параллелям при создании делает генератор, игрок её не задаёт.
|
||
|
||
Из этого следует, что подписи кабинетов в ванильной карте — **номера помещений** («101», «204»),
|
||
как в настоящей школе, а не имена классов. Имя класса живёт на классе и меняется вместе с ним.
|
||
|
||
## Из чего состоит человек
|
||
|
||
Шесть слоёв. Первые два есть у всех, остальные — по роли.
|
||
|
||
| Слой | Что это | Пример |
|
||
| --- | --- | --- |
|
||
| **Личность** | ФИО со склонениями, пол, дата рождения, роль | Иванова Мария Петровна, ж, 2001-03-14 |
|
||
| **Тело** | Рост, вес, цвет волос, цвет глаз, телосложение | 164 см, 52 кг, русые, серые, худощавое |
|
||
| **Навыки** | Числовые шкалы | Математика 62, Ловкость 31 |
|
||
| **Черты** | Дискретные, с весами и несовместимостями | Усидчивый, Задира |
|
||
| **Нужды** | Числовые шкалы, убывают со временем | Сон 0.7, Голод 0.4 |
|
||
| **Связи** | Семья: родители, дети, братья и сёстры | дочь Иванова П.С. и Ивановой О.М. |
|
||
|
||
Роли три: **ученик**, **работник**, **родитель**. Роль — не def: код различает их по существу,
|
||
а не по данным. Должность работника — `PositionDef`, он уже есть.
|
||
|
||
Один человек может быть в двух ролях сразу: учительница математики, чей сын учится в седьмом
|
||
классе, — это **один** человек с ролью работника и связью «родитель» к ученику. Отдельной сущности
|
||
«родитель Иванова» для неё не заводится.
|
||
|
||
## Родители
|
||
|
||
Родители — **полноценные сущности** в мире школы, но **без места на карте**. Они существуют,
|
||
потому что у ученика есть семья, а не потому что ходят по коридорам.
|
||
|
||
Это задел, а не упрощение: позже родителя можно будет вызвать в школу — тогда у него появится
|
||
местоположение и цель, но не появится новый тип сущности. Поэтому родитель с самого начала лежит
|
||
в `World` наравне с учеником, а не отдельным списком «карточек при ученике».
|
||
|
||
## Генерация семьями
|
||
|
||
Люди генерируются **не по одному**. Единица генерации — семья:
|
||
|
||
```
|
||
Семья Ивановых
|
||
├── Иванов Пётр Сергеевич родитель, 41 год
|
||
├── Иванова Ольга Михайловна родитель, 39 лет
|
||
├── Иванова Мария Петровна ученица, 7Б
|
||
└── Иванов Кирилл Петрович ученик, 3А
|
||
```
|
||
|
||
Что это даёт бесплатно и чего иначе не получить:
|
||
|
||
- **Фамилии повторяются.** Школа без братьев и сестёр читается как список случайных строк.
|
||
- **Отчества сходятся.** Отчество ребёнка — от имени отца, а не от отдельного словаря.
|
||
- **Родовые формы согласованы.** Иванов / Иванова в одной семье, а не вразнобой.
|
||
- **Работник может быть родителем ученика** — фактом семьи, без специального правила.
|
||
|
||
Генератор идёт сверху вниз: сначала решает, сколько семей нужно, чтобы заполнить места и
|
||
должности; потом строит взрослых; потом детей нужных возрастов; и только затем раскладывает детей
|
||
по классам, а взрослых — по должностям. Обратный порядок («сгенерировать 400 учеников, потом
|
||
приписать им родителей») не даёт ни братьев, ни учителей-родителей.
|
||
|
||
**Места раздаются вперемешку по всей школе, а не подряд.** Карта отдаёт ученические места
|
||
сгруппированными по кабинетам, и семья, берущая подряд идущие места, получала бы всех детей в один
|
||
класс — то есть ровесниками, с одним и тем же окном рождения. Порядок мест перемешивается от
|
||
школьного сида до раздачи.
|
||
|
||
Цена решения названа прямо: набор мест перестаёт быть «дописываемым с конца». Более крупная карта
|
||
даёт другую раскладку по классам с самого начала, а не только в хвосте. Что остаётся неизменным —
|
||
**как разыгрывается сама семья**: её сид зависит только от номера, поэтому фамилия, состав и имена
|
||
семьи №5 одинаковы в школе на четыре кабинета и в школе на пять. Меняется то, в каком классе сидят
|
||
её дети, и вместе с классом — год рождения.
|
||
|
||
### Неполные семьи
|
||
|
||
Примерно **8%** семей с детьми живут с одним родителем. Кто именно остался — отец или мать —
|
||
решается броском, без перевеса в чью-либо сторону.
|
||
|
||
**Причина не моделируется.** Ростер записывает, кто живёт в доме, а не почему. Развод, вдовство и
|
||
прочее — это события, а событий в этом срезе нет; появится лента — появится и повод завести признак.
|
||
|
||
Ребёнок **в любом случае носит отцовскую фамилию и отчество**. Значит, отсутствующему отцу всё
|
||
равно разыгрывается имя — оно записывается на семью вместе с фамилией. Читать их с присутствующего
|
||
родителя нельзя: у матери-одиночки нет мужской формы фамилии, а сыну нужна именно она.
|
||
|
||
Решение «кто остался» берётся из **отдельного потока**, а не из общего с внешностью. В общем потоке
|
||
два соседних броска оказались связаны, и все неполные семьи до единой вышли материнскими.
|
||
|
||
**Номер ребёнка в идентификаторе — счётчик, а не длина списка.** Выпускник уходит из ростера;
|
||
если следующий ребёнок семьи получит номер по числу оставшихся детей, он унаследует идентификатор
|
||
ушедшего, и все ссылки на него — семейные связи, открытая карточка — молча начнут показывать
|
||
другого человека.
|
||
|
||
## Дефы
|
||
|
||
Пять новых видов. Ссылки — строками `defName`, как везде.
|
||
|
||
1. **SkillDef** — навык. Диапазон, распределение при генерации, зависимость от возраста,
|
||
ограничения со стороны тела (см. ниже). Не каждый человек получает каждый навык:
|
||
`always` — у всех, предметы — по параллели ученика, `work` — только взрослым,
|
||
`adultChance` — шанс у взрослого поверх родного языка.
|
||
2. **TraitDef** — черта. Вес (частота), список несовместимых черт, ограничения по роли и возрасту,
|
||
модификаторы навыков.
|
||
3. **BodyAttributeDef** — свойство тела. Либо число с распределением (рост, вес), либо выбор из
|
||
списка с весами (цвет волос, цвет глаз). Распределение зависит от пола и возраста.
|
||
4. **NeedDef** — нужда. Начальное значение и скорость убывания.
|
||
5. **NameSetDef** — набор имён (см. отдельный раздел).
|
||
|
||
Телосложение — не отдельный def, а **производное**: считается из роста и веса кодом. Данные не
|
||
должны дублировать то, что выводится.
|
||
|
||
### Что кладём в `core`
|
||
|
||
| Вид | Ванильное содержание |
|
||
| --- | --- |
|
||
| Навыки | Школьные предметы, языки набора имён, общение, физические (ловкость, сила, выносливость) и рабочие (педагогика, медицина, кухня…) |
|
||
| Черты | Около десяти для начала: усидчивый, рассеянный, задира, тихоня, лидер, лентяй, любопытный, вспыльчивый, добрый, аккуратный |
|
||
| Тело | Рост, вес, цвет волос, цвет глаз |
|
||
| Нужды | Сон, голод, туалет, общение |
|
||
|
||
Слои одинаковы у всех ролей: у родителя те же *виды* данных, что у ученика. Набор ключей
|
||
навыков — нет. Нет ключа — нет навыка, а не ноль: карточка его не показывает, урок, если
|
||
предмет всё же начался, стартует с `Range.Min`. Иначе первоклассник носил бы химию «для
|
||
полноты», а код всё равно спрашивал бы, есть ли она.
|
||
|
||
### Как тело ограничивает навыки
|
||
|
||
«Толстый не может быть ловким» — правило **генерации**, а не игровой эффект: характеристики пока
|
||
ни на что не влияют, но между собой согласованы.
|
||
|
||
Ограничение живёт в `SkillDef` и ссылается на свойство тела:
|
||
|
||
```jsonc
|
||
{
|
||
"defName": "Agility",
|
||
"range": { "min": 0, "max": 100 },
|
||
"bodyLimits": [
|
||
{ "attribute": "Build", "value": "Obese", "max": 25 },
|
||
{ "attribute": "Build", "value": "Heavy", "max": 45 },
|
||
{ "attribute": "Build", "value": "Athletic", "min": 40 },
|
||
],
|
||
}
|
||
```
|
||
|
||
Генератор сначала бросает тело, потом те навыки, которые человеку положены, потом применяет
|
||
ограничения как зажим. Порядок важен и фиксируется: **тело первично**, навык подстраивается.
|
||
Иначе один и тот же сид даст разных людей в зависимости от порядка перебора.
|
||
|
||
Выдача навыков тоже фиксирована: `always` → родной язык школы → предметы параллели (ученик) →
|
||
лишние академические, рабочие и `adultChance` (взрослый) → черты и зажим тела → родственные
|
||
языки набора. Годовой набор добавляет только новые ключи предметов; уже выданные значения не
|
||
перебрасываются.
|
||
|
||
Ограничения — не только вниз: «атлет не может быть совсем неловким» так же осмысленно, поэтому
|
||
`min` есть наравне с `max`.
|
||
|
||
## Нужды
|
||
|
||
Четыре нужды в `core`: **сон, голод, туалет, общение**. `NeedDef` описывает шкалу и скорость
|
||
убывания. Машинерия работает с этого среза: значение лежит на человеке, тикает вместе со школой,
|
||
показывается в карточке.
|
||
|
||
**Но в `core` скорость убывания равна нулю.** Есть тела, которые тратят, и нет ничего, что
|
||
восполняет: некому поесть, негде поспать. Ненулевая скорость в этом срезе означала бы школу, где
|
||
через игровые сутки все нужды на нуле, — и это выглядело бы поломкой, а не игрой.
|
||
|
||
Скорость — данные, не код. Когда появится еда и сон, цифра меняется в JSONC, а не в C#.
|
||
|
||
## Имена
|
||
|
||
`NameSetDef` — набор имён целиком: мужские имена, женские имена, фамилии, правила отчеств и
|
||
склонений. В `core` один набор — славянский. Другие наборы приходят модами.
|
||
|
||
**Один набор на школу.** Выбирается в диалоге создания рядом с модами и сохраняется в файле школы.
|
||
Смеси с весами («80% славянских, 20% прочих») — не в этом срезе: они требуют UI для весов.
|
||
|
||
Набор несёт список языков, на которых здесь говорят (`nativeLanguages`). Школа выбирает **один**
|
||
при создании — это родной язык всех людей. Остальные языки списка часто появляются на низком
|
||
уровне (`relatedLanguageChance` и соседние поля на том же def): русскоязычный может понимать
|
||
белорусский. Уже выданный ключ — родной или предмет школы — не перезаписывается, поэтому
|
||
белорусский ученик сохраняет школьный русский, а не обрезанный «чуть-чуть». Шанс `0` оставляет
|
||
родственников выключенными (одноязычный пакет).
|
||
|
||
Набор имён **не связан с языком интерфейса**. Английский UI не превращает Иванову в Ivanova:
|
||
язык интерфейса — про подписи кнопок, набор имён — про то, кто учится в школе.
|
||
|
||
### Склонения
|
||
|
||
Русскому тексту нужны падежи: «вызвать **Иванову Марию**», «дневник **Ивановой Марии**». Шесть
|
||
падежей на каждую часть ФИО.
|
||
|
||
Два способа, и нужны оба:
|
||
|
||
- **Правило** — по умолчанию. Код знает небольшой набор моделей склонения (`-ов/-ова`, `-ий/-ая`,
|
||
`-а/-я`, несклоняемые). В данных — только имя и id модели.
|
||
- **Явная таблица** — когда правило не работает. Любая запись может задать все шесть форм руками.
|
||
|
||
Это тот же принцип, что и везде: код знает *как*, данные говорят *что*. Словарь из шести форм на
|
||
каждое из тысячи имён никто не выдержит, а одними правилами русские фамилии не покрываются.
|
||
|
||
Падежи нужны заранее, до появления ленты событий: набор имён с одной формой потом придётся
|
||
переписывать целиком, а он самый объёмный файл в `core`.
|
||
|
||
## Отдельная библиотека
|
||
|
||
Новый проект **`HSchool.People`**.
|
||
|
||
```
|
||
Protocol ← Server → Simulation → People → Content
|
||
```
|
||
|
||
- Зависит от `HSchool.Content` (нужны defs и каталог).
|
||
- **Не** зависит от Arch, ASP.NET и сокетов — как `Content` сейчас.
|
||
- Отдаёт простые записи. Превращает их в сущности `World` уже `HSchool.Simulation`.
|
||
|
||
Так генератор тестируется без мира и без хоста: «этот сид + эта карта + этот набор имён + этот
|
||
родной язык → ровно эти люди». Это единственный способ поймать регрессию в генераторе — глазами
|
||
такое не проверяется.
|
||
|
||
### Детерминизм
|
||
|
||
Генерация детерминирована от **сида**. Сид — своё поле школы, не её идентификатор: при создании
|
||
его бросает сервер, либо его передают в `POST /api/schools`. Он лежит в файле людей и виден в
|
||
списке школ и на экране школы, чтобы им можно было поделиться. Один сид + одна карта + один набор
|
||
имён + один родной язык = одна и та же школа, всегда. Если родной язык при создании не указан,
|
||
его выбирает тот же сид — повтор без поля даёт тот же язык.
|
||
|
||
Существующие школы не перебрасываются: они продолжают жить с числом, уже записанным в файле людей.
|
||
|
||
Сид у каждой семьи свой, выведенный из школьного: добавление тринадцатой семьи не должно менять
|
||
первые двенадцать. Иначе тест на генератор ломается от любой правки порядка.
|
||
|
||
## Годовой набор
|
||
|
||
Состав живёт: 1 сентября классы переходят в следующую параллель, одиннадцатый выпускается, его
|
||
кабинет освобождается под новый первый.
|
||
|
||
Вместимость при этом постоянна — она задана картой. Набор не увеличивает школу, а **замещает**
|
||
выпуск. Школа растёт только стройкой.
|
||
|
||
Выпускается **старшая имеющаяся** параллель: школа из четырёх кабинетов не должна ждать
|
||
одиннадцатого класса, чтобы кого-то выпустить.
|
||
|
||
Выпускники уходят из ростера. Их родители уходят следом, но только если в школе не осталось
|
||
других их детей и сами они в ней не работают, — иначе ростер копил бы людей, ни с чем не
|
||
связанных, до бесконечности.
|
||
|
||
Школа создаётся посреди учебного года (по умолчанию 3 апреля), поэтому при создании классы уже
|
||
сформированы и возраст ученика соответствует его параллели: в N-й класс ходят те, кому
|
||
исполнилось N+6 до 1 сентября. Переход в следующую параллель **добавляет** навыки новых
|
||
предметов (английский с пятого, химия с восьмого) и не перебрасывает уже выданные.
|
||
|
||
## Просмотр
|
||
|
||
Не отдельный экран. Список людей — **панель в оболочке менеджера**, рядом с картой:
|
||
уходя в отдельный экран, игрок теряет из виду часы и локацию, а смысл этой оболочки
|
||
ровно в том, чтобы всё было на одном экране. Ориентир — прогрессивный QSP: текст, списки и ссылки,
|
||
без сцены.
|
||
|
||
Панель «Люди» — вторая вкладка той же панели, что и карта: фильтрам, колонкам и пейджеру нужна
|
||
ширина, а держать список третьим рядом под картой значило бы отдать ему высоту, которой на экране
|
||
школы нет. Вкладка переключается рядом с деревом, выбранная строка открывает карточку справа —
|
||
там же, где содержимое локации.
|
||
|
||
- **Фильтры**: роль (ученики / работники / родители), параллель и литера, должность, пол,
|
||
возрастной диапазон.
|
||
- **Сортировки**: фамилия, возраст, параллель, должность.
|
||
- **Пейджинг** обязателен: тысяча учеников — это три тысячи человек с семьями.
|
||
- **Строка списка** — только лёгкое: ФИО, роль, класс или должность, возраст, пол.
|
||
- **Карточка** одного человека — тело, навыки (только те, что есть), черты, нужды, семья со
|
||
ссылками на родных.
|
||
|
||
## Масштаб
|
||
|
||
Школа на 1000 учеников — это около **3000 человек** вместе с родителями, и до шести таких школ
|
||
живут одновременно. Три решения следуют отсюда напрямую.
|
||
|
||
**Ростер не ходит в снимке карты.** Снимок при открытии школы остаётся про помещения. Люди —
|
||
отдельный путь, иначе открытие школы означало бы мегабайт по сокету.
|
||
|
||
**Список — HTTP, а не сокет.** Запрос-ответ с фильтром, сортировкой и страницей — это REST по
|
||
природе, как и меню. Воркер публикует неизменяемый снимок ростера (он меняется редко: создание,
|
||
набор, наём), обработчик читает опубликованный снимок и не трогает воркер — инвариант 3 цел.
|
||
|
||
**Живые значения — из воркера.** Нужды тикают, поэтому карточка одного человека запрашивается у
|
||
воркера через мейлбокс и `TaskCompletionSource`, как create и delete. Один человек — дешёвый
|
||
запрос; три тысячи людей двадцать раз в секунду — нет.
|
||
|
||
**Ростер — отдельный файл.** `saves/{id}.people.json` пишется только когда состав изменился;
|
||
`saves/{id}.json` остаётся маленьким и частым. Сейчас файл школы переписывается каждые 30 секунд —
|
||
таскать через это мегабайт ростера, который меняется раз в игровой год, незачем.
|
||
|
||
## Советы, которые стоит принять сразу
|
||
|
||
- Не делать «родителя» отдельным видом сущности. Иначе учительница-мать станет двумя людьми.
|
||
- Не хранить телосложение в данных — оно выводится из роста и веса.
|
||
- Не начинать с падежных таблиц на каждое имя: правило по умолчанию, таблица как исключение.
|
||
- Не отправлять черты и навыки в списке — только в карточке. Список читают глазами, карточку
|
||
открывают по одному человеку.
|
||
- Сид на семью, а не один на школу: иначе любая правка генератора переставит всех.
|
||
- Ненулевую скорость нужд не включать, пока нечем их восполнять.
|
||
|
||
## Заведомо не сейчас
|
||
|
||
- Поведение: расписание, уроки, перемещение по карте, исполнение действий.
|
||
- Влияние характеристик на что-либо. Черты и навыки в этом срезе — текст в карточке.
|
||
- Вызов родителя в школу. Задел есть (родитель — сущность), реализации нет.
|
||
- Наём и увольнение вручную. Должности закрываются генератором.
|
||
- Смеси наборов имён с весами.
|
||
- Новые роли из модов: ученик, работник, родитель — код, не данные.
|
||
- Портреты и любой арт.
|
||
- Причина неполной семьи: развод, вдовство и прочее — это события, а ленты событий ещё нет.
|
||
|
||
## Зафиксировано этим разговором
|
||
|
||
| Тема | Решение |
|
||
| --- | --- |
|
||
| Размер школы | Из карты: `PupilSlots` — ученики, `RoomDef.positions` — штат |
|
||
| Класс | Один кабинет = один класс; класс — сущность ростера, не поле карты |
|
||
| Параллель и литера | Поля класса, а не разбор подписи комнаты; раскладывает генератор |
|
||
| Подписи кабинетов | Номера помещений («204»), имя класса живёт на классе |
|
||
| Ванильная карта | Дорабатывается до 11 кабинетов — по одному на параллель |
|
||
| Когда генерируются | Полный состав при создании, затем набор каждое 1 сентября |
|
||
| Годовой набор | Замещает выпуск; вместимость меняет только стройка |
|
||
| Кого выпускать | Старшую имеющуюся параллель, а не обязательно одиннадцатую |
|
||
| Уход из ростера | Выпускники уходят; родители — если не осталось детей и они здесь не работают |
|
||
| Роли | Ученик, работник, родитель; роль — код, должность — `PositionDef` |
|
||
| Родители | Сущности в `World`, без места на карте; задел на вызов в школу |
|
||
| Совмещение ролей | Один человек может быть работником и родителем ученика |
|
||
| Единица генерации | Семья, а не человек |
|
||
| Неполные семьи | Около 8% семей с детьми; остаётся случайный родитель; причина не моделируется |
|
||
| Фамилия и отчество | Всегда отцовские; имя отца и фамилия записаны на семье, а не на человеке |
|
||
| Раздача мест | Вперемешку по школе от сида: иначе братья и сёстры — всегда одноклассники |
|
||
| Стабильность сида | Гарантируется по семье (фамилия, состав, имена), не по месту в классе |
|
||
| Идентификатор ребёнка | Счётчик семьи; номер выпустившегося не переиспользуется |
|
||
| Набор в первый класс | Новые семьи приходят по одному ребёнку — иначе это тройняшки-ровесники |
|
||
| Порядок ограничений | Черта не может пробить потолок тела: зажим повторяется после модификаторов |
|
||
| Слои человека | Личность, тело, навыки, черты, нужды, связи |
|
||
| Новые defs | `SkillDef`, `TraitDef`, `BodyAttributeDef`, `NeedDef`, `NameSetDef` |
|
||
| Телосложение | Производное от роста и веса, не def |
|
||
| Тело и навыки | `SkillDef.bodyLimits` зажимают навык; тело бросается первым |
|
||
| Влияние характеристик | Никакого; только просмотр |
|
||
| Навыки в `core` | Предметы, языки, общение, физические, рабочие |
|
||
| Выдача навыков | Не полный каталог: always, родной, предметы года, взрослые лишние, родственные языки |
|
||
| Черты в `core` | Около десяти |
|
||
| Нужды в `core` | Сон, голод, туалет, общение |
|
||
| Нужды | Машинерия есть, скорость убывания в `core` — ноль |
|
||
| Слои по ролям | Одинаковые виды данных; ключи навыков зависят от роли и возраста |
|
||
| Набор имён | Один на школу, выбор в create, в `core` славянский; прочие — моды |
|
||
| Родной язык | Один из `nativeLanguages` набора, выбор в create; остальные языки списка — часто низкий навык |
|
||
| Падежи | Правило по умолчанию (код), явная таблица как исключение (данные) |
|
||
| Имена и язык UI | Независимы |
|
||
| Библиотека | `HSchool.People`: зависит от Content, не знает Arch и ASP.NET |
|
||
| Детерминизм | Свой сид школы (не id), в сейве и в API; свой сид на семью; родной язык — часть входа |
|
||
| Просмотр | Панель в оболочке менеджера, вкладкой рядом с картой; не отдельный экран |
|
||
| Список | Фильтры, сортировки, пейджинг; в строке — только лёгкие поля |
|
||
| Транспорт списка | HTTP по опубликованному снимку ростера |
|
||
| Транспорт карточки | Запрос в воркер, потому что нужды живые |
|
||
| Сохранение | `saves/{id}.people.json`, пишется при изменении состава |
|