Content generated with AI — it may contain mistakes.

Competitive

ELO and ranks

Nine ranks, per-kit and global ladders, placements, the demotion shield, boosts and the anti-boost checks.

Every ranked match moves two ratings for each player: their rating on that kit and their global rating. Both are ordinary Elo, both live in practice_player_season_stats, and the global one is stored under the kit id global.

The nine ranks

ranks.yml ships with nine, each starting at an MMR and carrying its own K-factor:

RankStarts atKDivisions
Ember050IV, III, II, I
Copper40050IV, III, II, I
Titanium80035IV, III, II, I
Solar120035IV, III, II, I
Nova160025IV, III, II, I
Prism200025IV, III, II, I
Apex240020—
Elite270020—
Legend300020—

Each division is 100 LP wide, so Copper spans 400–799 as Copper IV, III, II, I. The top three ranks have no divisions: their LP just counts up from the rank's floor.

New players start at elo.starting-mmr — 400, which is Copper IV.

ranks.yml is yours to rewrite

The file is read as plain YAML, not as a fixed schema. Rename the ranks, change how many there are, change the division count and LP width per rank, give each its own icon and gradient. A rank with no divisions key simply has none. k-factor defaults to 30 and lp-per-division to 100 for the short form.

The formula

Standard Elo with a few practice-server adjustments:

expected = 1 / (1 + 10^((opponentMmr - playerMmr) / 400))
delta    = round(K × (result − expected))

K is the K-factor of the rank the player is currently in — high at the bottom so new players find their level quickly, low at the top so a Legend's rating is stable.

SettingDefaultWhat it does
elo.lp-max-per-game25Hard cap on the movement in either direction
elo.placement-game-count10Ranked games before a player is out of placements
elo.placement-k-multiplier2.0K is multiplied by this during placements
elo.flat-elo-enabledfalseReplaces the whole formula with two fixed numbers
elo.flat-elo-win25The win, when flat is on
elo.flat-elo-loss25The loss, when flat is on

Placements

The first placement-game-count ranked games on a kit — and separately on the global ladder — use a doubled K and skip both the cap and the asymmetric reduction. A player's placement games move their rating hard and fast, which is the point.

The asymmetric reduction

When a higher-rated player loses and the gap is more than elo.asymmetric-threshold-mmr (200), the loss is reduced by elo.asymmetric-reduction-per-100-mmr (5) for every 100 MMR of gap beyond the threshold, and the result is bounded so it can never cost more than elo.asymmetric-min-loss (5).

In practice: with the defaults, a player more than 200 MMR above their opponent loses at most 5 LP, and by a gap of about 700 the loss reaches zero. It exists so that a high-rated player who keeps getting matched down is not punished for the matchmaker's choices.

The winner's gain is unaffected — only the loss is reduced.

The demotion shield

A loss can never drop a player below the floor of the division they are currently in. Losing at Copper II with 40 LP takes you to Copper II 0 LP, not into Copper III.

The shield only applies while you are above the floor. Once you are sitting exactly on it, the next loss demotes normally. It does not apply during placements.

Ratings also never go below 0.

Boosts

An admin can multiply a player's LP gains for a while.

CommandWhat it does
/epc boost add <player> <multiplier> <duration>A personal boost
/epc boost remove <player>Cancel it
/epc boost info <player>Multiplier and time left
/epc boost global add <multiplier> <duration>Everybody at once
/epc boost global removeCancel it
/epc boost global infoMultiplier and time left

Durations are written as 1d, 12h, 30m, 90s, or combined: 1d12h. The multiplier must be greater than 1.

A player's effective multiplier is the higher of their personal boost and the global one — they do not stack. It only ever applies to a winner's positive delta; a loss is never boosted, and the bonus LP is reported separately in chat.

Personal boosts survive a restart. Both kinds are cancelled by a season rotation.

Anti-boosting

Two checks, both consulted before the queue pairs anybody:

SettingDefaultWhat it does
elo-security.enabledtrueThe master switch for both
elo-security.same-ip-protectiontrueTwo players from the same address are never paired
elo-security.opponent-cooldowntrueThe recent-opponent rule
elo-security.opponent-cooldown-seconds300How long two players must wait before meeting again
Duels are not filtered by these

Both checks run at matchmaking time only. /duel bypasses them entirely, so two accounts can still farm each other on a ranked kit through direct challenges. The duel does start the recent-opponent cooldown for the queue, but nothing blocks the next duel.

Same-IP protection makes solo testing awkward

Two clients on one machine will never be paired. Turn same-ip-protection off while you are setting the server up.

Adjusting ratings by hand

/epc stats set <player> <kit|global> elo <value>
/epc stats add <player> <kit|global> elo <amount>

See stats for the full field list. /epc → Data Management also offers Reset kit ELO and Reset all ELO, which put every row of the current season back to elo.starting-mmr. Previous seasons and the lifetime tier are untouched.

Something missing on this page? Tell us on Discord