diff --git a/commands/alarm.js b/commands/alarm.js index c4e2a83..810ada8 100644 --- a/commands/alarm.js +++ b/commands/alarm.js @@ -1,4 +1,4 @@ -const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); +const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, SelectMenuBuilder } = require('discord.js'); const bitfieldCalculator = require('discord-bitfield-calculator'); module.exports = { @@ -51,9 +51,10 @@ module.exports = { }, { name: "channel", - description: "Channel for Zone Alarm Pings", + description: "The channel to configure", value: "channel", type: 7, + channel_types: [0], // Restrict to text channel required: true, }, { @@ -66,7 +67,14 @@ module.exports = { { name: "emp-exempt", description: "Is this Alarm Exempt to EMP Attacks?", - value: "emp-exempt", + value: false, + type: 5, + required: false, + }, + { + name: "show-player-coords", + description: "Show a players coords when in the zone", + value: true, type: 5, required: false, } @@ -112,29 +120,41 @@ module.exports = { }] }, { - name: "set-rule", - description: "Add a Rule to an Alarm", - value: "set-rule", + name: "disable", + description: "Disable an Zone Alarm", + value: "disable", type: 1, - options: [{ - name: "rule", - description: "Rule to Add to an Alarm", - value: "rule", - type: 3, - required: true, - choices: [ - { name: 'Ban on Entry', value: 'ban_on_entry' }, - { name: 'Ban on Kill', value: 'ban_on_kill' }, - { name: 'Ban on IED Set', value: 'ban_on_ied_set' }, - ] - }] }, { - name: "remove-rule", - description: "Remove a Rule from an Alarm", - value: "set-rule", + name: "enable", + description: "Enable an Zone Alarm", + value: "enable", type: 1, } + // { + // name: "set-rule", + // description: "Add a Rule to an Alarm", + // value: "set-rule", + // type: 1, + // options: [{ + // name: "rule", + // description: "Rule to Add to an Alarm", + // value: "rule", + // type: 3, + // required: true, + // choices: [ + // { name: 'Ban on Entry', value: 'ban_on_entry' }, + // { name: 'Ban on Kill', value: 'ban_on_kill' }, + // { name: 'Ban on IED Set', value: 'ban_on_ied_set' }, + // ] + // }] + // }, + // { + // name: "remove-rule", + // description: "Remove a Rule from an Alarm", + // value: "remove-rule", + // type: 1, + // } ], SlashCommand: { /** @@ -164,7 +184,8 @@ module.exports = { ignoredPlayers: [], rules: [], empExempt: client.exists(args[0].options[6]) ? args[0].options[6].value : false, - disabled: false, // emp related + showPlayerCoord: client.exists(args[0].options[7]) ? args[0].options[7].value : true, + disabled: false, }; client.dbo.collection('guilds').updateOne({ 'server.serverID': GuildDB.serverID }, { @@ -243,6 +264,37 @@ module.exports = { const opt = new ActionRowBuilder().addComponents(alarms); return interaction.send({ components: [opt], flags: (1 << 6) }); + + } else if (args[0].name == 'enable' || args[0].name == 'disable') { + + if (GuildDB.alarms.length == 0) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Default).setDescription('**Notice:** No Existing Alarms to configure.')] }); + + let disable = args[0].name == 'disable' ? true : false; + + let alarms = new SelectMenuBuilder() + .setCustomId(`EnableOrDisableAlarm-${disable ? 'disable' : 'enable'}-${interaction.member.user.id}`) + .setPlaceholder(`Select an Alarm to ${disable ? 'disable' : 'enable'}.`); + + for (let i = 0; i < GuildDB.alarms.length; i++) { + if (disable && !GuildDB.alarms[i].disabled) { + alarms.addOptions({ + label: GuildDB.alarm[i].name, + description: `Disable this alarm`, + value: GuildDB.alarm[i].name, + }) + } else if (!disable && GuildDB.alarms[i].disabled) { + alarms.addOptions({ + label: GuildDB.alarm[i].name, + description: `Enable this alarm`, + value: GuildDB.alarm[i].name, + }) + } + } + + const opt = new ActionRowBuilder().addComponents(alarms); + + return interaction.send({ components: [opt], flags: (1 << 6) }); + } }, }, @@ -423,5 +475,35 @@ module.exports = { return interaction.update({ embeds: [successEmbed], components: [] }); } }, + EnableOrDisableAlarm: { + run: async(client, interaction, GuildDB) => { + if (!interaction.customId.endsWith(interaction.member.user.id)) { + return interaction.reply({ + content: "This menu is not for you", + flags: (1 << 6) + }) + } + + let alarm = GuildDB.alarms.find(alarm => alarm.name == interaction.values[0]); + let alarmIndex = GuildDB.alarms.indexOf(alarm); + let disable = interaction.customId.split('-')[1] == 'disable' ? true : false; + alarm.disabled = disable; + GuildDB.alarms[alarmIndex] = alarm + + client.dbo.collection('guilds').updateOne({ 'server.serverID': GuildDB.serverID }, { + $set: { + 'server.alarms': GuildDB.alarms, + } + }, function (err, res) { + if (err) return client.sendInternalError(interaction, err); + }); + + let successEmbed = new EmbedBuilder() + .setColor(client.config.Colors.Green) + .setDescription(`**Success:** Successfully ${disable ? 'disabled' : 'enabled'} the Alarm **${interaction.values[0]}**`); + + return interaction.update({ embeds: [successEmbed], components: [] }); + } + } } } diff --git a/commands/bounty.js b/commands/bounty.js new file mode 100644 index 0000000..7f27c93 --- /dev/null +++ b/commands/bounty.js @@ -0,0 +1,57 @@ +const { EmbedBuilder } = require('discord.js'); + +module.exports = { + name: "bounty", + debug: false, + global: false, + description: "Set or view bounties", + usage: "[cmd] [opt]", + permissions: { + channel: ["VIEW_CHANNEL", "SEND_MESSAGES", "EMBED_LINKS"], + member: [], + }, + options: [{ + name: "set", + description: "Set a bounty on a player", + value: "set", + type: 1, + options: [{ + name: "gamertag", + description: "Gamertag of player for bounty", + value: "gamertag", + type: 3, + required: true, + }, { + name: "value", + description: "Amount of the bounty", + value: "value", + type: 10, + min_value: 0.01, + required: true + }] + }, { + name: "view", + description: "View all active bounties", + value: "view", + type: 1, + }], + SlashCommand: { + /** + * + * @param {require("../structures/QuarksBot")} client + * @param {import("discord.js").Message} message + * @param {string[]} args + * @param {*} param3 + */ + run: async (client, interaction, args, { GuildDB }) => { + + if (args[0].name == 'set') { + + + + } else if (args[0].name == 'view') { + + } + }, + }, +} \ No newline at end of file diff --git a/commands/collect-income.js b/commands/collect-income.js new file mode 100644 index 0000000..e69de29 diff --git a/commands/config.js b/commands/config.js index 0cf4f3a..e8ceda5 100644 --- a/commands/config.js +++ b/commands/config.js @@ -48,6 +48,61 @@ module.exports = { }, ] }, + { + name: "killfeed_channel", + description: "Set the Killfeed Channel", + value: "killfeed_channel", + type: 1, + options: [{ + name: "channel", + description: "The channel to configure", + value: "channel", + type: 7, + channel_types: [0], // Restrict to text channel + required: true, + }] + }, + { + name: "admin_logs_channel", + description: "Set the Admin Logs Channel", + value: "admin_logs_channel", + type: 1, + options: [{ + name: "channel", + description: "The channel to configure", + value: "channel", + type: 7, + channel_types: [0], // Restrict to text channel + required: true, + }] + }, + { + name: "welcome_channel", + description: "Set the channel for users to gain access", + value: "welcome_channel", + type: 1, + options: [{ + name: "channel", + description: "The channel to configure", + value: "channel", + type: 7, + channel_types: [0], // Restrict to text channel + required: true, + }] + }, + { + name: "linked_gt_role", + description: "Access Role to give to users", + value: "linked_gt_role", + type: 1, + options: [{ + name: "role", + description: "Role to configure", + value: "role", + type: 8, + required: true, + }] + }, { name: "bot_admin_role", description: "Set/remove bot admin role", @@ -288,6 +343,58 @@ module.exports = { ); return interaction.send({ embeds: [settingsEmbed] }); + } else if (args[0].name == 'killfeed_channel') { + const channel = args[0].options[0].value; + + client.dbo.collection("guilds").updateOne({"server.serverID":GuildDB.serverID},{$set: {"server.killfeedChannel": channel}}, function(err, res) { + if (err) return client.sendInternalError(interaction, err); + }); + + const successEmbed = new EmbedBuilder() + .setDescription(`Successfully added <#${channel}> as the Killfeed Channel.`) + .setColor(client.config.Colors.Green); + + return interaction.send({ embeds: [successEmbed] }); + + } else if (args[0].name == 'admin_logs_channel') { + const channel = args[0].options[0].value; + + client.dbo.collection("guilds").updateOne({"server.serverID":GuildDB.serverID},{$set: {"server.connectionLogsChannel": channel}}, function(err, res) { + if (err) return client.sendInternalError(interaction, err); + }); + + const successEmbed = new EmbedBuilder() + .setDescription(`Successfully set <#${channel}> as the Admin Logs Channel.`) + .setColor(client.config.Colors.Green); + + return interaction.send({ embeds: [successEmbed] }); + + } else if (args[0].name == 'welcome_channel') { + const channel = args[0].options[0].value; + + client.dbo.collection("guilds").updateOne({"server.serverID":GuildDB.serverID},{$set: {"server.welcomeChannel": channel}}, function(err, res) { + if (err) return client.sendInternalError(interaction, err); + }); + + const successEmbed = new EmbedBuilder() + .setDescription(`Successfully set <#${channel}> as the Welcome Channel.`) + .setColor(client.config.Colors.Green); + + return interaction.send({ embeds: [successEmbed] }); + + } else if (args[0].name == 'linked_gt_role') { + const role = args[0].options[0].value; + + client.dbo.collection("guilds").updateOne({"server.serverID":GuildDB.serverID},{$set: {"server.linkedGamertagRole": role}}, function(err, res) { + if (err) return client.sendInternalError(interaction, err); + }); + + const successEmbed = new EmbedBuilder() + .setDescription(`Successfully set <@&${role}> to give to users who link their gamertag.`) + .setColor(client.config.Colors.Green); + + return interaction.send({ embeds: [successEmbed] }); + } }, }, diff --git a/commands/debug.js b/commands/debug.js index cea62c3..6d5c094 100644 --- a/commands/debug.js +++ b/commands/debug.js @@ -21,11 +21,13 @@ module.exports = { */ run: async (client, interaction, args, { GuildDB }, start) => { - let alarmEmbed = new EmbedBuilder() - .setDescription('test des.') - .addFields({ name: 'Test Field', value: `[Test Data](https://www.izurvive.com/chernarusplussatmap/#location=11467.6;7452)`, inline: false }) + if (client.config.Dev != 'DEV.') return interaction.send({ content: 'This command is not available to Production Version.' }); + + let embed = new EmbedBuilder() + .setColor(client.config.Colors.Default) + .setDescription(`**Welcome** <@${interaction.member.user.id}> to **DayZ Reforger**\nTo gain access please use the command `); - return interaction.send({ embeds: [alarmEmbed] }); + interaction.send({ embeds: [embed] }); }, }, } \ No newline at end of file diff --git a/commands/gamertag-link.js b/commands/gamertag-link.js new file mode 100644 index 0000000..6b16346 --- /dev/null +++ b/commands/gamertag-link.js @@ -0,0 +1,54 @@ +const { EmbedBuilder } = require('discord.js'); + +module.exports = { + name: "gamertag-link", + debug: false, + global: false, + description: "Connect DayZ account to gain server access", + usage: "[cmd] [opt]", + permissions: { + channel: ["VIEW_CHANNEL", "SEND_MESSAGES", "EMBED_LINKS"], + member: [], + }, + options: [{ + name: "gamertag", + description: "Gamertag of player for bounty", + value: "gamertag", + type: 3, + required: true, + }], + SlashCommand: { + /** + * + * @param {require("../structures/QuarksBot")} client + * @param {import("discord.js").Message} message + * @param {string[]} args + * @param {*} param3 + */ + run: async (client, interaction, args, { GuildDB }) => { + + let playerStat = GuildDB.playerstats.find(stat => stat.player == args[0].value[0]); + if (playerStat == undefined) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription('**Not Found** This player cannot be found, the gamertag may be incorrect or this player has not logged onto the server before for at least ` 5 minutes `.')] }); + + playerStat.discordID = interaction.member.user.id; + + let playerStatIndex = GuildDB.playerstats.indexOf(playerStat); + let playerstats = GuildDB.playerstats; + playerstats[playerStatIndex] = playerStatIndex; + + client.dbo.collectin("guilds").updateOne({ 'server.serverID': GuildDB.serverID }, { + $set: { + 'server.playerstats': playerstats, + } + }) + + const role = interaction.guild.roles.cache.get(GuildDB.linkedGamertagRole); + const member = interaction.guild.members.cache.get(interaction.member.user.id); + member.roles.add(role); + + let connectedEmbed = new EmbedBuilder() + .setColor(client.config.Colors.Default) + .setDescription(``) + }, + }, +} \ No newline at end of file diff --git a/commands/help.js b/commands/help.js index aef8f4a..bc35e47 100644 --- a/commands/help.js +++ b/commands/help.js @@ -37,9 +37,9 @@ module.exports = { type: 1, }, { - name: "version", - description: "Current version of the bot", - value: "version", + name: "stats", + description: "Current Bot Statistics", + value: "stats", type: 1, } ], @@ -52,7 +52,7 @@ module.exports = { * @param {*} param3 */ - run: async (client, interaction, args) => { + run: async (client, interaction, args, start) => { if (args[0].name == 'version') { const versionEmbed = new EmbedBuilder() .setTitle(`Current DayzArmbands Version`) @@ -137,6 +137,21 @@ module.exports = { `); return interaction.send({ embeds: [creditsEmbed] }) + } else if (args[0].name == 'stats') { + const end = new Date().getTime(); + const stats = new EmbedBuilder() + .setColor(client.config.Colors.Default) + .setTitle('QuarksBot Statistics') + .addFields( + { name: 'Guilds', value: `${client.guilds.cache.size}`, inline: true }, + { name: 'Users', value: `${client.users.cache.size}`, inline: true }, + { name: 'Latency', value: `${end - start}ms`, inline: true }, + { name: 'Uptime', value: `${client.secondsToDhms(process.uptime().toFixed(2))}`, inline: true }, + { name: 'Bot Version', value: `${client.config.Dev} v${client.config.Version}`, inline: true }, + { name: 'Discord Version', value: 'Discord.js v14.3.0', inline: true }, + ) + + return interaction.send({ embeds: [stats] }) } }, }, diff --git a/commands/player-list.js b/commands/player-list.js new file mode 100644 index 0000000..e69de29 diff --git a/commands/stats.js b/commands/stats.js index 427c62f..652d43b 100644 --- a/commands/stats.js +++ b/commands/stats.js @@ -23,7 +23,7 @@ module.exports = { const end = new Date().getTime(); const stats = new EmbedBuilder() .setColor(client.config.Colors.Default) - .setTitle('QuarksBot Statistics') + .setTitle('DayZ Reforger Bot Statistics') .addFields( { name: 'Guilds', value: `${client.guilds.cache.size}`, inline: true }, { name: 'Users', value: `${client.users.cache.size}`, inline: true }, diff --git a/config/config.js b/config/config.js index 3ccdda1..1312bdd 100644 --- a/config/config.js +++ b/config/config.js @@ -2,7 +2,7 @@ const package = require('../package.json'); require('dotenv').config(); module.exports = { - Dev: "PROD.", + Dev: process.env.Dev || "DEV.", Version: package.version, // (major).(feature).(revision/bug/refactoring) Admins: ["362791661274660874", "329371697570381824"], // Admins of the bot ServerID: "1050215624053374976", @@ -17,7 +17,8 @@ module.exports = { IconURL: "", Colors: { Default: "#8a7c72", - Red: "#ba0f0f", + DarkRed: "#ba0f0f", + Red: "#f55c5c", Green: "#32a852", Yellow: "#ffb01f" }, diff --git a/events/guildMemberAdd.js b/events/guildMemberAdd.js new file mode 100644 index 0000000..462db9d --- /dev/null +++ b/events/guildMemberAdd.js @@ -0,0 +1,13 @@ +const { EmbedBuilder } = require('discord.js'); + +module.exports = async (client, member) => { + + let GuildDB = await client.GetGuild(member.guild.id); + const channel = client.channels.cache.get(GuildDB.welcomeChannel); + + let embed = new EmbedBuilder() + .setColor(client.config.Colors.Default) + .setDescription(`**Welcome** <@${member.user.id}> to **DayZ Reforger**\nTo gain access please use the command `); + + channel.send({ embeds: [embed] }); +}; diff --git a/events/ready.js b/events/ready.js index 952124f..f907edd 100644 --- a/events/ready.js +++ b/events/ready.js @@ -7,5 +7,5 @@ module.exports = async (client) => { client.log(`Successfully Logged in as ${client.user.tag}`); client.log(`Ready to serve in ${client.channels.cache.size} channels on ${client.guilds.cache.size} servers, for a total of ${client.users.cache.size} users.`) client.RegisterSlashCommands(); - client.logsUpdateTimer(); + // client.logsUpdateTimer(); }; \ No newline at end of file diff --git a/index.js b/index.js index c51804b..a07e8a5 100644 --- a/index.js +++ b/index.js @@ -2,5 +2,5 @@ const DayzArmbands = require('./structures/DayzArmbands'); const config = require('./config/config'); const { GatewayIntentBits } = require('discord.js'); -let client = new DayzArmbands({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages] }, config); +let client = new DayzArmbands({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMembers] }, config); client.build() diff --git a/package.json b/package.json index 1627014..e68d140 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dayz-armbands", - "version": "5.4.0.6", + "version": "5.5.3.7", "description": "A General Purpose Discord Bot for DayZ Servers.", "main": "index.js", "nodemonConfig": { diff --git a/structures/DayzArmbands.js b/structures/DayzArmbands.js index 1da07d8..b3309bc 100644 --- a/structures/DayzArmbands.js +++ b/structures/DayzArmbands.js @@ -85,7 +85,7 @@ class DayzArmbands extends Client { try { cmd.SlashCommand.run(this, interaction, args, { GuildDB }, start); // start is only used in ping / stats command } catch (err) { - this.sendInternalError(err); + this.sendInternalError(interaction, err); } } }); @@ -93,19 +93,26 @@ class DayzArmbands extends Client { const client = this; } - async updateLogs() { - const res = await fetch(`https://api.nitrado.net/services/${this.config.Nitrado.ServerID}/gameservers/file_server/download?file=/games/${this.config.Nitrado.UserID}/noftp/dayzxb/config/DayZServer_X1_x64.ADM`, { + async downloadFile(file, outputDir) { + const res = await fetch(`https://api.nitrado.net/services/${this.config.Nitrado.ServerID}/gameservers/file_server/download?file=${file}`, { headers: { "Authorization": this.config.Nitrado.Auth } }).then(response => response.json().then(data => data) ).then(res => res); - - const stream = fs.createWriteStream('./logs/server-logs.ADM'); + + const stream = fs.createWriteStream(outputDir); const { body } = await fetch(res.data.token.url); await finished(Readable.fromWeb(body).pipe(stream)); - + } + + async handleBanList(gamertag) { + await this.downloadFile(`/games/${this.config.Nitrado.UserID}/noftp/dayzxb/ban.txt`, './logs/ban.txt').then(() => { + fs.appendFile('./logs/ban.txt', gamertag, (err) => { + if (err) throw err; + }); + }); } async handleKillfeed(guildId, line) { @@ -198,18 +205,29 @@ class DayzArmbands extends Client { if (distance < alarm.radius) { const channel = this.channels.cache.get(alarm.channel); - + let today = new Date(); let newDt = new Date(`${today.toLocaleDateString('default', { month: 'long' })} ${today.getDate()}, ${today.getFullYear()} ${data.time} EST`); let unixTime = Math.floor(newDt.getTime()/1000); + + // if (alarm.rules.includes['ban_on_entry']) { + + + // let alarmEmbed = new EmbedBuilder() + // .setColor(this.config.Colors.Default) + // .setDescription(`**Zone Ping - **\n**${data.player}** was located within **${distance} meters** of the Zone **${alarm.name}** __and has been banned.__`) + // .addFields({ name: '**Location**', value: `**[${data.pos[0]}, ${data.pos[1]}](https://www.izurvive.com/chernarusplussatmap/#location=${data.pos[0]};${data.pos[1]})**`, inline: false }) + + // channel.send({ content: `<@&${alarm.role}>`, embeds: [alarmEmbed] }); + // } else { let alarmEmbed = new EmbedBuilder() .setColor(this.config.Colors.Default) .setDescription(`**Zone Ping - **\n**${data.player}** was located within **${distance} meters** of the Zone **${alarm.name}**`) .addFields({ name: '**Location**', value: `**[${data.pos[0]}, ${data.pos[1]}](https://www.izurvive.com/chernarusplussatmap/#location=${data.pos[0]};${data.pos[1]})**`, inline: false }) - channel.send({ content: `<@&${alarm.role}>`, embeds: [alarmEmbed] }); - break; // we break because no need to check if they are in two alarms at once, can't be in two places at once. + return channel.send({ content: `<@&${alarm.role}>`, embeds: [alarmEmbed] }); + // } } } } @@ -392,7 +410,7 @@ class DayzArmbands extends Client { async logsUpdateTimer() { setTimeout(async () => { this.readLogs('992982520591294524'); - // await this.updateLogs().then(() => { + // await this.downloadFile(`/games/${this.config.Nitrado.UserID}/noftp/dayzxb/config/DayZServer_X1_x64.ADM`, './logs/server-logs.ADM').then(() => { // this.guilds.cache.forEach((guild) => { // this.killfeed(guild.id); // Check logs for killfeed // // this.alarms(); // check for base alarms (+ rules that may apply such as safe zone) @@ -488,8 +506,8 @@ class DayzArmbands extends Client { if (err) this.error(err); else files.forEach((file) => { - const event = require(EventsDir + "/" + file);; - if (file.split(".")[0] == 'interactionCreate') this.on(file.split(".")[0], i => event(this, i)); + const event = require(EventsDir + "/" + file); + if (['interactionCreate','guildMemberAdd'].includes(file.split(".")[0])) this.on(file.split(".")[0], i => event(this, i)); else this.on(file.split(".")[0], event.bind(null, this)); this.logger.log("Event Loaded: " + file.split(".")[0]); }); @@ -529,6 +547,7 @@ class DayzArmbands extends Client { allowedChannels: [], killfeedChannel: "", connectionLogsChannel: "", + welcomeChannel: "", factionArmbands: {}, usedArmbands: [], excludedRoles: [], @@ -542,6 +561,7 @@ class DayzArmbands extends Client { return { gamertag: gt, playerID: pID, + discordID: "", KDR: 0.00, kills: 0, deaths: 0, @@ -581,6 +601,9 @@ class DayzArmbands extends Client { botAdminRoles: guild.server.botAdminRoles, playerstats: guild.server.playerstats, alarms: guild.server.alarms, + killfeedChannel: guild.server.killfeedChannel, + connectionLogsChannel: guild.server.connectionLogsChannel, + welcomeChannel: guild.server.welcomeChannel, }; }