# Одежда, вещи и климат Договорённость на следующий срез, не текущий код. Люди: [`people.md`](people.md). Типы и карта: [`defs.md`](defs.md). Жизнь школы: [`ai.md`](ai.md). Экран: [`near-term.md`](near-term.md). Проекты: [`projects.md`](projects.md). У человека появляется то, что на нём надето и что он несёт. Школа получает климат и правила одежды. Игрок это **смотрит** и выбирает правила; надевает не он — система сама приводит гардероб к уместности, сезону и погоде. Срез отвечает на вопросы «во что одеты», «что в сумке», «какая на улице погода» и «что человек делал сегодня». Магазинов, стирки, краж и выдачи со склада нет. ## Что меняется в уже принятом | Было | Стало | Почему | | --- | --- | --- | | Create выбирает набор имён | Create выбирает **страну**; набор имён вложен в неё | Климат, имена и вкус к одежде — одна культура, а не три пикера | | `ThingDef` — мебель на карте | Тот же вид def, поля отличают размещаемое / носимое / переносимое | Стул и футболка — предметы, но живут в разных местах | | Карточка — один свиток | Вкладки: обзор, одежда, ноша, сейчас + история | Гардероб в узкую колонку списком навыков не влезает | | «Управление» — деньги и штат | Плюс вкладка **«Правила»** | Дресс-код — единственное действие игрока в этом срезе | | Часы несут дату и паузу | Плюс температура и осадки | Погода должна быть видна, не спрятана в карточке | | Одна раздевалка на 12 шкафчиков | Две (м / ж); шкафчик принадлежит ученику | Переодевание на физкультуру и личное хранение — разные вещи | Старые школы без страны поднимаются: нынешний набор имён отображается на ванильную страну, климат — первый пресет этой страны. Файл не переписывается молча в новый вид, пока школа не сохранится сама. ## Страна Новый вид def — `CountryDef`. Это то, что игрок выбирает при создании школы. В стране лежит всё, что раньше было «набором имён», плюс ссылки на климатические пресеты: ```jsonc { "defName": "Russia", "climatePresets": ["TemperateContinental", "ContinentalCold"], "names": { "patronymicRule": "Slavic", "nativeLanguages": ["Russian", "Belarusian", "Ukrainian"], "relatedLanguageChance": 0.35, // maleGiven, femaleGiven, surnames — как у нынешнего NameSetDef }, } ``` Набор имён **перестаёт быть выбираемым видом**. Он не удаляется как форма данных: это вложенный объект страны. Мод, который хочет другую страну, кладёт свой `CountryDef` целиком, а не «набор имён плюс климат сбоку». Родной язык по-прежнему выбирается из `names.nativeLanguages`, если их больше одного. Это не третий пикер культуры — это язык внутри уже выбранной страны. Не указан — бросает сид школы, как сейчас. Климатический пресет школа получает **случайный из списка страны**, от того же сида, и записывает у себя. Повтор create с тем же сидом даёт ту же погоду. Сменить пресет у живой школы нельзя: это часть рождения, как набор имён раньше. В `core` одна страна — `Russia`: нынешний славянский набор вложен в неё, пресеты — умеренно- континентальные. Другие страны приходят модами. Форма создания говорит «Страна», не «Набор имён». `GET /api/catalog` отдаёт `countries` вместо `nameSets`. `POST /api/schools` принимает `countryId`; неизвестная страна — `400` `unknown-country`. Старое поле `nameSetId` не принимается. ## Климат и погода Погода — не картинка и не текст. На школе живёт состояние: **уличная температура** и **осадки** (нет / дождь / снег). Его видно у часов, и от него одеваются. Числа живут в `ClimatePresetDef`, не в коде. Страна только ссылается на id. Мод меняет зиму, не трогая имена. Пресет описывает: - ход температуры по году (месячные нормы); - как температура гуляет внутри дня и от нормы (разброс); - когда и какие осадки — с поправкой на температуру: ниже нуля тот же бросок даёт снег, выше — дождь. Погода пересчитывается не каждый тик, а когда это меняет одежду или надпись у часов: сдвиг на несколько десятых градуса, смена осадков. Детерминизм: пресет + сид школы + календарная дата и час. Тот же сид, тот же день — та же улица. **В здании теплее, чем на улице**, даже без сотрудника: стены держат. Но комфорт — работа техника. Без него зимой в кабинетах прохладно, летом душно; с ним держится жилая полоса. Двор, крыльцо и переход между корпусами — улица. Пропуск пустого времени погоду не «перепрыгивает молча»: к утру рабочего дня состояние считается из даты, как годовой набор уже считается через каникулы. ## Тепло как нужда Новая нужда — **тепло** (`Warmth`). Шкала как у остальных: 0–1, полоска на карточке. Она падает, когда одежда не соответствует **температуре места**, где человек сейчас: на морозе без куртки, в жару в шубе. В комфортной полосе почти не падает. Дома (вне школы) восстанавливается за кадром, как сон. Две черты, несовместимые друг с другом: - **теплолюбивый** — комфортная полоса сдвинута вверх, на жару реагирует спокойнее, на холод — раньше; - **холодолюбивый** — наоборот. Сдвиг — поле на `TraitDef` (смещение комфортной температуры), не список фамилий в коде. Мод добавляет «мерзлявый» тем же полем. Голодный учится хуже уже сейчас. Замёрзший в этом срезе **ещё не** получает штраф к уроку: нужда видна и двигает переодевание, но таблицу оценок мы не заводим. Когда появятся последствия состояния, тепло встанет рядом с голодом. ## Один ThingDef, три роли Мебель, одежда и портфель — один вид. Различают поля, а не отдельные классы. Стул без слоёв по-прежнему ставится на карту; футболка со слоями на карту не ставится. | Поле | Зачем | | --- | --- | | `layers` | Какие слои занимает. Пусто — не одежда | | `portable` | Можно нести в сумке / шкафчике / дома | | `mass` | Килограммы; ноша складывается | | `insulation` | Насколько греет (и преет в жару) | | `formality` | Формальность, 0–100 | | `age` | Допустимый возраст | | `sex` | `male` / `female` / нет поля = любой | | `colors` | Какие `ColorDef` допустимы на этом def | | `skirtLength` | Длина низа; для «короткой» формы | | `pe` | Форма для физкультуры | | `subject` | Только у дефа учебника: какой предмет | Учебник — **один** `ThingDef`, экземпляр несёт id предмета. Не двенадцать дефов «учебник математики». Цвет — поле **экземпляра**, не отдельный def вещи. «Синяя футболка» и «красная футболка» — один `TShirt` с разным `color`. `ColorDef` — свой вид: id, теги уместности (`neutral`, `bright`, `school`). Правила школы фильтруют теги, а не имена цветов. Мод добавляет «бордовый» файлом, не пересборкой. Новые слои — пересборка: слои как роли, код их знает. Подписи — в локалях. ### Слои Код знает десять, в `core` все используются: | Слой | Что надевают | | --- | --- | | `Underwear` | трусы | | `UpperUnderwear` | бюстгальтер (поверх трусов, под верх) | | `Socks` | носки | | `Bottom` | юбка, штаны, джинсы, брюки | | `Top` | футболка, рубашка | | `OverTop` | свитер, жилет | | `Outer` | куртка, пальто, шуба | | `Shoes` | обувь | | `Head` | шапка, кепка | | `Accessory` | ремень, шарф, значок | Платье — **один предмет на несколько слоёв**: `layers: ["Bottom", "Top"]`. Пиджак, если его можно снять отдельно от брюк, — отдельная вещь на `OverTop` или `Outer`, не «костюм-монолит». На одном слое — не больше одной вещи. Надеть свитер поверх рубашки можно: это разные слои. Надеть две футболки нельзя. ### Ванильный набор Не витрина моды, а достаточный гардероб, чтобы генератор и правила было чем кормить: - бельё: абстрактный `Underwear`, от него трусы / боксеры / трусики и бюстгальтеры (`UpperUnderwear`); - носки нескольких цветов; - низы: юбка (женская), штаны, джинсы, брюки — длины обычная и короткая; - верх: футболка, рубашка; - поверх: свитер; - верхняя: куртка, пальто, шуба; - обувь: повседневная и зимняя; - голова: шапка; - аксессуары: ремень, шарф; - платье (два слоя); - форма физкультуры (верх + низ, `pe: true`); - ноша: портфель, учебник (один def), телефон, бутылка. Цвета палитры: белый, чёрный, серый, синий, голубой, красный, зелёный, бежевый. Красный и зелёный — `bright`; белый, чёрный, серый, синий — `school` и `neutral`. ## Где лежит вещь У экземпляра одно место из четырёх: | Место | Что это | | --- | --- | | **Надето** | занимает слои | | **Сумка** | с собой, давит на ношу | | **Шкафчик** | в школе, не несёт | | **Дом** | не локация, а состояние «не в школе» | Домашнего узла на карте нет и не будет. «Дом» — событие и подпись текущего дела, как «вне школы» уже есть у присутствия. **Шкафчик — слот на карте, привязанный к ученику.** Число шкафчиков в раздевалке = число слотов. Раздача: ученики этого пола, старшие параллели раньше, при равенстве — стабильный id. Не хватило — не досталось: запас только в сумке и дома. Сотрудники шкафчик ученика не получают. Сменить одежду в школе можно и без шкафчика: снятое уходит в сумку. Шкафчик — чтобы не таскать форму для физкультуры весь день. Две раздевалки на ванильной карте — два узла, мужская и женская, у спортзала. Def разный, чтобы ИИ шёл в свою. В редакторе шкафчики по-прежнему число в слоте: поставили 40 — сорок учеников этого пола получат место. ## Генератор одевает Люди больше не рождаются голыми. Генератор, тем же семейным сидом, собирает гардероб: - повседневное и уместное полу, возрасту и дефолтным правилам школы; - сезонную верхнюю одежду; - форму для физкультуры ученикам, у кого в сетке есть этот предмет; - учебники **по одному на каждый предмет параллели** (не все книги каталога); - портфель, телефон и бутылку — с шансом и возрастом (первокласснику телефон не обязателен). Родители одеты: на них есть планы появиться в школе, и раздетой карточки быть не должно. Соискатели — тоже полные люди, значит тоже одеты. Цвет бросается из допустимых у def с учётом правил школы. Красную рубашку в школу с политикой «без яркого» генератор не выдаст на тело; в домашнем запасе яркое может лежать. Детерминизм тот же: страна + пресет + сид + карта + язык = те же люди в той же одежде. Золотой отпечаток ростера обновляется в той фазе, которая начинает одевать. ## Ноша Новый навык `Hauling` («Переноска»), `always`, как сила. Предел массы: **предел = f(Strength, Endurance, Hauling)** — точная формула в `BehaviorDef` или соседнем дефе правил, не константа в коде. На карточке — два числа: несёшь / можешь. Перегруз **не** замедляет ходьбу в этом срезе. Вещи сверх предела генератор не выдаёт в сумку: лишнее остаётся дома или в шкафчике. В сумке в учебный день: портфель, учебники **сегодняшних** уроков, телефон, бутылка, то, чему не хватило шкафчика. Остальные учебники — в шкафчике или дома. Иначе одиннадцатиклассник с двенадцатью учебниками всегда перегружен, и шкала лжёт. ## Износ У экземпляра одежды прочность 0–1. Пока вещь **на теле в школе**, она чуть падает со временем. Ходьбу отдельно не считаем. Сумка и шкафчик не изнашиваются. На карточке — полоска и подпись по порогам из данных (`целая`, `поношенная`, `порванная`, `висит лохмотьями`). Пороги — def, не `if` в UI. Из дома в одежде ниже порога **не выходят**. Утром вне школы срабатывает событие: ветхая вещь заменяется свежей того же def и цвета (или ближайшего уместного). Это видно в истории («получил новую рубашку»), не как поход по узлам карты. Пропуск ночи это событие обязан применить: иначе после «пропустить» школа выходит в лохмотьях. ## Уместность Не запрет «юбку надеть нельзя», а оценка. Надеть можно; система сама так не оденет, а если ситуация сменилась — переоденет. Оси, все из данных на вещи, цвете и правилах школы: - пол и возраст; - сезон и текущая погода (утепление vs улица); - урок: на физкультуре нужна `pe`-форма; - формальность вещи vs дресс-код; - цвет vs цветовая политика; - длина низа vs «короткая» форма. «Короткая» форма — про **длину юбки** (и летний короткий рукав), не про «можно без формы». Малышам короткое неуместно: даже если школа выбрала «короткую», младшие параллели ходят в обычной. Порог возраста — поле на правиле, не магическая семёрка в коде. Цветовая политика **отдельно от строгости**. Строгая форма всё ещё может быть «без яркого» или «белый верх, чёрный низ». У учителей свой комплект правил: ученику белая рубашка, директору — не обязательно. Смена правил в «Управлении» вступает в силу **со следующего рабочего дня**. Сегодняшняя одежда не вспыхивает в раздевалках посреди урока. На карточке правил видно: «с завтра». ## Переодевание Дома — мгновенно, событием, в момент ухода/прихода. В школе — **действие**: дойти до своей раздевалки и сменить. Снятое — в шкафчик, если он есть, иначе в сумку. Надетое — из шкафчика или сумки. Типичные поводы, все через уже существующий выбор цели: - утром пришёл не по погоде (вчера было тепло, ночью ударил мороз) — переодеть верх; - сейчас физкультура — форма `pe`, после урока — обратно; - с завтра действует новый дресс-код — утром уже в нём (домашнее мгновенное + проверка при входе). Действие занимает раздевалку как комнату, не чужой шкафчик. Вместимость переодевания — сколько человек одновременно могут здесь действовать; это не путать с числом личных шкафчиков. ## Техник Новая должность и комната: **техник** (`Technician`) в теплоузле / кабинете техника. Комната открывает должность, как медкабинет — медсестру. Игрок нанимает из пула. Пока техник не нанят, здание держит тепло по-плохому: зимой зябко, летом душно. Нанятый сдвигает внутреннюю температуру в комфортную полосу. Числа — в дефе правил климата, не в `if (month)`. Ванильная карта получает эту комнату в основном корпусе. Без неё должность не рождается, и нанять некого. ## Что видит игрок ### Часы Рядом с датой: температура улицы и осадки. Клиент не считает погоду из месяца — только рисует кадр. Кадр часов растёт, версия протокола поднимается. ### Карточка человека — вкладки Не отдельный экран и не вкладка оболочки. То же окно подробностей справа, внутри него вкладки: 1. **Обзор** — то, что есть сейчас: тело, навыки, черты, нужды (включая тепло), семья, расписание. 2. **Одежда** — слои, надетое, цвет, прочность с полоской и подписью, уместность к текущей ситуации (коротко: «к уроку», «холодно», «не по форме»). 3. **Ноша** — сумка, масса несёшь/можешь, шкафчик если есть, домашнее не тащить сюда списком из пятидесяти строк: дом — кратко «ещё N вещей дома». 4. **Сейчас** — текущее дело на территории школы (`ест`, `идёт`, `учится (математика)`, `переодевается`). Вне школы — одна подпись «дома», без фальшивого расписания домашней жизни. Ниже — **история за сегодня**: сортировка, поиск, пейджинг. Игрок с карточки ничего не надевает и не забирает. Чистый просмотр. История — HTTP, как список людей: `GET .../people/{id}/log`, страница, фильтр. Не сокет и не общая лента школы. Хранится на работнике за текущие сутки (граница — шесть утра), к новому дню обнуляется. Пропуск ночи не оставляет вчерашний лог. ### Управление — «Правила» Вкладка рядом с нынешним штатом, не новый верхний режим. Четыре комбобокса: | Кого | Форма | Цвет | | --- | --- | --- | | Ученики | обычная / короткая / строгая | свободно / без яркого / белый верх чёрный низ | | Сотрудники | обычная / короткая / строгая | свободно / без яркого / белый верх чёрный низ | «Применить» меняет **завтрашнее** правило. Сегодняшний день доигрывается как был. ## Поток данных Инвентарь лежит **на человеке** в `people.json`. Он меняется чаще состава (переодевание, износ), но реже нужд: писать файл на каждом тике нельзя, писать при смене состава — мало. Шов тот же, что у найма: запись, когда гардероб изменился содержательно (утро, переодевание, выдача новой вещи), не каждый кадр. Карточка по-прежнему через мейлбокс: нужды и текущее действие живые, одежда едет тем же ответом. Список людей одежду не несёт. История — отдельный GET, чтобы карточку не раздувать сотней строк. Погода — в кадре часов. Открытая школа, 20 Гц, потеря старого кадра допустима: как с датой. ## Где живёт код Нового проекта нет. | Что | Куда | | --- | --- | | `CountryDef`, `ClimatePresetDef`, `ColorDef`, поля `ThingDef`, слои | `HSchool.Content` | | Генерация гардероба, раздача шкафчиков, учебники параллели | `HSchool.People` | | Погода от пресета и даты, износ, утренняя замена | `HSchool.Simulation` | | Действие «переодеться», цель «одеться по погоде / к физкультуре» | `HSchool.Ai` | | Кадр часов, карточка, лог, правила, create | `HSchool.Server` + клиент | | Раскладка часов | `HSchool.Protocol` + `protocol.ts` + `docs/protocol.md` | ## Советы, которые стоит принять сразу - Не заводить `ApparelDef`. Поля на `ThingDef` дешевле, чем два загрузчика и вечный вопрос «а рюкзак — это что». - Не делать цвет отдельным def вещи. Экземпляр + палитра. - Не ставить домашний узел на карту. Тридцать тысяч «комнат» семей не окупить. - Не раздавать шкафчик каждому на ванильной карте. Нехватка — правило, не баг. - Не вешать перегруз на ходьбу, пока не измерен. Число на карточке сначала. - Не возвращать общую ленту событий школы. История — у человека, за сегодня. ## Заведомо не сейчас - Магазины, деньги за одежду, стирка, кража, выдача со склада игроком. - Игрок одевает человека с карточки. - Штраф к уроку от холода, болезни от промокания, прогул «не в форме» как оценка. - Смена страны или климатического пресета у живой школы. - Почасовая анимация погоды, ветер, грязь, зонты как система. - Шкафчики сотрудников, раздевалки в каждом корпусе сверх двух ванильных. - История старше суток и школьная лента на весь экран. - Портреты и спрайты одежды. Слои — текст и цвет, не картинка. ## Зафиксировано этим разговором | Тема | Решение | | --- | --- | | Вид def | Один `ThingDef`; одежда и ноша — поля | | Цвет | Поле экземпляра; `ColorDef` с тегами уместности | | Костюм / платье | Один предмет на несколько слоёв; снимаемый пиджак — отдельная вещь | | Слои | Бельё, носки, низ, верх, поверх, верхняя, обувь, голова, аксессуар | | Уместность | Пол, возраст, сезон/погода, урок (физкультура), формальность, дресс-код, цвет | | Запрет vs оценка | Оценка; система сама не наденет неуместное | | Короткая форма | Длина юбки и летний рукав; малышам неуместно — ходят в обычной | | Цвет vs строгость | Два независимых правила; своё у учеников и у сотрудников | | Ноша | Навык `Hauling` + сила + выносливость; на карточке число, ходьбу не трогает | | Учебники | Один def, экземпляр на предмет параллели; в сумке — сегодняшние | | Прочее в сумке | Портфель, телефон, бутылка | | Генератор | Одевает всех, включая родителей и соискателей | | Переодевание дома | Мгновенно, событием | | Переодевание в школе | Действие в своей раздевалке | | Дом | Не узел карты; текущее дело «дома» | | Шкафчик | Слот карты, один ученик; старшие раньше; не хватило — не досталось | | Раздевалки | Два узла, м/ж; шкафчики добавляются числом в редакторе | | Износ | Падает на теле в школе; полоска + подписи; из дома в ветхом не выходят | | Замена одежды | Утром дома событием | | Страна | `CountryDef`: вложенные имена + ссылки на пресеты климата | | Create | Пикер страны вместо набора имён; язык — если у страны их несколько | | Климат | Пресет выбирается сидом из списка страны, на живой школе не меняется | | Погода | Температура и осадки; у часов; в кадре часов | | В здании | Теплее улицы всегда; комфорт — если нанят техник | | Техник | Комната + должность; холод летом и тепло зимой | | Нужда | `Warmth`; черты теплолюбивый / холодолюбивый | | Правила | Вкладка в «Управлении»; четыре комбобокса; с завтра | | Карточка | Вкладки обзор / одежда / ноша / сейчас+история; чистый просмотр | | История | Только этот человек, только сегодня, HTTP, поиск и пейджинг | | Инвентарь в сейве | На человеке в `people.json`, писать при содержательной смене | | Игрок надевает | Нет | | Погода влияет на ИИ | Да: переодеться. Ходьбу и урок в этом срезе не штрафует |