extend playban to ragequitters
parent
e4c4c8cf7f
commit
b3e9941ffb
|
@ -7,8 +7,10 @@
|
|||
<p>You'll be able to play again <strong>@secondsFromNow(ban.remainingSeconds)</strong>.</p>
|
||||
<h2>Why?</h2>
|
||||
<p>Either you have <strong>aborted too many games</strong>,<br />
|
||||
or you have <strong>not played</strong> the games you started.
|
||||
or you have <strong>not played</strong> the games you started,<br />
|
||||
or you <strong>quit games without resigning</strong>.
|
||||
</p>
|
||||
<br />
|
||||
<p>Once you start a game, you <strong>must</strong> play it!</p>
|
||||
<br />
|
||||
<p>To avoid starting unwanted games,<br />
|
||||
|
|
|
@ -27,16 +27,19 @@ final class PlaybanApi(coll: Coll) {
|
|||
private def blameable(game: Game) = game.source == Some(Source.Lobby) && game.hasClock
|
||||
|
||||
def abort(pov: Pov): Funit = blameable(pov.game) ?? {
|
||||
if (pov.game olderThan 45) pov.game.playerWhoDidNotMove map { Blame(_, Outcome.NoPlay) }
|
||||
else if (pov.game olderThan 15) none
|
||||
else pov.player.some map { Blame(_, Outcome.Abort) }
|
||||
} ?? {
|
||||
case Blame(player, outcome) => player.userId.??(save(outcome))
|
||||
}
|
||||
|
||||
val blame =
|
||||
if (pov.game olderThan 45) pov.game.playerWhoDidNotMove map { Blame(_, Outcome.NoPlay) }
|
||||
else if (pov.game olderThan 15) none
|
||||
else pov.player.some map { Blame(_, Outcome.Abort) }
|
||||
def rageQuit(game: Game): Funit = blameable(game) ?? {
|
||||
game.loser.flatMap(_.userId) ?? save(Outcome.RageQuit)
|
||||
}
|
||||
|
||||
blame match {
|
||||
case None => pov.game.userIds.map(save(Outcome.Good)).sequenceFu.void
|
||||
case Some(Blame(player, outcome)) => player.userId.??(save(outcome))
|
||||
}
|
||||
def goodFinish(game: Game): Funit = blameable(game) ?? {
|
||||
game.userIds.map(save(Outcome.Good)).sequenceFu.void
|
||||
}
|
||||
|
||||
def currentBan(userId: String): Fu[Option[TempBan]] = coll.find(
|
||||
|
|
|
@ -60,6 +60,7 @@ object Outcome {
|
|||
case object Good extends Outcome(0, "Nothing unusual")
|
||||
case object Abort extends Outcome(1, "Aborts the game")
|
||||
case object NoPlay extends Outcome(2, "Won't play a move")
|
||||
case object RageQuit extends Outcome(3, "Quit without resigning")
|
||||
|
||||
val all = List(Good, Abort, NoPlay)
|
||||
|
||||
|
|
|
@ -26,9 +26,9 @@ private[round] final class Drawer(
|
|||
|
||||
def yes(pov: Pov): Fu[Events] = pov match {
|
||||
case pov if pov.game.toChessHistory.threefoldRepetition =>
|
||||
finisher(pov.game, _.Draw)
|
||||
finisher.other(pov.game, _.Draw)
|
||||
case pov if pov.opponent.isOfferingDraw =>
|
||||
finisher(pov.game, _.Draw, None, Some(_.drawOfferAccepted))
|
||||
finisher.other(pov.game, _.Draw, None, Some(_.drawOfferAccepted))
|
||||
case Pov(g, color) if (g playerCanOfferDraw color) => GameRepo save {
|
||||
messenger.system(g, color.fold(_.whiteOffersDraw, _.blackOffersDraw))
|
||||
Progress(g) map { g => g.updatePlayer(color, _ offerDraw g.turns) }
|
||||
|
@ -49,7 +49,7 @@ private[round] final class Drawer(
|
|||
}
|
||||
|
||||
def claim(pov: Pov): Fu[Events] =
|
||||
(pov.game.playable && pov.game.toChessHistory.threefoldRepetition) ?? finisher(pov.game, _.Draw)
|
||||
(pov.game.playable && pov.game.toChessHistory.threefoldRepetition) ?? finisher.other(pov.game, _.Draw)
|
||||
|
||||
def force(game: Game): Fu[Events] = finisher(game, _.Draw, None, None)
|
||||
def force(game: Game): Fu[Events] = finisher.other(game, _.Draw, None, None)
|
||||
}
|
||||
|
|
|
@ -28,7 +28,19 @@ private[round] final class Finisher(
|
|||
bus.publish(AbortedBy(pov), 'abortGame)
|
||||
}
|
||||
|
||||
def apply(
|
||||
def rageQuit(game: Game, winner: Option[Color]): Fu[Events] =
|
||||
apply(game, _.Timeout, winner) addEffect { _ =>
|
||||
playban.rageQuit(game)
|
||||
}
|
||||
|
||||
def other(
|
||||
game: Game,
|
||||
status: Status.type => Status,
|
||||
winner: Option[Color] = None,
|
||||
message: Option[SelectI18nKey] = None): Fu[Events] =
|
||||
apply(game, status, winner, message) >>- playban.goodFinish(game)
|
||||
|
||||
private def apply(
|
||||
game: Game,
|
||||
status: Status.type => Status,
|
||||
winner: Option[Color] = None,
|
||||
|
|
|
@ -76,12 +76,10 @@ private[round] final class Player(
|
|||
|
||||
private def moveFinish(game: Game, color: Color): Fu[Events] = {
|
||||
lazy val winner = game.toChess.situation.winner
|
||||
|
||||
game.status match {
|
||||
|
||||
case Status.Mate => finisher(game, _.Mate, winner)
|
||||
case Status.VariantEnd => finisher(game, _.VariantEnd, winner)
|
||||
case status@(Status.Stalemate | Status.Draw) => finisher(game, _ => status)
|
||||
case Status.Mate => finisher.other(game, _.Mate, winner)
|
||||
case Status.VariantEnd => finisher.other(game, _.VariantEnd, winner)
|
||||
case status@(Status.Stalemate | Status.Draw) => finisher.other(game, _ => status)
|
||||
case _ => fuccess(Nil)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,11 +56,11 @@ private[round] final class Round(
|
|||
}
|
||||
|
||||
case Resign(playerId) => handle(playerId) { pov =>
|
||||
pov.game.resignable ?? finisher(pov.game, _.Resign, Some(!pov.color))
|
||||
pov.game.resignable ?? finisher.other(pov.game, _.Resign, Some(!pov.color))
|
||||
}
|
||||
|
||||
case ResignColor(color) => handle(color) { pov =>
|
||||
pov.game.resignable ?? finisher(pov.game, _.Resign, Some(!pov.color))
|
||||
pov.game.resignable ?? finisher.other(pov.game, _.Resign, Some(!pov.color))
|
||||
}
|
||||
|
||||
case GoBerserk(color) => handle(color) { pov =>
|
||||
|
@ -74,20 +74,20 @@ private[round] final class Round(
|
|||
case ResignForce(playerId) => handle(playerId) { pov =>
|
||||
(pov.game.resignable && !pov.game.hasAi && pov.game.hasClock) ?? {
|
||||
socketHub ? Ask(pov.gameId, IsGone(!pov.color)) flatMap {
|
||||
case true => finisher(pov.game, _.Timeout, Some(pov.color))
|
||||
case true => finisher.rageQuit(pov.game, Some(pov.color))
|
||||
case _ => fuccess(List(Event.Reload))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case NoStartColor(color) => handle(color) { pov =>
|
||||
finisher(pov.game, _.NoStart, Some(!pov.color))
|
||||
finisher.other(pov.game, _.NoStart, Some(!pov.color))
|
||||
}
|
||||
|
||||
case DrawForce(playerId) => handle(playerId) { pov =>
|
||||
(pov.game.drawable && !pov.game.hasAi && pov.game.hasClock) ?? {
|
||||
socketHub ? Ask(pov.gameId, IsGone(!pov.color)) flatMap {
|
||||
case true => finisher(pov.game, _.Timeout, None)
|
||||
case true => finisher.rageQuit(pov.game, None)
|
||||
case _ => fuccess(List(Event.Reload))
|
||||
}
|
||||
}
|
||||
|
@ -103,8 +103,8 @@ private[round] final class Round(
|
|||
case Abandon => fuccess {
|
||||
GameRepo game gameId foreach { gameOption =>
|
||||
gameOption filter (_.abandoned) foreach { game =>
|
||||
if (game.abortable) finisher(game, _.Aborted)
|
||||
else finisher(game, _.Resign, Some(!game.player.color))
|
||||
if (game.abortable) finisher.other(game, _.Aborted)
|
||||
else finisher.other(game, _.Resign, Some(!game.player.color))
|
||||
self ! PoisonPill
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ private[round] final class Round(
|
|||
case DrawForce => handle(drawer force _)
|
||||
case Cheat(color) => handle { game =>
|
||||
(game.playable && !game.imported) ?? {
|
||||
finisher(game, _.Cheat, Some(!color))
|
||||
finisher.other(game, _.Cheat, Some(!color))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,12 +172,12 @@ private[round] final class Round(
|
|||
case AbortForMaintenance => handle { game =>
|
||||
messenger.system(game, (_.untranslated("Game aborted for server maintenance")))
|
||||
messenger.system(game, (_.untranslated("Sorry for the inconvenience!")))
|
||||
game.playable ?? finisher(game, _.Aborted)
|
||||
game.playable ?? finisher.other(game, _.Aborted)
|
||||
}
|
||||
}
|
||||
|
||||
private def outOfTime(game: Game)(p: lila.game.Player) =
|
||||
finisher(game, _.Outoftime, Some(!p.color) filterNot { color =>
|
||||
finisher.other(game, _.Outoftime, Some(!p.color) filterNot { color =>
|
||||
game.toChess.board.variant.drawsOnInsufficientMaterial &&
|
||||
chess.InsufficientMatingMaterial(game.toChess.board, color)
|
||||
})
|
||||
|
|
|
@ -592,7 +592,7 @@ body.fpmenu > div.content {
|
|||
display: block;
|
||||
margin-bottom: 3px;
|
||||
color: #555;
|
||||
opacity: 0.6;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.13s;
|
||||
}
|
||||
#site_title:hover {
|
||||
|
|
Loading…
Reference in New Issue