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.
This commit is contained in:
@@ -0,0 +1,299 @@
|
||||
# Общение, отношения и романтический пак
|
||||
|
||||
Договорённость на срез после сессии/темпа, не текущий код.
|
||||
Люди: [`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 — разговоры
|
||||
|
||||
### Кружок
|
||||
|
||||
В одном узле собирается **2–4** человека, одна тема на всех. Пятый начинает соседний кружок,
|
||||
не влезает в этот.
|
||||
|
||||
Кого зовут: сначала друзья и одноклассники в узле, потом остальные. Врагов сами не зовут —
|
||||
столкновение может уйти в ссору. Тихоня реже инициатор, лидер чаще. Веса — поля на `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+, взаимно, одна; разрыв — событие; сотрудник↔ученик нет |
|
||||
| Сотрудники | Симпатия и пара между собой — да |
|
||||
@@ -0,0 +1,42 @@
|
||||
# Фаза 41. Мнения и вкладка «Связи»
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 8](08-people-browser.md)
|
||||
- [Фаза 36](36-person-card-tabs.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
У пары появляется число. Семья больше не «просто родственники». Карточка умеет это показать,
|
||||
даже пока кружков ещё нет.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] Мнение A→B: −100…100, несимметрично, ноль не хранить
|
||||
- [ ] Пороги и подписи в `BehaviorDef`; клиент рисует присланную подпись, не считает сам
|
||||
- [ ] Генератор ставит семейные старты (родители, сиблинги, партнёры семьи) из данных
|
||||
- [ ] Каждое рабочее утро (и skip) ненулевые мнения слегка дрейфуют к семейному базису или к нулю;
|
||||
дошли до нуля — запись выкинуть
|
||||
- [ ] `people.json` пишет мнение при сдвиге; старый сейв без поля — все нули кроме семьи
|
||||
после первой загрузки-переписи
|
||||
- [ ] Вкладка карточки **Связи**: семья с числами, топ друзей/врагов, поиск по ненулевым
|
||||
- [ ] Игрок с вкладки ничего не меняет
|
||||
- [ ] `docs/protocol.md` — HTTP карточки
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] Родитель и ребёнок после генерации имеют плюс в обе стороны; чужие одноклассники — нет записи
|
||||
- [ ] A→B и B→A могут различаться
|
||||
- [ ] После нескольких утренних дрейфов без разговоров мнение одноклассников (если появилось)
|
||||
ближе к нулю, семейное — к старту, не к нулю
|
||||
- [ ] Карточка без отдельного запроса «всех пар школы»: только этот человек
|
||||
- [ ] Клиентский тест: вкладка «Связи» не монтирует лог
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Открыть ученика, на «Связях» родители с подписью «близкие» или соседней, одноклассник без строки
|
||||
- `dotnet test` и `npm test` / `build` проходят
|
||||
|
||||
## Стоп
|
||||
|
||||
Не собирать кружки. Не бампить сокет. Не заводить романтику.
|
||||
@@ -0,0 +1,41 @@
|
||||
# Фаза 42. Темы и кружки
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 41](41-opinions.md)
|
||||
- [Фаза 21](21-decisions.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
`Chat` перестаёт быть соло. В узле говорят 2–4 человека об одной теме. Язык и
|
||||
`Communication` влияют на исход.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] `TopicDef`: теги, возраст, роли, шёпот-на-уроке, опциональный язык
|
||||
- [ ] Ванильный набор тем (учёба, игры, еда, семья, спорт, сплетни, грубое) в `core`
|
||||
- [ ] Кружок 2–4 в одном узле; пятый не влезает
|
||||
- [ ] Кого зовут: друзья и одноклассники в узле, врагов не зовут; тихоня/лидер — поля черты
|
||||
- [ ] Нет общего языка — кружок можно, сдвиг мнения слабый и чаще вниз
|
||||
- [ ] `Communication` растёт от разговора меньше, чем предмет за урок; язык разговора — капля,
|
||||
если не у потолка
|
||||
- [ ] Черты **сплетник** и **общительный** в `core` с полями, не списками в коде
|
||||
- [ ] Исход пишет мнения всех пар кружка и строку лога
|
||||
- [ ] На уроке обычный `Chat` не стартует (шёпот — фаза 43)
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] Двое свободных друзей в коридоре на перемене собирают кружок; враги — нет
|
||||
- [ ] Пятый в узле не входит в тот же кружок
|
||||
- [ ] Без общего языка мнение почти не растёт при том же `Communication`
|
||||
- [ ] Высокий `Communication` сильнее двигает число, чем низкий, на одной теме
|
||||
- [ ] Каталог без `TopicDef` не стартует школу с кружками — или падает загрузка, не молча соло-Chat
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- На перемене в коридоре двое «разговаривают», на карточке мнение сдвинулось, в логе тема
|
||||
- `dotnet test` проходит
|
||||
|
||||
## Стоп
|
||||
|
||||
Не шёпот на уроке. Не драка. Не менять кадр присутствия (локация может ещё писать «Разговор»).
|
||||
@@ -0,0 +1,36 @@
|
||||
# Фаза 43. Шёпот и учитель
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 42](42-talk-circles.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
На уроке можно шептаться — ценой учёбы. Учитель иногда слышит. После урока учитель сам
|
||||
говорит с учениками.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] Тема с тегом шёпота может стартовать кружок на уроке в кабинете класса
|
||||
- [ ] У участников на время шёпота режется рост навыка урока (доля в `BehaviorDef`)
|
||||
- [ ] Учитель в том же кабинете: шанс оборвать (данные + черты); не 100 %
|
||||
- [ ] Пойманный шёпот → выговор (кружок учитель + ученики, тема дисциплины), мнения как у
|
||||
строгого разговора
|
||||
- [ ] После урока учитель может взять 2–4 учеников (вопрос / похвала / выговор) по весу цели
|
||||
- [ ] Лог: «шептались», «учитель оборвал»
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] Шёпот на уроке даёт меньше прироста предмета, чем тихий урок без кружка
|
||||
- [ ] При фиксированном сиде не каждый шёпот с учителем в кабинете обрывается
|
||||
- [ ] Без учителя в узле шёпот не обрывается этим правилом
|
||||
- [ ] Обычный не-шёпотный `Chat` на уроке не стартует
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- На математике двое шепчутся, иногда учитель обрывает, в логе это видно
|
||||
- `dotnet test` проходит
|
||||
|
||||
## Стоп
|
||||
|
||||
Не драка. Не политика речи в UI. Не протокол.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Фаза 44. Ссора и драка
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 42](42-talk-circles.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
Вражда — не только минус в JSON. На перемене ссорятся, на дворе или физкультуре редко дерутся.
|
||||
Травм нет.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] Действие ссоры: 2 (иногда 3), перемена, мнение падает сильнее грубого разговора
|
||||
- [ ] Действие драки: редко, двор или зал; коротко; без травм и медпункта
|
||||
- [ ] Триггер: низкое взаимное мнение, задира/вспыльчивый — поля, не if по defName
|
||||
- [ ] Сотрудник в узле обрывает драку и делает выговор; нет сотрудника — действие просто кончается
|
||||
- [ ] Лог обоих; кабинет директора не заводим
|
||||
- [ ] Игрок не приказывает разнять
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] Двое врагов на дворе чаще ссорятся, чем двое друзей
|
||||
- [ ] Драка не меняет нужду «здоровье» — такой нужды нет и не появляется
|
||||
- [ ] Выговор после обрыва есть, если в узле был сотрудник
|
||||
- [ ] Skip пустого времени не оставляет «вечную драку» в состоянии
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Задира с врагом на дворе: в логе ссора или драка, мнения ниже, оба живы и на ногах
|
||||
- `dotnet test` проходит
|
||||
|
||||
## Стоп
|
||||
|
||||
Не вызов родителей. Не травмы. Не романтика.
|
||||
@@ -0,0 +1,34 @@
|
||||
# Фаза 45. Кружок в присутствии
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 42](42-talk-circles.md)
|
||||
- [Фаза 19](19-presence-screen.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
В панели локации видно, с кем и о чём говорят, без открытия карточки.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] Кадр присутствия: у человека, который в кружке, список id участников и id темы.
|
||||
Имена не строкой. Клиент собирает «говорит с Машей о футболе» из справочника и локали
|
||||
- [ ] Версия протокола +1. `ProtocolCodec.cs`, `protocol.ts`, `docs/protocol.md` в одном коммите
|
||||
- [ ] Не в кружке — пустой список, как сейчас только id/узел/состояние
|
||||
- [ ] Вкладка «Сейчас» на карточке согласована с тем же составом
|
||||
- [ ] Старый клиент отваливается Hello, как обычно
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] Круглый трип и байтовая раскладка человека с кружком и без — на обеих сторонах
|
||||
- [ ] Имя человека не встречается в кадре присутствия
|
||||
- [ ] Клиентский тест: локация показывает тему и имя напарника из directory, не из кадра
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Клик по коридору на перемене: в «персонажах» видно, кто с кем говорит
|
||||
- `dotnet test` и `npm test` / `build` проходят
|
||||
|
||||
## Стоп
|
||||
|
||||
Не политика речи. Не пак.
|
||||
@@ -0,0 +1,37 @@
|
||||
# Фаза 46. Политика речи и дом
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 42](42-talk-circles.md)
|
||||
- [Фаза 37](37-school-rules.md)
|
||||
- [Фаза 34](34-wear-home.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
Школа задаёт, какие темы уместны — тем же жестом, что дресс-код. Родители двигают мнение утром,
|
||||
не приходя на карту.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] В «Правилах» два комбобокса речи: ученики / сотрудники × свободно / без грубого / только учёба
|
||||
- [ ] В силу с завтра; API сегодня не переодевает темы текущих кружков
|
||||
- [ ] Система не стартует кружок с темой вне политики; начатый вчера доигрывает
|
||||
- [ ] Одно семейное событие на человека за рабочее утро; skip ночи применяет
|
||||
- [ ] Семейные темы из `TopicDef`; сдвиг меньше школьного разговора
|
||||
- [ ] `docs/protocol.md` — HTTP правил речи
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] POST «только учёба» сегодня не мешает текущему кружку «игры»
|
||||
- [ ] На следующее рабочее утро грубая тема у учеников не стартует
|
||||
- [ ] Skip с пятницы на понедельник применяет домашнее событие; мнение с родителем сдвинуто
|
||||
- [ ] Клиентский тест: комбобоксы речи рядом с одеждой, подпись «с завтра»
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Сменить политику, пережить ночь кнопкой, на перемене нет грубых кружков у учеников
|
||||
- `dotnet test` и `npm test` / `build` проходят
|
||||
|
||||
## Стоп
|
||||
|
||||
Не романтика. Не вызов родителей в школу.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Фаза 47. Пак romance
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 42](42-talk-circles.md)
|
||||
- [Фаза 23](23-example-pack.md)
|
||||
- [Фаза 41](41-opinions.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
Контентный мод, не скучный образец. Ваниль без романтики. Пак добавляет ориентацию, симпатию,
|
||||
пару 18+ и романтические темы патчем.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] `mods/romance/`: `pack.jsonc` `requires: ["core"]`, локали, ориентация как данные,
|
||||
черты влюбчивый/ревнивый полями, патч тем и при необходимости `Chat`
|
||||
- [ ] Без пака в create ориентации и романтических состояний нет; ванильный каталог без
|
||||
романтических тем
|
||||
- [ ] Симпатия учеников: ±2 года или соседняя параллель
|
||||
- [ ] Симпатия ученик → учитель можно, видна на обеих карточках; учитель → ученик никогда;
|
||||
осадить — разговор; пары сотрудник↔ученик нет
|
||||
- [ ] Пара: оба 18+, взаимно, одна; разрыв — событие, новая не раньше следующего дня
|
||||
- [ ] Сотрудники между собой — симпатия и пара можно
|
||||
- [ ] Никаких сексуальных действий и текстов. Детская линия — дразнилки и ярлык
|
||||
- [ ] Тесты хоста: школа с паком и без; запрет учительской взаимности
|
||||
- [ ] `example` не трогать
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] `GET /api/catalog` без `romance` не отдаёт романтические темы
|
||||
- [ ] Create с паком пишет ориентацию; без пака поля нет
|
||||
- [ ] Двое 16-летних не получают статус пары при любом мнении
|
||||
- [ ] Учитель не получает романтическое состояние на ученика
|
||||
- [ ] Первоклассник не получает симпатию к одиннадцатому (возраст)
|
||||
- [ ] Школа с `example` и без `romance` ведёт себя как ваниль в части тем
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Создать школу с галкой пака, увидеть симпатию на «Связях» и тему пака в логе; снять галку на
|
||||
новой школе — этого нет
|
||||
- `dotnet test` проходит
|
||||
|
||||
## Стоп
|
||||
|
||||
Не секс. Не пара учителя и ученика. Не раздувать `example`. Не смена модов у живой школы.
|
||||
@@ -182,3 +182,43 @@
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [40. Темп часов](40-clock-tempo.md) | ⬜ | ×1 = минута/с, кнопки ×½ ×1 ×2 ×5 ×10, страйд тяжёлых систем |
|
||||
|
||||
## Срез 9. Общение и романтический пак
|
||||
|
||||
Дизайн: [`../design/social.md`](../design/social.md).
|
||||
|
||||
Разговор становится кружком, мнение — числом, вражда — ссорой. Романтика не ваниль: отдельный
|
||||
пак. Срез можно остановить после этапа B — школа болтает, даже если драк и пака ещё нет.
|
||||
|
||||
**Этап A — мнения.** Число и вкладка.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [41. Мнения и «Связи»](41-opinions.md) | ⬜ | −100…100, семья-старт, вкладка карточки |
|
||||
|
||||
**Этап B — разговоры.** Кружок, язык, шёпот.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [42. Темы и кружки](42-talk-circles.md) | ⬜ | `TopicDef`, 2–4 человека, язык, `Communication` |
|
||||
| [43. Шёпот и учитель](43-whisper.md) | ⬜ | Шёпот на уроке, шанс оборвать, разговор после звонка |
|
||||
|
||||
42 стоит на 41; 43 — на 42.
|
||||
|
||||
**Этап C — конфликт и экран.**
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [44. Ссора и драка](44-quarrel-fight.md) | ⬜ | Перемена / двор / физкультура, выговор, без травм |
|
||||
| [45. Кружок в присутствии](45-presence-talk.md) | ⬜ | Id участников и темы в кадре, протокол +1 |
|
||||
|
||||
44 и 45 стоят на 42, можно параллельно.
|
||||
|
||||
**Этап D — правила, дом, пак.**
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [46. Политика речи и дом](46-speech-home.md) | ⬜ | Комбобоксы речи с завтра; утреннее семейное событие |
|
||||
| [47. Пак romance](47-romance-pack.md) | ⬜ | Ориентация, симпатия, пара 18+, патч тем |
|
||||
|
||||
46 стоит на 37 и 42; 47 — на 42 и 23. `example` не трогать.
|
||||
|
||||
+20
-1
@@ -389,13 +389,32 @@ is `404` `unknown-school`; unknown person is `404` `unknown-person`. Invalid `ki
|
||||
"kind": "avatar",
|
||||
"positive": "cinematic photo, …, close up, head and shoulders portrait, …, age 12, …",
|
||||
"negative": "(low quality, worst quality:1.4), …",
|
||||
"promptExtra": null
|
||||
"promptExtra": null,
|
||||
"presetId": "default",
|
||||
"presetLabel": "Default"
|
||||
}
|
||||
```
|
||||
|
||||
`GET /api/status` includes `swarmUiConfigured` and `swarmUiConnected` (`null` when not configured)
|
||||
so the client can disable generate buttons and show reachability without trying POST first.
|
||||
|
||||
### `GET /api/settings/swarmui`
|
||||
|
||||
Returns the editable SwarmUI preset file (`swarmui.json`): named presets (model, steps, sampler,
|
||||
LoRA lists, per-kind sizes/prompts), `activePresetId` and `ageRules` mapping age bands to presets.
|
||||
Portrait generation resolves the preset from the person's age before building the prompt.
|
||||
|
||||
### `PUT /api/settings/swarmui`
|
||||
|
||||
Replaces the preset file after validation. Invalid preset ids, age rules or numeric ranges return
|
||||
`400` `invalid-body`. Changes apply immediately to new portrait generations.
|
||||
|
||||
### `GET /api/settings/swarmui/discovery`
|
||||
|
||||
When SwarmUI is configured and reachable, proxies `ListT2IParams` and returns
|
||||
`{ connected, models, loras, samplers, schedulers }` for the settings UI comboboxes. When SwarmUI
|
||||
is off or unreachable, `connected` is false and the lists are empty.
|
||||
|
||||
### `GET /api/schools/{id}/dress-rules`
|
||||
|
||||
Student and staff dress-code pairs for the school. Unknown `{id}` is `404` `unknown-school`.
|
||||
|
||||
Reference in New Issue
Block a user