Ваш уровень наконец что-то значит
Теперь опыт получает каждое место за столом, первый уровень стоит 60 XP вместо двух недель игры, а уровни дают ранг и коллекционные карточки.

Простыми словами
Опыт был числом, которое ничего не делало. Ни одна возможность в игре не зависела от уровня, и получал его только победитель матча — а значит, примерно две трети сидящих за каждым столом играли партию целиком, проигрывали, видели «Опыт за матч +0» и не имели повода считать, что это число вообще про них.
Теперь зарабатывает каждое место. Платят за занятое место, за монополии, которые у вас на руках к концу партии, и за то, что вы дошли до конца и не вылетели. Победа по-прежнему главная — она стоит больше, чем двойной лучший возможный проигрыш, — но хороший проигрыш больше не стоит ноль.
| Что вы сделали | Опыт |
|---|---|
| Выиграли партию | +200 |
| Второе место | +50 |
| Третье место | +30 |
| Четвёртое место и ниже | +15 |
| Каждая монополия на руках к концу (до 3) | +10 |
| Дошли до конца и не выбыли | +20 |
Кривая была перестроена вокруг этого. Первый уровень теперь стоит 60 XP — это закрывается одной приличной партией, даже проигранной, — тогда как раньше на него уходило около десяти дней игры. Следующие уровни дорожают постепенно, а не разом.
И уровни теперь дают две вещи. Уровню соответствует ранг — их 7, от «Квалификации» до «Мастера», — он показывается рядом с вашим именем в профиле и в таблице лидеров. А переход через уровень-веху роняет в вашу коллекцию карточку недвижимости: уровни 3, 5, 7, 10, 13, 16, 20, а дальше каждый 5-й.

Для тех, кому интересны детали
Самая интересная половина этой работы — удаление копий. Старое правило (уровень за каждые 500 XP) было вручную вписано в пять миграций базы и три файла TypeScript, и они уже разошлись между собой: тестовые данные засевали уровень, который не даёт ни одна версия правила. Теперь кривая одна, в одном файле, и она в точности отражена в базе:
// packages/game-engine/src/progression.ts — one curve, mirrored exactly in SQL
step(L → L+1) = min(60 + 100·(L−1), 1500)
level 2 3 4 5 10 16 17+
xp 60 220 480 840 4,140 11,400 +1,500 eachАрифметика намеренно целочисленная — без квадратных корней и без плавающей точки, — чтобы SQL и TypeScript совпадали на каждой границе точно, а не приблизительно; тест, работающий с настоящей базой, сравнивает их значение за значением. Обе кривые возрастающие, поэтому при пересчёте никто никого в таблице лидеров не обогнал.
По пути нашлись три ошибки, которые давно жили в проде и которые не поймал ни один тест: полоса уровня на экране результата читала награду за матч вместо общего счёта, поэтому каждый игрок на каждом уровне видел одну и ту же полосу, застывшую на 40%; победа в короткой партии записывалась как поражение, так что такие победы никогда не двигали задание на победу; а в командном режиме выигравший напарник не получал ничего и записывался проигравшим, потому что один из двух победителей по номеру строки не был первым. Все три исправлены, и у каждой есть тест, который без исправления падает.
