Files
h-school/docs/design/03-staffing/staffing.md
T

238 lines
20 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`](../02-people/people.md). Типы и карта: [`defs.md`](../01-shell/defs.md).
Экран игрока: [`near-term.md`](../01-shell/near-term.md). Проекты: [`projects.md`](../01-shell/projects.md).
Первый срез, где игрок **что-то решает**. До сих пор школа собиралась сама: генератор закрывал
все должности, игрок смотрел. Теперь школа открывается пустой — без единого учителя, — и её
надо укомплектовать: нанять людей из пула соискателей, раздать им предметы и уложиться в
выделенные деньги.
Уроков по-прежнему нет. Предмет — это то, что учитель **числится** вести, а не то, что происходит
в кабинете. Расписание, звонки и оценки — следующий разговор.
## Что меняется в уже принятом
Три решения прошлых срезов приходится поправить. Это не мелочь, поэтому названы отдельно.
| Было | Стало | Почему |
| --- | --- | --- |
| Генератор закрывает все должности | Школа стартует без сотрудников | Иначе игроку нечего решать |
| Кабинет — таблица именованных слотов | Кабинет — число мест | Никто не будет выбирать, какой стул у доски |
| `PETeacher` — отдельная должность | Должность одна, физкультура — предмет | Иначе на каждый предмет заводится должность |
## Мебель и вместимость
Вместимость по-прежнему **физическая**: в классе не может сидеть больше учеников, чем стоит парт.
Это не меняется — от неё зависит весь ростер.
Меняется то, как эта мебель задаётся. У кабинета исчезает таблица именованных слотов — «доска»,
«стол учителя», «стул учителя», «парты» — и остаётся одно число: сколько парт в кабинете.
Выбирать между стулом и креслом у доски игрок не будет никогда, а таблица из четырёх строк на
каждый из одиннадцати кабинетов делает редактор нечитаемым.
Именованные слоты **остаются** там, где обстановка действительно разная: столовая, медкабинет,
кабинет директора, библиотека. Там выбор осмыслен — сколько столов, какая кушетка.
Правило простое: **слоты — там, где есть из чего выбирать; число — там, где важно только сколько.**
## Предметы
Новый вид def — `SubjectDef`. Не навык и не работа: навык — это то, что растёт у ребёнка, работа —
то, чем занят человек в комнате, а предмет — то, что стоит в дипломе и в нагрузке.
`SubjectDef` описывает:
- **какие навыки развивает и насколько** — список пар «навык + доля»;
- **в каких параллелях преподаётся**;
- **сколько часов в неделю** в каждой из них — учебный план.
Часы здесь не задел на расписание, а рабочая величина уже этого среза: из них считается нагрузка
учителя, а из нагрузки — зарплата. Расписание ([`schedule.md`](../04-schedule/schedule.md)) только расставит эти
часы по дням; сколько их — решает учебный план.
Так «начальные классы» получаются естественно: один предмет, который развивает всё понемногу и
преподаётся с первой по четвёртую параллель. Дальше идут предметники: математика с пятой по
одиннадцатую, развивает один навык, но сильно.
```jsonc
{
"defName": "PrimarySchool",
"grades": { "min": 1, "max": 4 },
"hoursPerWeek": 20,
"skills": [
{ "skill": "Mathematics", "share": 0.3 },
{ "skill": "RussianLanguage", "share": 0.3 },
{ "skill": "Literature", "share": 0.2 },
{ "skill": "Biology", "share": 0.2 },
],
}
```
Имена предметов и навыков **намеренно совпадают** там, где это одно и то же слово: `SubjectDef`
`Mathematics` и `SkillDef` `Mathematics` — разные def'ы разных видов, но подпись у них одна, потому
что локали ключуются по имени. Это то, что нужно: игрок не должен видеть «Математика (предмет)».
Доли не обязаны давать в сумме единицу — это не проценты, а вес влияния. Ни на что в этом срезе
они не влияют; они здесь потому, что предмет без ответа на вопрос «что он развивает» не проверишь,
а дописывать поле позже — значит переписывать весь ванильный контент.
## Учитель
Должность одна — `Teacher`. Предмет не в должности, а в **назначении**: у нанятого учителя
один предмет или несколько.
Отсюда следует важное: **потребность в учителях больше не берётся из комнат.** Раньше кабинет
открывал вакансию «учитель», спортзал — «физрук». Теперь кабинет не открывает ничего: он лишь
место, где идёт урок. Школе нужны не «люди в комнатах», а **покрытие предметов по параллелям**
на каждый предмет, преподаваемый в существующих параллелях, нужен хотя бы один учитель.
Нетренерские должности — директор, секретарь, медсестра, библиотекарь, повар — по-прежнему рождаются
из комнат, как описано в [`defs.md`](../01-shell/defs.md). Их игрок тоже нанимает, но предметов им не назначают.
## Соискатели
Пул соискателей — **общий** список на школу, не «по трое на вакансию».
Соискатель — **полноценный человек** со всеми слоями: тело, навыки, черты, семья. Иначе выбирать
не из чего: весь смысл в том, чтобы сравнить «математика 78, усидчивый» с «математика 41,
вспыльчивый».
Соискателем **может оказаться родитель ученика** — и это не частный случай, а естественное
следствие уже принятого: человек может быть в двух ролях сразу. Нанятый родитель становится
работником, оставаясь родителем, и никакой второй сущности для него не заводится.
Пул **обновляется раз в неделю и не целиком**. Часть людей уходит — нашли работу в другом месте, —
часть остаётся искать дальше, приходят новые. Полная замена раз в неделю превращала бы выбор в
лотерею: понравившийся кандидат исчезал бы, пока игрок думает.
Не нанятый и не ушедший остаётся тем же человеком: с тем же именем, теми же навыками и тем же
запросом по зарплате. Обновление детерминировано от сида школы и номера недели.
## Деньги
**Баланса нет.** Сверху выделяют фиксированную сумму на зарплаты в месяц — не на счёт, а как
предел. Ничего не копится, сэкономленное не переносится.
Значит и правило одно: **месячный фонд оплаты не может превысить выделенную сумму.** Выделили
10 000, наняли одного за 3 000 и второго за 7 000 — всё, больше никого. Не «ушли в минус», не
«долг», а просто нельзя.
### Сколько просит человек
Соискатель называет **цену часа**. Она складывается из двух вещей:
- **навыки** — сильный предметник стоит дороже слабого;
- **черты** — самоуверенный просит больше, зажатый меньше, при тех же навыках.
Черта, влияющая на запрос, — это поле у `TraitDef`, а не список фамилий в коде. Мод, добавивший
«скромный», сразу получает более дешёвого кандидата.
### Сколько он в итоге стоит
Месячная зарплата — **цена часа × недельная нагрузка**. Нагрузка не выдумывается: она следует из
учебного плана. Назначили человеку математику — он забирает все часы математики во всех
параллелях, где она преподаётся, и это может оказаться много.
Ниже одной ставки (`BaseWeeklyHours`) не платят: нанятый стоит денег, даже если ему ничего не
назначили. Иначе набрать полный штат «про запас» было бы бесплатно.
Отсюда два ограничения вместо одного:
- **Деньги.** Фонд оплаты не может превысить выделенную сумму. Проверяется при найме и назначении.
- **Человек.** Никто не вытянет больше `MaxWeeklyHours` часов. Если часов предмета больше, нужен
второй учитель — часы делятся между ними, и первому становится легче и дешевле.
**Предел часов не запрещает назначение, а помечает предмет непокрытым.** Запрет завёл бы в тупик:
первый учитель предмета всегда получает все его часы, поэтому первым не смог бы стать никто.
Считать часы «до предела» тоже нельзя — тогда седьмой предмет тому, кто уже за пределом, достаётся
бесплатно, а это ровно та дыра, ради которой почасовая оплата и вводилась. Поэтому часы считаются
целиком, деньги это показывают, а список непокрытого говорит, что один человек столько не выучит.
Поэтому «нанять посильнее» и «нагрузить одного вместо двоих» — два разных способа потратить один
фонд, и в этом весь выбор среза. Дешёвый учитель, взявший три предмета, упрётся в часы; дорогой
с одним предметом съест фонд.
Цифры — шкала цены часа, влияние черт, предел часов — живут в настройках и в `core`, не в коде.
## Старт в выходной
Школа создаётся пустой, и первое, что делает игрок, — нанимает людей. Делать это под тикающие
часы учебного дня незачем, поэтому дата по умолчанию переезжает с вторника **3 апреля 2012** на
субботу **31 марта 2012**: у игрока есть выходные, чтобы собрать штат до того, как в понедельник
придут дети.
Учебный год при этом тот же, ростер не меняется.
## Экран
Не третья вкладка в панели и не модальное окно. Под часами появляется **два верхних раздела**:
| Раздел | Что в нём |
| --- | --- |
| **Обзор** | Всё, что есть сейчас: карта / люди слева, просмотр выбранного справа |
| **Управление** | Деньги, соискатели, штат и назначение предметов |
Верхние разделы, а не вкладки внутри панели, потому что управление — это другой режим работы, а
не ещё один список. Часы и дата остаются на месте в обоих: наём идёт по игровому времени, пул
обновляется по неделям, и прятать календарь на время найма нельзя.
Внутри «Управления» та же схема, что и в «Обзоре»: список слева, карточка справа. Карточка
соискателя — та же карточка человека, что и в «Людях»; он и есть человек, просто пока не ваш.
Сверху — одна строка про деньги: выделено, расписано, свободно. Ниже — непокрытые предметы,
соискатели и нанятый штат.
## Советы, которые стоит принять сразу
- Не заводить должность на каждый предмет. Иначе `PositionDef` превращается в справочник
специальностей, а назначение предмета становится увольнением и повторным наймом.
- Не делать баланс, пока сверху приходит фиксированная сумма. Баланс — это уже экономика:
накопления, долги, проценты. Здесь нужен предел, а предел — одно число.
- Не обновлять пул целиком. Кандидат, исчезнувший, пока игрок его разглядывал, читается как баг.
- Не выкидывать не нанятых людей в ростер школы. Соискатель — не сотрудник и не житель школы;
в ростер он попадает только при найме.
- Проверять предел в момент действия, а не в конце месяца. «Нельзя нанять» игрок понимает,
«в конце месяца что-то случилось» — нет.
## Заведомо не сейчас
- Само расписание: когда именно идут эти часы. Следующий срез, [`schedule.md`](../04-schedule/schedule.md).
Здесь предмет — нагрузка в часах, а не событие в кабинете.
- Уроки, звонки, оценки, посещаемость.
- Классное руководство: класс закреплён за кабинетом, но не за учителем.
- Увольнение и уход по собственному желанию.
- Переговоры о зарплате, повышения, стаж.
- Любые траты, кроме зарплат: ремонт, закупки, коммуналка.
- Накопление денег, долги, штрафы.
- Требования к диплому: любой нанятый может вести любой предмет, вопрос только в его навыке.
## Зафиксировано этим разговором
| Тема | Решение |
| --- | --- |
| Старт школы | Без сотрудников вообще; игрок нанимает всех |
| Стартовая дата | Суббота 31 марта 2012 — выходные на сборку штата |
| Вместимость класса | По-прежнему физическая: не больше учеников, чем парт |
| Кабинет | Одно число мест вместо таблицы именованных слотов |
| Слоты | Остаются там, где обстановка разная: столовая, медкабинет, кабинет директора |
| Должность учителя | Одна, `Teacher`; `PETeacher` упраздняется |
| Предмет | Новый `SubjectDef`: какие навыки развивает и в каких параллелях |
| Начальные классы | Предмет, развивающий всё понемногу, параллели 1–4 |
| Назначение | У учителя один предмет или несколько |
| Потребность в учителях | Покрытие предметов по параллелям, а не вакансии в комнатах |
| Прочие должности | По-прежнему из комнат; игрок нанимает и их |
| Соискатель | Полноценный человек; может быть родителем ученика |
| Пул | Общий, обновляется раз в неделю частично, детерминированно |
| Учебный план | Часы в неделю по параллелям — поле `SubjectDef`, а не задел |
| Запрос по деньгам | Цена часа: от навыков и от черт (самоуверенный просит больше) |
| Зарплата | Цена часа × недельная нагрузка из учебного плана, но не меньше одной ставки |
| Деление часов | Учителя одного предмета делят его часы поровну |
| Предел нагрузки | `MaxWeeklyHours` не запрещает назначение, а делает предмет непокрытым |
| Непокрытый предмет | Нет учителя **или** назначенные не вытягивают его часы |
| Бюджет | Фиксированная сумма в месяц из настроек; баланса нет |
| Предел | Фонд оплаты не может превысить выделенное; проверка в момент действия |
| Экран | Два верхних раздела под часами: «Обзор» и «Управление» |
| Внутри управления | Список слева, карточка человека справа — та же, что в «Людях» |