Играйте 2 на 2 и 3 на 3: командный режим
Объединитесь с другом, сложите ваше имущество вместе и побеждайте сообща — теперь в opolyx есть командные игры 2×2 и 3×3.

Простыми словами
Некоторые партии лучше играть с напарником. Командный режим сталкивает две стороны — 2 на 2 в игре на четверых или 3 на 3 в игре на шестерых — так что вы с друзьями играете за один цвет, а не каждый сам за себя.
Игра на одной стороне меняет всё в том, как вы действуете вместе. Ваши товарищи по команде — союзники, а не соперники, и поле раскрывается:
- Попав на имущество товарища по команде, вы ничего не платите — аренда взимается только с другой команды.
- Передавайте деньги и имущество между товарищами по команде свободно — правила 50% нет, так что вы можете попросту подарить оступившемуся напарнику всё, что ему нужно.
- Если товарищ по команде обанкротится, всё его имущество достанется вам, а не банку — команда выбывает лишь тогда, когда выбыл каждый её участник.
- Вы побеждаете командой: последняя устоявшая сторона или самая богатая сторона по достижении лимита раундов — и оба товарища по команде получают награду за победу (XP и карту).
Согласовывайте свои обмены, прикрывайте друг друга и вместе вытесняйте команду соперников с поля. Это тот же opolyx, что вы знаете, — только теперь напарник на вашей стороне.
Для тех, кому интересны детали
Командный режим — это набор правил Classic с одним новым понятием для каждого игрока: команда. Движок добавляет поле PlayerState.team и горстку селекторов (sameTeam, teamOf, aliveTeams, teamNetWorth), которые читают правила: computeRent освобождает товарищей по команде, doProposeTrade пропускает правило 50% между ними, а выбывание направляет имущество живому товарищу по команде с наименьшим слотом, а не банку. Условия окончания оцениваются по командам — последняя устоявшая команда или самая богатая команда при достижении предела раундов.
Реализуют это три миграции. Postgres запрещает использовать новое значение enum в той же транзакции, что его добавляет, поэтому 0028 фиксирует командный game_mode отдельно; затем 0029 позволяет create_game принимать его (с проверкой полного и равного состава) и добавляет award_game_winners для награды нескольким победителям; а 0030 добавляет выбираемый столбец team и его RPC для комнаты ожидания.
-- 0028_team_mode_enum.sql — its own migration (see above)
alter type game_mode add value 'team';
-- 0030_team_picker.sql — pickable side; NULL = slot-parity default (slot % 2)
alter table game_players
add column team smallint check (team is null or team in (0, 1));
-- SECURITY DEFINER lobby write (RLS has no user write on game_players):
-- a player sets their own seat; the creator may set any seat (to arrange bots).
create function set_player_team(p_game uuid, p_slot int, p_team smallint)
returns void language plpgsql security definer as $$ ... $$;Менять enum event_kind не понадобилось — командные данные едут в необязательных полях payload существующих событий (game_started.players[].team, player_eliminated.inheritedBySlot, game_finished.winnerTeam). Выбранные команды (а не чётность) протягиваются в initializeGame; daemon отказывается запускать командную игру, состав которой неполон (team_roster_not_full) или несбалансирован (team_not_balanced). Тесты Engine 214 / daemon 82 зелёные, а свойство завершимости в fast-check теперь доводит игры 2×2 и 3×3 до конца.
