wynham-games 1.0.0-beta.13 → 1.0.0-beta.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +149 -153
- package/dist/games/Connect4.d.ts +6 -8
- package/dist/games/Connect4.d.ts.map +1 -1
- package/dist/games/Connect4.js +44 -105
- package/dist/games/Connect4.js.map +1 -1
- package/dist/games/Hangman.d.ts +8 -9
- package/dist/games/Hangman.d.ts.map +1 -1
- package/dist/games/Hangman.js +83 -140
- package/dist/games/Hangman.js.map +1 -1
- package/dist/games/RPS.d.ts +12 -110
- package/dist/games/RPS.d.ts.map +1 -1
- package/dist/games/RPS.js +63 -226
- package/dist/games/RPS.js.map +1 -1
- package/dist/games/Snake.d.ts +6 -9
- package/dist/games/Snake.d.ts.map +1 -1
- package/dist/games/Snake.js +68 -108
- package/dist/games/Snake.js.map +1 -1
- package/dist/games/TicTacToe.d.ts +8 -9
- package/dist/games/TicTacToe.d.ts.map +1 -1
- package/dist/games/TicTacToe.js +75 -131
- package/dist/games/TicTacToe.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/locales/en/en-US.d.ts +8 -5
- package/dist/locales/en/en-US.d.ts.map +1 -1
- package/dist/locales/en/en-US.js +15 -12
- package/dist/locales/en/en-US.js.map +1 -1
- package/dist/locales/es/es.d.ts +8 -5
- package/dist/locales/es/es.d.ts.map +1 -1
- package/dist/locales/es/es.js +15 -12
- package/dist/locales/es/es.js.map +1 -1
- package/dist/locales/fr/fr.d.ts +8 -5
- package/dist/locales/fr/fr.d.ts.map +1 -1
- package/dist/locales/fr/fr.js +15 -12
- package/dist/locales/fr/fr.js.map +1 -1
- package/dist/locales/index.d.ts +32 -124
- package/dist/locales/index.d.ts.map +1 -1
- package/dist/locales/index.js +1 -1
- package/dist/locales/index.js.map +1 -1
- package/dist/locales/it/it.d.ts +8 -5
- package/dist/locales/it/it.d.ts.map +1 -1
- package/dist/locales/it/it.js +15 -12
- package/dist/locales/it/it.js.map +1 -1
- package/dist/structures/BaseGame.d.ts +39 -0
- package/dist/structures/BaseGame.d.ts.map +1 -0
- package/dist/structures/BaseGame.js +87 -0
- package/dist/structures/BaseGame.js.map +1 -0
- package/dist/structures/Errors.d.ts +96 -0
- package/dist/structures/Errors.d.ts.map +1 -0
- package/dist/structures/Errors.js +264 -0
- package/dist/structures/Errors.js.map +1 -0
- package/dist/structures/GameManager.d.ts +18 -13
- package/dist/structures/GameManager.d.ts.map +1 -1
- package/dist/structures/GameManager.js +136 -142
- package/dist/structures/GameManager.js.map +1 -1
- package/dist/structures/Types.d.ts +152 -66
- package/dist/structures/Types.d.ts.map +1 -1
- package/dist/structures/Types.js +42 -8
- package/dist/structures/Types.js.map +1 -1
- package/dist/structures/Utils.d.ts +24 -27
- package/dist/structures/Utils.d.ts.map +1 -1
- package/dist/structures/Utils.js +90 -100
- package/dist/structures/Utils.js.map +1 -1
- package/dist/variables/Game.d.ts +0 -1
- package/dist/variables/Game.d.ts.map +1 -1
- package/dist/variables/Game.js +11 -77
- package/dist/variables/Game.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,24 +1,15 @@
|
|
|
1
1
|
# wynham-games
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Mini-games for Discord bots, built on [discord.js](https://discord.js.org/). You get Connect Four, Tic-Tac-Toe, Rock Paper Scissors, Hangman and Snake, each started with one call.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
- 🎮 **5 ready-to-play games** — Connect Four, Tic-Tac-Toe, Rock Paper Scissors, Hangman and Snake.
|
|
10
|
-
- 🤖 **Play against the bot** — set player 2 to your client user and pick a difficulty (`Easy` → `Impossible`).
|
|
11
|
-
- 👥 **Player-vs-player invites** — the challenged user gets an Accept / Decline prompt before the game starts.
|
|
12
|
-
- 🛡️ **Anti-spam & cooldowns** — built-in protection so the same users can't flood your bot with games.
|
|
13
|
-
- 🌍 **i18n out of the box** — English, French, Spanish and Italian, selectable per manager or per game.
|
|
14
|
-
- 🎨 **Theming** — customise embed colors, emojis, titles and input mode (buttons or select menu).
|
|
5
|
+
The library handles the boring parts for you: the invite your opponent accepts or declines, turn timers, anti-spam cooldowns, a Tic-Tac-Toe bot with four difficulty levels, and translations in English, French, Spanish and Italian.
|
|
15
6
|
|
|
16
7
|
## Requirements
|
|
17
8
|
|
|
18
|
-
- Node.js
|
|
19
|
-
-
|
|
9
|
+
- Node.js 22 or later (22, 24 and 26 are the versions Node.js still maintains)
|
|
10
|
+
- discord.js `^14.23.0`, installed in your bot (it is a peer dependency)
|
|
20
11
|
|
|
21
|
-
|
|
12
|
+
The boards use Components V2 and the modal `LabelBuilder`. Older discord.js versions don't ship them, so 14.23.0 is the minimum.
|
|
22
13
|
|
|
23
14
|
## Installation
|
|
24
15
|
|
|
@@ -28,25 +19,21 @@ npm install wynham-games@beta discord.js
|
|
|
28
19
|
|
|
29
20
|
## Quick start
|
|
30
21
|
|
|
31
|
-
|
|
22
|
+
Create one `GameManager` next to your client, then call `createGame` from your slash commands.
|
|
32
23
|
|
|
33
24
|
```ts
|
|
34
25
|
import { Client, GatewayIntentBits } from "discord.js";
|
|
35
26
|
import { GameManager, GameNameType } from "wynham-games";
|
|
36
27
|
|
|
37
28
|
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
|
38
|
-
|
|
39
|
-
// Create the manager once, ideally next to your client setup.
|
|
40
29
|
const games = new GameManager(client);
|
|
41
30
|
|
|
42
31
|
client.on("interactionCreate", async interaction => {
|
|
43
32
|
if (!interaction.isChatInputCommand()) return;
|
|
44
33
|
|
|
45
34
|
if (interaction.commandName === "connect4") {
|
|
46
|
-
const opponent = interaction.options.getUser("opponent", true);
|
|
47
|
-
|
|
48
35
|
await games.createGame(GameNameType.Connect4, interaction, {
|
|
49
|
-
players: [interaction.user, opponent],
|
|
36
|
+
players: [interaction.user, interaction.options.getUser("opponent", true)],
|
|
50
37
|
});
|
|
51
38
|
}
|
|
52
39
|
});
|
|
@@ -54,83 +41,83 @@ client.on("interactionCreate", async interaction => {
|
|
|
54
41
|
client.login(process.env.TOKEN);
|
|
55
42
|
```
|
|
56
43
|
|
|
57
|
-
|
|
44
|
+
`createGame` defers the reply if you haven't, sends the invite, waits for the answer and runs the game until it ends.
|
|
58
45
|
|
|
59
|
-
##
|
|
60
|
-
|
|
61
|
-
### Constructor
|
|
46
|
+
## GameManager
|
|
62
47
|
|
|
63
48
|
```ts
|
|
64
49
|
new GameManager(client: Client, options?: GameManagerOptions)
|
|
65
50
|
```
|
|
66
51
|
|
|
67
|
-
| Option | Type | Default | Description
|
|
68
|
-
| ----------------- | --------- | ------------------ |
|
|
69
|
-
| `antiSpam.enable` | `boolean` | `true` |
|
|
70
|
-
| `antiSpam.time` | `number` | `5000` |
|
|
71
|
-
| `locale` | `Locale` | `Locale.EnglishUS` |
|
|
52
|
+
| Option | Type | Default | Description |
|
|
53
|
+
| ----------------- | --------- | ------------------ | ----------------------------------------------------------- |
|
|
54
|
+
| `antiSpam.enable` | `boolean` | `true` | Blocks the same players from starting games back to back. |
|
|
55
|
+
| `antiSpam.time` | `number` | `5000` | Anti-spam cooldown, in milliseconds. |
|
|
56
|
+
| `locale` | `Locale` | `Locale.EnglishUS` | Language of every game. A game's own `locale` overrides it. |
|
|
57
|
+
| `colors.play` | `number` | `0x5865f2` | Board color while a game runs. |
|
|
58
|
+
| `colors.win` | `number` | `0xffd700` | Board color when someone wins. |
|
|
59
|
+
| `colors.end` | `number` | `0x808080` | Board color on a draw, a loss or a timeout. |
|
|
60
|
+
|
|
61
|
+
The colors apply to every game and menu of the manager. A game's `theme.colors` still wins over them, so you can set your brand colors once and tweak a single game when you need to.
|
|
72
62
|
|
|
73
63
|
```ts
|
|
74
64
|
import { Locale } from "discord.js";
|
|
75
65
|
|
|
76
66
|
const games = new GameManager(client, {
|
|
77
|
-
antiSpam: {
|
|
67
|
+
antiSpam: { time: 10_000 },
|
|
78
68
|
locale: Locale.French,
|
|
69
|
+
colors: { play: 0x2b2d31, win: 0x57f287 },
|
|
79
70
|
});
|
|
80
71
|
```
|
|
81
72
|
|
|
82
|
-
###
|
|
83
|
-
|
|
84
|
-
Validates the players, displays the invitation/difficulty menu when needed, and launches the game.
|
|
73
|
+
### createGame(gameName, interaction, options)
|
|
85
74
|
|
|
86
75
|
```ts
|
|
87
|
-
createGame(gameName:
|
|
76
|
+
createGame<G extends GameNameType>(gameName: G, interaction: Interaction, options: GameOptionsMap[G]): Promise<void>
|
|
88
77
|
```
|
|
89
78
|
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
|
|
94
|
-
The method is overloaded, so TypeScript infers the correct options type from the `gameName` you pass.
|
|
79
|
+
- `gameName`: a `GameNameType` value.
|
|
80
|
+
- `interaction`: a repliable interaction, usually a slash command.
|
|
81
|
+
- `options`: the options of that game. TypeScript picks the right type from `gameName`, so passing `players` to Snake or `lifeCount` to Connect Four fails to compile.
|
|
95
82
|
|
|
96
|
-
|
|
83
|
+
### Who can play against whom
|
|
97
84
|
|
|
98
|
-
|
|
85
|
+
- **Connect Four** and **Hangman** need two humans. The second player gets an Accept / Decline invite.
|
|
86
|
+
- **Rock Paper Scissors** accepts a bot as player 2. The game starts at once and the bot picks at random.
|
|
87
|
+
- **Tic-Tac-Toe** accepts a bot as player 2. The challenger picks a difficulty first, unless you set `difficulty`.
|
|
88
|
+
- **Snake** is single-player. It takes a `player` instead of `players` and starts without an invite.
|
|
99
89
|
|
|
100
|
-
|
|
101
|
-
- **Tic-Tac-Toe** first shows a difficulty-selection menu, then runs against the bot.
|
|
90
|
+
A player can't challenge themselves, and the challenger can't be a bot.
|
|
102
91
|
|
|
103
|
-
|
|
92
|
+
### Timers
|
|
104
93
|
|
|
105
|
-
|
|
94
|
+
Each game ends after `turnTimeout` seconds without a move. Tic-Tac-Toe, Hangman, Rock Paper Scissors and Snake show a live countdown under the board ("The game ends in 25 seconds if nobody plays."). In Connect Four, a missed turn passes to the other player, and the game is cancelled once both players miss in a row.
|
|
106
95
|
|
|
107
|
-
|
|
96
|
+
Connect Four and Hangman mention the player whose turn it is, so the message lights up for them. Discord doesn't send a notification for a mention added by an edit, though.
|
|
108
97
|
|
|
109
|
-
##
|
|
110
|
-
|
|
111
|
-
Every option object shares the `players` field and most share `turnTimeout`, `locale`, `theme` and `lang`. The table below lists what is specific to each game.
|
|
98
|
+
## Game options
|
|
112
99
|
|
|
113
100
|
### Shared options
|
|
114
101
|
|
|
115
|
-
| Option | Type | Default
|
|
116
|
-
| ------------------ | -------------- |
|
|
117
|
-
| `players` | `[User, User]` |
|
|
118
|
-
| `turnTimeout` | `number` | `30`
|
|
119
|
-
| `locale` | `Locale` | manager
|
|
120
|
-
| `theme.colors` | `object` |
|
|
121
|
-
| `lang.title` | `string` | game name
|
|
122
|
-
| `lang.inviteTitle` | `string` | `"… Challenge"`
|
|
123
|
-
|
|
124
|
-
###
|
|
125
|
-
|
|
126
|
-
| Option | Type
|
|
127
|
-
| ---------------------- |
|
|
128
|
-
| `theme.emojis.player1` | `string`
|
|
129
|
-
| `theme.emojis.player2` | `string`
|
|
130
|
-
| `theme.emojis.empty` | `string`
|
|
131
|
-
| `theme.emojis.win` | `string`
|
|
132
|
-
| `theme.inputType` | `InputType`
|
|
133
|
-
| `theme.buttonStyle` | `ButtonStyle` | `Primary` |
|
|
102
|
+
| Option | Type | Default | Description |
|
|
103
|
+
| ------------------ | -------------- | --------------- | ------------------------------------------------------------ |
|
|
104
|
+
| `players` | `[User, User]` | required | Challenger first, opponent second. |
|
|
105
|
+
| `turnTimeout` | `number` | `30` | Seconds without a move before the game ends, from 15 to 360. |
|
|
106
|
+
| `locale` | `Locale` | manager locale | Language of this game only. |
|
|
107
|
+
| `theme.colors` | `object` | manager colors | Board colors for this game only. |
|
|
108
|
+
| `lang.title` | `string` | game name | Title on the board. |
|
|
109
|
+
| `lang.inviteTitle` | `string` | `"… Challenge"` | Title of the invite. |
|
|
110
|
+
|
|
111
|
+
### Connect Four: `Connect4Options`
|
|
112
|
+
|
|
113
|
+
| Option | Type | Default | Description |
|
|
114
|
+
| ---------------------- | ------------- | --------- | ------------------------------------------------- |
|
|
115
|
+
| `theme.emojis.player1` | `string` | `🔴` | Player 1 pieces. |
|
|
116
|
+
| `theme.emojis.player2` | `string` | `🟡` | Player 2 pieces. |
|
|
117
|
+
| `theme.emojis.empty` | `string` | `⬛` | Empty cells. |
|
|
118
|
+
| `theme.emojis.win` | `string` | `⚪` | Pieces of the winning line. |
|
|
119
|
+
| `theme.inputType` | `InputType` | `Buttons` | Pick a column with buttons or with a select menu. |
|
|
120
|
+
| `theme.buttonStyle` | `ButtonStyle` | `Primary` | `Primary`, `Secondary`, `Success` or `Danger`. |
|
|
134
121
|
|
|
135
122
|
```ts
|
|
136
123
|
import { GameNameType, InputType } from "wynham-games";
|
|
@@ -141,135 +128,144 @@ await games.createGame(GameNameType.Connect4, interaction, {
|
|
|
141
128
|
turnTimeout: 45,
|
|
142
129
|
theme: {
|
|
143
130
|
emojis: { player1: "🔵", player2: "🔴" },
|
|
144
|
-
inputType: InputType.
|
|
131
|
+
inputType: InputType.SelectMenu,
|
|
145
132
|
buttonStyle: ButtonStyle.Success,
|
|
146
133
|
},
|
|
147
134
|
});
|
|
148
135
|
```
|
|
149
136
|
|
|
150
|
-
###
|
|
137
|
+
### Tic-Tac-Toe: `TicTacToeOptions`
|
|
151
138
|
|
|
152
|
-
| Option | Type | Default | Description
|
|
153
|
-
| ---------------------- | --------------- | ------- |
|
|
154
|
-
| `difficulty` | `BotDifficulty` |
|
|
155
|
-
| `theme.emojis.player1` | `string` | `❌` | Player 1 marks.
|
|
156
|
-
| `theme.emojis.player2` | `string` | `⭕` | Player 2 marks.
|
|
157
|
-
| `theme.emojis.empty` | `string` | `⬜` | Empty cells.
|
|
139
|
+
| Option | Type | Default | Description |
|
|
140
|
+
| ---------------------- | --------------- | ------- | ------------------------------------------ |
|
|
141
|
+
| `difficulty` | `BotDifficulty` | menu | Bot strength, used when player 2 is a bot. |
|
|
142
|
+
| `theme.emojis.player1` | `string` | `❌` | Player 1 marks. |
|
|
143
|
+
| `theme.emojis.player2` | `string` | `⭕` | Player 2 marks. |
|
|
144
|
+
| `theme.emojis.empty` | `string` | `⬜` | Empty cells. |
|
|
158
145
|
|
|
159
|
-
|
|
146
|
+
| Difficulty | Bot behaviour |
|
|
147
|
+
| ------------ | ---------------------------------------------- |
|
|
148
|
+
| `Easy` | Random moves. |
|
|
149
|
+
| `Normal` | Best move half the time, random otherwise. |
|
|
150
|
+
| `Hard` | Best move 80% of the time. |
|
|
151
|
+
| `Impossible` | Best move every turn (minimax). You can't win. |
|
|
160
152
|
|
|
161
|
-
|
|
162
|
-
| ------------ | ---------------------------------------------------------- |
|
|
163
|
-
| `Easy` | Always plays a random move. |
|
|
164
|
-
| `Normal` | Plays the optimal move ~50% of the time, random otherwise. |
|
|
165
|
-
| `Hard` | Plays the optimal move ~80% of the time. |
|
|
166
|
-
| `Impossible` | Always optimal (minimax, unbeatable). |
|
|
153
|
+
Leave `difficulty` out and the challenger picks it from a menu before the game. Set it and the game starts straight away.
|
|
167
154
|
|
|
168
|
-
###
|
|
155
|
+
### Rock Paper Scissors: `RPSOptions`
|
|
169
156
|
|
|
170
|
-
| Option | Type | Default |
|
|
171
|
-
| ----------------------- | -------- | ------- |
|
|
172
|
-
| `theme.emojis.rock` | `string` | `✊` |
|
|
173
|
-
| `theme.emojis.paper` | `string` | `🤚` |
|
|
174
|
-
| `theme.emojis.scissors` | `string` | `✌️` |
|
|
157
|
+
| Option | Type | Default |
|
|
158
|
+
| ----------------------- | -------- | ------- |
|
|
159
|
+
| `theme.emojis.rock` | `string` | `✊` |
|
|
160
|
+
| `theme.emojis.paper` | `string` | `🤚` |
|
|
161
|
+
| `theme.emojis.scissors` | `string` | `✌️` |
|
|
175
162
|
|
|
176
|
-
|
|
163
|
+
If only one player picks before the timer runs out, that player wins by default.
|
|
177
164
|
|
|
178
|
-
|
|
179
|
-
| ----------- | ------- | ------- | -------------------------------- |
|
|
180
|
-
| `lifeCount` | `1`–`9` | `6` | Number of wrong guesses allowed. |
|
|
165
|
+
### Hangman: `HangmanOptions`
|
|
181
166
|
|
|
182
|
-
|
|
167
|
+
| Option | Type | Default | Description |
|
|
168
|
+
| ----------- | ---------- | ------- | ------------------------------ |
|
|
169
|
+
| `lifeCount` | `1` to `9` | `6` | Wrong guesses before you lose. |
|
|
183
170
|
|
|
184
|
-
|
|
171
|
+
Players take turns picking a letter or guessing the whole word. A wrong word costs two lives. The word list comes from the locale, so a French game gives French words.
|
|
185
172
|
|
|
186
|
-
|
|
173
|
+
### Snake: `SnakeOptions`
|
|
187
174
|
|
|
188
|
-
| Option | Type | Default
|
|
189
|
-
| -------------------- | -------- |
|
|
190
|
-
| `player` | `User` |
|
|
191
|
-
| `
|
|
192
|
-
| `
|
|
193
|
-
| `
|
|
194
|
-
| `theme.
|
|
195
|
-
| `theme.emojis.
|
|
196
|
-
| `theme.emojis.
|
|
197
|
-
| `theme.emojis.
|
|
198
|
-
| `theme.emojis.empty` | `string` | `⬛` | Empty cells. |
|
|
199
|
-
| `lang.title` | `string` | `"Snake"` | Title shown on the game board. |
|
|
175
|
+
| Option | Type | Default | Description |
|
|
176
|
+
| -------------------- | -------- | ------------- | ------------------------------------------ |
|
|
177
|
+
| `player` | `User` | required | The player. Bots are refused. |
|
|
178
|
+
| `boardWidth` | `number` | `10` | Width in cells, clamped between 5 and 12. |
|
|
179
|
+
| `boardHeight` | `number` | `10` | Height in cells, clamped between 5 and 12. |
|
|
180
|
+
| `theme.colors.lose` | `number` | manager `end` | Color on game over or timeout. |
|
|
181
|
+
| `theme.emojis.head` | `string` | `🟢` | Head. |
|
|
182
|
+
| `theme.emojis.body` | `string` | `🟩` | Body. |
|
|
183
|
+
| `theme.emojis.food` | `string` | `🍎` | Food. |
|
|
184
|
+
| `theme.emojis.empty` | `string` | `⬛` | Empty cells. |
|
|
200
185
|
|
|
201
|
-
|
|
186
|
+
Snake also takes `turnTimeout`, `locale` and `lang.title`. Each arrow button moves the snake one cell and ⏹️ quits. Eating an apple adds a point. Hitting a wall or your own tail ends the game, and filling the whole board wins it.
|
|
202
187
|
|
|
203
188
|
```ts
|
|
204
|
-
import { GameNameType } from "wynham-games";
|
|
205
|
-
|
|
206
189
|
await games.createGame(GameNameType.Snake, interaction, {
|
|
207
190
|
player: interaction.user,
|
|
208
|
-
boardWidth:
|
|
209
|
-
boardHeight:
|
|
191
|
+
boardWidth: 8,
|
|
192
|
+
boardHeight: 8,
|
|
210
193
|
});
|
|
211
194
|
```
|
|
212
195
|
|
|
213
|
-
##
|
|
196
|
+
## Languages
|
|
214
197
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
| Locale | Enum value |
|
|
198
|
+
| Language | Value |
|
|
218
199
|
| ------------ | ------------------ |
|
|
219
200
|
| English (US) | `Locale.EnglishUS` |
|
|
220
201
|
| French | `Locale.French` |
|
|
221
|
-
| Spanish
|
|
202
|
+
| Spanish | `Locale.SpanishES` |
|
|
222
203
|
| Italian | `Locale.Italian` |
|
|
223
204
|
|
|
224
|
-
|
|
205
|
+
To speak each player's language, pass `interaction.locale` (or `interaction.guildLocale`) as the game's `locale`. An unsupported locale falls back to English.
|
|
225
206
|
|
|
226
207
|
```ts
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
208
|
+
await games.createGame(GameNameType.Hangman, interaction, {
|
|
209
|
+
players: [interaction.user, opponent],
|
|
210
|
+
locale: interaction.locale,
|
|
211
|
+
});
|
|
230
212
|
```
|
|
231
213
|
|
|
232
|
-
|
|
214
|
+
The `GameManager` constructor rejects an unsupported `locale` with a `LocaleNotSupported` error.
|
|
215
|
+
|
|
216
|
+
## Errors
|
|
217
|
+
|
|
218
|
+
The library wraps every Discord call it makes. Raw `DiscordAPIError`s come back as a `WynhamGamesError` with a stable `code`, so you never compare Discord error numbers yourself.
|
|
233
219
|
|
|
234
|
-
|
|
220
|
+
Some failures only mean the game can't go on: the message was deleted (`10008`), the interaction expired (`10062`, `50027`), the channel is gone (`10003`), the interaction was already answered (`40060`) or the thread got archived (`50083`). The game then stops quietly and nothing is thrown.
|
|
221
|
+
|
|
222
|
+
Anything else throws. That covers missing permissions (`50013`), missing access (`50001`), an invalid payload (`50035`), rate limits and network errors. `createGame()` rejects, and your command handler can catch it:
|
|
235
223
|
|
|
236
224
|
```ts
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
Normal,
|
|
247
|
-
Hard,
|
|
248
|
-
Impossible,
|
|
249
|
-
}
|
|
250
|
-
enum InputType {
|
|
251
|
-
SelectMenu,
|
|
252
|
-
Buttons,
|
|
253
|
-
}
|
|
254
|
-
enum Choice {
|
|
255
|
-
Rock,
|
|
256
|
-
Paper,
|
|
257
|
-
Scissors,
|
|
258
|
-
}
|
|
259
|
-
enum InviteResult {
|
|
260
|
-
Accepted,
|
|
261
|
-
Declined,
|
|
262
|
-
Timeout,
|
|
225
|
+
import { MessageFlags } from "discord.js";
|
|
226
|
+
import { GameNameType, WynhamGamesError, WynhamErrorCode } from "wynham-games";
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
await games.createGame(GameNameType.Snake, interaction, { player: interaction.user });
|
|
230
|
+
} catch (error) {
|
|
231
|
+
if (error instanceof WynhamGamesError && error.code === WynhamErrorCode.MissingPermissions) {
|
|
232
|
+
await interaction.followUp({ content: "I need permission to edit my messages here.", flags: MessageFlags.Ephemeral });
|
|
233
|
+
}
|
|
263
234
|
}
|
|
264
235
|
```
|
|
265
236
|
|
|
237
|
+
A `WynhamGamesError` carries `code`, `discordCode`, `status`, `action` (the discord.js call that failed), `game` and `cause` (the original error).
|
|
238
|
+
|
|
239
|
+
Once `createGame()` has resolved, errors come from collectors and timers that your code can't await. The library logs them with `console.error` instead of crashing your bot. Send them to your own logger with `setErrorHandler`:
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
import { setErrorHandler } from "wynham-games";
|
|
243
|
+
|
|
244
|
+
setErrorHandler(error => logger.error({ code: error.code, game: error.game }, error.message));
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Bad options throw the same error type before anything reaches Discord: `ClientMissing`, `LocaleNotSupported`, `InvalidAntiSpamTime`, `InvalidColor`, `InvalidTurnTimeout`, `InvalidLifeCount` and `InteractionNotRepliable`.
|
|
248
|
+
|
|
249
|
+
The guarded helpers are exported if you want the same behaviour in your own code: `safeDiscordCall`, `safeEdit`, `safeFollowUp`, `safeReply`, `safeNotify`, `safeUpdate`, `safeDeferUpdate`, `safeMessageEdit`, `toWynhamError` and `isWynhamGamesError`.
|
|
250
|
+
|
|
251
|
+
## Enums
|
|
252
|
+
|
|
253
|
+
| Enum | Values |
|
|
254
|
+
| ----------------- | ------------------------------------------------------------------------ |
|
|
255
|
+
| `GameNameType` | `Connect4`, `RPS`, `TicTacToe`, `Hangman`, `Snake` |
|
|
256
|
+
| `BotDifficulty` | `Easy`, `Normal`, `Hard`, `Impossible` |
|
|
257
|
+
| `InputType` | `Buttons`, `SelectMenu` |
|
|
258
|
+
| `Choice` | `Rock`, `Paper`, `Scissors` |
|
|
259
|
+
| `DiscordAction` | `EditReply`, `FollowUp`, `Reply`, `Update`, `DeferUpdate`, `EditMessage` |
|
|
260
|
+
| `WynhamErrorCode` | See [Errors](#errors) and `src/structures/Types.ts`. |
|
|
261
|
+
|
|
266
262
|
## Building from source
|
|
267
263
|
|
|
268
264
|
```bash
|
|
269
|
-
npm run build
|
|
270
|
-
npm run format
|
|
265
|
+
npm run build # tsc && tsc-alias
|
|
266
|
+
npm run format # prettier --write .
|
|
271
267
|
```
|
|
272
268
|
|
|
273
269
|
## License
|
|
274
270
|
|
|
275
|
-
MIT
|
|
271
|
+
MIT, by Yanis Hamburger and Stefanoz.
|
package/dist/games/Connect4.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BaseGame } from "../structures/BaseGame.js";
|
|
2
|
+
import { type Connect4Options, type GameManagerType, type GameLocale } from "../structures/Types.js";
|
|
2
3
|
import { RepliableInteraction } from "discord.js";
|
|
3
|
-
export default class Connect4
|
|
4
|
-
readonly gameName = GameNameType.Connect4;
|
|
5
|
-
private readonly manager;
|
|
6
|
-
private interaction;
|
|
4
|
+
export default class Connect4 extends BaseGame {
|
|
7
5
|
private readonly players;
|
|
8
6
|
private readonly colors;
|
|
9
7
|
private readonly emojis;
|
|
@@ -17,9 +15,7 @@ export default class Connect4 implements IGame {
|
|
|
17
15
|
private currentPlayer;
|
|
18
16
|
private turnTimer;
|
|
19
17
|
private consecutiveMisses;
|
|
20
|
-
private collector;
|
|
21
18
|
private readonly buttonStyle;
|
|
22
|
-
private readonly cooldownKey;
|
|
23
19
|
constructor(manager: GameManagerType, interaction: RepliableInteraction, options: Connect4Options, gameLocale: GameLocale);
|
|
24
20
|
private cellEmoji;
|
|
25
21
|
private renderBoard;
|
|
@@ -29,10 +25,12 @@ export default class Connect4 implements IGame {
|
|
|
29
25
|
private createButtons;
|
|
30
26
|
private createSelectMenu;
|
|
31
27
|
private buildContainer;
|
|
28
|
+
/** Discord timestamp of the current turn's deadline. */
|
|
29
|
+
private deadline;
|
|
32
30
|
private startTurnTimer;
|
|
33
31
|
private handleTurnTimeout;
|
|
34
32
|
launch(): Promise<void>;
|
|
35
33
|
private playMove;
|
|
36
|
-
|
|
34
|
+
protected cleanup(): void;
|
|
37
35
|
}
|
|
38
36
|
//# sourceMappingURL=Connect4.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Connect4.d.ts","sourceRoot":"","sources":["../../src/games/Connect4.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Connect4.d.ts","sourceRoot":"","sources":["../../src/games/Connect4.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAA2B,KAAK,eAAe,EAAE,KAAK,eAAe,EAAuB,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE/I,OAAO,EAYH,oBAAoB,EAEvB,MAAM,YAAY,CAAC;AAYpB,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,QAAQ;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8C;IACrE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyD;IAChF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAiB;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IAEtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA8B;IAEpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAC9D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAE1C,YAAY,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,oBAAoB,EAAE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAwBxH;IAED,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,QAAQ;IAyBhB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,cAAc;IAatB,wDAAwD;IACxD,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,cAAc;YAOR,iBAAiB;IAczB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAoB5B;YAEa,QAAQ;IA4BtB,UAAmB,OAAO,IAAI,IAAI,CAMjC;CACJ"}
|