←
{m.name || 'Match'}
Best of {config.bestOf} · First to {winsNeeded}
{#if m.osuLobbyId}
· osu! mp/{m.osuLobbyId}
{/if}
{stateLabel(m.state)}
{#if !['FINISHED', 'CANCELLED'].includes(m.state) && data.isStaff}
{/if}
{#if p1 && p2}
{#if p1.team.avatarUrl}

{/if}
{p1.team.name}
{#if p1.rollValue != null}
Roll: {p1.rollValue}{p1.pickOrder === 1 ? ' โ
' : ''}
{/if}
{p1.score}
vs
{p2.score}
{p2.team.name}
{#if p2.rollValue != null}
{p2.pickOrder === 1 ? 'โ
' : ''}Roll: {p2.rollValue}
{/if}
{#if p2.team.avatarUrl}

{/if}
{/if}
{#if ['LOBBY', 'ROLLING', 'PICKING', 'PLAYING'].includes(m.state)}
{/if}
{#if m.state === 'ROLLING'}
๐ฒ Roll Phase
Highest roll picks first
{#each m.participants as p}
{p.team.name}
{#if p.rollValue != null}
{p.rollValue}
{:else}
โ
{/if}
{/each}
{#if canRoll}
or type !roll in osu! chat
{:else}
Waiting for all rolls...
{/if}
{/if}
{#if m.state === 'PLAYING'}
{@const currentGame = m.games[m.games.length - 1]}
{@const bm = currentGame ? data.beatmapCache[currentGame.slot?.beatmapId] : null}
{lobbyStatus?.gameInProgress ? 'Playing' : 'Now Playing โ Waiting for ready'}
{#if bm}
{bm.artist} - {bm.title} [{bm.version}]
โ
{bm.starRating.toFixed(1)} · {bm.bpm}bpm · {formatLength(bm.totalLength)}
{/if}
{#if lobbyStatus}
{#each m.participants as participant}
{#each participant.players as player}
{@const username = playerNames[player.userId]}
{@const inLobby = username && lobbyStatus.inLobby.includes(username)}
{@const isReady = username && lobbyStatus.readyPlayers.includes(username)}
{username ?? player.userId}
{#if lobbyStatus.gameInProgress}
Playing
{:else if isReady}
Ready
{:else if inLobby}
In Lobby
{:else}
Not in lobby
{/if}
{/each}
{/each}
{:else}
Waiting for players to ready up & play in osu!...
{/if}
{#if data.isStaff}
{/if}
{/if}
{#if showMappool && Object.keys(groupedSlots()).length > 0}
Mappool
{#if pickingPhase}
{isMyTurnToPick ? 'Your pick!' : `${expectedPicker?.team.name}'s pick`}
{:else if m.state === 'PLAYING'}
In progress
{:else if m.state === 'ROLLING'}
Rolling...
{/if}
{#if pickingPhase && !isMyTurnToPick}
Waiting for {expectedPicker?.team.name} to pick...
You can also type !pick NM1 in osu! chat when it's your turn.
{:else if pickingPhase && isMyTurnToPick}
Pick a map below, or type !pick NM1 in osu! chat.
{/if}
{#if pickError}
{pickError}
{/if}
{#if !mappoolCollapsed}
{#each Object.entries(groupedSlots()) as [category, slots]}
{category}
{#each slots as slot}
{@const bm = data.beatmapCache[slot.beatmapId]}
{@const isPlayed = playedSlotIds.has(slot.id)}
{@const isTB = slot.category === 'TB'}
{@const tbLocked = isTB && !isTiebreakerAllowed}
{@const cantPick = !isMyTurnToPick || !pickingPhase}
{/each}
{/each}
{/if}
{/if}
{#if m.state === 'FINISHED'}
{@const winner = m.participants.find((p: any) => p.teamId === m.winnerId)}
๐
{winner?.team.name} wins!
{p1?.score} โ {p2?.score}
{#each m.games as game}
{@const bm = data.beatmapCache[game.slot?.beatmapId]}
{@const winnerP = m.participants.find((p: any) => p.id === game.winnerParticipantId)}
{game.slot?.category}{game.slot?.orderInCategory}
{bm ? `${bm.artist} - ${bm.title}` : `#${game.slot?.beatmapId}`}
{winnerP?.team.name}
{/each}
Back to Dashboard
{/if}
{#if m.games.length > 0}
Games Played
{#each m.games as game}
{@const bm = data.beatmapCache[game.slot?.beatmapId]}
{@const pickerTeam = m.participants.find((p: any) => p.id === game.pickedByParticipantId)?.team}
{@const winnerTeam = m.participants.find((p: any) => p.id === game.winnerParticipantId)?.team}
{game.gameNumber}
{#if bm?.listCoverUrl}

{/if}
{#if bm}
{bm.artist} - {bm.title} [{bm.version}]
{/if}
{game.slot?.category}{game.slot?.orderInCategory}
{#if pickerTeam}Picked by {pickerTeam.name}{/if}
{#if game.state === 'PLAYING'}
Live
{:else if winnerTeam}
โ {winnerTeam.name}
{/if}
{#if game.state === 'FINISHED' && game.scores?.length > 0}
{#each game.scores as s}
{@const username = playerNames[s.player?.userId]}
{username ?? s.player?.userId ?? '?'}
{s.score.toLocaleString()}
{#if s.accuracy > 0}
{(s.accuracy * 100).toFixed(2)}%
{/if}
{#if s.maxCombo > 0}
{s.maxCombo}x
{/if}
{#if s.count300 > 0 || s.count100 > 0 || s.countMiss >= 0}
{s.count300}
/{s.count100}
/{s.count50}
/{s.countMiss}
{/if}
{#if s.pp != null}
{Math.round(s.pp)}pp
{/if}
{#if !s.passed}
FAILED
{/if}
{/each}
{/if}
{/each}
{/if}
{#if m.state === 'CREATED'}
{/if}
{#if m.state === 'LOBBY'}
Lobby created. Waiting for players to join...
{#if m.osuLobbyId}
osu! mp/{m.osuLobbyId}
{/if}
{#if lobbyStatus}
{#each m.participants as participant}
{#each participant.players as player}
{@const username = playerNames[player.userId]}
{@const inLobby = username && lobbyStatus.inLobby.includes(username)}
{username ?? player.userId}
{#if inLobby}
In Lobby
{:else}
Not in lobby
{/if}
{/each}
{/each}
{/if}
{@render reinviteButton()}
{/if}
{#if m.state === 'CANCELLED'}
This match was cancelled.
{/if}