@@ -86,6 +86,7 @@ export class BaseGame<State extends BaseState> {
8686 mod ?: string | null ;
8787
8888 winCtx ?: { type : 'win' ; winner : Player } | { type : 'win' ; winnerIds : string [ ] } | { type : 'draw' } | { type : string } ;
89+ forcewinPlayers ?: string [ ] ;
8990
9091 // Game-provided methods:
9192 render ( side : State [ 'turn' ] | null ) : ReactElement ;
@@ -510,14 +511,26 @@ export class BaseGame<State extends BaseState> {
510511 return `${ process . env . WEB_URL } /${ this . meta . id } /${ this . id . replace ( / ^ # / , '' ) } ` ;
511512 }
512513
513- forceWin ( _player : Player ) : void {
514+ forceWin ( player : Player ) : void {
514515 if ( ! this . started ) this . throw ( 'GAME.NOT_STARTED' ) ;
515- this . end ( 'force' ) ;
516- // TODO
516+ this . forcewinPlayers = Object . values ( this . players )
517+ . filter ( activePlayer => activePlayer . id !== player . id && ! activePlayer . out )
518+ . map ( activePlayer => activePlayer . turn ) ;
519+ this . forcewinPlayers . forEach ( turn => ( this . players [ turn ] . out = true ) ) ;
520+ this . end ( 'dq' ) ;
517521 }
518522
519523 end ( type ?: EndType ) : void {
520- const message = this . onEnd ( type ) ;
524+ let message = this . onEnd ( type ) ;
525+ // Override message for forcewin
526+ if ( type === 'dq' && this . forcewinPlayers ) {
527+ const lastPlayers = Object . values ( this . players ) . filter ( player => ! player . out ) ;
528+ if ( lastPlayers . length !== 1 ) {
529+ Logger . errorLog ( new Error ( JSON . stringify ( { players : this . players , state : this . state } ) ) ) ;
530+ throw new Error ( `Found ${ lastPlayers . length } winners in a forcewin!` ) ;
531+ }
532+ message = this . $T ( 'GAME.FORCE_WIN' , { player : lastPlayers [ 0 ] . name , id : this . id } ) ;
533+ }
521534 this . clearTimer ( ) ;
522535 this . update ( ) ;
523536 if ( this . started && ( this . meta . players === 'many' || this . canBroadcastFinish ?.( ) ) ) {
@@ -563,7 +576,9 @@ export class BaseGame<State extends BaseState> {
563576 if ( checkUGO ( this ) && this . winCtx ) {
564577 if ( this . winCtx . type === 'win' || this . winCtx . type === 'draw' || type === 'dq' ) {
565578 const allPlayers = Object . values ( this . players ) ;
566- const players = allPlayers . filter ( player => ! player . out ) . map ( player => player . turn ) ;
579+ const players = allPlayers
580+ . filter ( player => ! player . out || this . forcewinPlayers ?. includes ( player . turn ) )
581+ . map ( player => player . turn ) ;
567582
568583 const winners =
569584 type === 'dq' && players . length === 1
0 commit comments