Skip to content

Commit 1726ede

Browse files
committed
games: Add forcewin
1 parent 7b4285e commit 1726ede

3 files changed

Lines changed: 27 additions & 11 deletions

File tree

src/i18n/languages/english.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export default {
8181
STASHED: 'Successfully stashed game {{id}}.',
8282
SUB: '{{out}} has been subbed with {{in}}!',
8383
DQ: '{{player}} has been disqualified from the game.',
84+
FORCE_WIN: '{{player}} was given the win for game {{id}}!',
8485
FORFEIT: 'You have forfeited the game.',
8586
REMOVED: '{{player}} has been removed from the game.',
8687
LEFT: 'You have left the game.',

src/ps/commands/games/core.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -328,15 +328,15 @@ export const command: PSCommand[] = Object.entries(Games).map(([_gameId, Game]):
328328
if (!game.started) game.signups();
329329
},
330330
},
331-
forcewin: {
331+
...conditionalCommand(Game.meta.players === 'many', {
332332
name: 'forcewin',
333333
aliases: ['fwin', 'win'],
334334
help: 'Forces the winner of a game.',
335335
perms: 'driver',
336336
syntax: 'CMD [#id], [user]',
337-
async run({ arg, message, $T }) {
338-
const [_gameId, _userId] = arg.lazySplit(',', 1);
339-
const gameId = '#' + toId(_gameId);
337+
async run({ arg, $T }) {
338+
const [_gameId, _userId = ''] = arg.lazySplit(',', 1);
339+
const gameId = '#' + toId(_gameId).toUpperCase();
340340
const userId = toId(_userId);
341341
if (!userId) throw new ChatError('You must specify the game ID for forcewin!' as ToTranslate);
342342
const game = PSGames[Game.meta.id]?.[gameId];
@@ -345,9 +345,9 @@ export const command: PSCommand[] = Object.entries(Games).map(([_gameId, Game]):
345345
if (!player) throw new ChatError($T('GAME.IMPOSTOR_ALERT'));
346346

347347
// UGO-CODE
348-
// TODO
348+
game.forceWin(player);
349349
},
350-
},
350+
}),
351351
rejoin: {
352352
name: 'rejoin',
353353
aliases: ['rj'],

src/ps/games/game.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)