team battle round leaderboard
parent
60097458c1
commit
11b1dab2da
|
@ -72,7 +72,7 @@ final class Challenge(
|
|||
case Some(pov) =>
|
||||
negotiate(
|
||||
html = Redirect(routes.Round.watcher(pov.gameId, "white")).fuccess,
|
||||
api = apiVersion => env.api.roundApi.player(pov, apiVersion) map { Ok(_) }
|
||||
api = apiVersion => env.api.roundApi.player(pov, none, apiVersion) map { Ok(_) }
|
||||
) flatMap withChallengeAnonCookie(ctx.isAnon, c, false)
|
||||
case None =>
|
||||
negotiate(
|
||||
|
|
|
@ -30,7 +30,7 @@ final class Round(
|
|||
else
|
||||
PreventTheft(pov) {
|
||||
pov.game.playableByAi ?? env.fishnet.player(pov.game)
|
||||
env.tournament.api.miniView(pov, true) flatMap {
|
||||
env.tournament.api.gameView.player(pov) flatMap {
|
||||
tour =>
|
||||
gameC.preloadUsers(pov.game) zip
|
||||
(pov.game.simulId ?? env.simul.repo.find) zip
|
||||
|
@ -39,7 +39,7 @@ final class Round(
|
|||
.withMatchup(pov.game)) zip
|
||||
(pov.game.isSwitchable ?? otherPovs(pov.game)) zip
|
||||
env.bookmark.api.exists(pov.game, ctx.me) zip
|
||||
env.api.roundApi.player(pov, lila.api.Mobile.Api.currentVersion) map {
|
||||
env.api.roundApi.player(pov, tour, lila.api.Mobile.Api.currentVersion) map {
|
||||
case _ ~ simul ~ chatOption ~ crosstable ~ playing ~ bookmarked ~ data =>
|
||||
simul foreach env.simul.api.onPlayerConnection(pov.game, ctx.me)
|
||||
Ok(
|
||||
|
@ -62,7 +62,7 @@ final class Round(
|
|||
else {
|
||||
pov.game.playableByAi ?? env.fishnet.player(pov.game)
|
||||
gameC.preloadUsers(pov.game) zip
|
||||
env.api.roundApi.player(pov, apiVersion) zip
|
||||
env.api.roundApi.player(pov, none, apiVersion) zip
|
||||
getPlayerChat(pov.game, none) map {
|
||||
case _ ~ data ~ chat =>
|
||||
Ok {
|
||||
|
@ -155,31 +155,33 @@ final class Round(
|
|||
html = {
|
||||
if (pov.game.replayable) analyseC.replay(pov, userTv = userTv)
|
||||
else if (HTTPRequest.isHuman(ctx.req))
|
||||
env.tournament.api.miniView(pov, false) zip
|
||||
env.tournament.api.gameView.watcher(pov.game) zip
|
||||
(pov.game.simulId ?? env.simul.repo.find) zip
|
||||
getWatcherChat(pov.game) zip
|
||||
(ctx.noBlind ?? env.game.crosstableApi.withMatchup(pov.game)) zip
|
||||
env.api.roundApi.watcher(
|
||||
pov,
|
||||
lila.api.Mobile.Api.currentVersion,
|
||||
tv = userTv.map { u =>
|
||||
lila.round.OnUserTv(u.id)
|
||||
}
|
||||
) zip
|
||||
env.bookmark.api.exists(pov.game, ctx.me) map {
|
||||
case tour ~ simul ~ chat ~ crosstable ~ data ~ bookmarked =>
|
||||
Ok(
|
||||
html.round.watcher(
|
||||
pov,
|
||||
data,
|
||||
tour,
|
||||
simul,
|
||||
crosstable,
|
||||
userTv = userTv,
|
||||
chatOption = chat,
|
||||
bookmarked = bookmarked
|
||||
env.bookmark.api.exists(pov.game, ctx.me) flatMap {
|
||||
case tour ~ simul ~ chat ~ crosstable ~ bookmarked =>
|
||||
env.api.roundApi.watcher(
|
||||
pov,
|
||||
tour,
|
||||
lila.api.Mobile.Api.currentVersion,
|
||||
tv = userTv.map { u =>
|
||||
lila.round.OnUserTv(u.id)
|
||||
}
|
||||
) map { data =>
|
||||
Ok(
|
||||
html.round.watcher(
|
||||
pov,
|
||||
data,
|
||||
tour.map(_.tourAndTeamVs),
|
||||
simul,
|
||||
crosstable,
|
||||
userTv = userTv,
|
||||
chatOption = chat,
|
||||
bookmarked = bookmarked
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
else
|
||||
for { // web crawlers don't need the full thing
|
||||
|
@ -189,7 +191,7 @@ final class Round(
|
|||
},
|
||||
api = apiVersion =>
|
||||
for {
|
||||
data <- env.api.roundApi.watcher(pov, apiVersion, tv = none)
|
||||
data <- env.api.roundApi.watcher(pov, none, apiVersion, tv = none)
|
||||
analysis <- analyser get pov.game
|
||||
chat <- getWatcherChat(pov.game)
|
||||
} yield Ok {
|
||||
|
@ -255,7 +257,7 @@ final class Round(
|
|||
|
||||
def sides(gameId: String, color: String) = Open { implicit ctx =>
|
||||
OptionFuResult(proxyPov(gameId, color)) { pov =>
|
||||
env.tournament.api.withTeamVs(pov.game) zip
|
||||
env.tournament.api.gameView.withTeamVs(pov.game) zip
|
||||
(pov.game.simulId ?? env.simul.repo.find) zip
|
||||
env.game.gameRepo.initialFen(pov.game) zip
|
||||
env.game.crosstableApi.withMatchup(pov.game) zip
|
||||
|
|
|
@ -260,7 +260,7 @@ final class Setup(
|
|||
negotiate(
|
||||
html = fuccess(redirectPov(pov)),
|
||||
api = apiVersion =>
|
||||
env.api.roundApi.player(pov, apiVersion) map { data =>
|
||||
env.api.roundApi.player(pov, none, apiVersion) map { data =>
|
||||
Created(data) as JSON
|
||||
}
|
||||
)
|
||||
|
|
|
@ -41,8 +41,8 @@ final class Tv(
|
|||
val pov = if (flip) Pov second game else Pov first game
|
||||
val onTv = lila.round.OnLichessTv(channel.key, flip)
|
||||
negotiate(
|
||||
html = {
|
||||
env.api.roundApi.watcher(pov, lila.api.Mobile.Api.currentVersion, tv = onTv.some) zip
|
||||
html = env.tournament.api.gameView.watcher(pov.game) flatMap { tour =>
|
||||
env.api.roundApi.watcher(pov, tour, lila.api.Mobile.Api.currentVersion, tv = onTv.some) zip
|
||||
env.game.crosstableApi.withMatchup(game) zip
|
||||
env.tv.tv.getChampions map {
|
||||
case data ~ cross ~ champions =>
|
||||
|
@ -51,7 +51,7 @@ final class Tv(
|
|||
}
|
||||
}
|
||||
},
|
||||
api = apiVersion => env.api.roundApi.watcher(pov, apiVersion, tv = onTv.some) map { Ok(_) }
|
||||
api = apiVersion => env.api.roundApi.watcher(pov, none, apiVersion, tv = onTv.some) map { Ok(_) }
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -118,14 +118,14 @@ object bits {
|
|||
private[round] def side(
|
||||
pov: Pov,
|
||||
data: play.api.libs.json.JsObject,
|
||||
tour: Option[lila.tournament.TourMiniView],
|
||||
tour: Option[lila.tournament.TourAndTeamVs],
|
||||
simul: Option[lila.simul.Simul],
|
||||
userTv: Option[lila.user.User] = None,
|
||||
bookmarked: Boolean
|
||||
)(implicit ctx: Context) = views.html.game.side(
|
||||
pov,
|
||||
(data \ "game" \ "initialFen").asOpt[String].map(chess.format.FEN),
|
||||
tour.map(_.tourAndTeamVs),
|
||||
tour,
|
||||
simul = simul,
|
||||
userTv = userTv,
|
||||
bookmarked = bookmarked
|
||||
|
|
|
@ -14,7 +14,7 @@ object player {
|
|||
def apply(
|
||||
pov: Pov,
|
||||
data: play.api.libs.json.JsObject,
|
||||
tour: Option[lila.tournament.TourMiniView],
|
||||
tour: Option[lila.tournament.GameView],
|
||||
simul: Option[lila.simul.Simul],
|
||||
cross: Option[lila.game.Crosstable.WithMatchup],
|
||||
playing: List[Pov],
|
||||
|
@ -51,17 +51,12 @@ object player {
|
|||
roundTag,
|
||||
embedJsUnsafe(s"""lichess=window.lichess||{};customWS=true;onload=function(){
|
||||
LichessRound.boot(${safeJsonValue(
|
||||
Json.obj(
|
||||
"data" -> data,
|
||||
"i18n" -> jsI18n(pov.game),
|
||||
"userId" -> ctx.userId,
|
||||
"chat" -> chatJson
|
||||
) ++ tour
|
||||
.flatMap(_.top)
|
||||
.??(top =>
|
||||
Json.obj(
|
||||
"tour" -> lila.tournament.JsonView.top(top, lightUser)
|
||||
)
|
||||
Json
|
||||
.obj(
|
||||
"data" -> data,
|
||||
"i18n" -> jsI18n(pov.game),
|
||||
"userId" -> ctx.userId,
|
||||
"chat" -> chatJson
|
||||
)
|
||||
)})}""")
|
||||
),
|
||||
|
@ -71,7 +66,7 @@ LichessRound.boot(${safeJsonValue(
|
|||
)(
|
||||
main(cls := "round")(
|
||||
st.aside(cls := "round__side")(
|
||||
bits.side(pov, data, tour, simul, bookmarked = bookmarked),
|
||||
bits.side(pov, data, tour.map(_.tourAndTeamVs), simul, bookmarked = bookmarked),
|
||||
chatOption.map(_ => chat.frag)
|
||||
),
|
||||
bits.roundAppPreload(pov, true),
|
||||
|
|
|
@ -14,7 +14,7 @@ object watcher {
|
|||
def apply(
|
||||
pov: Pov,
|
||||
data: JsObject,
|
||||
tour: Option[lila.tournament.TourMiniView],
|
||||
tour: Option[lila.tournament.TourAndTeamVs],
|
||||
simul: Option[lila.simul.Simul],
|
||||
cross: Option[lila.game.Crosstable.WithMatchup],
|
||||
userTv: Option[lila.user.User] = None,
|
||||
|
|
|
@ -12,7 +12,7 @@ import lila.round.JsonView.WithFlags
|
|||
import lila.round.{ Forecast, JsonView }
|
||||
import lila.security.Granter
|
||||
import lila.simul.Simul
|
||||
import lila.tournament.TourAndRanks
|
||||
import lila.tournament.{ GameView => TourView }
|
||||
import lila.tree.Node.partitionTreeJsonWriter
|
||||
import lila.user.User
|
||||
|
||||
|
@ -23,10 +23,14 @@ final private[api] class RoundApi(
|
|||
bookmarkApi: lila.bookmark.BookmarkApi,
|
||||
gameRepo: lila.game.GameRepo,
|
||||
tourApi: lila.tournament.TournamentApi,
|
||||
simulApi: lila.simul.SimulApi
|
||||
simulApi: lila.simul.SimulApi,
|
||||
getTeamName: lila.team.GetTeamName,
|
||||
getLightUser: lila.common.LightUser.GetterSync
|
||||
)(implicit ec: scala.concurrent.ExecutionContext) {
|
||||
|
||||
def player(pov: Pov, apiVersion: ApiVersion)(implicit ctx: Context): Fu[JsObject] =
|
||||
def player(pov: Pov, tour: Option[TourView], apiVersion: ApiVersion)(
|
||||
implicit ctx: Context
|
||||
): Fu[JsObject] =
|
||||
gameRepo
|
||||
.initialFen(pov.game)
|
||||
.flatMap { initialFen =>
|
||||
|
@ -40,14 +44,13 @@ final private[api] class RoundApi(
|
|||
initialFen = initialFen,
|
||||
nvui = ctx.blind
|
||||
) zip
|
||||
tourApi.tourAndRanks(pov.game) zip
|
||||
(pov.game.simulId ?? simulApi.find) zip
|
||||
(ctx.me.ifTrue(ctx.isMobileApi) ?? (me => noteApi.get(pov.gameId, me.id))) zip
|
||||
forecastApi.loadForDisplay(pov) zip
|
||||
bookmarkApi.exists(pov.game, ctx.me) map {
|
||||
case json ~ tourOption ~ simulOption ~ note ~ forecast ~ bookmarked =>
|
||||
case json ~ simulOption ~ note ~ forecast ~ bookmarked =>
|
||||
(
|
||||
withTournament(pov, tourOption) _ compose
|
||||
withTournament(pov, tour) _ compose
|
||||
withSimul(simulOption) _ compose
|
||||
withSteps(pov, initialFen) _ compose
|
||||
withNote(note) _ compose
|
||||
|
@ -60,6 +63,7 @@ final private[api] class RoundApi(
|
|||
|
||||
def watcher(
|
||||
pov: Pov,
|
||||
tour: Option[TourView],
|
||||
apiVersion: ApiVersion,
|
||||
tv: Option[lila.round.OnTv],
|
||||
initialFenO: Option[Option[FEN]] = None
|
||||
|
@ -77,13 +81,12 @@ final private[api] class RoundApi(
|
|||
initialFen = initialFen,
|
||||
withFlags = WithFlags(blurs = ctx.me ?? Granter(_.ViewBlurs))
|
||||
) zip
|
||||
tourApi.tourAndRanks(pov.game) zip
|
||||
(pov.game.simulId ?? simulApi.find) zip
|
||||
(ctx.me.ifTrue(ctx.isMobileApi) ?? (me => noteApi.get(pov.gameId, me.id))) zip
|
||||
bookmarkApi.exists(pov.game, ctx.me) map {
|
||||
case json ~ tourOption ~ simulOption ~ note ~ bookmarked =>
|
||||
case json ~ simulOption ~ note ~ bookmarked =>
|
||||
(
|
||||
withTournament(pov, tourOption) _ compose
|
||||
withTournament(pov, tour) _ compose
|
||||
withSimul(simulOption) _ compose
|
||||
withNote(note) _ compose
|
||||
withBookmark(bookmarked) _ compose
|
||||
|
@ -114,13 +117,13 @@ final private[api] class RoundApi(
|
|||
initialFen = initialFen,
|
||||
withFlags = withFlags.copy(blurs = ctx.me ?? Granter(_.ViewBlurs))
|
||||
) zip
|
||||
tourApi.tourAndRanks(pov.game) zip
|
||||
tourApi.gameView.analysis(pov.game) zip
|
||||
(pov.game.simulId ?? simulApi.find) zip
|
||||
(ctx.me.ifTrue(ctx.isMobileApi) ?? (me => noteApi.get(pov.gameId, me.id))) zip
|
||||
bookmarkApi.exists(pov.game, ctx.me) map {
|
||||
case json ~ tourOption ~ simulOption ~ note ~ bookmarked =>
|
||||
case json ~ tour ~ simulOption ~ note ~ bookmarked =>
|
||||
(
|
||||
withTournament(pov, tourOption) _ compose
|
||||
withTournament(pov, tour) _ compose
|
||||
withSimul(simulOption) _ compose
|
||||
withNote(note) _ compose
|
||||
withBookmark(bookmarked) _ compose
|
||||
|
@ -236,30 +239,32 @@ final private[api] class RoundApi(
|
|||
analysisJson.bothPlayers(g, a)
|
||||
})
|
||||
|
||||
private def withTournament(pov: Pov, tourOption: Option[TourAndRanks])(
|
||||
json: JsObject
|
||||
)(implicit lang: Lang) =
|
||||
json.add("tournament" -> tourOption.map { data =>
|
||||
def withTournament(pov: Pov, viewO: Option[TourView])(json: JsObject)(implicit lang: Lang) =
|
||||
json.add("tournament" -> viewO.map { v =>
|
||||
Json
|
||||
.obj(
|
||||
"id" -> data.tour.id,
|
||||
"name" -> data.tour.name(false),
|
||||
"running" -> data.tour.isStarted
|
||||
"id" -> v.tour.id,
|
||||
"name" -> v.tour.name(false),
|
||||
"running" -> v.tour.isStarted
|
||||
)
|
||||
.add("secondsToFinish" -> data.tour.isStarted.option(data.tour.secondsToFinish))
|
||||
.add("berserkable" -> data.tour.isStarted.option(data.tour.berserkable))
|
||||
.add("secondsToFinish" -> v.tour.isStarted.option(v.tour.secondsToFinish))
|
||||
.add("berserkable" -> v.tour.isStarted.option(v.tour.berserkable))
|
||||
// mobile app API BC / should use game.expiration instead
|
||||
.add("nbSecondsForFirstMove" -> data.tour.isStarted.option {
|
||||
.add("nbSecondsForFirstMove" -> v.tour.isStarted.option {
|
||||
pov.game.timeForFirstMove.toSeconds
|
||||
})
|
||||
.add(
|
||||
"ranks" -> data.tour.isStarted.option(
|
||||
Json.obj(
|
||||
"white" -> data.whiteRank,
|
||||
"black" -> data.blackRank
|
||||
)
|
||||
.add("ranks" -> v.ranks.map { r =>
|
||||
Json.obj(
|
||||
"white" -> r.whiteRank,
|
||||
"black" -> r.blackRank
|
||||
)
|
||||
)
|
||||
})
|
||||
.add("top", v.top.map {
|
||||
lila.tournament.JsonView.top(_, getLightUser)
|
||||
})
|
||||
.add("team", v.teamVs.map(_.teams(pov.color)) map { id =>
|
||||
Json.obj("name" -> getTeamName(id))
|
||||
})
|
||||
})
|
||||
|
||||
private def withSimul(simulOption: Option[Simul])(json: JsObject) =
|
||||
|
|
|
@ -51,6 +51,8 @@ final class TournamentApi(
|
|||
private val workQueue =
|
||||
new WorkQueues(buffer = 256, expiration = 1 minute, timeout = 10 seconds, name = "tournament")
|
||||
|
||||
def get(id: Tournament.ID) = tournamentRepo byId id
|
||||
|
||||
def createTournament(
|
||||
setup: TournamentSetup,
|
||||
me: User,
|
||||
|
@ -152,22 +154,6 @@ final class TournamentApi(
|
|||
}
|
||||
}
|
||||
|
||||
def tourAndRanks(game: Game): Fu[Option[TourAndRanks]] = ~ {
|
||||
for {
|
||||
tourId <- game.tournamentId
|
||||
whiteId <- game.whitePlayer.userId
|
||||
blackId <- game.blackPlayer.userId
|
||||
} yield tournamentRepo byId tourId flatMap {
|
||||
_ ?? { tour =>
|
||||
cached ranking tour map { ranking =>
|
||||
ranking.get(whiteId) |@| ranking.get(blackId) apply {
|
||||
case (whiteR, blackR) => TourAndRanks(tour, whiteR + 1, blackR + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private[tournament] def start(oldTour: Tournament): Funit =
|
||||
Sequencing(oldTour.id)(tournamentRepo.createdById) { tour =>
|
||||
tournamentRepo.setStatus(tour.id, Status.Started) >>-
|
||||
|
@ -371,7 +357,7 @@ final class TournamentApi(
|
|||
game.userIds.map(updatePlayer(tour, game.some)).sequenceFu.void >>- {
|
||||
duelStore.remove(game)
|
||||
socket.reload(tour.id)
|
||||
updateTournamentStanding(tour.id)
|
||||
updateTournamentStanding(tour)
|
||||
withdrawNonMover(game)
|
||||
}
|
||||
}
|
||||
|
@ -477,31 +463,63 @@ final class TournamentApi(
|
|||
def tournamentTop(tourId: Tournament.ID): Fu[TournamentTop] =
|
||||
tournamentTopCache get tourId
|
||||
|
||||
def miniView(pov: Pov, withTop: Boolean): Fu[Option[TourMiniView]] =
|
||||
withTeamVs(pov.game) flatMap {
|
||||
_ ?? {
|
||||
case TourAndTeamVs(tour, teamVs) =>
|
||||
withTop ?? {
|
||||
teamVs.fold(tournamentTop(tour.id) dmap some) { vs =>
|
||||
cached.teamInfo.get(tour.id -> vs.teams(pov.color)) map2 { info =>
|
||||
TournamentTop(info.topPlayers take tournamentTopNb)
|
||||
}
|
||||
}
|
||||
} dmap {
|
||||
TourMiniView(tour, _, teamVs).some
|
||||
}
|
||||
}
|
||||
}
|
||||
object gameView {
|
||||
|
||||
def withTeamVs(game: Game): Fu[Option[TourAndTeamVs]] =
|
||||
game.tournamentId ?? tournamentRepo.byId flatMap {
|
||||
_ ?? { tour =>
|
||||
(tour.isTeamBattle ?? playerRepo.teamVs(tour.id, game)) map {
|
||||
TourAndTeamVs(tour, _).some
|
||||
def player(pov: Pov): Fu[Option[GameView]] =
|
||||
(pov.game.tournamentId ?? get) flatMap {
|
||||
_ ?? { tour =>
|
||||
getTeamVs(tour, pov.game) zip getGameRanks(tour, pov.game) flatMap {
|
||||
case (teamVs, ranks) =>
|
||||
teamVs.fold(tournamentTop(tour.id) dmap some) { vs =>
|
||||
cached.teamInfo.get(tour.id -> vs.teams(pov.color)) map2 { info =>
|
||||
TournamentTop(info.topPlayers take tournamentTopNb)
|
||||
}
|
||||
} dmap {
|
||||
GameView(tour, teamVs, ranks, _).some
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def watcher(game: Game): Fu[Option[GameView]] =
|
||||
(game.tournamentId ?? get) flatMap {
|
||||
_ ?? { tour =>
|
||||
getTeamVs(tour, game) zip getGameRanks(tour, game) dmap {
|
||||
case (teamVs, ranks) => GameView(tour, teamVs, ranks, none).some
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def analysis(game: Game): Fu[Option[GameView]] =
|
||||
(game.tournamentId ?? get) flatMap {
|
||||
_ ?? { tour =>
|
||||
getTeamVs(tour, game) dmap { GameView(tour, _, none, none).some }
|
||||
}
|
||||
}
|
||||
|
||||
def withTeamVs(game: Game): Fu[Option[TourAndTeamVs]] =
|
||||
(game.tournamentId ?? get) flatMap {
|
||||
_ ?? { tour =>
|
||||
getTeamVs(tour, game) dmap { TourAndTeamVs(tour, _).some }
|
||||
}
|
||||
}
|
||||
|
||||
private def getGameRanks(tour: Tournament, game: Game): Fu[Option[GameRanks]] = ~ {
|
||||
for {
|
||||
whiteId <- game.whitePlayer.userId
|
||||
blackId <- game.blackPlayer.userId
|
||||
if tour.isStarted // don't fetch ranks of finished tournaments
|
||||
} yield cached ranking tour map { ranking =>
|
||||
ranking.get(whiteId) |@| ranking.get(blackId) apply {
|
||||
case (whiteR, blackR) => GameRanks(whiteR + 1, blackR + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def getTeamVs(tour: Tournament, game: Game): Fu[Option[TeamBattle.TeamVs]] =
|
||||
(tour.isTeamBattle ?? playerRepo.teamVs(tour.id, game))
|
||||
}
|
||||
|
||||
def fetchVisibleTournaments: Fu[VisibleTournaments] =
|
||||
tournamentRepo.publicCreatedSorted(6 * 60) zip
|
||||
tournamentRepo.publicStarted zip
|
||||
|
@ -613,12 +631,13 @@ final class TournamentApi(
|
|||
|
||||
private val throttler = system.actorOf(Props(new EarlyMultiThrottler(logger = logger)))
|
||||
|
||||
def apply(tourId: Tournament.ID): Unit =
|
||||
throttler ! EarlyMultiThrottler.Work(
|
||||
id = tourId,
|
||||
run = () => publishNow(tourId),
|
||||
cooldown = 15.seconds
|
||||
)
|
||||
def apply(tour: Tournament): Unit =
|
||||
if (!tour.isTeamBattle)
|
||||
throttler ! EarlyMultiThrottler.Work(
|
||||
id = tour.id,
|
||||
run = () => publishNow(tour.id),
|
||||
cooldown = 15.seconds
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,15 @@ case class TourMiniView(
|
|||
|
||||
case class TourAndTeamVs(tour: Tournament, teamVs: Option[TeamBattle.TeamVs])
|
||||
|
||||
case class GameView(
|
||||
tour: Tournament,
|
||||
teamVs: Option[TeamBattle.TeamVs],
|
||||
ranks: Option[GameRanks],
|
||||
top: Option[TournamentTop]
|
||||
) {
|
||||
def tourAndTeamVs = TourAndTeamVs(tour, teamVs)
|
||||
}
|
||||
|
||||
case class MyInfo(rank: Int, withdraw: Boolean, gameId: Option[lila.game.Game.ID]) {
|
||||
def page = {
|
||||
math.floor((rank - 1) / 10) + 1
|
||||
|
@ -39,11 +48,7 @@ case class PlayerInfoExt(
|
|||
recentPovs: List[lila.game.LightPov]
|
||||
)
|
||||
|
||||
case class TourAndRanks(
|
||||
tour: Tournament,
|
||||
whiteRank: Int,
|
||||
blackRank: Int
|
||||
)
|
||||
case class GameRanks(whiteRank: Int, blackRank: Int)
|
||||
|
||||
case class RankedPairing(pairing: Pairing, rank1: Int, rank2: Int) {
|
||||
|
||||
|
|
|
@ -76,6 +76,20 @@ export interface Tournament {
|
|||
ranks?: TournamentRanks;
|
||||
running?: boolean;
|
||||
nbSecondsForFirstMove?: number;
|
||||
top?: TourPlayer[];
|
||||
team?: Team;
|
||||
}
|
||||
|
||||
export interface TourPlayer {
|
||||
n: string; // name
|
||||
s: number; // score
|
||||
t?: string; // title
|
||||
f: boolean; // fire
|
||||
w: boolean; // withdraw
|
||||
}
|
||||
|
||||
export interface Team {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Simul {
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
&:hover {
|
||||
overflow-y: auto!important;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.2em;
|
||||
padding: .5em 1em;
|
||||
}
|
||||
table {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { RoundOpts, RoundData } from './interfaces';
|
||||
import { RoundApi, RoundMain } from './main';
|
||||
import { ChatCtrl } from 'chat';
|
||||
import { tourStandingCtrl, TourStandingCtrl, TourPlayer } from './tourStanding';
|
||||
import { TourPlayer } from 'game';
|
||||
import { tourStandingCtrl, TourStandingCtrl } from './tourStanding';
|
||||
|
||||
export default function(opts: RoundOpts): void {
|
||||
const li = window.lichess;
|
||||
|
@ -61,14 +62,15 @@ export default function(opts: RoundOpts): void {
|
|||
};
|
||||
opts.element = element;
|
||||
opts.socketSend = li.socket.send;
|
||||
if (!opts.tour && !data.simul) opts.onChange = (d: RoundData) => {
|
||||
if (!opts.data.tournament && !data.simul) opts.onChange = (d: RoundData) => {
|
||||
if (chat) chat.preset.setGroup(getPresetGroup(d));
|
||||
};
|
||||
|
||||
console.log(opts);
|
||||
round = (window['LichessRound'] as RoundMain).app(opts);
|
||||
if (opts.chat) {
|
||||
if (opts.tour) {
|
||||
opts.chat.plugin = tourStandingCtrl(opts.tour, opts.i18n.standing);
|
||||
if (opts.data.tournament?.top) {
|
||||
opts.chat.plugin = tourStandingCtrl(opts.data.tournament.top, opts.data.tournament.team, opts.i18n.standing);
|
||||
opts.chat.alwaysEnabled = true;
|
||||
} else if (!data.simul) {
|
||||
opts.chat.preset = getPresetGroup(opts.data);
|
||||
|
|
|
@ -2,7 +2,6 @@ import { VNode } from 'snabbdom/vnode';
|
|||
import { GameData, Status } from 'game';
|
||||
import { ClockData, Seconds, Centis } from './clock/clockCtrl';
|
||||
import { CorresClockData } from './corresClock/corresClockCtrl';
|
||||
import { TourPlayer } from './tourStanding';
|
||||
import RoundController from './ctrl';
|
||||
import { ChatPlugin } from 'chat';
|
||||
import * as cg from 'chessground/types';
|
||||
|
@ -91,7 +90,6 @@ export interface RoundOpts {
|
|||
crosstableEl: HTMLElement;
|
||||
i18n: any;
|
||||
chat?: Chat;
|
||||
tour?: TourPlayer[];
|
||||
}
|
||||
|
||||
export interface Chat {
|
||||
|
|
|
@ -2,46 +2,44 @@ import { h } from 'snabbdom'
|
|||
import { VNode } from 'snabbdom/vnode'
|
||||
import { onInsert } from './util'
|
||||
import { ChatPlugin } from 'chat'
|
||||
import { Team, TourPlayer } from 'game';
|
||||
|
||||
export interface TourStandingCtrl extends ChatPlugin {
|
||||
set(data: TourPlayer[]): void;
|
||||
set(players: TourPlayer[]): void;
|
||||
}
|
||||
|
||||
export interface TourPlayer {
|
||||
n: string; // name
|
||||
s: number; // score
|
||||
t?: string; // title
|
||||
f: boolean; // fire
|
||||
w: boolean; // withdraw
|
||||
}
|
||||
|
||||
export function tourStandingCtrl(data: TourPlayer[], name: string): TourStandingCtrl {
|
||||
export function tourStandingCtrl(players: TourPlayer[], team: Team | undefined, name: string): TourStandingCtrl {
|
||||
return {
|
||||
set(d: TourPlayer[]) { data = d },
|
||||
set(d: TourPlayer[]) { players = d },
|
||||
tab: {
|
||||
key: 'tourStanding',
|
||||
name: name
|
||||
},
|
||||
view(): VNode {
|
||||
return h('table.slist', {
|
||||
return h('div', {
|
||||
hook: onInsert(_ => {
|
||||
window.lichess.loadCssPath('round.tour-standing');
|
||||
})
|
||||
}, [
|
||||
h('tbody', data.map((p: TourPlayer, i: number) => {
|
||||
return h('tr.' + p.n, [
|
||||
h('td.name', [
|
||||
h('span.rank', '' + (i + 1)),
|
||||
h('a.user-link.ulpt', {
|
||||
attrs: { href: `/@/${p.n}` }
|
||||
}, (p.t ? p.t + ' ' : '') + p.n)
|
||||
]),
|
||||
h('td.total', p.f ? {
|
||||
class: { 'is-gold': true },
|
||||
attrs: { 'data-icon': 'Q' }
|
||||
} : {}, '' + p.s)
|
||||
])
|
||||
}))
|
||||
team ? h('h3.text', {
|
||||
attrs: { 'data-icon': 'f' }
|
||||
}, team.name) : null,
|
||||
h('table.slist', [
|
||||
h('tbody', players.map((p: TourPlayer, i: number) => {
|
||||
return h('tr.' + p.n, [
|
||||
h('td.name', [
|
||||
h('span.rank', '' + (i + 1)),
|
||||
h('a.user-link.ulpt', {
|
||||
attrs: { href: `/@/${p.n}` }
|
||||
}, (p.t ? p.t + ' ' : '') + p.n)
|
||||
]),
|
||||
h('td.total', p.f ? {
|
||||
class: { 'is-gold': true },
|
||||
attrs: { 'data-icon': 'Q' }
|
||||
} : {}, '' + p.s)
|
||||
])
|
||||
}))
|
||||
])
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue