2013-05-18 09:26:37 -06:00
|
|
|
package lila.round
|
|
|
|
|
2019-11-26 14:44:08 -07:00
|
|
|
import lila.common.Bus
|
2019-12-13 07:30:20 -07:00
|
|
|
import lila.game.{ Event, Game, GameRepo, Pov, Progress, Rewind, UciMemo }
|
2014-05-01 06:08:54 -06:00
|
|
|
import lila.pref.{ Pref, PrefApi }
|
2019-08-19 02:41:49 -06:00
|
|
|
import RoundDuct.TakebackSituation
|
2013-05-18 09:26:37 -06:00
|
|
|
|
2019-12-13 07:30:20 -07:00
|
|
|
final private class Takebacker(
|
2014-05-01 06:08:54 -06:00
|
|
|
messenger: Messenger,
|
2019-12-02 09:41:05 -07:00
|
|
|
gameRepo: GameRepo,
|
2014-05-01 06:08:54 -06:00
|
|
|
uciMemo: UciMemo,
|
2019-11-26 14:44:08 -07:00
|
|
|
prefApi: PrefApi
|
2017-02-14 08:34:07 -07:00
|
|
|
) {
|
2013-05-18 09:26:37 -06:00
|
|
|
|
2019-12-13 07:30:20 -07:00
|
|
|
def yes(
|
|
|
|
situation: TakebackSituation
|
|
|
|
)(pov: Pov)(implicit proxy: GameProxy): Fu[(Events, TakebackSituation)] = IfAllowed(pov.game) {
|
2014-05-01 06:08:54 -06:00
|
|
|
pov match {
|
2016-06-21 03:52:42 -06:00
|
|
|
case Pov(game, _) if pov.opponent.isProposingTakeback => {
|
2015-03-26 04:04:40 -06:00
|
|
|
if (pov.opponent.proposeTakebackAt == pov.game.turns) single(game)
|
|
|
|
else double(game)
|
2016-06-21 03:52:42 -06:00
|
|
|
} map (_ -> situation.reset)
|
2019-10-28 02:35:36 -06:00
|
|
|
case Pov(game, _) if pov.game.playableByAi => single(game) map (_ -> situation)
|
2019-12-13 07:30:20 -07:00
|
|
|
case Pov(game, _) if pov.opponent.isAi => double(game) map (_ -> situation)
|
2016-06-21 03:52:42 -06:00
|
|
|
case Pov(game, color) if (game playerCanProposeTakeback color) && situation.offerable => {
|
2014-05-01 06:08:54 -06:00
|
|
|
messenger.system(game, _.takebackPropositionSent)
|
2015-03-26 04:04:40 -06:00
|
|
|
val progress = Progress(game) map { g =>
|
|
|
|
g.updatePlayer(color, _ proposeTakeback g.turns)
|
|
|
|
}
|
2017-09-04 13:40:24 -06:00
|
|
|
proxy.save(progress) >>- publishTakebackOffer(pov) inject
|
2017-09-04 13:33:36 -06:00
|
|
|
List(Event.TakebackOffers(color.white, color.black))
|
2016-06-21 03:52:42 -06:00
|
|
|
} map (_ -> situation)
|
2016-03-19 23:15:30 -06:00
|
|
|
case _ => fufail(ClientError("[takebacker] invalid yes " + pov))
|
2014-05-01 06:08:54 -06:00
|
|
|
}
|
2013-05-18 09:26:37 -06:00
|
|
|
}
|
2014-05-01 06:08:54 -06:00
|
|
|
|
2019-12-13 07:30:20 -07:00
|
|
|
def no(situation: TakebackSituation)(pov: Pov)(implicit proxy: GameProxy): Fu[(Events, TakebackSituation)] =
|
|
|
|
pov match {
|
|
|
|
case Pov(game, color) if pov.player.isProposingTakeback =>
|
|
|
|
proxy.save {
|
|
|
|
messenger.system(game, _.takebackPropositionCanceled)
|
|
|
|
Progress(game) map { g =>
|
|
|
|
g.updatePlayer(color, _.removeTakebackProposition)
|
|
|
|
}
|
|
|
|
} inject {
|
|
|
|
List(Event.TakebackOffers(false, false)) -> situation.decline
|
|
|
|
}
|
|
|
|
case Pov(game, color) if pov.opponent.isProposingTakeback =>
|
|
|
|
proxy.save {
|
|
|
|
messenger.system(game, _.takebackPropositionDeclined)
|
|
|
|
Progress(game) map { g =>
|
|
|
|
g.updatePlayer(!color, _.removeTakebackProposition)
|
|
|
|
}
|
|
|
|
} inject {
|
|
|
|
List(Event.TakebackOffers(false, false)) -> situation.decline
|
|
|
|
}
|
|
|
|
case _ => fufail(ClientError("[takebacker] invalid no " + pov))
|
2016-06-21 03:52:42 -06:00
|
|
|
}
|
2013-05-18 09:26:37 -06:00
|
|
|
|
2019-07-31 03:47:16 -06:00
|
|
|
def isAllowedIn(game: Game): Fu[Boolean] =
|
|
|
|
if (game.isMandatory) fuFalse
|
|
|
|
else isAllowedByPrefs(game)
|
|
|
|
|
|
|
|
private def isAllowedByPrefs(game: Game): Fu[Boolean] =
|
2018-03-16 17:20:53 -06:00
|
|
|
if (game.hasAi) fuTrue
|
2019-12-13 07:30:20 -07:00
|
|
|
else
|
|
|
|
game.userIds.map {
|
|
|
|
prefApi.getPref(_, (p: Pref) => p.takeback)
|
|
|
|
}.sequenceFu map {
|
|
|
|
_.forall { p =>
|
|
|
|
p == Pref.Takeback.ALWAYS || (p == Pref.Takeback.CASUAL && game.casual)
|
|
|
|
}
|
2014-05-01 06:08:54 -06:00
|
|
|
}
|
|
|
|
|
2017-09-04 13:40:24 -06:00
|
|
|
private def publishTakebackOffer(pov: Pov): Unit =
|
2019-12-08 09:58:50 -07:00
|
|
|
if (pov.game.isCorrespondence && pov.game.nonAi && pov.player.hasUser)
|
2019-11-26 14:44:08 -07:00
|
|
|
Bus.publish(
|
2017-09-04 13:40:24 -06:00
|
|
|
lila.hub.actorApi.round.CorresTakebackOfferEvent(pov.gameId),
|
2019-11-29 17:07:51 -07:00
|
|
|
"offerEventCorres"
|
2017-09-04 13:33:36 -06:00
|
|
|
)
|
|
|
|
|
2016-06-21 03:52:42 -06:00
|
|
|
private def IfAllowed[A](game: Game)(f: => Fu[A]): Fu[A] =
|
2016-03-19 23:15:30 -06:00
|
|
|
if (!game.playable) fufail(ClientError("[takebacker] game is over " + game.id))
|
2019-07-31 03:47:16 -06:00
|
|
|
else if (game.isMandatory) fufail(ClientError("[takebacker] game disallows it " + game.id))
|
2019-12-13 07:30:20 -07:00
|
|
|
else
|
|
|
|
isAllowedByPrefs(game) flatMap {
|
|
|
|
case true => f
|
|
|
|
case _ => fufail(ClientError("[takebacker] disallowed by preferences " + game.id))
|
|
|
|
}
|
2014-05-01 06:08:54 -06:00
|
|
|
|
2019-12-13 07:30:20 -07:00
|
|
|
private def single(game: Game)(implicit proxy: GameProxy): Fu[Events] =
|
|
|
|
for {
|
|
|
|
fen <- gameRepo initialFen game
|
|
|
|
progress <- Rewind(game, fen).future
|
|
|
|
_ <- fuccess { uciMemo.drop(game, 1) }
|
|
|
|
events <- saveAndNotify(progress)
|
|
|
|
} yield events
|
2013-05-18 09:26:37 -06:00
|
|
|
|
2019-12-13 07:30:20 -07:00
|
|
|
private def double(game: Game)(implicit proxy: GameProxy): Fu[Events] =
|
|
|
|
for {
|
|
|
|
fen <- gameRepo initialFen game
|
|
|
|
prog1 <- Rewind(game, fen).future
|
|
|
|
prog2 <- Rewind(prog1.game, fen).future map { progress =>
|
|
|
|
prog1 withGame progress.game
|
|
|
|
}
|
|
|
|
_ <- fuccess { uciMemo.drop(game, 2) }
|
|
|
|
events <- saveAndNotify(prog2)
|
|
|
|
} yield events
|
2013-05-18 09:26:37 -06:00
|
|
|
|
2016-03-22 07:06:48 -06:00
|
|
|
private def saveAndNotify(p1: Progress)(implicit proxy: GameProxy): Fu[Events] = {
|
2013-05-18 09:26:37 -06:00
|
|
|
val p2 = p1 + Event.Reload
|
2014-02-01 00:54:03 -07:00
|
|
|
messenger.system(p2.game, _.takebackPropositionAccepted)
|
2016-03-22 07:06:48 -06:00
|
|
|
proxy.save(p2) inject p2.events
|
2013-05-18 09:26:37 -06:00
|
|
|
}
|
|
|
|
}
|