@m3rcena/weky
Version:
A fun npm package to play games within Discord with buttons!
254 lines (253 loc) • 8.9 kB
JavaScript
import chalk from "chalk";
import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
import { checkPackageUpdates, createEmbed } from "../functions/functions.js";
import { OptionsChecking } from "../functions/OptionChecking.js";
const Snake = async (options) => {
OptionsChecking(options, "snake");
let interaction;
if (options.interaction.author) {
interaction = options.interaction;
}
else {
interaction = options.interaction;
}
if (!interaction)
throw new Error(chalk.red("[@m3rcena/weky] Snake Error:") + " No interaction provided.");
let client = options.client;
let id = "";
if (options.interaction.author) {
id = options.interaction.author.id;
}
else {
id = options.interaction.user.id;
}
;
if (!interaction.guild) {
throw new Error(chalk.red("[@m3rcena/weky] Snake Error:") + " Guild is not available in this interaction.");
}
;
if (!interaction.channel || !interaction.channel.isSendable()) {
throw new Error(chalk.red("[@m3rcena/weky] Snake Error:") + " Channel is not available in this interaction.");
}
;
const snake = [{ x: 5, y: 5 }];
let apple = { x: 1, y: 1 };
let snakeLength = 1;
const gameBoard = [];
let score = 0;
let foods = ['🍎', '🍇', '🍊', '🥕', '🥝', '🌽'];
let baseDescription = options.embed.description;
if (!options.emojis) {
options.emojis = {
up: "⬆️",
down: "⬇️",
left: "⬅️",
right: "➡️",
stop: "🛑",
board: "⬛",
food: "🍎"
};
}
;
if (!options.snake) {
options.snake = {
head: "🟢",
body: "🟩",
tail: "🟢",
skull: "💀"
};
}
for (let y = 0; y < 10; y++) {
for (let x = 0; x < 15; x++) {
gameBoard[y * 15 + x] = options.emojis.board ? options.emojis.board : "⬛";
}
}
;
function getBoardContent(isSkull) {
const emojis = options.snake ? options.snake : {
head: "🟢",
body: "🟩",
tail: "🟢",
skull: "💀"
};
let board = '';
for (let y = 0; y < 10; y++) {
for (let x = 0; x < 15; x++) {
if (x == apple.x && y == apple.y) {
board += options.emojis.food ? options.emojis.food : "🍎";
continue;
}
;
const isSnakeBody = isSnake({ x: x, y: y });
if (isSnakeBody) {
const pos = snake.indexOf(isSnakeBody);
if (pos === 0) {
const isHead = (!isSkull || snakeLength >= (10 * 15));
board += isHead ? emojis.head : emojis.skull;
}
else if (pos === snake.length - 1) {
board += emojis.tail;
}
else {
board += emojis.body;
}
}
;
if (!isSnakeBody) {
board += gameBoard[y * 15 + x];
}
;
}
board += '\n';
}
;
return board;
}
;
function isSnake(pos) {
return snake.find(snake => (snake.x === pos.x && snake.y === pos.y)) ?? false;
}
;
function updateFoodLoc() {
let applePos = { x: 0, y: 0 };
do {
applePos = { x: Math.floor(Math.random() * 15), y: Math.floor(Math.random() * 10) };
} while (isSnake(applePos));
if (!options.emojis.food) {
options.emojis.food = "🍎";
}
if (foods.length) {
options.emojis.food = foods[Math.floor(Math.random() * foods.length)];
}
;
apple = { x: applePos.x, y: applePos.y };
}
;
const emojis = options.emojis ? options.emojis : {
up: "⬆️",
down: "⬇️",
left: "⬅️",
right: "➡️",
stop: "🛑",
board: "⬛",
food: "🍎"
};
updateFoodLoc();
options.embed.title = options.embed.title ?? "Snake Game";
options.embed.description = baseDescription.replace('{{score}}', score.toString()).replace('{{board}}', getBoardContent(false)) ?? `**Score:** ${score}\n\n${getBoardContent(false)}`;
let embed = createEmbed(options.embed);
const up = new ButtonBuilder()
.setEmoji(emojis.up)
.setStyle(ButtonStyle.Primary)
.setCustomId("weky-snake_up");
const down = new ButtonBuilder()
.setEmoji(emojis.down)
.setStyle(ButtonStyle.Primary)
.setCustomId("weky-snake_down");
const left = new ButtonBuilder()
.setEmoji(emojis.left)
.setStyle(ButtonStyle.Primary)
.setCustomId("weky-snake_left");
const right = new ButtonBuilder()
.setEmoji(emojis.right)
.setStyle(ButtonStyle.Primary)
.setCustomId("weky-snake_right");
const stop = new ButtonBuilder()
.setEmoji(emojis.stop)
.setStyle(ButtonStyle.Danger)
.setCustomId("weky-snake_stop");
const dis1 = new ButtonBuilder()
.setLabel(`\u200b`)
.setStyle(ButtonStyle.Secondary)
.setCustomId("weky-snake_dis1")
.setDisabled(true);
const dis2 = new ButtonBuilder()
.setLabel(`\u200b`)
.setStyle(ButtonStyle.Secondary)
.setCustomId("weky-snake_dis2")
.setDisabled(true);
const row1 = new ActionRowBuilder().addComponents(dis1, up, dis2, stop);
const row2 = new ActionRowBuilder().addComponents(left, down, right);
const msg = await options.interaction.reply({
embeds: [embed],
components: [row1, row2]
});
const collector = msg.createMessageComponentCollector({
time: options.time ? options.time : 60000
});
collector.on("collect", async (btn) => {
await btn.deferUpdate();
if (btn.user.id !== id) {
return btn.followUp({
content: "This is not your game!",
ephemeral: true
});
}
;
const snakeHead = snake[0];
const nextPos = { x: snakeHead.x, y: snakeHead.y };
const buttonId = btn.customId.split("_")[1];
if (buttonId === 'left') {
nextPos.x = (snakeHead.x - 1);
}
else if (buttonId === 'right') {
nextPos.x = (snakeHead.x + 1);
}
else if (buttonId === 'down') {
nextPos.y = (snakeHead.y + 1);
}
else if (buttonId === 'up') {
nextPos.y = (snakeHead.y - 1);
}
;
if (nextPos.x < 0 || (nextPos.x >= 15)) {
nextPos.x = (nextPos.x < 0) ? 0 : 14;
return collector.stop();
}
;
if (nextPos.y < 0 || (nextPos.y >= 10)) {
nextPos.y = (nextPos.y < 0) ? 0 : 9;
return collector.stop();
}
;
if (isSnake(nextPos) || buttonId === 'stop') {
return collector.stop();
}
else {
snake.unshift(nextPos);
if (apple.x === snake[0].x && apple.y === snake[0].y) {
score += 1;
snakeLength += 1;
updateFoodLoc();
}
else if (snake.length > snakeLength) {
snake.pop();
}
const newBoardContent = getBoardContent(false);
options.embed.description = baseDescription ? baseDescription.replace("{{score}}", `${score}`).replace("{{board}}", `${newBoardContent}`) : `**Score:** ${score}\n\n${newBoardContent}`;
let embd = createEmbed(options.embed);
return msg.edit({ embeds: [embd] });
}
});
collector.on("end", async (_, reason) => {
if (reason === 'time' || reason === 'user') {
options.embed.description = baseDescription.replace('{{board}}', getBoardContent(true)) ?? `**Game Over!**\n\n**Score:** ${score}\n\n${getBoardContent(true)}`;
let embed = createEmbed(options.embed);
up.setDisabled(true);
down.setDisabled(true);
left.setDisabled(true);
right.setDisabled(true);
stop.setDisabled(true);
dis1.setDisabled(true);
dis2.setDisabled(true);
const row1 = new ActionRowBuilder().addComponents(dis1, up, dis2, stop);
const row2 = new ActionRowBuilder().addComponents(left, down, right);
return msg.edit({
embeds: [embed],
components: [row1, row2]
});
}
});
checkPackageUpdates("Snake", options.notifyUpdate);
};
export default Snake;