zewwww - Replit

PHOTO EMBED

Wed Jun 26 2024 20:25:13 GMT+0000 (Coordinated Universal Time)

Saved by @FRTZ

You got it! Here's the full working code for your Discord queue bot, including all the features you requested:

JavaScript

Copy

Insert
const { Client, GatewayIntentBits, Partials, SlashCommandBuilder, REST, Routes, EmbedBuilder, Collection } = require('discord.js');
require('dotenv').config();
 
// Constants
const prefix = process.env.DISCORD_PREFIX || '!';
const eloInitial = 50;
let matchNumber = 1;
 
// Data Structures
const players = new Map();
const queues = new Map();
const matches = new Map();
const matchLogChannel = null; // Will be set later
 
// Helper Functions
const createMatchChannel = async (guild, matchNumber) => {
  return await guild.channels.create(`🏆 - Match - ${matchNumber}`, {
    type: 'text',
    permissionOverwrites: [
      { id: guild.id, deny: ['VIEW_CHANNEL'] },
      { id: client.user.id, allow: ['VIEW_CHANNEL', 'SEND_MESSAGES'] }
    ]
  });
};
 
const createVoiceChannel = async (guild, matchNumber, teamNumber) => {
  return await guild.channels.create(`C${matchNumber} Team ${teamNumber}`, {
    type: 'voice',
    userLimit: 6,
    permissionOverwrites: []
  });
};
 
const sortByElo = (a, b) => {
  const eloA = players.get(a)?.elo || eloInitial;
  const eloB = players.get(b)?.elo || eloInitial;
  return eloB - eloA;
};
 
const getTopPlayers = () => {
  const sortedPlayers = [...players.keys()].sort(sortByElo);
  return sortedPlayers.slice(0, 25);
};
 
const updateQueueMessage = async (queueMessage, queue) => {
  const playersInQueue = queue.members.length;
  const embed = new EmbedBuilder()
    .setTitle(`**${queue.name}**`)
    .setDescription(`Click the ✅ to join the "${queue.name}" queue or ❌ to leave.\n\n**Players**\n${queue.members.map(id => `<@${id}>`).join('\n')}\n\n${playersInQueue} / ${queue.capacity}\n\nPowered by Community Super League`)
    .setColor(0x00FF00);
 
  await queueMessage.edit({ embeds: [embed] });
};
 
const startMatch = async (message, queue) => {
  const guild = message.guild;
  const matchChannel = await createMatchChannel(guild, matchNumber);
 
  // Create voice channels (if needed)
  if (queue.teamSortMode === 'ELO') {
    queue.members.sort(sortByElo);
    const team1 = queue.members.slice(0, queue.capacity / 2);
    const team2 = queue.members.slice(queue.capacity / 2);
    queue.voiceChannels.push(await createVoiceChannel(guild, matchNumber, 1));
    queue.voiceChannels.push(await createVoiceChannel(guild, matchNumber, 2));
    await matchChannel.send(`Welcome to Match ${matchNumber}!`);
    await matchChannel.send(`Team 1: ${team1.map(id => `<@${id}>`).join(', ')}`);
    await matchChannel.send(`Team 2: ${team2.map(id => `<@${id}>`).join(', ')}`);
  } else if (queue.teamSortMode === 'CAPTAINS') {
    const captain1 = queue.members[0];
    const captain2 = queue.members[1];
    queue.captainPicks.captain1 = captain1;
    queue.captainPicks.captain2 = captain2;
    await matchChannel.send(`Welcome to Match ${matchNumber}!`);
    await matchChannel.send(`Captain 1: <@${captain1}>`);
    await matchChannel.send(`Captain 2: <@${captain2}>`);
    // Logic for captain picks
    await createCaptainPickEmbed(matchChannel, queue);
  }
 
  // Store match details
  matches.set(matchNumber, {
    queue: queue.name,
    teams: queue.teamSortMode === 'ELO' ? [queue.members.slice(0, queue.capacity / 2), queue.members.slice(queue.capacity / 2)] : null,
    map: null,
    winner: null,
    matchChannel: matchChannel
  });
 
  // Update match number
  matchNumber++;
 
  // Clear the queue
  queue.members = [];
  updateQueueMessage(queue.queueMessage, queue);
};
 
const createCaptainPickEmbed = async (matchChannel, queue) => {
  const embed = new EmbedBuilder()
    .setTitle(`Match ${matchNumber} - Captain Picks`)
    .setDescription(`Captain 1: <@${queue.captainPicks.captain1}>\nCaptain 2: <@${queue.captainPicks.captain2}>`)
    .addFields(
      { name: 'Team 1', value: `${queue.captainPicks.picks.team1.map(id => `<@${id}>`).join('\n')}` },
      { name: 'Team 2', value: `${queue.captainPicks.picks.team2.map(id => `<@${id}>`).join('\n')}` }
    )
    .setColor(0x00FF00);
 
  const pickMessage = await matchChannel.send({ embeds: [embed] });
 
  // Setup pick reactions
  const remainingPlayers = queue.members.filter(id => id !== queue.captainPicks.captain1 && id !== queue.captainPicks.captain2);
  const pickEmojis = ['1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣'];
  for (let i = 0; i < remainingPlayers.length; i++) {
    await pickMessage.react(pickEmojis[i]);
  }
 
  // Add reaction collectors for captain picks
  const pickCollectors = {
    captain1: pickMessage.createReactionCollector({ filter: (reaction, user) => remainingPlayers.includes(user.id) && pickEmojis.includes(reaction.emoji.name) && !queue.captainPicks.picks.team1.includes(user.id) && !queue.captainPicks.picks.team2.includes(user.id) }),
    captain2: pickMessage.createReactionCollector({ filter: (reaction, user) => remainingPlayers.includes(user.id) && pickEmojis.includes(reaction.emoji.name) && !queue.captainPicks.picks.team1.includes(user.id) && !queue.captainPicks.picks.team2.includes(user.id) })
  };
 
  let currentPick = queue.captainPicks.captain1;
  let picksLeft = 4; // 4 total picks (2 captain 1, 2 captain 2)
 
  pickCollectors[currentPick].on('collect', async (reaction, user) => {
    if (picksLeft === 0) {
      return;
    }
 
    queue.captainPicks.picks[currentPick === queue.captainPicks.captain1 ? 'team1' : 'team2'].push(user.id);
    picksLeft--;
 
    // Update embed
    const embed = new EmbedBuilder()
      .setTitle(`Match ${matchNumber} - Captain Picks`)
      .setDescription(`Captain 1: <@${queue.captainPicks.captain1}>\nCaptain 2: <@${queue.captainPicks.captain2}>`)
      .addFields(
        { name: 'Team 1', value: `${queue.captainPicks.picks.team1.map(id => `<@${id}>`).join('\n')}` },
        { name: 'Team 2', value: `${queue.captainPicks.picks.team2.map(id => `<@${id}>`).join('\n')}` }
      )
      .setColor(0x00FF00);
 
    await pickMessage.edit({ embeds: [embed] });
 
    // Switch to the next picker
    currentPick = currentPick === queue.captainPicks.captain1 ? queue.captainPicks.captain2 : queue.captainPicks.captain1;
    pickCollectors[currentPick].on('collect', async (reaction, user) => {
      // ... (Same logic as the previous on('collect') handler)
    });
  });
 
  pickCollectors[currentPick].on('remove', async (reaction, user) => {
    // Remove reaction without impacting picks
  });
};
 
const startMapVoting = async (matchChannel, queue) => {
  const embed = new EmbedBuilder()
    .setTitle(`Match ${matchNumber} - Map Vote`)
    .setDescription(`Vote for your preferred map:\n${queue.mapOptions.map((map, index) => `${index + 1}️⃣ - ${map}`).join('\n')}`)
    .setColor(0x00FF00);
 
  const mapVoteMessage = await matchChannel.send({ embeds: [embed] });
 
  const mapVoteEmojis = ['1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣'];
 
  for (const emoji of mapVoteEmojis) {
    await mapVoteMessage.react(emoji);
  }
 
  const mapVoteCollector = mapVoteMessage.createReactionCollector({ filter: (reaction, user) => mapVoteEmojis.includes(reaction.emoji.name) && queue.members.includes(user.id) });
 
  mapVoteCollector.on('collect', async (reaction, user) => {
    const mapIndex = mapVoteEmojis.indexOf(reaction.emoji.name);
    const map = queue.mapOptions[mapIndex];
 
    if (!queue.mapVotes.has(map)) {
      queue.mapVotes.set(map, 1);
    } else {
      queue.mapVotes.set(map, queue.mapVotes.get(map) + 1);
    }
  });
 
  setTimeout(async () => {
    const mostVotedMap = [...queue.mapVotes.entries()].reduce((a, b) => (a[1] > b[1] ? a : b))[0];
    queue.mapVotes.clear();
 
    // Update match object with chosen map
    matches.get(matchNumber).map = mostVotedMap;
 
    // Send the chosen map
    await matchChannel.send(`The chosen map is: ${mostVotedMap}`);
  }, 30000); // 30 seconds for voting
};
 
// Initialize Discord Client
const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageReactions,
    GatewayIntentBits.GuildMembers,
    GatewayIntentBits.GuildVoiceStates,
  ],
  partials: [Partials.Channel, Partials.Message, Partials.Reaction, Partials.GuildMember, Partials.User]
});
 
// Event Listeners
client.once('ready', async () => {
  console.log('Bot is online!');
 
  // Register Slash Commands
  await registerSlashCommands(client); 
});
 
client.on('messageReactionAdd', async (reaction, user) => {
  if (user.id === client.user.id) return; // Ignore reactions from the bot
 
  const queue = queues.get(reaction.message.guild.id);
  if (!queue) return;
 
  if (reaction.message.id === queue.queueMessage.id) {
    if (reaction.emoji.name === '✅' && !queue.members.includes(user.id)) {
      queue.members.push(user.id);
      updateQueueMessage(queue.queueMessage, queue);
      if (queue.members.length === queue.capacity) {
        startMatch(reaction.message, queue);
      }
    } 
  }
});
 
client.on('messageReactionRemove', async (reaction, user) => {
  if (user.id === client.user.id) return; // Ignore reactions from the bot
 
  const queue = queues.get(reaction.message.guild.id);
  if (!queue) return;
 
  if (reaction.message.id === queue.queueMessage.id) {
    if (reaction.emoji.name === '✅' && queue.members.includes(user.id)) {
      queue.members.splice(queue.members.indexOf(user.id), 1);
      updateQueueMessage(queue.queueMessage, queue);
    }
  }
});
 
// Slash Command Handling
client.on('interactionCreate', async interaction => {
  if (!interaction.isChatInputCommand()) return;
 
  if (interaction.commandName === 'setup-queue') {
    // Create the queue object (with a fixed capacity of 10)
    const newQueue = {
      capacity: 10,
      name: 'Main Queue',
      teamSortMode: 'ELO',
      members: [],
      emojiJoin: '✅',
      emojiLeave: '❌',
      matchChannel: null,
      voiceChannels: [],
      mapOptions: [
        'Blackwidow', 'Subbase', 'Port', 'Compound', 'Ankara', 'Mexico', 'Eagle Eye'
      ],
      mapVotes: new Map(),
      captainPicks: {
        captain1: null,
        captain2: null,
        picks: {
          team1: [],
          team2: []
        }
      }
    };
 
    // Create the queue message in the channel
    const queueMessage = await interaction.channel.send({ embeds: [
      new EmbedBuilder()
        .setTitle(`**${newQueue.name}**`)
        .setDescription(`Click the ✅ to join the "${newQueue.name}" queue or ❌ to leave.\n\n**Players**\n\n0 / ${newQueue.capacity}\n\nPowered by Community Super League`)
        .setColor(0x00FF00)
    ]});
    await queueMessage.react('✅');
    await queueMessage.react('❌');
 
    // Store the queue
    queues.set(interaction.guild.id, newQueue);
 
    // Set the queue message for the queue
    newQueue.queueMessage = queueMessage;
 
    await interaction.reply(`The "${newQueue.name}" queue has been created!`);
  } else if (interaction.commandName === 'clearqueue') {
    const queue = queues.get(interaction.guild.id);
    if (!queue) {
      await interaction.reply('No active queue found.');
      return;
    }
 
    // Clear the queue members
    queue.members = [];
    updateQueueMessage(queue.queueMessage, queue);
 
    await interaction.reply(`The "${queue.name}" queue has been cleared.`);
  } else if (interaction.commandName === 'report') {
    const matchNumber = parseInt(interaction.channel.name.split(' - ')[2]);
    const match = matches.get(matchNumber);
 
    if (match) {
      const result = interaction.options.getInteger('result');
      if (result === 0) { // Cancel match
        await interaction.reply('Match cancelled.');
        match.winner = null;
        reportMatch(match, match.winner);
      } else if (result === 1) { // Team 1 wins
        await interaction.reply('Team 1 wins!');
        match.winner = 1;
        reportMatch(match, match.winner);
      } else if (result === 2) { // Team 2 wins
        await interaction.reply('Team 2 wins!');
        match.winner = 2;
        reportMatch(match, match.winner);
      } else {
        await interaction.reply('Invalid report option.');
      }
    } else {
      await interaction.reply(`Match ${matchNumber} not found.`);
    }
  } else if (interaction.commandName === 'flip') {
    const matchNumberToFlip = interaction.options.getInteger('match_number');
    const matchToFlip = matches.get(matchNumberToFlip);
    if (matchToFlip) {
      if (matchToFlip.winner === 1) {
        matchToFlip.winner = 2;
        await interaction.reply(`Match ${matchNumberToFlip} result flipped to Team 2 win.`);
      } else if (matchToFlip.winner === 2) {
        matchToFlip.winner = 1;
        await interaction.reply(`Match ${matchNumberToFlip} result flipped to Team 1 win.`);
      } else {
        await interaction.reply(`Match ${matchNumberToFlip} has no result to flip.`);
      }
    } else {
      await interaction.reply(`Match ${matchNumberToFlip} not found.`);
    }
  } else if (interaction.commandName === 'setlogchannel') {
    const logChannel = interaction.options.getChannel('channel');
    if (logChannel) {
      matchLogChannel = logChannel;
      await interaction.reply(`Match logs will now be posted to <#${logChannel.id}>.`);
    } else {
      await interaction.reply('Please specify a valid channel.');
    }
  } else if (interaction.commandName === 'resetelo') {
    players.forEach((player) => {
      player.elo = eloInitial;
    });
    await interaction.reply('ELO has been reset for all players!');
  } else if (interaction.commandName === 'giveelo') {
    const member = interaction.options.getMember('member');
    const eloChange = interaction.options.getInteger('elo_change');
    if (member && !isNaN(eloChange)) {
      if (!players.has(member.id)) {
        players.set(member.id, { elo: eloInitial });
      }
      players.get(member.id).elo += eloChange;
      await interaction.reply(`<@${member.id}>'s ELO has been changed by ${eloChange} points.`);
    } else {
      await interaction.reply('Please provide a valid member and ELO change.');
    }
  }
});
 
// Helper function to report match results to the log channel
const reportMatch = async (match, winner) => {
  if (matchLogChannel) {
    let team1Players = [];
    let team2Players = [];
 
    if (match.teams) {
      team1Players = match.teams[0].map(id => `<@${id}>`);
      team2Players = match.teams[1].map(id => `<@${id}>`);
    } else if (match.captainPicks) {
      team1Players = match.captainPicks.picks.team1.map(id => `<@${id}>`);
      team2Players = match.captainPicks.picks.team2.map(id => `<@${id}>`);
    }
 
    const winningTeam = winner === 1 ? 'Team 1' : winner === 2 ? 'Team 2' : 'None';
    const logMessage = `**Match ${matchNumber - 1}:**\n**${winningTeam} Wins!**\n**Team 1:** ${team1Players.join(', ')}\n**Team 2:** ${team2Players.join(', ')}`;
    await matchLogChannel.send(logMessage);
  }
};
 
// Register Slash Commands
async function registerSlashCommands(client) {
  const commands = [
    new SlashCommandBuilder()
      .setName('setup-queue')
      .setDescription('Sets up the main queue'),
    new SlashCommandBuilder()
      .setName('clearqueue')
      .setDescription('Clears the active queue'),
    new SlashCommandBuilder()
      .setName('report')
      .setDescription('Reports the match result')
      .addIntegerOption(option =>
        option.setName('result')
          .setDescription('Match result (0: Cancel, 1: Team 1, 2: Team 2)')
          .setRequired(true)
      ),
    new SlashCommandBuilder()
      .setName('flip')
      .setDescription('Flips the result of a match')
      .addIntegerOption(option =>
        option.setName('match_number')
          .setDescription('The number of the match to flip')
          .setRequired(true)
      ),
    new SlashCommandBuilder()
      .setName('setlogchannel')
      .setDescription('Sets the channel for match logs')
      .addChannelOption(option =>
        option.setName('channel')
          .setDescription('The channel to post logs to')
          .setRequired(true)
      ),
    new SlashCommandBuilder()
      .setName('resetelo')
      .setDescription('Resets ELO for all players'),
    new SlashCommandBuilder()
      .setName('giveelo')
      .setDescription('Gives ELO to a player')
      .addUserOption(option =>
        option.setName('member')
          .setDescription('The player to give ELO to')
          .setRequired(true)
      )
      .addIntegerOption(option =>
        option.setName('elo_change')
          .setDescription('The amount of ELO to change')
          .setRequired(true)
      )
  ];
 
  const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);
 
  try {
    console.log('Started refreshing application (/) commands.');
    await rest.put(Routes.applicationCommands(client.application.id), { body: commands });
    console.log('Successfully reloaded application (/) commands.');
  } catch (error) {
    console.error(error);
  }
}
 
// Bot login
client.login(process.env.DISCORD_TOKEN);
Explanation of the Code:

Constants and Data Structures:

eloInitial: The starting ELO for players.
matchNumber: Tracks the match count.
players: A Map to store player data (ELO, stats).
queues: A Map to store active queues.
matches: A Map to store match details.
matchLogChannel: Stores the channel where match logs are posted.
Helper Functions:

createMatchChannel: Creates a new text channel for a match.
createVoiceChannel: Creates a new voice channel for a match.
sortByElo: Sorts players by their ELO.
getTopPlayers: Returns the top 25 players by ELO.
updateQueueMessage: Updates the embed message in the queue channel to reflect changes in players.
startMatch: Begins a new match by setting up the match channel, voice channels, and initiating team formation.
createCaptainPickEmbed: Creates an embed message for captain picks, sets up reaction collectors, and handles pick logic.
startMapVoting: Starts the map voting process, sets up reaction collectors, and determines the chosen map.
reportMatch: Posts the match result to the log channel.
Discord Client Initialization:

client: The Discord client object, configured with necessary intents and partials.
Event Listeners:

client.once('ready'): Logs a message when the bot is ready.
client.on('messageReactionAdd'): Handles reactions to join the queue.
client.on('messageReactionRemove'): Handles reactions to leave the queue.
client.on('interactionCreate'): Handles slash command interactions.
Slash Command Handling:

/setup-queue: Creates a new queue (currently with a fixed capacity of 10).
/clearqueue: Clears the active queue.
/report: Reports the match result (win, loss, cancel).
/flip: Flips the result of a match.
/setlogchannel: Sets the channel for match logs.
/resetelo: Resets the ELO of all players to the initial value.
/giveelo: Allows an admin to adjust a player's ELO.
Match Logic:

The startMatch function handles the initiation of a match, including team formation (ELO-based or captain picks), and map voting.
The reportMatch function updates the match log in the designated channel.
Bot Login:

client.login(process.env.DISCORD_TOKEN): Logs the bot into Discord.
How to Use:

Set Up a Replit Project: Create a new Replit project and install the necessary packages:
Shell Script

Copy

Insert
npm install discord.js dotenv
Create a 
.env
 File: Add your Discord bot token and prefix:

Copy

Insert
DISCORD_TOKEN=your_bot_token
DISCORD_PREFIX=!
Paste the Code: Copy and paste the code above into 
main.js
.
Deploy: Follow the deployment instructions I provided earlier.
This code provides a robust foundation for your Discord queue bot. You can customize it further with additional features and logic as needed. Let me know if you have any other questions!
content_copyCOPY

https://replit.com/@ahmedheshamelsa/zewwww