Skip to content
This repository was archived by the owner on Sep 1, 2023. It is now read-only.

Commit f8755c7

Browse files
committed
update join mid game option
1 parent 7ec3700 commit f8755c7

File tree

7 files changed

+45
-15
lines changed

7 files changed

+45
-15
lines changed

src/commands/uno.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,20 @@ export const cmd = {
1818
Jump: https://discord.com/channels/${existingGame.message.channel.guild.id}/${existingGame.message.channel.id}/${existingGame.message.id}`);
1919
games[msg.channel.id] = { started: false } as UnoGame<false>;
2020

21-
const data = database.getOrCreate(msg.channel.guild.id, msg.author.id);
21+
const data = database.getOrCreate(msg.guild.id, msg.author.id);
22+
23+
const { canRejoin } = data.preferredSettings;
24+
if (typeof canRejoin === "boolean") {
25+
data.preferredSettings.canRejoin = canRejoin ? "temporarily" : "no";
26+
database.set(msg.guild.id, msg.author.id, { preferredSettings: data.preferredSettings });
27+
}
28+
2229
const gameObj = {
2330
uid: Math.random().toString().substring(2),
2431
started: false,
2532
starting: Math.floor(Date.now() / 1000) + autoStartTimeout,
2633
host: msg.author.id,
27-
settings: data?.preferredSettings,
34+
settings: data.preferredSettings,
2835
players: [msg.author.id],
2936
_allowSolo: args[0]?.toLowerCase() === "solo",
3037
_modified: false,

src/components.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ComponentBuilder } from "@oceanicjs/builders";
22
import { ButtonStyles, ComponentTypes, MessageActionRow } from "oceanic.js";
33

44
import { client, sendMessage } from "./client.js";
5-
import { ButtonIDs, cardEmotes, defaultSettings, SelectIDs, SettingsIDs } from "./constants.js";
5+
import { ButtonIDs, cardEmotes, defaultSettings, maxRejoinableTurnCount, SelectIDs, SettingsIDs } from "./constants.js";
66
import { sendGameMessage } from "./gameLogic/index.js";
77
import { Card, UnoGame } from "./types.js";
88
import { cardArrayToCount, getUsername, next, toHumanReadableTime, toTitleCase } from "./utils.js";
@@ -38,7 +38,7 @@ export const JoinButtons = new ComponentBuilder<MessageActionRow>()
3838
})
3939
.toJSON();
4040

41-
export const GameButtons = ((canRejoin: boolean) => {
41+
export const GameButtons = ((game: UnoGame<true>) => {
4242
const components = new ComponentBuilder<MessageActionRow>()
4343
.addInteractionButton({
4444
style: ButtonStyles.SECONDARY,
@@ -67,7 +67,8 @@ export const GameButtons = ((canRejoin: boolean) => {
6767
style: ButtonStyles.PRIMARY,
6868
customID: ButtonIDs.JOIN_MID_GAME,
6969
label: "Join",
70-
disabled: !canRejoin,
70+
disabled: game.settings.canRejoin === "no"
71+
|| (game.settings.canRejoin === "temporarily" && game.turn > maxRejoinableTurnCount),
7172
emoji: ComponentBuilder.emojiToPartial("➡️", "default")
7273
});
7374
return components.toJSON();
@@ -182,7 +183,19 @@ export const SettingsSelectMenu = (game: UnoGame<false>) => new ComponentBuilder
182183
{
183184
label: "Allow joining mid game",
184185
value: SettingsIDs.ALLOW_REJOINING,
185-
description: game.settings.canRejoin ? "Enabled" : "Disabled"
186+
description: (() => {
187+
switch (game.settings.canRejoin) {
188+
case "no": {
189+
return "Disabled";
190+
}
191+
case "temporarily": {
192+
return "Only quickly after game start";
193+
}
194+
case "permanently": {
195+
return "For the whole game";
196+
}
197+
}
198+
})()
186199
}
187200
]
188201
})

src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export const defaultSettings: UnoGameSettings = {
7979
allowStacking: true,
8080
randomizePlayerList: true,
8181
resendGameMessage: true,
82-
canRejoin: false,
82+
canRejoin: "no",
8383
sevenAndZero: false
8484
} as const;
8585

src/gameLogic/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { AnyTextableGuildChannel, ComponentInteraction, ComponentTypes, Guild, M
33

44
import { client, deleteMessage, sendMessage } from "../client.js";
55
import { GameButtons, SettingsSelectMenu } from "../components.js";
6-
import { ButtonIDs, cardEmojis, cardEmotes, coloredUniqueCards, defaultColor, defaultSettings, maxRejoinableTurnCount, rainbowColors, SelectIDs, SettingsIDs, uniqueVariants, veryLongTime } from "../constants.js";
6+
import { ButtonIDs, cardEmojis, cardEmotes, coloredUniqueCards, defaultColor, defaultSettings, rainbowColors, SelectIDs, SettingsIDs, uniqueVariants, veryLongTime } from "../constants.js";
77
import database from "../database.js";
88
import { config } from "../index.js";
99
import timeouts from "../timeouts.js";
@@ -89,7 +89,7 @@ ${game.players.map((p, i) => makeGameLine(game, p, i)).join("\n")}
8989
.setFooter((game._modified ? "This game will not count towards the leaderboard. " : "")
9090
+ `Timeout is ${toHumanReadableTime(game.settings.timeoutDuration).toLowerCase()}`)
9191
.toJSON()],
92-
components: GameButtons(game.settings.canRejoin && game.turn < maxRejoinableTurnCount)
92+
components: GameButtons(game)
9393
}).then(msg => {
9494
if (!msg) return cancelGameMessageFail(game);
9595

src/gameLogic/notStarted.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { ButtonIDs, cardEmotes, cards, defaultSettings, SettingsIDs, uniqueVaria
77
import database from "../database.js";
88
import timeouts from "../timeouts.js";
99
import { Card, DebugState, DebugStateType, UnoGame } from "../types.js";
10-
import { getPlayerMember, hasStarted, shuffle, toTitleCase, updateStats, without } from "../utils.js";
10+
import { getPlayerMember, hasStarted, next, shuffle, toTitleCase, updateStats, without } from "../utils.js";
1111
import { games, makeStartMessage, sendGameMessage } from "./index.js";
1212

1313
export function makeDrawCardProxy(startedGame: UnoGame<true>, userId: string, t, p, n) {
@@ -198,6 +198,8 @@ export function makeSettingsModal(ctx: ComponentInteraction) {
198198
});
199199
}
200200
export function onSettingsChange(ctx: ComponentInteraction<ComponentTypes.STRING_SELECT>, game: UnoGame<false>) {
201+
const rejoinOptionOrder = ["no", "temporarily", "permanently"] as const;
202+
201203
switch (ctx.data.values.raw[0]) {
202204
case SettingsIDs.KICK_ON_TIMEOUT: {
203205
game.settings.kickOnTimeout = !game.settings.kickOnTimeout;
@@ -224,7 +226,8 @@ export function onSettingsChange(ctx: ComponentInteraction<ComponentTypes.STRING
224226
break;
225227
}
226228
case SettingsIDs.ALLOW_REJOINING: {
227-
game.settings.canRejoin = !game.settings.canRejoin;
229+
// @ts-ignore Argument of type 'readonly ["no", "temporarily", "permanently"]' is not assignable to parameter of type '("no" | "temporarily" | "permanently")[]'.
230+
game.settings.canRejoin = next(rejoinOptionOrder, rejoinOptionOrder.indexOf(game.settings.canRejoin));
228231
break;
229232
}
230233
default: {

src/gameLogic/started.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ButtonStyles, ComponentInteraction, ComponentTypes, MessageActionRow, M
33

44
import { sendMessage } from "../client.js";
55
import { DrawStackedCardSelect, PickCardSelect } from "../components.js";
6-
import { ButtonIDs, cardEmotes } from "../constants.js";
6+
import { ButtonIDs, cardEmotes, maxRejoinableTurnCount } from "../constants.js";
77
import database from "../database.js";
88
import { config } from "../index.js";
99
import { UnoGame } from "../types.js";
@@ -96,16 +96,23 @@ export function onGameButtonPress(ctx: ComponentInteraction<ComponentTypes.BUTTO
9696
content: "You can't rejoin a game you left!",
9797
flags: MessageFlags.EPHEMERAL
9898
});
99+
if (game.settings.canRejoin === "no"
100+
|| (game.settings.canRejoin === "temporarily" && game.turn > maxRejoinableTurnCount))
101+
return ctx.createFollowup({
102+
content: "You can't rejoin this game",
103+
flags: MessageFlags.EPHEMERAL
104+
});
99105

100106
game.players.push(ctx.member.id);
101107
database.getOrCreate(ctx.guild.id, ctx.member.id);
102108
// in ascending order
103109
const cardCounts = Object.values(game.cards).map(c => c.length).sort((a, b) => a - b);
104-
// amount of cards is the same as the player with the highest amount of cards
110+
// amount of cards is the same as the player with the highest amount of cards (minimum of 7)
105111
// but at most 5 above the 2nd highest amount of cards
106112
const highest = cardCounts.pop();
107113
const secondHighest = cardCounts.pop();
108-
const { cards, newDeck } = game.draw(highest > secondHighest + 5 ? secondHighest + 5 : highest);
114+
const { cards, newDeck } = game.draw(Math.min(highest, secondHighest + 5, 7));
115+
109116
game.cards[ctx.member.id] = new Proxy(cards, {
110117
set(t, p, n) {
111118
makeDrawCardProxy(game, ctx.member.id, t, p, n);

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export type UnoGameSettings = {
4949
allowStacking: boolean,
5050
randomizePlayerList: boolean,
5151
resendGameMessage: boolean,
52-
canRejoin: boolean,
52+
canRejoin: "no" | "temporarily" | "permanently",
5353
sevenAndZero: boolean
5454
}
5555
export type UnoGame<T extends boolean> = T extends true ? {

0 commit comments

Comments
 (0)