Files
h-school/docs/design/social.md
T
Leonid Pershin 5a400be792 Add SwarmUI settings management and portrait generation enhancements
- Introduced new API endpoints for managing SwarmUI settings, including fetching and saving presets and age rules.
- Updated the portrait generation logic to utilize the new settings structure, allowing for dynamic preset selection based on age.
- Enhanced UI components to support SwarmUI settings, including localization for new strings and improved styling for settings sections.
- Added tests to verify the functionality of new settings endpoints and portrait generation behavior.

This commit lays the groundwork for more flexible and user-friendly portrait generation options.
2026-08-20 06:06:45 +03:00

300 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Общение, отношения и романтический пак
Договорённость на срез после сессии/темпа, не текущий код.
Люди: [`people.md`](people.md). ИИ: [`ai.md`](ai.md). Одежда (уместность как образец):
[`inventory.md`](inventory.md). Моды: [`defs.md`](defs.md), [`foundation.md`](foundation.md).
У человека появляется, **с кем** он говорит и **что** о нём думают другие. Нужда «общение» уже
есть, действие `Chat` уже есть — но это соло в коридоре. Срез делает разговор кружком, тему —
дефом, мнение — числом, вражду — ссорой и редкой дракой. Игрок это **смотрит**. Романтика не
ваниль: отдельный пак, который ещё и проверяет, что контентный мод на живой дороге работает.
Срез отвечает на вопросы «кто кому друг», «о чём болтают» и «что меняет пак». Настроения-нужды,
приказов директора и секса нет.
## Что меняется в уже принятом
| Было | Стало | Почему |
| --- | --- | --- |
| `Chat` — один человек стоит в коридоре | Кружок 2–4 в одном узле, одна тема | Иначе общение не общение |
| Семья на карточке — только родство | Плюс число мнения; вкладка «Связи» | Родители по умолчанию не ноль |
| Конфликтов нет (`ai.md`) | Ссора и редкая драка без травм | Вражда должна быть видна, не только −40 в JSON |
| `example` — единственный не-core пак | Рядом контентный `romance` | Скучный образец не доказывает темы, ориентацию и патч `Chat` |
| Присутствие: id, узел, идёт/стоит | Плюс кружок (id участников + тема) | «Говорит с Машей о футболе» в локации |
| «Правила» — только одежда | Плюс политика речи | Уместность тем — тот же жест, что дресс-код |
## Этап A — мнения и темы
### Мнение
У упорядоченной пары `(A → B)` одно число **−100…100**. Несимметрично: A может любить B, B —
терпеть A. Ноль не храним. Пороги и подписи — в `BehaviorDef`, не в UI:
знакомые / приятели / друзья / близкие друзья на плюсе; натянуто / неприязнь / враги на минусе.
Семья даёт **стартовое** смещение при генерации (числа тоже в данных):
| Связь | Типичный старт |
| --- | --- |
| Родитель → ребёнок и обратно | сильно плюс |
| Братья и сёстры | плюс слабее |
| Партнёры в семье (уже есть на карточке) | плюс, не обязательно потолок |
Дальше число живёт: разговоры, дом, ссоры. Родство не переписывается.
**Дрейф.** Раз в рабочее утро (и skip ночи) каждое ненулевое мнение чуть сдвигается к своему
базису: семейная связь — к стартовому семейному числу, остальные — к нулю. Без этого дружба
первой недели вечная. Скорость — в `BehaviorDef`. Ноль снова не храним: дошли до базиса-нуля —
запись выкидываем.
Хранение — **на человеке**, разреженно, в `people.json`. Писать при содержательном сдвиге
(разговор кончился, драка, утреннее семейное, утренний дрейф), не каждый тик. Тот же шов, что у
одежды.
### Темы
Новый вид `TopicDef`: id, теги уместности, возраст, роли, можно ли на уроке (шёпот), какой
язык помогает (опционально), какой навык качается каплей сверх Communication.
Ванильные теги, не витрина:
- учёба, игры, еда, семья, спорт, сплетни, грубое, внешность.
Тема «внешность / форма» стыкует срез 7: исход смотрит уместность надетого (фаза 35). Не по
форме — насмешка или неловкость; по форме / ярко в свободной школе — комплимент. Нет ещё
уместности на карточке — тема живёт, модификатор ноль.
Уместность — **оценка**, как одежда: систему саму не заставит взять грубое на линейке с
директором; взяли — мнение может упасть, учитель может оборвать.
### Политика речи
Вкладка «Правила», рядом с одеждой. Два комбобокса (ученики / сотрудники), не четыре как форма
и цвет:
| Кого | Речь |
| --- | --- |
| Ученики | свободно / без грубого / только учёба |
| Сотрудники | свободно / без грубого / только учёба |
«Применить» — **с завтра**, как дресс-код. Сегодняшние кружки доигрывают тему.
### Вкладка карточки
Пятая: **Связи**. Семья с числами, топ друзей и врагов, поиск по ненулевым (иначе тихая вражда
не видна). Игрок ничего не назначает. Без романтического пака колонки симпатий нет.
## Этап B — разговоры
### Кружок
В одном узле собирается **24** человека, одна тема на всех. Пятый начинает соседний кружок,
не влезает в этот.
Кого зовут: сначала друзья и одноклассники в узле, потом остальные. Врагов сами не зовут —
столкновение может уйти в ссору. Тихоня реже инициатор, лидер чаще. Веса — поля на `TraitDef`
и `BehaviorDef`, не фамилии в коде.
`Chat` перестаёт быть соло: действие занимает людей кружка. Совместимость ролей как сейчас
(ученик и сотрудник могут говорить — учитель после урока, вопрос в коридоре).
Где: перемена, двор, обед, раздевалка, коридор. **Учительская** — отдельное действие
`StaffChat` (`room: TeachersRoom`, только сотрудники): взрослые не обязаны болтать в коридоре
с детьми, чтобы восполнить общение. На уроке — только **шёпот** (тема с тегом «можно шептать»).
Шёпот восполняет общение слабее, **режет рост навыка урока** у участников.
**Вместе.** На перемене и в обед друзья тянутся в узел, где уже стоят свои, а не в случайный
коридор. Враги не садятся в один кружок (уже) и не выбирают тот же обеденный узел, если есть
другой. Это веса цели «досуг», не новая ходьба парой и не состояние присутствия: на карте
видно кучку в одном узле.
**Телефон.** У кого в сумке или в руках есть телефон (срез 7), на перемене может быть **парный**
чат слабее живого кружка: оба с телефоном, тема из того же каталога, общение восполняется
меньше. Без телефона действия нет. На уроке телефоном не сидят — это шёпот голосом, не экран.
### Язык и красноречие
Отдельного навыка «красноречие» нет: это `Communication`. Языки — как сейчас.
Общий язык: лучший общий навык среди участников выше порога из `BehaviorDef`. Нет общего —
кружок всё равно возможен (жесты), но сдвиг мнения почти нулевой и чаще отрицательный.
`Communication` чуть растёт от разговора (меньше, чем предмет за урок). Язык, на котором
говорили, чуть растёт, если он ещё не у потолка.
### Шёпот
Если учитель **в том же кабинете**, шанс оборвать — из `BehaviorDef`, черты тише/громче
сдвигают. Не каждый шёпот ловят. Учитель, поймавший, начинает разговор-выговор (тот же
механизм кружка, тема «дисциплина»).
После урока учитель может сам взять 2–4 учеников (вопрос по предмету, похвала, выговор) —
обязанность с весом, не приказ игрока. Сдвиг мнения ученика об учителе слегка масштабируется
**педагогикой** учителя: сильный педагог после похвалы плюсует больше, слабый выговор злит
сильнее. Оценок по-прежнему нет.
### Дом
Родители на карту не приходят. **Одно** семейное событие на человека за рабочее утро; skip
ночи его применяет, как утреннюю одежду. Тема из семейного набора, сдвиг небольшой.
Тем же утренним проходом — дрейф всех мнений к базису. Настроения-нужды нет.
### Черты в `core`
Уже крутят разговор: задира, тихоня, лидер, добрый, вспыльчивый. Добавляются две:
- **сплетник** — чаще берёт темы «сплетни», сильнее двигает мнение;
- **общительный** — чаще инициатор, выше шанс большого кружка.
Поля на `TraitDef` (вес инициативы, сдвиг к тегам тем), не списки id в коде.
## Этап C — ссора и драка
Отдельные действия, не только −N к мнению.
**Ссора** — на перемене, двое (иногда трое из распавшегося кружка), общение восполняется
криком, мнения падают сильнее обычного грубого разговора.
**Задира** не бросает кубик по школе каждый день: на человеке память жертвы (id), пока та в
ростере. Смена цели — если жертва выпустилась, ушла или мнение уже на полу. Поля на черте, не
`if (defName == "Bully")` в коде сверх проверки поля.
**Заступничество.** Третий в том же узле с высоким плюсом к жертве может встать в ссору на её
стороне. Мнение к задире падает, к жертве растёт; кружок ссоры становится тройкой.
**Извиниться** — отдельное действие после ссоры или выговора, пока оба в одном узле. Возвращает
часть (не всё) потерянного мнения. Задира извиняется реже (поле черты). Без этого единственный
путь вверх — «ещё поболтать» и утренний дрейф к нулю.
**Драка** — редко, двор или физкультура. Короткая. Травм, медкабинета и вызова родителей нет.
Мнения резко падают, оба в логе. Дежурный учитель или физрук в узле **обрывает** и делает
выговор. Никого в кабинете директора насильно нет: игрока нет в приказе, отдельной очереди
«к директору» этот срез не заводит.
Нет сотрудника рядом — драка кончается по длительности действия, лог всё равно пишется.
## Этап D — что видит игрок
Игрок **наблюдает**. Не мирит, не рассаживает, не запрещает дружить.
- **Локация** — «говорит с Машей о футболе»: кадр присутствия несёт id участников и id темы,
клиент собирает строку через справочник имён и локаль темы. Имена по-прежнему не строкой в
сокете. Раскладка присутствия меняется, **версия протокола +1**.
- **Сейчас** на карточке — то же плюс история за сегодня (уже есть лог).
- **Связи** — числа и подписи.
- **Правила** — политика речи, с завтра.
Список людей мнения не несёт.
## Этап E — пак `romance`
Первый **контентный** мод. `example` не раздуваем: он образец папки. `romance` выбирается в
create, `requires: ["core"]`, патчит `Chat`/темы (романтические темы появляются только с паком).
Без пака генератор не пишет ориентацию и романтические состояния. Живой школе мод не добавить —
как все паки сейчас.
### Ориентация
Поле на человеке, только если пак в школе. Значения — данные пака (гетеро / би / гомо и веса
генератора), не черта «ради галочки» и не хардкод. Пак без поля ориентации романтику не крутит.
### Симпатия и пара
Симпатия — односторонний ярлык поверх мнения (порог из данных пака). «Тили-тили тесто» —
подпись и лог, не свидание.
| Кто | Симпатия | Пара / свидание |
| --- | --- | --- |
| Ученик ↔ ученик близкого возраста | да | только если **обоим 18+** |
| Ученик → учитель | да, класс может дразнить; на карточке учителя видно | нет |
| Учитель → ученик | **нет**, взаимности нет, осаживает разговором | нет |
| Сотрудник ↔ сотрудник | да | да, оба взрослые |
| Сотрудник ↔ ученик как пара | нет | нет |
Близкий возраст учеников: **±2 года или соседняя параллель**. К учителю — исключение из этого
фильтра (иначе взрослый никогда не попадает).
Пара: только **взаимная**, только **одна**. Разрыв — событие (разговор или мнение ниже порога):
мнение падает, симпатия может остаться. Новая пара не раньше следующего дня. Неразделённая
симпатия живёт сколько угодно. Измену как механику не делаем: вторая симпатия просто висит.
Никакого сексуального контента, портретов «для романтики» и действий кроме разговора / ссоры /
уже существующих перемещений. Детская линия — дразнилки и ярлык симпатии.
Пак может добавить черты вроде «влюбчивый», «ревнивый» теми же полями `TraitDef`.
## Поток данных
Мнения и кружок — состояние мира, считает `HSchool.Ai` (выбор темы, состав, исход), пишет
симуляция. Карточка — HTTP через мейлбокс. Присутствие — сокет. Политика речи — снимок школы,
как будущий дресс-код.
Детерминизм: свой поток на человека, обход по id, тема из сида кружка. Тот же сид и те же
паки — те же первые дружбы на той же неделе (золотой отпечаток мнений — в фазе, которая
начинает писать ненулевые пары сверх семьи).
## Где живёт код
Нового проекта нет.
| Что | Куда |
| --- | --- |
| `TopicDef`, теги, поля черт, политика речи | `HSchool.Content` + JSONC |
| Стартовые мнения семьи, ориентация при паке | `HSchool.People` |
| Кружок, шёпот, ссора, драка, дом-утро | `HSchool.Ai` + адаптер в `HSchool.Simulation` |
| Кадр присутствия | `HSchool.Protocol` + `protocol.ts` + `docs/protocol.md` |
| Вкладка, правила, лог | `HSchool.Server` + клиент |
| Пак | `mods/romance/` рядом с `core` и `example` |
## Советы, которые стоит принять сразу
- Не заводить нужду «настроение»: мнение + общение уже две шкалы.
- Не класть имена в кадр присутствия — только id, как с людьми сейчас.
- Не лечить драку травмой: медкабинет тогда обязан стать больницей.
- Не делать «ходить вместе» отдельным состоянием присутствия: достаточно одного узла.
- `ActionDef` по-прежнему одна комната: учительская и телефон — отдельные действия, не массив комнат.
- Не вшивать романтику в `core`: ванильная школа должна собираться без пака.
- Не расширять `example`. Контент — другой пак.
- Не делать учительскую взаимность «опцией мода»: пак проверяет запрет тестом.
## Заведомо не сейчас
- Настроение как нужда, приказы, вызов родителей, рассадка класса.
- Секс, поцелуи как действие, свидания вне карты, ревность-сюжет.
- Пара учителя и ученика, даже 18+.
- Травмы, дневник дисциплины как журнал оценок.
- Смена модов у живой школы.
- Общая лента событий школы — по-прежнему лог человека.
## Зафиксировано этим разговором
| Тема | Решение |
| --- | --- |
| Мнение | −100…100, несимметрично, подписи по порогам, семья — старт |
| Дрейф | Каждое рабочее утро к семейному базису или к нулю; skip применяет |
| Хранение | Разреженно на человеке, писать при сдвиге |
| Темы | `TopicDef` + теги включая внешность; оценка, не запрет |
| Политика речи | Ученики/сотрудники: свободно / без грубого / только учёба; с завтра |
| Кружок | Сразу 2–4; пятый — другой кружок |
| Кого зовут | Друзья и класс в узле, врагов не зовут |
| Вместе | Друзья на перемене/обеде тянутся в один узел |
| Где | Перемена, двор, обед, после урока, учительская; на уроке — шёпот |
| Телефон | Парный чат на перемене, оба с телефоном, слабее живого |
| Шёпот | Режет урок; учитель в кабинете — шанс оборвать |
| Язык | Нет общего — слабый разговор, не отказ |
| Красноречие | `Communication`; растёт от разговора |
| Педагогика | Масштабирует мнение ученика об учителе после разговора |
| Игрок | Только смотрит |
| Экран | Вкладка «Связи»; локация из id в присутствии; протокол +1 |
| Ссора / драка | Действия; жертва задиры помнится; заступник; извинение; без травм |
| Дом | Одно семейное событие на рабочее утро; skip применяет |
| Настроение | Нет |
| Черты core | + сплетник, общительный |
| Романтика | Пак `romance`, патчит темы/`Chat` |
| Ориентация | Только с паком, поле и веса в данных |
| Симпатия учеников | Близкий возраст ±2 / соседняя параллель |
| Симпатия к учителю | Можно, видно, учитель осаждает, взаимности нет |
| Пара | Оба 18+, взаимно, одна; разрыв — событие; сотрудник↔ученик нет |
| Сотрудники | Симпатия и пара между собой — да |