Merge remote-tracking branch 'origin/typescript' into typescript-nitrado-api

This commit is contained in:
knighthawk4227 committed 2025-10-01 12:46:02 -07:00
commit 07024664ca
49 files changed
+2016 -1222

No files matched your search

+44 -6
View File
@@ -18,6 +18,7 @@
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"mongodb": "^4.12.1", "mongodb": "^4.12.1",
"tsconfig-paths": "^4.2.0",
"winston": "^3.8.1" "winston": "^3.8.1"
}, },
"devDependencies": { "devDependencies": {
@@ -3352,6 +3353,18 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"license": "MIT",
"bin": {
"json5": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/keyv": { "node_modules/keyv": {
"version": "4.5.4", "version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -3511,7 +3524,6 @@
"version": "1.2.8", "version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true,
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
@@ -4047,7 +4059,6 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=4" "node": ">=4"
@@ -4284,6 +4295,20 @@
"strip-json-comments": "^2.0.0" "strip-json-comments": "^2.0.0"
} }
}, },
"node_modules/tsconfig-paths": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
"integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==",
"license": "MIT",
"dependencies": {
"json5": "^2.2.2",
"minimist": "^1.2.6",
"strip-bom": "^3.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/tsconfig/node_modules/strip-json-comments": { "node_modules/tsconfig/node_modules/strip-json-comments": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
@@ -6977,6 +7002,11 @@
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
"dev": true "dev": true
}, },
"json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
},
"keyv": { "keyv": {
"version": "4.5.4", "version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -7096,8 +7126,7 @@
"minimist": { "minimist": {
"version": "1.2.8", "version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
"dev": true
}, },
"mkdirp": { "mkdirp": {
"version": "1.0.4", "version": "1.0.4",
@@ -7426,8 +7455,7 @@
"strip-bom": { "strip-bom": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="
"dev": true
}, },
"strip-json-comments": { "strip-json-comments": {
"version": "3.1.1", "version": "3.1.1",
@@ -7578,6 +7606,16 @@
} }
} }
}, },
"tsconfig-paths": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
"integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==",
"requires": {
"json5": "^2.2.2",
"minimist": "^1.2.6",
"strip-bom": "^3.0.0"
}
},
"tslib": { "tslib": {
"version": "2.5.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
-564
View File
@@ -1,564 +0,0 @@
const { RegisterGlobalCommands, RegisterGuildCommands } = require("./util/RegisterSlashCommands");
const { Collection, Client, EmbedBuilder, Routes, InteractionResponseType, InteractionType, GatewayDispatchEvents } = require("discord.js");
const MongoClient = require("mongodb").MongoClient;
const { REST } = require("@discordjs/rest");
const Logger = require("./util/Logger");
const crypto = require("crypto");
// custom util imports
const { DownloadNitradoFile,
CheckServerStatus,
FetchServerSettings,
PostServerSettings,
NitradoCredentialStatus } = require("./util/NitradoAPI");
const { HandlePlayerLogs,
HandleActivePlayersList } = require("./util/LogsHandler");
const { HandleKillfeed, UpdateLastDeathDate } = require("./util/KillfeedHandler");
const { HandleExpiredUAVs, HandleEvents, PlaceFireplaceInAlarm } = require("./util/AlarmsHandler");
const { decrypt } = require("./util/Cryptic");
const { GetWebhook, WebhookSend } = require("./util/WebhookHandler");
// Data structures imports
const { getDefaultPlayer, UpdatePlayer } = require("./database/player");
const { Missions } = require("./database/destinations");
const { GetGuild } = require("./database/guild");
const path = require("path");
const fs = require("fs");
const readline = require("readline");
const MINUTE = 60000; // 1 minute in milliseconds
const AUTO_RESTART_INTERVAL = 600000; // Set auto-restart interval 10 minutes (600,000ms)
class DayZR extends Client {
constructor(options, config) {
super(options);
this.config = config;
this.commands = new Collection();
this.interactionHandlers = new Collection();
this.logger = new Logger(path.join(__dirname, "..", "logs", "Logs.log"));
this.timer = this.config.Dev == "PROD." ? MINUTE * 5 : MINUTE / 4;
if (
this.config.Token === "" ||
this.config.SecretKey === "" ||
this.config.SecretIv === ""
) {
throw new TypeError(
"The config.js is not filled out. Please make sure nothing is blank, otherwise the bot will not work properly."
);
}
if (!["DEV.", "PROD."].includes(this.config.Dev)) {
throw new TypeError(
"The Dev version in the config.js does not match the allowed cases of \"DEV.\" or \"PROD.\""
);
}
// Generate secret hash with crypto to use for encryption
this.key = crypto
.createHash("sha512")
.update(this.config.SecretKey)
.digest("hex")
.substring(0, 32);
this.encryptionIV = crypto
.createHash("sha512")
.update(this.config.SecretIv)
.digest("hex")
.substring(0, 16);
this.db;
this.dbo;
this.databaseConnected = false;
this.arInterval = AUTO_RESTART_INTERVAL;
this.arIntervalIds = new Map();
this.playerSessions = new Map();
this.logHistory = new Map();
this.alarmPingQueue = new Map();
this.playerListMsgIds = new Map();
this.initialize();
this.LoadCommandsAndInteractionHandlers();
this.LoadEvents();
this.Ready = false;
this.activePlayersTick = 11;
this.ws.on(GatewayDispatchEvents.InteractionCreate, async (interaction) => {
const start = new Date().getTime();
if (interaction.type == InteractionType.ApplicationCommand) {
let GuildDB = await GetGuild(this, interaction.guild_id);
if (this.exists(GuildDB.Nitrado) && this.exists(GuildDB.Nitrado.Auth)) {
GuildDB.Nitrado.Auth = decrypt(
GuildDB.Nitrado.Auth,
this.config.EncryptionMethod,
this.key,
this.encryptionIV
);
}
const command = interaction.data.name.toLowerCase();
const args = interaction.data.options;
// Free unused armbands for related commands
if (["armbands", "claim", "factions"].includes(command)) {
for (const [factionID, data] of Object.entries(GuildDB.factionArmbands)) {
const guild = this.guilds.cache.get(GuildDB.serverID);
const role = guild.roles.cache.find(role => role.id == factionID);
if (!role) {
let query = {
$pull: { "server.usedArmbands": data.armband },
$unset: { [`server.factionArmbands.${factionID}`]: "" },
};
this.dbo.collection("guilds").updateOne({ "server.serverID": GuildDB.serverID }, query, (err, res) => {
if (err) return this.sendInternalError(interaction, err);
});
}
}
}
this.log(`Interaction [${interaction.guild_id}] - ${command}`);
const rest = new REST({ version: "10" }).setToken(this.config.Token);
// Easy to send response so ;)
interaction.guild = await this.guilds.fetch(interaction.guild_id);
const handleCallback = async (interactionType, message) => {
return await rest.post(Routes.interactionCallback(interaction.id, interaction.token), {
body: {
type: interactionType,
data: message,
}
});
}
// Nicely name our custom callback functions and pass correct type because discord is picky with numbers...
interaction.send = async (message) => handleCallback(InteractionResponseType.ChannelMessageWithSource, message);
interaction.deferReply = async (message) => handleCallback(InteractionResponseType.DeferredChannelMessageWithSource, message);
interaction.showModal = async (message) => handleCallback(InteractionResponseType.Modal, message);
interaction.editReply = async (message) => {
return await rest.patch(Routes.webhookMessage(this.application.id, interaction.token), {
body: message,
});
};
if (!this.databaseConnected) {
let dbFailedEmbed = new EmbedBuilder()
.setDescription(`**Internal Error:**\nUh Oh D: Its not you, its me.\nThe bot has failed to connect to the database 5 times!\nContact the Developers\nhttps://discord.gg/YCXhvy9uZw`)
.setColor(this.config.Colors.Red)
return interaction.send({ embeds: [dbFailedEmbed] });
}
let cmd = this.commands.get(command);
try {
cmd.SlashCommand.run(this, interaction, args, { GuildDB }, start); // start is only used in ping / stats command
} catch (err) {
this.sendInternalError(interaction, err);
}
}
});
}
log(Text) { this.logger.log(Text); }
error(Text) { this.logger.error(Text); }
async getDateEST(time) {
let timeArray = time.split(" ")[0].split(":");
let t = new Date(); // Get current date & time (UTC)
let f = new Date(t.getTime() - 4 * 3600000); // Convert UTC into EST time to roll back the day as necessary
f.setUTCHours(timeArray[0], timeArray[1], timeArray[2]); // Apply the supplied EST time to the converted date (EST is the timezone produced from the Nitrado logs).
return new Date(f.getTime() + 4 * 3600000); // Add EST time offset to return timestamp in UTC
}
async readLogs(guild) {
const fileStream = fs.createReadStream(`./logs/${guild.Nitrado.ServerID}-logs.ADM`);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
let lines = [];
for await (const line of rl) { lines.push(line); }
let logIndex = lines.indexOf(this.logHistory.get(guild.Nitrado.ServerID));
if (this.playerSessions.get(guild.Nitrado.ServerID).size === 0) {
let players = await this.dbo.collection("players").find({ "nitradoServerID": guild.Nitrado.ServerID }) // Get all players of this server
.toArray().then(all => all.filter(p => p.connected).map(p => p.connected = false)); // assume all players who were previously connected are not connected on init only.
for (let i = 0; i < players.length; i++) {
await UpdatePlayer(this, players[i])
}
}
for (let i = logIndex + 1; i < lines.length; i++) {
// Handle lines to skip
if (lines[i].includes("| ####")) continue;
if (lines[i].includes("(id=Unknown") || lines[i].includes("Player \"Unknown Entity\"")) continue;
if ((i - 1) >= 0 && lines[i] == lines[i - 1]) continue; // continue if this line is a duplicate of the last line
// Handle general logs
if (lines[i].includes("connected") || lines[i].includes("pos=<")) await HandlePlayerLogs(guild.Nitrado.ServerID, this, guild, lines[i], guild.combatLogTimer);
if (lines[i].includes("killed by Zmb") || lines[i].includes(">) died.")) await UpdateLastDeathDate(guild.Nitrado.ServerID, this, lines[i]); // Updates users last death date for non PVP deaths.
if (lines[i].includes(") placed Fireplace")) await PlaceFireplaceInAlarm(this, guild, lines[i]);
// Handle killfeed logs
if (
(lines[i].includes("killed by with") || lines[i].includes("killed by LandMineTrap")) || // Handle explosive deaths
(!(i + 1 >= lines.length) && lines[i + 1].includes("killed by") && lines[i].includes("TransportHit")) || // Handle vehicle deaths
(!(i + 1 >= lines.length) && lines[i + 1].includes("killed by Player") && lines[i].includes("hit by Player")) || // Handle PVP deaths
(lines[i].includes("killed by Player") && !lines[i - 1].includes("hit by Player")) // Handle deaths missing hit by log
) await HandleKillfeed(guild.Nitrado.ServerID, this, guild, lines[i]);
}
// Handle alarm pings
const maxEmbed = 10;
this.alarmPingQueue.forEach(queue => {
queue.forEach(async (data, channel_id) => {
const channel = this.GetChannel(channel_id);
if (!channel) return;
const NAME = "DayZ.R Zone Alert";
const webhook = await GetWebhook(this, NAME, channel_id);
data.forEach(async (embeds, role) => {
let embedArrays = [];
while (embeds.length > 0)
embedArrays.push(embeds.splice(0, maxEmbed));
for (let i = 0; i < embedArrays.length; i++) {
let content = { embeds: embedArrays[i] };
if (role != "-no-role-ping-") content.content = `<@&${role}>`;
WebhookSend(this, webhook, content);
// if (role == "-no-role-ping-") channel.send({ embeds: embedArrays[i] });
// else channel.send({ content: `<@&${role}>`, embeds: embedArrays[i] });
}
});
});
});
this.alarmPingQueue.set(guild.serverID, new Map()); // Clear alarm queue for this guild
const playerTemplate = /(.*) \| Player \"(.*)\" \(id=(.*) pos=<(.*)>\)/g;
let previouslyConnected = await this.dbo.collection("players").find({ "nitradoServerID": guild.Nitrado.ServerID })
.toArray().then(players => players.filter(p => p.connected)); // All players with connection log captured above and no disconnect log
let lastDetectedTime;
for (let i = lines.length - 1; i > 0; i--) {
if (lines[i].includes("PlayerList log:")) {
for (let j = i + 1; j < lines.length; j++) {
let line = lines[j];
if (line.includes("| ####")) break;
let data = [...line.matchAll(playerTemplate)][0];
if (!data) continue;
let info = {
time: data[1],
player: data[2],
playerID: data[3],
};
if (!this.exists(info.player) || !this.exists(info.playerID)) continue; // Skip this player if the player does not exist.
lastDetectedTime = await this.getDateEST(info.time);
let playerStat = await this.dbo.collection("players").findOne({ "playerID": info.playerID });
if (!this.exists(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID, guild.Nitrado.ServerID);
if (!previouslyConnected.includes(playerStat) && this.exists(playerStat.lastDisconnectionDate) && playerStat.lastDisconnectionDate !== null && playerStat.lastDisconnectionDate.getTime() > lastDetectedTime.getTime()) continue; // Skip this player if the lastDisconnectionDate time is later than the player log entry.
// Track adjusted sessions this instance has handled (e.g. no bot crashes or restarts).
if (this.playerSessions.get(guild.Nitrado.ServerID).has(info.playerID)) {
// Player is already in a session, update the session"s end time.
const session = this.playerSessions.get(guild.Nitrado.ServerID).get(info.playerID);
session.endTime = lastDetectedTime; // Update end time.
} else {
// Player is not in a session, create a new session.
const newSession = {
startTime: lastDetectedTime,
endTime: null, // Initialize end time as null.
};
this.playerSessions.get(guild.Nitrado.ServerID).set(info.playerID, newSession);
// Check if the player has been marked as connected before, but only if a session doesn"t exist
// in the map, indicating the connection was discovered in the logs during this session.
if (!previouslyConnected.includes(playerStat)) {
playerStat.connected = true;
playerStat.lastConnectionDate = lastDetectedTime; // Update last connection date.
}
}
await UpdatePlayer(this, playerStat);
}
break;
}
}
const lastLine = lines[lines.length - 1]
this.logHistory.set(guild.Nitrado.ServerID, lastLine);
this.dbo.collection("guilds").updateOne({ "server.serverID": guild.serverID }, { $set: { "server.lastLog": lastLine } }, (err, res) => {
if (err) this.error(`Failed to save last log to guild config [${guild.serverID}] for nitrado server [${guild.Nitrado.ServerID}]`);
});
}
async logsUpdateTimer(c) {
c.activePlayersTick++;
c.guilds.cache.forEach(async (guild) => {
let GuildDB = await GetGuild(c, guild.id);
/*
Note to self:
return statements do not prematurely exit out of a forEach loop like it does in a for loop.
*/
if (!c.exists(GuildDB.Nitrado)) return; // Continue if no nitrado credentials
if (GuildDB.Nitrado.Status == NitradoCredentialStatus.FAILED) return; // Continue if these credentials are marked as failed
const NitradoCred = {
ServerID: GuildDB.Nitrado.ServerID,
UserID: GuildDB.Nitrado.UserID,
Auth: decrypt(
GuildDB.Nitrado.Auth,
c.config.EncryptionMethod,
c.key,
c.encryptionIV
),
};
const response = await FetchServerSettings(NitradoCred, c, "logsUpdateTimer").then(res => res);
if (response == 1) {
c.dbo.collection("guilds").updateOne({ "server.serverID": GuildDB.serverID }, { $set: { "Nitrado.Status": NitradoCredentialStatus.FAILED } }, (err, _) => {
if (err) this.error(`Failed to update Nitrado status to failed. [${GuildDB.serverID}]`);
});
return;
};
const settings = response.data.gameserver;
// Update Nitrado DayZ Mission if change is detected
if (GuildDB.Nitrado.Mission !== Missions[settings.settings.config.mission]) {
c.dbo.collection("guilds").updateOne({ "server.serverID": GuildDB.serverID }, { $set: { "Nitrado.Mission": Missions[settings.settings.config.mission] } }, (err, res) => {
if (err) this.error(`Failed to save mission to guild config [${GuildDB.serverID}] for nitrado server [${GuildDB.Nitrado.ServerID}]`);
});
}
GuildDB.Nitrado.Mission = Missions[settings.settings.config.mission];
if (settings.game_specific.log_files.length == 0) return; // Ignore if no log files on Nitrado server
const filename = settings.game_specific.log_files.sort((a, b) => a.length - b.length)[0];
const path = `${settings.game_specific.path.slice(0, -1)}${filename.split(settings.game)[1]}`;
// Ensure Player List is logged for next update
const playerListEnabled = parseInt(settings.settings.config.adminLogPlayerList)
if (!playerListEnabled) PostServerSettings(NitradoCred, c, "config", "adminLogPlayerList", "1")
await DownloadNitradoFile(NitradoCred, c, path, `./logs/${NitradoCred.ServerID}-logs.ADM`).then(async (status) => {
if (status == 1) return c.error(`Failed to Download Nitrado Log Files - [${NitradoCred.ServerID}]`);
await c.readLogs(GuildDB).then(async () => {
HandleExpiredUAVs(c, GuildDB);
HandleEvents(c, GuildDB)
if (c.activePlayersTick == 12) await HandleActivePlayersList(NitradoCred, c, GuildDB);
})
});
});
}
async connectMongo(mongoURI, dbo) {
let failed = false;
let dbLogDir = path.join(__dirname, "..", "logs", "database-logs.json");
let databaselogs;
try {
databaselogs = JSON.parse(fs.readFileSync(dbLogDir));
} catch (err) {
databaselogs = {
attempts: 0,
connected: false,
};
}
if (databaselogs.attempts >= 5) {
this.error("Failed to connect to mongodb after multiple attempts");
return; // prevent further attempts
}
try {
// Connect to Mongo database.
this.db = await MongoClient.connect(mongoURI, { connectTimeoutMS: 1000 });
this.dbo = this.db.db(dbo);
this.log("Successfully connected to mongoDB");
databaselogs.connected = true;
databaselogs.attempts = 0; // reset attempts
this.databaseConnected = true;
} catch (err) {
databaselogs.attempts++;
databaselogs.connected = false;
let db = mongoURI.includes("@") ? mongoURI.split("@")[1] : mongoURI.split("//")[1];
db = db.includes("/") ? db.split("/")[0] : db;
this.error(`Failed to connect to mongodb (mongodb://${db}/${dbo}): attempt ${databaselogs.attempts} - ${err}`);
failed = true;
}
// write JSON string to a file
fs.writeFileSync(dbLogDir, JSON.stringify(databaselogs));
if (failed) process.exit(-1);
}
async initialize() {
// Wait for MongoDB to connect
await this.connectMongo(this.config.mongoURI, this.config.dbo);
if (!this.databaseConnected) return;
let guilds = await this.dbo.collection("guilds").find({}).toArray();
/*
Initialize auto restart for enabled servers
Initialize last logs
Initialize Player Sessions
*/
for (let i = 0; i < guilds.length; i++) {
if (!this.exists(guilds[i].Nitrado)) continue;
if (guilds[i].server.autoRestart) {
const NitradoCred = {
ServerID: guilds[i].Nitrado.ServerID,
UserID: guilds[i].Nitrado.UserID,
Auth: decrypt(
guilds[i].Nitrado.Auth,
this.config.EncryptionMethod,
this.key,
this.encryptionIV
)
};
this.arIntervalIds.set(guilds[i].server.serverID, setInterval(CheckServerStatus, this.arInterval, NitradoCred, this))
}
this.logHistory.set(guilds[i].Nitrado.ServerID, guilds[i].server.lastLog); // Using Nitrado Server ID over guild ID in case of future support for multiple nitrado servers in a single guild
this.playerSessions.set(guilds[i].Nitrado.ServerID, new Map()); // Same reason here as named above.
this.alarmPingQueue.set(guilds[i].server.serverID, new Map()); // Initialize alarm queue to be empty
this.playerListMsgIds.set(guilds[i].server.serverID, ""); // Initialize player list message ids
this.log(`[${guilds[i].server.serverID}] Initialized existing Nitrado Server: (${guilds[i].Nitrado.ServerID})`);
}
}
async initNewNitradoServer(guildId, Nitrado) {
let guild = await GetGuild(this, guildId)
if (guild.autoRestart) this.arIntervalIds.set(guildId, setInterval(CheckServerStatus, this.arInterval, Nitrado, this))
this.logHistory.set(Nitrado.ServerID, guild.lastLog);
this.playerSessions.set(Nitrado.ServerID, new Map());
this.alarmPingQueue.set(guildId, new Map());
this.playerListMsgIds.set(guildId, "");
this.log(`[${guildId}] Initialized new Nitrado`);
}
exists(n) { return typeof (n) == "number" ? !isNaN(n) : null != n && undefined != n && "" != n }
secondsToDhms(seconds) {
seconds = Number(seconds);
const d = Math.floor(seconds / (3600 * 24));
const h = Math.floor(seconds % (3600 * 24) / 3600);
const m = Math.floor(seconds % 3600 / 60);
const s = Math.floor(seconds % 60);
const dDisplay = d > 0 ? d + (d == 1 ? " day, " : " days, ") : "";
const hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : "";
const mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : "";
const sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : "";
return dDisplay + hDisplay + mDisplay + sDisplay;
}
LoadCommandsAndInteractionHandlers() {
let CommandsDir = path.join(__dirname, "commands");
fs.readdir(CommandsDir, (err, files) => {
if (err) this.error(err);
else
files.forEach((file) => {
let cmd = require(CommandsDir + "/" + file);
if (!this.exists(cmd.name) || !this.exists(cmd.description))
return this.error(
"Unable to load Command: " +
file.split(".")[0] +
", Reason: File doesn't had name/desciption"
);
this.commands.set(file.split(".")[0].toLowerCase(), cmd);
if (this.exists(cmd.Interactions)) {
for (let [interaction, handler] of Object.entries(cmd.Interactions)) {
this.interactionHandlers.set(interaction, handler);
}
}
this.log("Command Loaded: " + file.split(".")[0]);
});
});
}
LoadEvents() {
let EventsDir = path.join(__dirname, "events");
fs.readdir(EventsDir, (err, files) => {
if (err) this.error(err);
else
files.forEach((file) => {
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.log("Event Loaded: " + file.split(".")[0]);
});
});
}
// Allows shorter lines of code elsewhere
GetChannel(channel_id) { return this.channels.cache.get(channel_id); }
sendError(Channel, Error) {
this.error(Error);
let embed = new EmbedBuilder()
.setColor(this.config.Red)
.setDescription(Error);
Channel.send(embed);
}
// Handles internal errors for slash commands. E.g failed to update database from slash command.
sendInternalError(Interaction, Error) {
this.error(Error);
const embed = new EmbedBuilder()
.setDescription(`**Internal Error:**\nUh Oh D: Its not you, its me.\nThis command has crashed\nContact the Developers\nhttps://discord.gg/YCXhvy9uZw`)
.setColor(this.config.Colors.Red)
try {
Interaction.send({ embeds: [embed] });
} catch {
Interaction.update({ embeds: [embed], components: [] });
}
}
// Calls register for guild and global commands
RegisterSlashCommands() {
RegisterGlobalCommands(this);
let p = Promise.resolve()
this.guilds.cache.forEach((guild) => {
p = p.then(() => {
RegisterGuildCommands(this, guild.id);
return new Promise((resolve) => {
setTimeout(resolve, 500);
})
})
});
}
build() {
this.login(this.config.Token);
}
}
module.exports = DayZR;
+1110
View File
File diff suppressed because it is too large. Load diff
+24 -23
View File
@@ -4,6 +4,7 @@ const bitfieldCalculator = require("discord-bitfield-calculator");
const { Armbands } = require("../database/armbands.js"); const { Armbands } = require("../database/armbands.js");
const { createUser, addUser } = require("../database/user"); const { createUser, addUser } = require("../database/user");
const { UpdatePlayer } = require("../database/player"); const { UpdatePlayer } = require("../database/player");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "admin", name: "admin",
@@ -19,7 +20,7 @@ module.exports = {
name: "gamertag-link", name: "gamertag-link",
description: "Link a gamertag for a user", description: "Link a gamertag for a user",
value: "gamertag-link", value: "gamertag-link",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "user", name: "user",
description: "User to link gamertag to", description: "User to link gamertag to",
@@ -38,7 +39,7 @@ module.exports = {
name: "gamertag-unlink", name: "gamertag-unlink",
description: "Unlink a gamertag for a user", description: "Unlink a gamertag for a user",
value: "gamertag-unlink", value: "gamertag-unlink",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "user", name: "user",
description: "User to link gamertag to", description: "User to link gamertag to",
@@ -50,7 +51,7 @@ module.exports = {
name: "claim-armband", name: "claim-armband",
description: "Claim an armband for a faction", description: "Claim an armband for a faction",
value: "claim-armband", value: "claim-armband",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "faction_role", name: "faction_role",
description: "Claim an armband for this faction role.", description: "Claim an armband for this faction role.",
@@ -62,7 +63,7 @@ module.exports = {
name: "bounty-clear", name: "bounty-clear",
description: "Clear a bounty off a player", description: "Clear a bounty off a player",
value: "bounty-clear", value: "bounty-clear",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "gamertag", name: "gamertag",
description: "Gamertag of player", description: "Gamertag of player",
@@ -75,17 +76,17 @@ module.exports = {
name: "money", name: "money",
description: "Add/Remove money to a user", description: "Add/Remove money to a user",
value: "money", value: "money",
type: ApplicationCommandOptionType.SubCommandGroup, type: ApplicationCommandOptionType.SubcommandGroup,
options: [{ options: [{
name: "add", name: "add",
description: "Add money to user", description: "Add money to user",
value: "add", value: "add",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "amount", name: "amount",
description: "The amount to add to balance", description: "The amount to add to balance",
value: "amount", value: "amount",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 0.01, min_value: 0.01,
required: true, required: true,
}, { }, {
@@ -99,12 +100,12 @@ module.exports = {
name: "remove", name: "remove",
description: "Remove money from a user", description: "Remove money from a user",
value: "remove", value: "remove",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "amount", name: "amount",
description: "The amount to remove from balance", description: "The amount to remove from balance",
value: "amount", value: "amount",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 0.01, min_value: 0.01,
required: true, required: true,
}, { }, {
@@ -134,7 +135,7 @@ module.exports = {
if (args[0].name == "gamertag-link") { if (args[0].name == "gamertag-link") {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -143,9 +144,9 @@ module.exports = {
} }
let playerStat = await client.dbo.collection("players").findOne({ "gamertag": args[0].options[1].value }); let playerStat = await client.dbo.collection("players").findOne({ "gamertag": args[0].options[1].value });
if (!client.exists(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** This gamertag \` ${args[0].options[1].value} \` cannot be found, the gamertag may be incorrect or this player has not logged onto the server before for at least \` 5 minutes \`.`)] }); if (!isDefined(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** This gamertag \` ${args[0].options[1].value} \` cannot be found, the gamertag may be incorrect or this player has not logged onto the server before for at least \` 5 minutes \`.`)] });
if (client.exists(playerStat.discordID)) { if (isDefined(playerStat.discordID)) {
const warnGTOverwrite = new EmbedBuilder() const warnGTOverwrite = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription(`**Notice:**\n> The gamertag has previously been linked to <@${playerStat.discordID}>. Are you sure you would like to change this?`) .setDescription(`**Notice:**\n> The gamertag has previously been linked to <@${playerStat.discordID}>. Are you sure you would like to change this?`)
@@ -170,12 +171,12 @@ module.exports = {
await UpdatePlayer(client, playerStat, interaction); await UpdatePlayer(client, playerStat, interaction);
let member = interaction.guild.members.cache.get(args[0].options[0].value); let member = interaction.guild.members.cache.get(args[0].options[0].value);
if (client.exists(GuildDB.linkedGamertagRole)) { if (isDefined(GuildDB.linkedGamertagRole)) {
let role = interaction.guild.roles.cache.get(GuildDB.linkedGamertagRole); let role = interaction.guild.roles.cache.get(GuildDB.linkedGamertagRole);
member.roles.add(role); member.roles.add(role);
} }
if (client.exists(GuildDB.memberRole)) { if (isDefined(GuildDB.memberRole)) {
let role = interaction.guild.roles.cache.get(GuildDB.memberRole); let role = interaction.guild.roles.cache.get(GuildDB.memberRole);
member.roles.add(role); member.roles.add(role);
} }
@@ -188,7 +189,7 @@ module.exports = {
} else if (args[0].name == "gamertag-unlink") { } else if (args[0].name == "gamertag-unlink") {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -197,7 +198,7 @@ module.exports = {
} }
let playerStat = await client.dbo.collection("players").findOne({ "discordID": args[0].options[0].value }); let playerStat = await client.dbo.collection("players").findOne({ "discordID": args[0].options[0].value });
if (!client.exists(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** <@${args[0].options[0].value}> has no gamertag linked.`)] }); if (!isDefined(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** <@${args[0].options[0].value}> has no gamertag linked.`)] });
const warnGTOverwrite = new EmbedBuilder() const warnGTOverwrite = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
@@ -281,7 +282,7 @@ module.exports = {
} else if (args[0].name == "bounty-clear") { } else if (args[0].name == "bounty-clear") {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -290,7 +291,7 @@ module.exports = {
} }
let playerStat = await client.dbo.collection("players").findOne({ "gamertag": args[0].options[0].value }); let playerStat = await client.dbo.collection("players").findOne({ "gamertag": args[0].options[0].value });
if (!client.exists(playerStat)) 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 `.")] }); if (!isDefined(playerStat)) 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.bounties = []; playerStat.bounties = [];
@@ -309,16 +310,16 @@ module.exports = {
if (!banking) { if (!banking) {
banking = await createUser(targetUserID, GuildDB.serverID, GuildDB.startingBalance, client) banking = await createUser(targetUserID, GuildDB.serverID, GuildDB.startingBalance, client)
if (!client.exists(banking)) return client.sendInternalError(interaction, err); if (!isDefined(banking)) return client.sendInternalError(interaction, err);
} }
banking = banking.user; banking = banking.user;
if (!client.exists(banking.guilds[GuildDB.serverID])) { if (!isDefined(banking.guilds[GuildDB.serverID])) {
const success = addUser(banking.guilds, GuildDB.serverID, targetUserID, client, GuildDB.startingBalance); const success = addUser(banking.guilds, GuildDB.serverID, targetUserID, client, GuildDB.startingBalance);
if (!success) return client.sendInternalError(interaction, "Failed to add bank"); if (!success) return client.sendInternalError(interaction, "Failed to add bank");
} }
if (!client.exists(banking.guilds[GuildDB.serverID].balance)) banking.guilds[GuildDB.serverID].balance = GuildDB.startingBalance; if (!isDefined(banking.guilds[GuildDB.serverID].balance)) banking.guilds[GuildDB.serverID].balance = GuildDB.startingBalance;
const add = args[0].options[0].name == "add"; const add = args[0].options[0].name == "add";
let newBalance = add let newBalance = add
@@ -354,12 +355,12 @@ module.exports = {
await UpdatePlayer(client, playerStat); await UpdatePlayer(client, playerStat);
let member = interaction.guild.members.cache.get(interaction.member.user.id); let member = interaction.guild.members.cache.get(interaction.member.user.id);
if (client.exists(GuildDB.linkedGamertagRole)) { if (isDefined(GuildDB.linkedGamertagRole)) {
let role = interaction.guild.roles.cache.get(GuildDB.linkedGamertagRole); let role = interaction.guild.roles.cache.get(GuildDB.linkedGamertagRole);
member.roles.add(role); member.roles.add(role);
} }
if (client.exists(GuildDB.memberRole)) { if (isDefined(GuildDB.memberRole)) {
let role = interaction.guild.roles.cache.get(GuildDB.memberRole); let role = interaction.guild.roles.cache.get(GuildDB.memberRole);
member.roles.add(role); member.roles.add(role);
} }
+21 -20
View File
@@ -1,6 +1,7 @@
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder } = require("discord.js"); const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder } = require("discord.js");
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const bitfieldCalculator = require("discord-bitfield-calculator"); const bitfieldCalculator = require("discord-bitfield-calculator");
const isDefined = require("../util/Validation.js");
const generateAlarmMenus = (alarms, customId, placeholder, description) => { const generateAlarmMenus = (alarms, customId, placeholder, description) => {
let alarmComponents = []; let alarmComponents = [];
@@ -40,13 +41,13 @@ module.exports = {
name: "create", name: "create",
description: "Create a new Zone Ping Alarm", description: "Create a new Zone Ping Alarm",
value: "create", value: "create",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [ options: [
{ {
name: "x-coord", name: "x-coord",
description: "X Coordinate of the origin", description: "X Coordinate of the origin",
value: "x-coord", value: "x-coord",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 0.01, min_value: 0.01,
required: true, required: true,
}, },
@@ -54,7 +55,7 @@ module.exports = {
name: "y-coord", name: "y-coord",
description: "Y Coordinate of the origin", description: "Y Coordinate of the origin",
value: "y-coord", value: "y-coord",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 0.01, min_value: 0.01,
required: true, required: true,
}, },
@@ -62,7 +63,7 @@ module.exports = {
name: "radius", name: "radius",
description: "Radius of Alarm", description: "Radius of Alarm",
value: "radius", value: "radius",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 25.00, min_value: 25.00,
required: true, required: true,
}, },
@@ -108,13 +109,13 @@ module.exports = {
name: "delete", name: "delete",
description: "Delete an Alarm", description: "Delete an Alarm",
value: "delete", value: "delete",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
{ {
name: "add-player", name: "add-player",
description: "Add player to be ignored list of an Alarm", description: "Add player to be ignored list of an Alarm",
value: "add-player", value: "add-player",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "gamertag", name: "gamertag",
description: "Gamertag of player to ignore", description: "Gamertag of player to ignore",
@@ -127,7 +128,7 @@ module.exports = {
name: "remove-player", name: "remove-player",
description: "Remove a player from the ignored list of an Alarm", description: "Remove a player from the ignored list of an Alarm",
value: "remove-player", value: "remove-player",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "gamertag", name: "gamertag",
description: "Gamertag of player to ignore", description: "Gamertag of player to ignore",
@@ -140,19 +141,19 @@ module.exports = {
name: "disable", name: "disable",
description: "Disable an Alarm", description: "Disable an Alarm",
value: "disable", value: "disable",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
{ {
name: "enable", name: "enable",
description: "Enable an Alarm", description: "Enable an Alarm",
value: "enable", value: "enable",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
{ {
name: "mute", name: "mute",
description: "Mute the role ping of an Alarm", description: "Mute the role ping of an Alarm",
value: "mute", value: "mute",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "toggle", name: "toggle",
description: "Turn on/off role pings for this alarm", description: "Turn on/off role pings for this alarm",
@@ -165,7 +166,7 @@ module.exports = {
name: "set-rule", name: "set-rule",
description: "Add a Rule to an Alarm", description: "Add a Rule to an Alarm",
value: "set-rule", value: "set-rule",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "rule", name: "rule",
description: "Select a rule to add to an Alarm", description: "Select a rule to add to an Alarm",
@@ -183,13 +184,13 @@ module.exports = {
name: "remove-rule", name: "remove-rule",
description: "Remove a rule from an Alarm", description: "Remove a rule from an Alarm",
value: "remove-rule", value: "remove-rule",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
{ {
name: "rename", name: "rename",
description: "Rename an Alarm", description: "Rename an Alarm",
value: "rename", value: "rename",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "name", name: "name",
description: "New Alarm Name", description: "New Alarm Name",
@@ -202,12 +203,12 @@ module.exports = {
name: "move-origin", name: "move-origin",
description: "Move the origin of an Alarm", description: "Move the origin of an Alarm",
value: "move-origin", value: "move-origin",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "x-coord", name: "x-coord",
description: "X Coordinate of the new origin", description: "X Coordinate of the new origin",
value: "x-coord", value: "x-coord",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 0.01, min_value: 0.01,
required: true, required: true,
}, },
@@ -215,7 +216,7 @@ module.exports = {
name: "y-coord", name: "y-coord",
description: "Y Coordinate of the new origin", description: "Y Coordinate of the new origin",
value: "y-coord", value: "y-coord",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 0.01, min_value: 0.01,
required: true, required: true,
}] }]
@@ -237,7 +238,7 @@ module.exports = {
if (GuildDB.hasBotAdmin && interaction.member.roles.filter(e => GuildDB.botAdminRoles.indexOf(e) !== -1).length > 0) canUseCommand = true; if (GuildDB.hasBotAdmin && interaction.member.roles.filter(e => GuildDB.botAdminRoles.indexOf(e) !== -1).length > 0) canUseCommand = true;
if (!canUseCommand) return interaction.send({ content: "You don\"t have the permissions to use this command." }); if (!canUseCommand) return interaction.send({ content: "You don\"t have the permissions to use this command." });
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -259,8 +260,8 @@ module.exports = {
role: args[0].options[5].value, role: args[0].options[5].value,
ignoredPlayers: [], ignoredPlayers: [],
rules: [], rules: [],
empExempt: client.exists(args[0].options[6]) ? args[0].options[6].value : false, empExempt: isDefined(args[0].options[6]) ? args[0].options[6].value : false,
showPlayerCoord: client.exists(args[0].options[7]) ? args[0].options[7].value : true, showPlayerCoord: isDefined(args[0].options[7]) ? args[0].options[7].value : true,
disabled: false, disabled: false,
empExpire: null, empExpire: null,
}; };
@@ -451,7 +452,7 @@ module.exports = {
let alarmIndex = GuildDB.alarms.indexOf(alarm); let alarmIndex = GuildDB.alarms.indexOf(alarm);
let playerStat = await client.dbo.collection("players").findOne({ "gamertag": interaction.customId.split("-")[2] }); let playerStat = await client.dbo.collection("players").findOne({ "gamertag": interaction.customId.split("-")[2] });
if (!client.exists(playerStat)) return interaction.update({ 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.")], components: [] }); if (!isDefined(playerStat)) return interaction.update({ 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.")], components: [] });
let add = interaction.customId.split("-")[1] == "add"; let add = interaction.customId.split("-")[1] == "add";
+10 -9
View File
@@ -1,6 +1,7 @@
const { EmbedBuilder } = require("discord.js"); const { EmbedBuilder } = require("discord.js");
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const { createUser, addUser } = require("../database/user"); const { createUser, addUser } = require("../database/user");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "bank", name: "bank",
@@ -17,7 +18,7 @@ module.exports = {
name: "balance", name: "balance",
description: "View your bank balance", description: "View your bank balance",
value: "balance", value: "balance",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "user", name: "user",
description: "User to view ballance", description: "User to view ballance",
@@ -30,7 +31,7 @@ module.exports = {
name: "transfer", name: "transfer",
description: "Transfer money to another user", description: "Transfer money to another user",
value: "transfer", value: "transfer",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [ options: [
{ {
name: "user", name: "user",
@@ -43,7 +44,7 @@ module.exports = {
name: "amount", name: "amount",
description: "The amount to transfer", description: "The amount to transfer",
value: "amount", value: "amount",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 0.01, min_value: 0.01,
required: true, required: true,
}, },
@@ -67,11 +68,11 @@ module.exports = {
if (!banking) { if (!banking) {
banking = await createUser(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, client) banking = await createUser(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, client)
if (!client.exists(banking)) return client.sendInternalError(interaction, err); if (!isDefined(banking)) return client.sendInternalError(interaction, err);
} }
banking = banking.user; banking = banking.user;
if (!client.exists(banking.guilds[GuildDB.serverID])) { if (!isDefined(banking.guilds[GuildDB.serverID])) {
const success = addUser(banking.guilds, GuildDB.serverID, interaction.member.user.id, client, GuildDB.startingBalance); const success = addUser(banking.guilds, GuildDB.serverID, interaction.member.user.id, client, GuildDB.startingBalance);
if (!success) return client.sendInternalError(interaction, "Failed to add bank"); if (!success) return client.sendInternalError(interaction, "Failed to add bank");
} }
@@ -88,11 +89,11 @@ module.exports = {
if (!targetUserBanking) { if (!targetUserBanking) {
targetUserBanking = await createUser(targetUserID, GuildDB.serverID, GuildDB.startingBalance, client) targetUserBanking = await createUser(targetUserID, GuildDB.serverID, GuildDB.startingBalance, client)
if (!client.exists(banking)) return client.sendInternalError(interaction, err); if (!isDefined(banking)) return client.sendInternalError(interaction, err);
} }
targetUserBanking = targetUserBanking.user; targetUserBanking = targetUserBanking.user;
if (!client.exists(targetUserBanking.guilds[GuildDB.serverID])) { if (!isDefined(targetUserBanking.guilds[GuildDB.serverID])) {
const success = addUser(banking.guilds, GuildDB.serverID, targetUserID, client, GuildDB.startingBalance); const success = addUser(banking.guilds, GuildDB.serverID, targetUserID, client, GuildDB.startingBalance);
if (!success) return client.sendInternalError(interaction, "Failed to add bank"); if (!success) return client.sendInternalError(interaction, "Failed to add bank");
} }
@@ -138,11 +139,11 @@ module.exports = {
if (!targetUserBanking) { if (!targetUserBanking) {
targetUserBanking = await createUser(targetUserID, GuildDB.serverID, GuildDB.startingBalance, client) targetUserBanking = await createUser(targetUserID, GuildDB.serverID, GuildDB.startingBalance, client)
if (!client.exists(banking)) return client.sendInternalError(interaction, err); if (!isDefined(banking)) return client.sendInternalError(interaction, err);
} }
targetUserBanking = targetUserBanking.user; targetUserBanking = targetUserBanking.user;
if (!client.exists(targetUserBanking.guilds[GuildDB.serverID])) { if (!isDefined(targetUserBanking.guilds[GuildDB.serverID])) {
const success = addUser(banking.guilds, GuildDB.serverID, targetUserID, client, GuildDB.startingBalance); const success = addUser(banking.guilds, GuildDB.serverID, targetUserID, client, GuildDB.startingBalance);
if (!success) return client.sendInternalError(interaction, "Failed to add bank"); if (!success) return client.sendInternalError(interaction, "Failed to add bank");
} }
+10 -9
View File
@@ -2,6 +2,7 @@ const { EmbedBuilder } = require("discord.js");
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const { createUser, addUser } = require("../database/user"); const { createUser, addUser } = require("../database/user");
const { UpdatePlayer } = require("../database/player"); const { UpdatePlayer } = require("../database/player");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "bounty", name: "bounty",
@@ -17,7 +18,7 @@ module.exports = {
name: "set", name: "set",
description: "Set a bounty on a player", description: "Set a bounty on a player",
value: "set", value: "set",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "gamertag", name: "gamertag",
description: "Gamertag of player for bounty", description: "Gamertag of player for bounty",
@@ -28,7 +29,7 @@ module.exports = {
name: "value", name: "value",
description: "Amount of the bounty", description: "Amount of the bounty",
value: "value", value: "value",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 0.01, min_value: 0.01,
required: true required: true
}, { }, {
@@ -42,12 +43,12 @@ module.exports = {
name: "pay", name: "pay",
description: "Pay off your bounty", description: "Pay off your bounty",
value: "pay", value: "pay",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, { }, {
name: "view", name: "view",
description: "View all active bounties", description: "View all active bounties",
value: "view", value: "view",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}], }],
SlashCommand: { SlashCommand: {
/** /**
@@ -59,7 +60,7 @@ module.exports = {
*/ */
run: async (client, interaction, args, { GuildDB }) => { run: async (client, interaction, args, { GuildDB }) => {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -73,11 +74,11 @@ module.exports = {
if (!banking) { if (!banking) {
banking = await createUser(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, client) banking = await createUser(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, client)
if (!client.exists(banking)) return client.sendInternalError(interaction, err); if (!isDefined(banking)) return client.sendInternalError(interaction, err);
} }
banking = banking.user; banking = banking.user;
if (!client.exists(banking.guilds[GuildDB.serverID])) { if (!isDefined(banking.guilds[GuildDB.serverID])) {
const success = addUser(banking.guilds, GuildDB.serverID, interaction.member.user.id, client, GuildDB.startingBalance); const success = addUser(banking.guilds, GuildDB.serverID, interaction.member.user.id, client, GuildDB.startingBalance);
if (!success) return client.sendInternalError(interaction, "Failed to add bank"); if (!success) return client.sendInternalError(interaction, "Failed to add bank");
} }
@@ -86,7 +87,7 @@ module.exports = {
if (args[0].name == "set") { if (args[0].name == "set") {
let playerStat = await client.dbo.collection("players").findOne({ "gamertag": args[0].options[0].value }); let playerStat = await client.dbo.collection("players").findOne({ "gamertag": args[0].options[0].value });
if (!client.exists(playerStat)) 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 `.")] }); if (!isDefined(playerStat)) 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 `.")] });
if (args[0].options[1].value > banking.guilds[GuildDB.serverID].balance) { if (args[0].options[1].value > banking.guilds[GuildDB.serverID].balance) {
let nsf = new EmbedBuilder() let nsf = new EmbedBuilder()
@@ -126,7 +127,7 @@ module.exports = {
} else if (args[0].name == "pay") { } else if (args[0].name == "pay") {
let playerStat = await client.dbo.collection("players").findOne({ "discordID": interaction.member.user.id }); let playerStat = await client.dbo.collection("players").findOne({ "discordID": interaction.member.user.id });
if (!client.exists(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription("**Not Found** Your user ID could not be found, contact an Admin.")] }); if (!isDefined(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription("**Not Found** Your user ID could not be found, contact an Admin.")] });
if (playerStat.bounties.length == 0) { if (playerStat.bounties.length == 0) {
const noBounty = new EmbedBuilder() const noBounty = new EmbedBuilder()
+4 -3
View File
@@ -1,5 +1,6 @@
const { EmbedBuilder, } = require("discord.js"); const { EmbedBuilder, } = require("discord.js");
const { createUser, addUser } = require("../database/user"); const { createUser, addUser } = require("../database/user");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "collect-income", name: "collect-income",
@@ -44,16 +45,16 @@ module.exports = {
if (!banking) { if (!banking) {
banking = await createUser(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, client) banking = await createUser(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, client)
if (!client.exists(banking)) return client.sendInternalError(interaction, err); if (!isDefined(banking)) return client.sendInternalError(interaction, err);
} }
banking = banking.user; banking = banking.user;
if (!client.exists(banking.guilds[GuildDB.serverID])) { if (!isDefined(banking.guilds[GuildDB.serverID])) {
const success = addUser(banking.guilds, GuildDB.serverID, interaction.member.user.id, client, GuildDB.startingBalance); const success = addUser(banking.guilds, GuildDB.serverID, interaction.member.user.id, client, GuildDB.startingBalance);
if (!success) return client.sendInternalError(interaction, "Failed to add bank"); if (!success) return client.sendInternalError(interaction, "Failed to add bank");
} }
if (!client.exists(banking.guilds[GuildDB.serverID].lastIncome)) banking.guilds[GuildDB.serverID].lastIncome = new Date("2000-01-01T00:00:00"); if (!isDefined(banking.guilds[GuildDB.serverID].lastIncome)) banking.guilds[GuildDB.serverID].lastIncome = new Date("2000-01-01T00:00:00");
let now = new Date(); let now = new Date();
let diff = (now - banking.guilds[GuildDB.serverID].lastIncome) / 1000; let diff = (now - banking.guilds[GuildDB.serverID].lastIncome) / 1000;
+6 -5
View File
@@ -1,6 +1,7 @@
const { EmbedBuilder } = require("discord.js"); const { EmbedBuilder } = require("discord.js");
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const { insertPVPstats } = require("../database/player"); const { insertPVPstats } = require("../database/player");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "compare-rating", name: "compare-rating",
@@ -34,7 +35,7 @@ module.exports = {
*/ */
run: async (client, interaction, args, { GuildDB }) => { run: async (client, interaction, args, { GuildDB }) => {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -56,8 +57,8 @@ module.exports = {
if (gamertag) comp = leaderboard.find(s => s.gamertag == gamertag); if (gamertag) comp = leaderboard.find(s => s.gamertag == gamertag);
let self = leaderboard.find(s => s.discordID == interaction.member.user.id); let self = leaderboard.find(s => s.discordID == interaction.member.user.id);
if (!client.exists(comp)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** Unable to find any records with the gamertag or user provided.`)] }); if (!isDefined(comp)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** Unable to find any records with the gamertag or user provided.`)] });
if (!client.exists(self)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** You haven"t linked your gamertag and your stats cannot be found.`)] }); if (!isDefined(self)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** You haven"t linked your gamertag and your stats cannot be found.`)] });
let lbPosSelf = leaderboard.indexOf(self) + 1; let lbPosSelf = leaderboard.indexOf(self) + 1;
let lbPosComp = leaderboard.indexOf(comp) + 1; let lbPosComp = leaderboard.indexOf(comp) + 1;
@@ -69,8 +70,8 @@ module.exports = {
let selfDataMax = Math.max(...selfData); let selfDataMax = Math.max(...selfData);
let compDataMax = Math.max(...compData); let compDataMax = Math.max(...compData);
if (!client.exists(self.highestCombatRating) || self.highestCombatRating < selfDataMax) self.highestCombatRating = selfDataMax; if (!isDefined(self.highestCombatRating) || self.highestCombatRating < selfDataMax) self.highestCombatRating = selfDataMax;
if (!client.exists(comp.highestCombatRating) || comp.highestCombatRating < compDataMax) comp.highestCombatRating = compDataMax; if (!isDefined(comp.highestCombatRating) || comp.highestCombatRating < compDataMax) comp.highestCombatRating = compDataMax;
let tag = comp.discordID != "" ? `<@${comp.discordID}>` : comp.gamertag; let tag = comp.discordID != "" ? `<@${comp.discordID}>` : comp.gamertag;
+46 -45
View File
@@ -2,6 +2,7 @@ const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const bitfieldCalculator = require("discord-bitfield-calculator"); const bitfieldCalculator = require("discord-bitfield-calculator");
const { getDefaultSettings } = require("../database/guild"); const { getDefaultSettings } = require("../database/guild");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "config", name: "config",
@@ -18,13 +19,13 @@ module.exports = {
name: "killfeed", name: "killfeed",
description: "Configure the killfeed", description: "Configure the killfeed",
value: "killfeed", value: "killfeed",
type: ApplicationCommandOptionType.SubCommandGroup, type: ApplicationCommandOptionType.SubcommandGroup,
options: [ options: [
{ {
name: "channel", name: "channel",
description: "Configure the killfeed channel", description: "Configure the killfeed channel",
value: "channel", value: "channel",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "channel", name: "channel",
description: "The channel to configure", description: "The channel to configure",
@@ -37,7 +38,7 @@ module.exports = {
name: "show_coords", name: "show_coords",
description: "Show the coordinates of the victim in the killfeed channel.", description: "Show the coordinates of the victim in the killfeed channel.",
value: "show_coords", value: "show_coords",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "configuration", name: "configuration",
description: "True or False", description: "True or False",
@@ -50,7 +51,7 @@ module.exports = {
name: "show_weapon", name: "show_weapon",
description: "Show the image of the weapon in the killfeed", description: "Show the image of the weapon in the killfeed",
value: "show_weapon", value: "show_weapon",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "configuration", name: "configuration",
description: "True or False", description: "True or False",
@@ -65,13 +66,13 @@ module.exports = {
name: "allowed_channels", name: "allowed_channels",
description: "Set channels you're allowed to use the bot in", description: "Set channels you're allowed to use the bot in",
value: "allowed_channels", value: "allowed_channels",
type: ApplicationCommandOptionType.SubCommandGroup, type: ApplicationCommandOptionType.SubcommandGroup,
options: [ options: [
{ {
name: "add", name: "add",
description: "Add channel", description: "Add channel",
value: "add", value: "add",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "channel", name: "channel",
description: "The channel to configure", description: "The channel to configure",
@@ -85,7 +86,7 @@ module.exports = {
name: "remove", name: "remove",
description: "Remove channel", description: "Remove channel",
value: "remove", value: "remove",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "channel", name: "channel",
description: "The channel to configure", description: "The channel to configure",
@@ -99,13 +100,13 @@ module.exports = {
name: "clear", name: "clear",
description: "Clears all configured channels", description: "Clears all configured channels",
value: "clear", value: "clear",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
{ {
name: "view", name: "view",
description: "View configured allowed channels", description: "View configured allowed channels",
value: "view", value: "view",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
} }
] ]
}, },
@@ -113,7 +114,7 @@ module.exports = {
name: "set_channel", name: "set_channel",
description: "Configure a channel", description: "Configure a channel",
value: "set_channel", value: "set_channel",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [ options: [
{ {
name: "channel_type", name: "channel_type",
@@ -140,7 +141,7 @@ module.exports = {
name: "linked_gt_role", name: "linked_gt_role",
description: "Role for users with linked gamertags", description: "Role for users with linked gamertags",
value: "linked_gt_role", value: "linked_gt_role",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "role", name: "role",
description: "Role to configure", description: "Role to configure",
@@ -153,7 +154,7 @@ module.exports = {
name: "member_role", name: "member_role",
description: "Role for users who join the server", description: "Role for users who join the server",
value: "member_role", value: "member_role",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "role", name: "role",
description: "Role to configure", description: "Role to configure",
@@ -166,13 +167,13 @@ module.exports = {
name: "bot_admin_role", name: "bot_admin_role",
description: "Set/remove bot admin role", description: "Set/remove bot admin role",
value: "bot_admin_role", value: "bot_admin_role",
type: ApplicationCommandOptionType.SubCommandGroup, type: ApplicationCommandOptionType.SubcommandGroup,
options: [ options: [
{ {
name: "add", name: "add",
description: "Configure role to be bot admin", description: "Configure role to be bot admin",
value: "add", value: "add",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "role", name: "role",
description: "Role to confiure", description: "Role to confiure",
@@ -185,7 +186,7 @@ module.exports = {
name: "remove", name: "remove",
description: "Remove configured role as bot admin", description: "Remove configured role as bot admin",
value: "remove", value: "remove",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "role", name: "role",
description: "Role to remove", description: "Role to remove",
@@ -198,7 +199,7 @@ module.exports = {
name: "view", name: "view",
description: "View the configured bot admin roles", description: "View the configured bot admin roles",
value: "view", value: "view",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
} }
] ]
}, },
@@ -206,7 +207,7 @@ module.exports = {
name: "admin_ping_role", name: "admin_ping_role",
description: "Admin role to ping in admin logs channel", description: "Admin role to ping in admin logs channel",
value: "admin_ping_role", value: "admin_ping_role",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "role", name: "role",
description: "Role to configure", description: "Role to configure",
@@ -219,13 +220,13 @@ module.exports = {
name: "exclude", name: "exclude",
description: "Exclude roles that can be used to claim armbands", description: "Exclude roles that can be used to claim armbands",
value: "exclude", value: "exclude",
type: ApplicationCommandOptionType.SubCommandGroup, type: ApplicationCommandOptionType.SubcommandGroup,
options: [ options: [
{ {
name: "add", name: "add",
description: "Configure role to be excluded", description: "Configure role to be excluded",
value: "add", value: "add",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "role", name: "role",
description: "Role to confiure", description: "Role to confiure",
@@ -238,7 +239,7 @@ module.exports = {
name: "remove", name: "remove",
description: "Remove configured role thats excluded", description: "Remove configured role thats excluded",
value: "remove", value: "remove",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "role", name: "role",
description: "Role to remove", description: "Role to remove",
@@ -251,7 +252,7 @@ module.exports = {
name: "view", name: "view",
description: "View the configured excluded roles", description: "View the configured excluded roles",
value: "view", value: "view",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
] ]
}, },
@@ -259,24 +260,24 @@ module.exports = {
name: "reset", name: "reset",
description: "Restore all settings to default configurations", description: "Restore all settings to default configurations",
value: "reset", value: "reset",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
{ {
name: "view", name: "view",
description: "View current settings configuration", description: "View current settings configuration",
value: "view", value: "view",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
{ {
name: "starting_balance", name: "starting_balance",
description: "Set the starting balance of a new user", description: "Set the starting balance of a new user",
value: "starting_balance", value: "starting_balance",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "amount", name: "amount",
description: "The amount to set the starting balance", description: "The amount to set the starting balance",
value: "amount", value: "amount",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 1.00, min_value: 1.00,
required: true, required: true,
}] }]
@@ -285,12 +286,12 @@ module.exports = {
name: "uav-price", name: "uav-price",
description: "Configure the price of a UAV", description: "Configure the price of a UAV",
value: "uav-price", value: "uav-price",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "amount", name: "amount",
description: "The amount to set the UAV price", description: "The amount to set the UAV price",
value: "amount", value: "amount",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 0.01, min_value: 0.01,
required: true, required: true,
}] }]
@@ -299,12 +300,12 @@ module.exports = {
name: "emp-price", name: "emp-price",
description: "Configure the price of an EMP", description: "Configure the price of an EMP",
value: "emp-price", value: "emp-price",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "amount", name: "amount",
description: "The amount to set the EMP price", description: "The amount to set the EMP price",
value: "amount", value: "amount",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 0.01, min_value: 0.01,
required: true, required: true,
}] }]
@@ -313,13 +314,13 @@ module.exports = {
name: "income_role", name: "income_role",
description: "Set/remove roles to recieve income", description: "Set/remove roles to recieve income",
value: "set_income_role", value: "set_income_role",
type: ApplicationCommandOptionType.SubCommandGroup, type: ApplicationCommandOptionType.SubcommandGroup,
options: [ options: [
{ {
name: "set", name: "set",
description: "Set role", description: "Set role",
value: "set", value: "set",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [ options: [
{ {
name: "role", name: "role",
@@ -332,7 +333,7 @@ module.exports = {
name: "amount", name: "amount",
description: "The amount to collect", description: "The amount to collect",
value: 120.00, value: 120.00,
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 0.01, min_value: 0.01,
required: true, required: true,
} }
@@ -342,7 +343,7 @@ module.exports = {
name: "remove", name: "remove",
description: "Remove role", description: "Remove role",
value: "remove", value: "remove",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "role", name: "role",
description: "Role to remove", description: "Role to remove",
@@ -357,12 +358,12 @@ module.exports = {
name: "income_limiter", name: "income_limiter",
description: "Change the number of hours to wait before collecting next income", description: "Change the number of hours to wait before collecting next income",
value: "income_limiter", value: "income_limiter",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "hours", name: "hours",
description: "Number of hours till income can be collected", description: "Number of hours till income can be collected",
value: 168.00, // 1 week value: 168.00, // 1 week
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 1.00, min_value: 1.00,
required: true, required: true,
}] }]
@@ -371,7 +372,7 @@ module.exports = {
name: "combat-log-timer", name: "combat-log-timer",
description: "Adjust number of minutes to detect combat logs (0 disables combat log)", description: "Adjust number of minutes to detect combat logs (0 disables combat log)",
value: "combat-log-timer", value: "combat-log-timer",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "minutes", name: "minutes",
description: "Minutes to qualify combat log", description: "Minutes to qualify combat log",
@@ -384,7 +385,7 @@ module.exports = {
name: "toggle-uav-purchase", name: "toggle-uav-purchase",
description: "Allow/Disallow UAV purchases", description: "Allow/Disallow UAV purchases",
value: "toggle-uav-purchase", value: "toggle-uav-purchase",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "configuration", name: "configuration",
description: "True or False", description: "True or False",
@@ -397,7 +398,7 @@ module.exports = {
name: "toggle-emp-purchase", name: "toggle-emp-purchase",
description: "Allow/Disallow EMP purchases", description: "Allow/Disallow EMP purchases",
value: "toggle-uav-purchase", value: "toggle-uav-purchase",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "configuration", name: "configuration",
description: "True or False", description: "True or False",
@@ -410,7 +411,7 @@ module.exports = {
name: "welcome_message_server_name", name: "welcome_message_server_name",
description: "Configure the server name in the welcome message", description: "Configure the server name in the welcome message",
value: "welcome_message_server_name", value: "welcome_message_server_name",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "name", name: "name",
description: "Server name to include in welcome message", description: "Server name to include in welcome message",
@@ -712,12 +713,12 @@ module.exports = {
// Role / channel display // Role / channel display
const NONE = `${w}${m}none${w}`; const NONE = `${w}${m}none${w}`;
const channelsInfo = GuildDB.customChannelStatus ? "\`</channels:1225869620813107246>\` to view" : NONE; const channelsInfo = GuildDB.customChannelStatus ? "\`</channels:1225869620813107246>\` to view" : NONE;
const killfeedChannel = client.exists(GuildDB.killfeedChannel) ? `<#${GuildDB.killfeedChannel}>` : NONE; const killfeedChannel = isDefined(GuildDB.killfeedChannel) ? `<#${GuildDB.killfeedChannel}>` : NONE;
const connectionLogs = client.exists(GuildDB.connectionLogsChannel) ? `<#${GuildDB.connectionLogsChannel}>` : NONE; const connectionLogs = isDefined(GuildDB.connectionLogsChannel) ? `<#${GuildDB.connectionLogsChannel}>` : NONE;
const activePlayers = client.exists(GuildDB.activePlayersChannel) ? `<#${GuildDB.activePlayersChannel}>` : NONE; const activePlayers = isDefined(GuildDB.activePlayersChannel) ? `<#${GuildDB.activePlayersChannel}>` : NONE;
const welcomeChannel = client.exists(GuildDB.welcomeChannel) ? `<#${GuildDB.welcomeChannel}>` : NONE; const welcomeChannel = isDefined(GuildDB.welcomeChannel) ? `<#${GuildDB.welcomeChannel}>` : NONE;
const linkedGTRole = client.exists(GuildDB.linkedGamertagRole) ? `<@&${GuildDB.linkedGamertagRole}>` : NONE; const linkedGTRole = isDefined(GuildDB.linkedGamertagRole) ? `<@&${GuildDB.linkedGamertagRole}>` : NONE;
const memberRole = client.exists(GuildDB.memberRole) ? `<@&${GuildDB.memberRole}>` : NONE; const memberRole = isDefined(GuildDB.memberRole) ? `<@&${GuildDB.memberRole}>` : NONE;
// value display // value display
const incomeLimiter = `${GuildDB.incomeLimiter} hours`; const incomeLimiter = `${GuildDB.incomeLimiter} hours`;
+5 -4
View File
@@ -1,6 +1,7 @@
const { EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require("discord.js"); const { EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require("discord.js");
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const bitfieldCalculator = require("discord-bitfield-calculator"); const bitfieldCalculator = require("discord-bitfield-calculator");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "event", name: "event",
@@ -16,7 +17,7 @@ module.exports = {
name: "player-track", name: "player-track",
description: "Track a player and announce location", description: "Track a player and announce location",
value: "player-track", value: "player-track",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "gamertag", name: "gamertag",
description: "Gamertag of player", description: "Gamertag of player",
@@ -60,7 +61,7 @@ module.exports = {
name: "delete", name: "delete",
description: "Delete an active event", description: "Delete an active event",
value: "delete", value: "delete",
type: ApplicationCommandOptionType.SubCommand type: ApplicationCommandOptionType.Subcommand
}], }],
SlashCommand: { SlashCommand: {
/** /**
@@ -72,7 +73,7 @@ module.exports = {
*/ */
run: async (client, interaction, args, { GuildDB }) => { run: async (client, interaction, args, { GuildDB }) => {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -92,7 +93,7 @@ module.exports = {
if (args[0].name == "player-track") { if (args[0].name == "player-track") {
let playerStat = await client.dbo.collection("players").findOne({ "gamertag": args[0].options[0].value }); let playerStat = await client.dbo.collection("players").findOne({ "gamertag": args[0].options[0].value });
if (!client.exists(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** This gamertag \` ${args[0].options[0].value} \` cannot be found, the gamertag may be incorrect or this player has not logged onto the server before for at least \` 5 minutes \`.`)] }); if (!isDefined(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** This gamertag \` ${args[0].options[0].value} \` cannot be found, the gamertag may be incorrect or this player has not logged onto the server before for at least \` 5 minutes \`.`)] });
let event = { let event = {
type: args[0].name, type: args[0].name,
+8 -7
View File
@@ -1,6 +1,7 @@
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"); const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const { UpdatePlayer } = require("../database/player"); const { UpdatePlayer } = require("../database/player");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "gamertag-link", name: "gamertag-link",
@@ -29,7 +30,7 @@ module.exports = {
*/ */
run: async (client, interaction, args, { GuildDB }) => { run: async (client, interaction, args, { GuildDB }) => {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -38,9 +39,9 @@ module.exports = {
} }
let playerStat = await client.dbo.collection("players").findOne({ "gamertag": args[0].value }); let playerStat = await client.dbo.collection("players").findOne({ "gamertag": args[0].value });
if (!client.exists(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** This gamertag \` ${args[0].value} \` cannot be found, the gamertag may be incorrect or this player has not logged onto the server before for at least \` 5 minutes \`.`)] }); if (!isDefined(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** This gamertag \` ${args[0].value} \` cannot be found, the gamertag may be incorrect or this player has not logged onto the server before for at least \` 5 minutes \`.`)] });
if (client.exists(playerStat.discordID)) { if (isDefined(playerStat.discordID)) {
const warnGTOverwrite = new EmbedBuilder() const warnGTOverwrite = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription(`**Notice:**\n> The gamertag has previously been linked to <@${playerStat.discordID}>. Are you sure you would like to change this?`) .setDescription(`**Notice:**\n> The gamertag has previously been linked to <@${playerStat.discordID}>. Are you sure you would like to change this?`)
@@ -65,12 +66,12 @@ module.exports = {
await UpdatePlayer(client, playerStat, interaction); await UpdatePlayer(client, playerStat, interaction);
let member = interaction.guild.members.cache.get(interaction.member.user.id); let member = interaction.guild.members.cache.get(interaction.member.user.id);
if (client.exists(GuildDB.linkedGamertagRole)) { if (isDefined(GuildDB.linkedGamertagRole)) {
let role = interaction.guild.roles.cache.get(GuildDB.linkedGamertagRole); let role = interaction.guild.roles.cache.get(GuildDB.linkedGamertagRole);
member.roles.add(role); member.roles.add(role);
} }
if (client.exists(GuildDB.memberRole)) { if (isDefined(GuildDB.memberRole)) {
let role = interaction.guild.roles.cache.get(GuildDB.memberRole); let role = interaction.guild.roles.cache.get(GuildDB.memberRole);
member.roles.add(role); member.roles.add(role);
} }
@@ -98,12 +99,12 @@ module.exports = {
await UpdatePlayer(client, playerStat, interaction); await UpdatePlayer(client, playerStat, interaction);
let member = interaction.guild.members.cache.get(interaction.member.user.id); let member = interaction.guild.members.cache.get(interaction.member.user.id);
if (client.exists(GuildDB.linkedGamertagRole)) { if (isDefined(GuildDB.linkedGamertagRole)) {
let role = interaction.guild.roles.cache.get(GuildDB.linkedGamertagRole); let role = interaction.guild.roles.cache.get(GuildDB.linkedGamertagRole);
member.roles.add(role); member.roles.add(role);
} }
if (client.exists(GuildDB.memberRole)) { if (isDefined(GuildDB.memberRole)) {
let role = interaction.guild.roles.cache.get(GuildDB.memberRole); let role = interaction.guild.roles.cache.get(GuildDB.memberRole);
member.roles.add(role); member.roles.add(role);
} }
+3 -2
View File
@@ -1,5 +1,6 @@
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"); const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
const { UpdatePlayer } = require("../database/player"); const { UpdatePlayer } = require("../database/player");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "gamertag-unlink", name: "gamertag-unlink",
@@ -21,7 +22,7 @@ module.exports = {
*/ */
run: async (client, interaction, args, { GuildDB }) => { run: async (client, interaction, args, { GuildDB }) => {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -30,7 +31,7 @@ module.exports = {
} }
let playerStat = await client.dbo.collection("players").findOne({ "discordID": interaction.member.user.id }); let playerStat = await client.dbo.collection("players").findOne({ "discordID": interaction.member.user.id });
if (!client.exists(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**No Gamertag Linked** It Appears your don"t have a gamertag linked to your account.`)] }); if (!isDefined(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**No Gamertag Linked** It Appears your don"t have a gamertag linked to your account.`)] });
const warnGTOverwrite = new EmbedBuilder() const warnGTOverwrite = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
+4 -4
View File
@@ -17,7 +17,7 @@ module.exports = {
name: "commands", name: "commands",
description: "List all commands", description: "List all commands",
value: "commands", value: "commands",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "command", name: "command",
description: "Get information on a specific command", description: "Get information on a specific command",
@@ -30,19 +30,19 @@ module.exports = {
name: "support", name: "support",
description: "Get support for Application", description: "Get support for Application",
value: "support", value: "support",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
{ {
name: "credits", name: "credits",
description: "DayZ.R Bot Credits", description: "DayZ.R Bot Credits",
value: "credits", value: "credits",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
{ {
name: "stats", name: "stats",
description: "Current Bot Statistics", description: "Current Bot Statistics",
value: "stats", value: "stats",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
} }
], ],
SlashCommand: { SlashCommand: {
+2 -1
View File
@@ -1,5 +1,6 @@
const { EmbedBuilder } = require("discord.js"); const { EmbedBuilder } = require("discord.js");
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "leaderboard", name: "leaderboard",
@@ -53,7 +54,7 @@ module.exports = {
*/ */
run: async (client, interaction, args, { GuildDB }) => { run: async (client, interaction, args, { GuildDB }) => {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
+4 -3
View File
@@ -1,5 +1,6 @@
const { EmbedBuilder } = require("discord.js"); const { EmbedBuilder } = require("discord.js");
const { nearest } = require("../database/destinations"); const { nearest } = require("../database/destinations");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "location", name: "location",
@@ -21,7 +22,7 @@ module.exports = {
*/ */
run: async (client, interaction, args, { GuildDB }) => { run: async (client, interaction, args, { GuildDB }) => {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth) || !client.exists(GuildDB.Nitrado.Mission)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth) || !isDefined(GuildDB.Nitrado.Mission)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -30,8 +31,8 @@ module.exports = {
} }
let playerStat = await client.dbo.collection("players").findOne({ "discordID": interaction.member.user.id }); let playerStat = await client.dbo.collection("players").findOne({ "discordID": interaction.member.user.id });
if (!client.exists(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** You haven"t linked your gamertag and are unable to use this command.`)], flags: (1 << 6) }); if (!isDefined(playerStat)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** You haven"t linked your gamertag and are unable to use this command.`)], flags: (1 << 6) });
if (!client.exists(playerStat.time)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** There is no location saved to your gamertag yet. Make sure you"ve logged into the server for more than **5 minutes.**`)], flags: (1 << 6) }); if (!isDefined(playerStat.time)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** There is no location saved to your gamertag yet. Make sure you"ve logged into the server for more than **5 minutes.**`)], flags: (1 << 6) });
console.log(true); console.log(true);
+5 -4
View File
@@ -1,5 +1,6 @@
const { EmbedBuilder } = require("discord.js"); const { EmbedBuilder } = require("discord.js");
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "lookup", name: "lookup",
@@ -15,7 +16,7 @@ module.exports = {
name: "discord", name: "discord",
description: "Find a Discord user from a Gamertag", description: "Find a Discord user from a Gamertag",
value: "discord", value: "discord",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "gamertag", name: "gamertag",
description: "Gamertag of player", description: "Gamertag of player",
@@ -27,7 +28,7 @@ module.exports = {
name: "gamertag", name: "gamertag",
description: "Find a Gamertag from a Discord user", description: "Find a Gamertag from a Discord user",
value: "gamertag", value: "gamertag",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "user", name: "user",
description: "Discord User", description: "Discord User",
@@ -46,7 +47,7 @@ module.exports = {
*/ */
run: async (client, interaction, args, { GuildDB }) => { run: async (client, interaction, args, { GuildDB }) => {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -59,7 +60,7 @@ module.exports = {
let playerStat = await client.dbo.collection("players").findOne({ "gamertag": args[0].options[0].value }); let playerStat = await client.dbo.collection("players").findOne({ "gamertag": args[0].options[0].value });
if (playerStat == undefined) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** This gamertag \` ${args[0].options[0].value} \` cannot be found, the gamertag may be incorrect or this player has not logged onto the server before for at least \` 5 minutes \`.`)] }); if (playerStat == undefined) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** This gamertag \` ${args[0].options[0].value} \` cannot be found, the gamertag may be incorrect or this player has not logged onto the server before for at least \` 5 minutes \`.`)] });
if (client.exists(playerStat.discordID)) { if (isDefined(playerStat.discordID)) {
const found = new EmbedBuilder() const found = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription(`**Record Found**\n> The gamertag \` ${playerStat.gamertag} \` is currently linked to <@${playerStat.discordID}>.`) .setDescription(`**Record Found**\n> The gamertag \` ${playerStat.gamertag} \` is currently linked to <@${playerStat.discordID}>.`)
+3 -2
View File
@@ -1,6 +1,7 @@
const { FetchServerSettings } = require("../util/NitradoAPI"); const { FetchServerSettings } = require("../services/NitradoAPI");
const { Missions } = require("../database/destinations"); const { Missions } = require("../database/destinations");
const { EmbedBuilder } = require("discord.js"); const { EmbedBuilder } = require("discord.js");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "player-list", name: "player-list",
@@ -23,7 +24,7 @@ module.exports = {
*/ */
run: async (client, interaction, args, { GuildDB }, start) => { run: async (client, interaction, args, { GuildDB }, start) => {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
+7 -6
View File
@@ -1,6 +1,7 @@
const { EmbedBuilder } = require("discord.js"); const { EmbedBuilder } = require("discord.js");
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const { insertPVPstats } = require("../database/player"); const { insertPVPstats } = require("../database/player");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "player-stats", name: "player-stats",
@@ -57,7 +58,7 @@ module.exports = {
*/ */
run: async (client, interaction, args, { GuildDB }, start) => { run: async (client, interaction, args, { GuildDB }, start) => {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -84,7 +85,7 @@ module.exports = {
if (gamertag) query = leaderboard.find(u => u.user.userID == playerStat.discordID); // Searching by gamertag if (gamertag) query = leaderboard.find(u => u.user.userID == playerStat.discordID); // Searching by gamertag
if (self) query = leaderboard.find(u => u.user.userID == interaction.member.user.id); // Searching for self if (self) query = leaderboard.find(u => u.user.userID == interaction.member.user.id); // Searching for self
if (!client.exists(query)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** Unable to find any records with the gamertag or user provided.`)] }); if (!isDefined(query)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** Unable to find any records with the gamertag or user provided.`)] });
leaderboardPos = leaderboard.indexOf(query); leaderboardPos = leaderboard.indexOf(query);
} else { } else {
@@ -97,7 +98,7 @@ module.exports = {
if (gamertag) query = leaderboard.find(s => s.gamertag == gamertag); // Searching by gamertag if (gamertag) query = leaderboard.find(s => s.gamertag == gamertag); // Searching by gamertag
if (self) query = leaderboard.find(s => s.discordID == interaction.member.user.id); // Searching for self if (self) query = leaderboard.find(s => s.discordID == interaction.member.user.id); // Searching for self
if (!client.exists(query)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** Unable to find any records with the gamertag or user provided.`)] }); if (!isDefined(query)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** Unable to find any records with the gamertag or user provided.`)] });
leaderboardPos = leaderboard.indexOf(query); leaderboardPos = leaderboard.indexOf(query);
} }
@@ -142,7 +143,7 @@ module.exports = {
statsEmbed.addFields({ name: "Leaderboard Position", value: `# ${leaderboardPos}`, inline: true }); statsEmbed.addFields({ name: "Leaderboard Position", value: `# ${leaderboardPos}`, inline: true });
if ((category == "shotsLanded" || category == "timesShot") && !client.exists(query.shotsLanded)) query = insertPVPstats(query); if ((category == "shotsLanded" || category == "timesShot") && !isDefined(query.shotsLanded)) query = insertPVPstats(query);
if (category == "totalSessionTime") { if (category == "totalSessionTime") {
statsEmbed.addFields( statsEmbed.addFields(
@@ -242,8 +243,8 @@ module.exports = {
let dataMax = Math.max(...query.combatRatingHistory); let dataMax = Math.max(...query.combatRatingHistory);
let dataMin = Math.min(...query.combatRatingHistory); let dataMin = Math.min(...query.combatRatingHistory);
if (!client.exists(query.highestCombatRating) || query.highestCombatRating < dataMax) query.highestCombatRating = dataMax; if (!isDefined(query.highestCombatRating) || query.highestCombatRating < dataMax) query.highestCombatRating = dataMax;
if (!client.exists(query.lowestCombatRating) || query.lowestCombatRating > dataMin) query.lowestCombatRating = dataMin; if (!isDefined(query.lowestCombatRating) || query.lowestCombatRating > dataMin) query.lowestCombatRating = dataMin;
statsEmbed.addFields( statsEmbed.addFields(
{ name: "Combat Rating", value: `${query.combatRating}`, inline: true }, { name: "Combat Rating", value: `${query.combatRating}`, inline: true },
+5 -4
View File
@@ -1,6 +1,7 @@
const { EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require("discord.js"); const { EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require("discord.js");
const { createUser, addUser } = require("../database/user"); const { createUser, addUser } = require("../database/user");
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "purchase-emp", name: "purchase-emp",
@@ -33,7 +34,7 @@ module.exports = {
*/ */
run: async (client, interaction, args, { GuildDB }) => { run: async (client, interaction, args, { GuildDB }) => {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -41,18 +42,18 @@ module.exports = {
return interaction.send({ embeds: [warnNitradoNotInitialized], flags: (1 << 6) }); return interaction.send({ embeds: [warnNitradoNotInitialized], flags: (1 << 6) });
} }
if (client.exists(GuildDB.purchaseEMP) && !GuildDB.purchaseEMP) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription("**Notice:** The admins have disabled this feature")] }); if (isDefined(GuildDB.purchaseEMP) && !GuildDB.purchaseEMP) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription("**Notice:** The admins have disabled this feature")] });
const duration = args[0].value; const duration = args[0].value;
let banking = await client.dbo.collection("users").findOne({ "user.userID": interaction.member.user.id }).then(banking => banking); let banking = await client.dbo.collection("users").findOne({ "user.userID": interaction.member.user.id }).then(banking => banking);
if (!banking) { if (!banking) {
banking = await createUser(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, client) banking = await createUser(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, client)
if (!client.exists(banking)) return client.sendInternalError(interaction, err); if (!isDefined(banking)) return client.sendInternalError(interaction, err);
} }
banking = banking.user; banking = banking.user;
if (!client.exists(banking.guilds[GuildDB.serverID])) { if (!isDefined(banking.guilds[GuildDB.serverID])) {
const success = addUser(banking.guilds, GuildDB.serverID, interaction.member.user.id, client, GuildDB.startingBalance); const success = addUser(banking.guilds, GuildDB.serverID, interaction.member.user.id, client, GuildDB.startingBalance);
if (!success) return client.sendInternalError(interaction, "Failed to add bank"); if (!success) return client.sendInternalError(interaction, "Failed to add bank");
} }
+8 -7
View File
@@ -1,6 +1,7 @@
const { EmbedBuilder } = require("discord.js"); const { EmbedBuilder } = require("discord.js");
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const { createUser, addUser } = require("../database/user") const { createUser, addUser } = require("../database/user");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "purchase-uav", name: "purchase-uav",
@@ -17,7 +18,7 @@ module.exports = {
name: "x-coord", name: "x-coord",
description: "X Coordinate of the origin", description: "X Coordinate of the origin",
value: "x-coord", value: "x-coord",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 0.01, min_value: 0.01,
required: true, required: true,
}, },
@@ -25,7 +26,7 @@ module.exports = {
name: "y-coord", name: "y-coord",
description: "Y Coordinate of the origin", description: "Y Coordinate of the origin",
value: "y-coord", value: "y-coord",
type: ApplicationCommandOptionType.Float, type: ApplicationCommandOptionType.Number,
min_value: 0.01, min_value: 0.01,
required: true, required: true,
}, },
@@ -40,7 +41,7 @@ module.exports = {
*/ */
run: async (client, interaction, args, { GuildDB }) => { run: async (client, interaction, args, { GuildDB }) => {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -48,17 +49,17 @@ module.exports = {
return interaction.send({ embeds: [warnNitradoNotInitialized], flags: (1 << 6) }); return interaction.send({ embeds: [warnNitradoNotInitialized], flags: (1 << 6) });
} }
if (client.exists(GuildDB.purchaseUAV) && !GuildDB.purchaseUAV) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription("**Notice:** The admins have disabled this feature")] }); if (isDefined(GuildDB.purchaseUAV) && !GuildDB.purchaseUAV) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription("**Notice:** The admins have disabled this feature")] });
let banking = await client.dbo.collection("users").findOne({ "user.userID": interaction.member.user.id }).then(banking => banking); let banking = await client.dbo.collection("users").findOne({ "user.userID": interaction.member.user.id }).then(banking => banking);
if (!banking) { if (!banking) {
banking = await createUser(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, client) banking = await createUser(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, client)
if (!client.exists(banking)) return client.sendInternalError(interaction, err); if (!isDefined(banking)) return client.sendInternalError(interaction, err);
} }
banking = banking.user; banking = banking.user;
if (!client.exists(banking.guilds[GuildDB.serverID])) { if (!isDefined(banking.guilds[GuildDB.serverID])) {
const success = addUser(banking.guilds, GuildDB.serverID, interaction.member.user.id, client, GuildDB.startingBalance); const success = addUser(banking.guilds, GuildDB.serverID, interaction.member.user.id, client, GuildDB.startingBalance);
if (!success) return client.sendInternalError(interaction, "Failed to add bank"); if (!success) return client.sendInternalError(interaction, "Failed to add bank");
} }
+2 -1
View File
@@ -2,6 +2,7 @@ const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const { addUser } = require("../database/user"); const { addUser } = require("../database/user");
const bitfieldCalculator = require("discord-bitfield-calculator"); const bitfieldCalculator = require("discord-bitfield-calculator");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "reset", name: "reset",
@@ -33,7 +34,7 @@ module.exports = {
let canUseCommand = false; let canUseCommand = false;
if (permissions.includes("MANAGE_GUILD")) canUseCommand = true; if (permissions.includes("MANAGE_GUILD")) canUseCommand = true;
if (client.exists(GuildDB.botAdmin) && interaction.member.roles.includes(GuildDB.botAdmin)) canUseCommand = true; if (isDefined(GuildDB.botAdmin) && interaction.member.roles.includes(GuildDB.botAdmin)) canUseCommand = true;
if (!canUseCommand) return interaction.send({ content: "You don\"t have the permissions to use this command." }); if (!canUseCommand) return interaction.send({ content: "You don\"t have the permissions to use this command." });
const targetUserID = args[0].value.replace("<@!", "").replace(">", ""); const targetUserID = args[0].value.replace("<@!", "").replace(">", "");
+14 -13
View File
@@ -1,8 +1,9 @@
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, ModalBuilder, TextInputBuilder, TextInputStyle } = require("discord.js"); const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, ModalBuilder, TextInputBuilder, TextInputStyle } = require("discord.js");
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const bitfieldCalculator = require("discord-bitfield-calculator"); const bitfieldCalculator = require("discord-bitfield-calculator");
const { BanPlayer, UnbanPlayer, RestartServer, CheckServerStatus, DisableBaseDamage, DisableContainerDamage, NitradoCredentialStatus } = require("../util/NitradoAPI"); const { BanPlayer, UnbanPlayer, RestartServer, CheckServerStatus, DisableBaseDamage, DisableContainerDamage, NitradoCredentialStatus } = require("../services/NitradoAPI");
const { encrypt, decrypt } = require("../util/Cryptic"); const { encrypt, decrypt } = require("../util/Cryptic");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "server", name: "server",
@@ -18,31 +19,31 @@ module.exports = {
name: "initialize", name: "initialize",
description: "Connect your Nitrado server to the bot", description: "Connect your Nitrado server to the bot",
value: "initialize", value: "initialize",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
{ {
name: "disconnect", name: "disconnect",
description: "Delete your Nitrado server from the bot database", description: "Delete your Nitrado server from the bot database",
value: "disconnect", value: "disconnect",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
{ {
name: "credentials-status", name: "credentials-status",
description: "Check the status of your Nitrado Credentials", description: "Check the status of your Nitrado Credentials",
value: "credentials-status", value: "credentials-status",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
{ {
name: "retry-credentials", name: "retry-credentials",
description: "If your credentials are marked as FAILED, try retreiving Nitrado logs again.", description: "If your credentials are marked as FAILED, try retreiving Nitrado logs again.",
value: "retry-credentials", value: "retry-credentials",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, },
{ {
name: "ban-player", name: "ban-player",
description: "Ban a player from the DayZ server", description: "Ban a player from the DayZ server",
value: "ban-player", value: "ban-player",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "gamertag", name: "gamertag",
description: "gamertag of the player to ban.", description: "gamertag of the player to ban.",
@@ -54,7 +55,7 @@ module.exports = {
name: "unban-player", name: "unban-player",
description: "Unban a player from the DayZ server", description: "Unban a player from the DayZ server",
value: "unban-player", value: "unban-player",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "gamertag", name: "gamertag",
description: "gamertag of the player to unban.", description: "gamertag of the player to unban.",
@@ -67,17 +68,17 @@ module.exports = {
name: "restart", name: "restart",
description: "Restart the DayZ Server", description: "Restart the DayZ Server",
value: "restart", value: "restart",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, { }, {
name: "auto-restart", name: "auto-restart",
description: "Enable/Disable periodic server checks and restart if stopped", description: "Enable/Disable periodic server checks and restart if stopped",
value: "auto-restart", value: "auto-restart",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
}, { }, {
name: "disable-base-damage", name: "disable-base-damage",
description: "Disable/Enable base damage", description: "Disable/Enable base damage",
value: "disable-base-damage", value: "disable-base-damage",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "preference", name: "preference",
description: "DisableBaseDamage Preference", description: "DisableBaseDamage Preference",
@@ -89,7 +90,7 @@ module.exports = {
name: "disable-container-damage", name: "disable-container-damage",
description: "Disable/Enable container damage", description: "Disable/Enable container damage",
value: "disable-container-damage", value: "disable-container-damage",
type: ApplicationCommandOptionType.SubCommand, type: ApplicationCommandOptionType.Subcommand,
options: [{ options: [{
name: "preference", name: "preference",
description: "disableContainerDamage Preference", description: "disableContainerDamage Preference",
@@ -117,7 +118,7 @@ module.exports = {
if (args[0].name == "initialize") { if (args[0].name == "initialize") {
if (client.exists(GuildDB.Nitrado)) { if (isDefined(GuildDB.Nitrado)) {
const prompt = new EmbedBuilder() const prompt = new EmbedBuilder()
.setTitle(`Nitrado Server Information Already Configured!`) .setTitle(`Nitrado Server Information Already Configured!`)
.setDescription("**Notice:** This will overwrite your previously configured Nitrado Server Information") .setDescription("**Notice:** This will overwrite your previously configured Nitrado Server Information")
@@ -190,7 +191,7 @@ module.exports = {
return interaction.send({ embeds: [prompt], components: [opt], flags: (1 << 6) }); return interaction.send({ embeds: [prompt], components: [opt], flags: (1 << 6) });
} }
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Red).setDescription(`**Notice:**\nThis Discord guild has not been configured with a Nitrado DayZ server. To configure your guild, use </server initialize:1166877457559851011>`)] }); if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Red).setDescription(`**Notice:**\nThis Discord guild has not been configured with a Nitrado DayZ server. To configure your guild, use </server initialize:1166877457559851011>`)] });
if (args[0].name == "credentials-status") { if (args[0].name == "credentials-status") {
+5 -4
View File
@@ -2,6 +2,7 @@ const { EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require("dis
const { ApplicationCommandOptionType } = require("discord.js"); const { ApplicationCommandOptionType } = require("discord.js");
const { weapons } = require("../database/weapons"); const { weapons } = require("../database/weapons");
const { insertPVPstats, createWeaponStats } = require("../database/player"); const { insertPVPstats, createWeaponStats } = require("../database/player");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
name: "weapon-stats", name: "weapon-stats",
@@ -54,7 +55,7 @@ module.exports = {
*/ */
run: async (client, interaction, args, { GuildDB }) => { run: async (client, interaction, args, { GuildDB }) => {
if (!client.exists(GuildDB.Nitrado) || !client.exists(GuildDB.Nitrado.ServerID) || !client.exists(GuildDB.Nitrado.UserID) || !client.exists(GuildDB.Nitrado.Auth)) { if (!isDefined(GuildDB.Nitrado) || !isDefined(GuildDB.Nitrado.ServerID) || !isDefined(GuildDB.Nitrado.UserID) || !isDefined(GuildDB.Nitrado.Auth)) {
const warnNitradoNotInitialized = new EmbedBuilder() const warnNitradoNotInitialized = new EmbedBuilder()
.setColor(client.config.Colors.Yellow) .setColor(client.config.Colors.Yellow)
.setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable."); .setDescription("**WARNING:** The DayZ Nitrado Server has not been configured for this guild yet. This command or feature is currently unavailable.");
@@ -78,7 +79,7 @@ module.exports = {
// Searching for self // Searching for self
if (self) query = await client.dbo.collection("players").findOne({ "discordID": interaction.member.user.id }); if (self) query = await client.dbo.collection("players").findOne({ "discordID": interaction.member.user.id });
if (!client.exists(query)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** Unable to find any records with the gamertag or user provided.`)] }); if (!isDefined(query)) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(`**Not Found** Unable to find any records with the gamertag or user provided.`)] });
let weaponSelect = new StringSelectMenuBuilder() let weaponSelect = new StringSelectMenuBuilder()
.setCustomId(`ViewWeaponStats-${query.playerID}-${interaction.member.user.id}`) .setCustomId(`ViewWeaponStats-${query.playerID}-${interaction.member.user.id}`)
@@ -110,8 +111,8 @@ module.exports = {
let player = await client.dbo.collection("players").findOne({ "playerID": playerID }); let player = await client.dbo.collection("players").findOne({ "playerID": playerID });
const tag = player.discordID != "" ? `<@${player.discordID}>"s` : `**${player.gamertag}"s**`; const tag = player.discordID != "" ? `<@${player.discordID}>"s` : `**${player.gamertag}"s**`;
if (!client.exists(player.shotsLanded)) player = insertPVPstats(player); if (!isDefined(player.shotsLanded)) player = insertPVPstats(player);
if (!client.exists(player.weaponStats[weapon])) player = createWeaponStats(player, weapon); if (!isDefined(player.weaponStats[weapon])) player = createWeaponStats(player, weapon);
let stats = new EmbedBuilder() let stats = new EmbedBuilder()
.setColor(client.config.Colors.Default) .setColor(client.config.Colors.Default)
+4 -1
View File
@@ -7,7 +7,8 @@ export const enum DevelopmentBranch {
Prod = "PROD.", Prod = "PROD.",
}; };
export const enum Colors { // switch to const later once removed Colors from config
export enum Colors {
Default = "#8a7c72", Default = "#8a7c72",
DarkRed = "#ba0f0f", DarkRed = "#ba0f0f",
Red = "#f55c5c", Red = "#f55c5c",
@@ -25,6 +26,7 @@ export interface Config {
Dev: DevelopmentBranch; Dev: DevelopmentBranch;
Version: string; Version: string;
Admins: Array<string>; Admins: Array<string>;
Colors: typeof Colors;
SupportServer: string; SupportServer: string;
Token: string; Token: string;
SecretKey: string; SecretKey: string;
@@ -43,6 +45,7 @@ export const config: Config = {
Dev: <DevelopmentBranch>process.env.Dev || DevelopmentBranch.Dev, Dev: <DevelopmentBranch>process.env.Dev || DevelopmentBranch.Dev,
Version: version, Version: version,
Admins: ["362791661274660874", "329371697570381824"], // Admins of the bot Admins: ["362791661274660874", "329371697570381824"], // Admins of the bot
Colors: Colors, // only here for backwards compatibility with commands/*
SupportServer: "https://discord.gg/KVFJCvvFtK", // Support Server Link SupportServer: "https://discord.gg/KVFJCvvFtK", // Support Server Link
Token: process.env.token || "", //Discord Bot Token Token: process.env.token || "", //Discord Bot Token
SecretKey: process.env.key || "01234567891", SecretKey: process.env.key || "01234567891",
-164
View File
@@ -1,164 +0,0 @@
module.exports = {
Armbands: [
{
name: "Black",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/8/82/ArmbandBlack.png/revision/latest?cb=20161127174754"
},
{
name: "Blue",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/bd/ArmbandBlue.png/revision/latest?cb=20161127174803"
},
{
name: "Green",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/ce/ArmbandGreen.png/revision/latest?cb=20161127174812"
},
{
name: "Orange",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/e6/ArmbandOrange.png/revision/latest?cb=20161127174846"
},
{
name: "Pink",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/f7/ArmbandPink.png/revision/latest?cb=20161127174854"
},
{
name: "Red",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/1/14/Armband.png/revision/latest?cb=20161127174901"
},
{
name: "Yellow",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/8/81/ArmbandYellow.png/revision/latest?cb=20161127174918"
},
{
name: "White",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c7/Armband_White.png/revision/latest?cb=20161127174926"
},
{
name: "Altis",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/ee/Flag_alti_co.png/revision/latest?cb=20200820222622"
},
{
name: "Asiain Pacific Alliance (APA)",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c2/Flag_apa_co.png/revision/latest?cb=20200820222623"
},
{
name: "Bear",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/e1/Flag_bear_co.png/revision/latest?cb=20200820222626"
},
{
name: "Bohemia Interactive",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/ee/Flag_bi_co.png/revision/latest?cb=20200820222627"
},
{
name: "Brain",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/7/7d/Flag_brain_co.png/revision/latest?cb=20200820222628"
},
{
name: "Chernarussian Defence Forces (CDF)",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/d/d6/Flag_cdf_co.png/revision/latest?cb=20200820222629"
},
{
name: "Chedaki (CHED)",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/9/96/Flag_ched_co.png/revision/latest?cb=20200820222630"
},
{
name: "CHEL",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/9/98/Flag_chel_co.png/revision/latest?cb=20200820222631"
},
{
name: "Chernarus",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/ef/Flag_chern_co.png/revision/latest?cb=20200820222632"
},
{
name: "Chernarus Mining Corporation (CMC)",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/d/da/Flag_cmc_co.png/revision/latest?cb=20200820222634"
},
{
name: "Rooster",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/4/44/Flag_cock_co.png/revision/latest?cb=20200820222635"
},
{
name: "DayZ",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/b2/Flag_dayz_co.png/revision/latest?cb=20200820222636"
},
{
name: "North Sahrani (DROS)",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/2/24/Flag_dros_co.png/revision/latest?cb=20200820222637"
},
{
name: "Fawn",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/d/d2/Flag_fawn_co.png/revision/latest/scale-to-width-down/1000?cb=20200820222639"
},
{
name: "Pirates",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/ab/Flag_jolly_co.png/revision/latest?cb=20200820222643"
},
{
name: "Cannibals",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/4/42/Flag_jolly_c_co.png/revision/latest?cb=20200820222641"
},
{
name: "South Sahrani (KOS)",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/a1/Flag_kos_co.png/revision/latest?cb=20200820222644"
},
{
name: "Livonia Army (LDF)",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c1/Flag_ldf_co.png/revision/latest?cb=20200820222645"
},
{
name: "Livonia",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/e6/Flag_livo_co.png/revision/latest?cb=20200820222647"
},
{
name: "NAPA",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/e4/Flag_napa_co.png/revision/latest?cb=20200820222648"
},
{
name: "Livonia Police",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/63/Flag_police_co.png/revision/latest?cb=20200820222649"
},
{
name: "TEC",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/ea/Flag_tec_co.png/revision/latest?cb=20200820222650"
},
{
name: "United Earth Coalition (UEC)",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/ca/Flag_uec_co.png/revision/latest?cb=20200820222651"
},
{
name: "Wolf",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/b2/Flag_wolf_co.png/revision/latest?cb=20200820222653"
},
{
name: "Zenit Radio Station",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/0/05/Flag_zenit_co.png/revision/latest?cb=20200820222654"
},
{
name: "Zombie Hunters",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/9/97/Flag_zhunters_co.png/revision/latest?cb=20200820222621"
},
{
name: "RSTA",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/2/20/Flag_rsta_co.png/revision/latest/scale-to-width-down/1000?cb=20210216191221"
},
{
name: "Refuge",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/8/8e/Flag_refuge_co.png/revision/latest/scale-to-width-down/1000?cb=20210216191205"
},
{
name: "Snake",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/5/54/Flag_snake_co.png/revision/latest/scale-to-width-down/1000?cb=20210216191234"
},
{
name: "Zagorky",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/7/75/Flag_zagorky_co.png/revision/latest/scale-to-width-down/1000?cb=20230619164704"
},
{
name: "Crook",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c8/Flag_crook_co.png/revision/latest/scale-to-width-down/1000?cb=20230619164705"
},
{
name: "Rex",
url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c5/Flag_rex_co.png/revision/latest/scale-to-width-down/1000?cb=20230619164706"
},
]
}
+93
View File
@@ -0,0 +1,93 @@
export enum ArmbandName
{
Black = "Black",
Blue = "Blue",
Green = "Green",
Orange = "Orange",
Pink = "Pink",
Red = "Red",
Yellow = "Yellow",
White = "White",
Altis = "Altis",
AsiainPacificAllianceAPA = "Asiain Pacific Alliance (APA)",
Bear = "Bear",
BohemiaInteractive = "Bohemia Interactive",
Brain = "Brain",
ChernarussianDefenceForcesCDF = "Chernarussian Defence Forces (CDF)",
ChedakiCHED = "Chedaki (CHED)",
CHEL = "CHEL",
Chernarus = "Chernarus",
ChernarusMiningCorporationCMC = "Chernarus Mining Corporation (CMC)",
Rooster = "Rooster",
DayZ = "DayZ",
NorthSahraniDROS = "North Sahrani (DROS)",
Fawn = "Fawn",
Pirates = "Pirates",
Cannibals = "Cannibals",
SouthSahraniKOS = "South Sahrani (KOS)",
LivoniaArmyLDF = "Livonia Army (LDF)",
Livonia = "Livonia",
NAPA = "NAPA",
LivoniaPolice = "Livonia Police",
TEC = "TEC",
UnitedEarthCoalitionUEC = "United Earth Coalition (UEC)",
Wolf = "Wolf",
ZenitRadioStation = "Zenit Radio Station",
ZombieHunters = "Zombie Hunters",
RSTA = "RSTA",
Refuge = "Refuge",
Snake = "Snake",
Zagorky = "Zagorky",
Crook = "Crook",
Rex = "Rex",
};
export interface Armband
{
name: ArmbandName;
url: string;
};
export const Armbands: Armband[] =
[
{ name: ArmbandName.Black, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/8/82/ArmbandBlack.png/revision/latest?cb=20161127174754" },
{ name: ArmbandName.Blue, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/bd/ArmbandBlue.png/revision/latest?cb=20161127174803" },
{ name: ArmbandName.Green, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/ce/ArmbandGreen.png/revision/latest?cb=20161127174812" },
{ name: ArmbandName.Orange, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/e6/ArmbandOrange.png/revision/latest?cb=20161127174846" },
{ name: ArmbandName.Pink, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/f7/ArmbandPink.png/revision/latest?cb=20161127174854" },
{ name: ArmbandName.Red, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/1/14/Armband.png/revision/latest?cb=20161127174901" },
{ name: ArmbandName.Yellow, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/8/81/ArmbandYellow.png/revision/latest?cb=20161127174918" },
{ name: ArmbandName.White, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c7/Armband_White.png/revision/latest?cb=20161127174926" },
{ name: ArmbandName.Altis, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/ee/Flag_alti_co.png/revision/latest?cb=20200820222622" },
{ name: ArmbandName.AsiainPacificAllianceAPA, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c2/Flag_apa_co.png/revision/latest?cb=20200820222623" },
{ name: ArmbandName.Bear, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/e1/Flag_bear_co.png/revision/latest?cb=20200820222626" },
{ name: ArmbandName.BohemiaInteractive, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/ee/Flag_bi_co.png/revision/latest?cb=20200820222627" },
{ name: ArmbandName.Brain, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/7/7d/Flag_brain_co.png/revision/latest?cb=20200820222628" },
{ name: ArmbandName.ChernarussianDefenceForcesCDF, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/d/d6/Flag_cdf_co.png/revision/latest?cb=20200820222629" },
{ name: ArmbandName.ChedakiCHED, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/9/96/Flag_ched_co.png/revision/latest?cb=20200820222630" },
{ name: ArmbandName.CHEL, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/9/98/Flag_chel_co.png/revision/latest?cb=20200820222631" },
{ name: ArmbandName.Chernarus, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/ef/Flag_chern_co.png/revision/latest?cb=20200820222632" },
{ name: ArmbandName.ChernarusMiningCorporationCMC, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/d/da/Flag_cmc_co.png/revision/latest?cb=20200820222634" },
{ name: ArmbandName.Rooster, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/4/44/Flag_cock_co.png/revision/latest?cb=20200820222635" },
{ name: ArmbandName.DayZ, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/b2/Flag_dayz_co.png/revision/latest?cb=20200820222636" },
{ name: ArmbandName.NorthSahraniDROS, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/2/24/Flag_dros_co.png/revision/latest?cb=20200820222637" },
{ name: ArmbandName.Fawn, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/d/d2/Flag_fawn_co.png/revision/latest/scale-to-width-down/1000?cb=20200820222639" },
{ name: ArmbandName.Pirates, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/ab/Flag_jolly_co.png/revision/latest?cb=20200820222643" },
{ name: ArmbandName.Cannibals, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/4/42/Flag_jolly_c_co.png/revision/latest?cb=20200820222641" },
{ name: ArmbandName.SouthSahraniKOS, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/a1/Flag_kos_co.png/revision/latest?cb=20200820222644" },
{ name: ArmbandName.LivoniaArmyLDF, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c1/Flag_ldf_co.png/revision/latest?cb=20200820222645" },
{ name: ArmbandName.Livonia, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/e6/Flag_livo_co.png/revision/latest?cb=20200820222647" },
{ name: ArmbandName.NAPA, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/e4/Flag_napa_co.png/revision/latest?cb=20200820222648" },
{ name: ArmbandName.LivoniaPolice, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/63/Flag_police_co.png/revision/latest?cb=20200820222649" },
{ name: ArmbandName.TEC, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/ea/Flag_tec_co.png/revision/latest?cb=20200820222650" },
{ name: ArmbandName.UnitedEarthCoalitionUEC, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/ca/Flag_uec_co.png/revision/latest?cb=20200820222651" },
{ name: ArmbandName.Wolf, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/b2/Flag_wolf_co.png/revision/latest?cb=20200820222653" },
{ name: ArmbandName.ZenitRadioStation, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/0/05/Flag_zenit_co.png/revision/latest?cb=20200820222654" },
{ name: ArmbandName.ZombieHunters, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/9/97/Flag_zhunters_co.png/revision/latest?cb=20200820222621" },
{ name: ArmbandName.RSTA, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/2/20/Flag_rsta_co.png/revision/latest/scale-to-width-down/1000?cb=20210216191221" },
{ name: ArmbandName.Refuge, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/8/8e/Flag_refuge_co.png/revision/latest/scale-to-width-down/1000?cb=20210216191205" },
{ name: ArmbandName.Snake, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/5/54/Flag_snake_co.png/revision/latest/scale-to-width-down/1000?cb=20210216191234" },
{ name: ArmbandName.Zagorky, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/7/75/Flag_zagorky_co.png/revision/latest/scale-to-width-down/1000?cb=20230619164704" },
{ name: ArmbandName.Crook, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c8/Flag_crook_co.png/revision/latest/scale-to-width-down/1000?cb=20230619164705" },
{ name: ArmbandName.Rex, url: "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c5/Flag_rex_co.png/revision/latest/scale-to-width-down/1000?cb=20230619164706" },
];
+10 -6
View File
@@ -1,6 +1,7 @@
import { calculateVector } from "@util/Vector"; import { calculateVector } from "../util/Vector";
export const Missions = { export const Missions =
{
"dayzOffline.chernarusplus": "Chernarus", "dayzOffline.chernarusplus": "Chernarus",
"dayzOffline.enoch": "Livonia", "dayzOffline.enoch": "Livonia",
"dayzOffline.sakhal": "Sakhal", "dayzOffline.sakhal": "Sakhal",
@@ -9,10 +10,11 @@ export const Missions = {
export type MissionKey = keyof typeof Missions; export type MissionKey = keyof typeof Missions;
export type MissionName = typeof Missions[MissionKey]; export type MissionName = typeof Missions[MissionKey];
export type Position = [number, number]; export type Position = [number, number] | [];
// Calculates the nearest location to a given coordinate // Calculates the nearest location to a given coordinate
export function nearest(pos: Position, mission: MissionName): string { export function nearest(pos: Position, mission: MissionName): string
{
let tempDest; let tempDest;
let lastDist = 1000000; let lastDist = 1000000;
let destination_dir; let destination_dir;
@@ -28,13 +30,15 @@ export function nearest(pos: Position, mission: MissionName): string {
return lastDist > 500 ? `${destination_dir} of ${tempDest}` : `Near ${tempDest}`; return lastDist > 500 ? `${destination_dir} of ${tempDest}` : `Near ${tempDest}`;
}; };
interface Destination { interface Destination
{
name: string; name: string;
coord: Position; coord: Position;
} }
// A curated list of destinations across DayZ Chernarus and Livonia // A curated list of destinations across DayZ Chernarus and Livonia
const destinations: Record<MissionName, Array<Destination>> = { const destinations: Record<MissionName, Array<Destination>> =
{
Chernarus: [ Chernarus: [
{ {
name: "Sinystok", name: "Sinystok",
+44 -21
View File
@@ -1,29 +1,50 @@
import { Snowflake } from "discord.js"; import { Snowflake } from "discord.js";
import DayZR from "../DayZRBot"; import DayZR from "../DayZRBot";
import { NitradoCredentialStatus } from "@util/NitradoAPI"; import { NitradoCredentialStatus } from "../services/NitradoAPI";
import { ArmbandName } from "./armbands";
import { MissionName } from "./destinations";
export const enum IntegerBoolean { export const enum IntegerBoolean
{
FALSE, FALSE,
TRUE TRUE
}; };
export interface UAV { export interface UAV
{
// TODO: fill this out // TODO: fill this out
}; };
export interface Alarm { export interface Alarm
{
// TODO: fill this out // TODO: fill this out
}; };
export interface NitradoConfig { export interface NitradoCredentials
{
ServerID: string;
UserID: string;
Auth: string;
};
export interface NitradoConfig
{
ServerID: string; ServerID: string;
UserID: string; UserID: string;
Auth: string; Auth: string;
Status: NitradoCredentialStatus; Status: NitradoCredentialStatus;
Mission: MissionName,
}; };
interface GuildConfigAttributes { export interface FactionArmband
serverID: Snowflake; {
faction: Snowflake; // faction role ID
armband: ArmbandName;
}
interface GuildConfigAttributes
{
serverID: Snowflake; // Guild ID
lastLog: string | null; lastLog: string | null;
serverName: string; serverName: string;
autoRestart: IntegerBoolean; autoRestart: IntegerBoolean;
@@ -31,40 +52,41 @@ interface GuildConfigAttributes {
showKillfeedWeapon: IntegerBoolean; showKillfeedWeapon: IntegerBoolean;
purchaseUAV: IntegerBoolean; purchaseUAV: IntegerBoolean;
purchaseEMP: IntegerBoolean; purchaseEMP: IntegerBoolean;
allowedChannels: Array<Snowflake>; allowedChannels: Array<Snowflake>; // Array of channel IDs
customChannelStatus?: boolean; // optional - generated outside of DB customChannelStatus?: boolean; // optional - generated outside of DB
hasBotAdmin?: boolean; // optional - generated outside of DB hasBotAdmin?: boolean; // optional - generated outside of DB
killfeedChannel: Snowflake; killfeedChannel: Snowflake; // Channel ID
connectionLogsChannel: Snowflake; connectionLogsChannel: Snowflake; // Channel ID
activePlayersChannel: Snowflake; activePlayersChannel: Snowflake; // Channel ID
welcomeChannel: Snowflake; welcomeChannel: Snowflake; // Channel ID
factionArmbands: any; factionArmbands: Record<Snowflake, FactionArmband>;
usedArmbands: Array<string>; usedArmbands: Array<string>;
excludedRoles: Array<string>; excludedRoles: Array<string>;
hasExcludedRoles?: boolean; // optional - generated outside of DB hasExcludedRoles?: boolean; // optional - generated outside of DB
botAdminRoles: Array<Snowflake>; botAdminRoles: Array<Snowflake>; // Array of role IDs
alarms: Array<Alarm>; alarms: Array<Alarm>;
events: Array<any>; events: Array<any>;
uavs: Array<UAV>; uavs: Array<UAV>;
incomeRoles: Array<Snowflake>; incomeRoles: Array<Snowflake>; // Array of role IDs
incomeLimiter: number; incomeLimiter: number;
startingBalance: number; startingBalance: number;
uavPrice: number; uavPrice: number;
empPrice: number; empPrice: number;
linkedGamertagRole: Snowflake; linkedGamertagRole: Snowflake; // Role ID
memberRole: Snowflake; memberRole: Snowflake; // Role ID
adminRole: Snowflake; adminRole: Snowflake; // Role ID
combatLogTimer: number; combatLogTimer: number;
} }
interface GuildConfigDB { export interface GuildConfigDB
{
server: GuildConfigAttributes; server: GuildConfigAttributes;
Nitrado: NitradoConfig | null; Nitrado: NitradoConfig | null;
}; };
@@ -75,7 +97,8 @@ interface GuildConfigDB {
// Also this is so stupid, in the DB all server attributes are under server, // Also this is so stupid, in the DB all server attributes are under server,
// while in the code we almost always have the attributes directly in top // while in the code we almost always have the attributes directly in top
// level of object, i.e. guild.startingBalance instead of guild.server.startingBalance // level of object, i.e. guild.startingBalance instead of guild.server.startingBalance
export interface GuildConfig extends GuildConfigAttributes { export interface GuildConfig extends GuildConfigAttributes
{
Nitrado: NitradoConfig | null; Nitrado: NitradoConfig | null;
} }
-131
View File
@@ -1,131 +0,0 @@
const { weapons } = require("./weapons");
// Creates a copy of an object to prevent mutation of parent (i.e BodyParts, createWeaponsObject)
const copy = (obj) => JSON.parse(JSON.stringify(obj));
const BodyParts = {
Head: 0,
Torso: 0,
RightArm: 0,
LeftArm: 0,
RightLeg: 0,
LeftLeg: 0,
};
const createWeaponsObject = (value) => {
const defaultWeapons = {};
for (const [_, weaponNames] of Object.entries(weapons)) {
for (const [name, _] of Object.entries(weaponNames)) {
defaultWeapons[name] = value;
}
}
return copy(defaultWeapons);
};
module.exports = {
UpdatePlayer: async (client, player, interaction = null) => {
/* Wrapping this function in a promise solves some bugs */
return new Promise(resolve => {
client.dbo.collection("players").updateOne(
{ "playerID": player.playerID },
{ $set: { ...player } },
{ upsert: true }, // Create player stat document if it does not exist
(err, _) => {
if (err) {
if (interaction == null) return client.error(`UpdatePlayer Error: ${err}`);
else return client.sendInternalError(interaction, `UpdatePlayer Error: ${err}`);
} else resolve();
}
);
});
},
getDefaultPlayer(gamertag, playerId, nitradoServerId) {
return {
// Identifiers
gamertag: gamertag,
playerID: playerId,
discordID: "",
nitradoServerID: nitradoServerId,
// General PVP Stats
KDR: 0.00,
kills: 0,
deaths: 0,
killStreak: 0,
bestKillStreak: 0,
longestKill: 0,
deathStreak: 0,
worstDeathStreak: 0,
// In depth PVP Stats
shotsLanded: 0,
timesShot: 0,
shotsLandedPerBodyPart: copy(BodyParts),
timesShotPerBodyPart: copy(BodyParts),
weaponStats: createWeaponsObject({
kills: 0,
deaths: 0,
shotsLanded: 0,
timesShot: 0,
shotsLandedPerBodyPart: copy(BodyParts),
timesShotPerBodyPart: copy(BodyParts),
}),
combatRating: 800,
highestCombatRating: 800,
lowestCombatRating: 800,
combatRatingHistory: [800],
// General Session Data
lastConnectionDate: null,
lastDisconnectionDate: null,
lastDamageDate: null,
lastDeathDate: null,
lastHitBy: null,
connected: false,
pos: [],
lastPos: [],
time: null,
lastTime: null,
// Session Stats
totalSessionTime: 0,
lastSessionTime: 0,
longestSessionTime: 0,
connections: 0,
// Other
bounties: [],
bountiesLength: 0,
}
},
insertPVPstats(player) {
player.shotsLanded = 0;
player.timesShot = 0;
player.shotsLandedPerBodyPart = copy(BodyParts);
player.timesShotPerBodyPart = copy(BodyParts);
player.weaponStats = createWeaponsObject({
kills: 0,
deaths: 0,
shotsLanded: 0,
timesShot: 0,
shotsLandedPerBodyPart: copy(BodyParts),
timesShotPerBodyPart: copy(BodyParts),
});
return player;
},
// If a new weapon is not in the existing weaponStats, this will add it.
createWeaponStats(player, weapon) {
player.weaponStats[weapon] = {
kills: 0,
deaths: 0,
shotsLanded: 0,
timesShot: 0,
shotsLandedPerBodyPart: copy(BodyParts),
timesShotPerBodyPart: copy(BodyParts),
}
return player;
}
}
+232
View File
@@ -0,0 +1,232 @@
import { ChatInputCommandInteraction } from "discord.js";
import { weapons, AllWeapons } from "./weapons";
import { Snowflake } from "discord.js";
import { Position } from "./destinations"
import DayZR from "../DayZRBot";
// Creates a copy of an object to prevent mutation of parent (i.e BodyParts, createWeaponsObject)
const copy = <T>(obj: T): T => JSON.parse(JSON.stringify(obj));
interface BodyPartStats
{
Head: number;
Torso: number;
RightArm: number;
LeftArm: number;
RightLeg: number;
LeftLeg: number;
}
interface IndividualWeaponStats
{
kills: number;
deaths: number;
shotsLanded: number;
timesShot: number;
shotsLandedPerBodyPart: BodyPartStats;
timesShotPerBodyPart: BodyPartStats;
}
const DefaultBodyPartStats: BodyPartStats =
{
Head: 0,
Torso: 0,
RightArm: 0,
LeftArm: 0,
RightLeg: 0,
LeftLeg: 0,
};
interface WeaponStats
{
[weaponName: string]: IndividualWeaponStats;
}
const createWeaponsObject = (defaultWeaponStats: IndividualWeaponStats): WeaponStats =>
{
const defaultWeapons: WeaponStats = {};
for (const [_, weaponNames] of Object.entries(weapons)) {
for (const [name, _] of Object.entries(weaponNames)) {
defaultWeapons[name] = defaultWeaponStats;
}
}
return copy(defaultWeapons);
};
export interface Player
{
// Identifiers
gamertag: string,
playerID: string,
discordID: Snowflake,
nitradoServerID: string,
// General PVP Stats
KDR: number,
kills: number,
deaths: number,
killStreak: number,
bestKillStreak: number,
longestKill: number,
deathStreak: number,
worstDeathStreak: number,
// In depth PVP Stats
shotsLanded: number,
timesShot: number,
shotsLandedPerBodyPart: BodyPartStats,
timesShotPerBodyPart: BodyPartStats,
weaponStats: WeaponStats,
combatRating: number,
highestCombatRating: number,
lowestCombatRating: number,
combatRatingHistory: Array<number>,
// General Session Data
lastConnectionDate: Date | null,
lastDisconnectionDate: Date | null,
lastDamageDate: Date | null,
lastDeathDate: Date | null,
lastHitBy: string | null,
connected: boolean,
pos: Position,
lastPos: Position,
time: string | null,
lastTime: string | null,
// Session Stats
totalSessionTime: number,
lastSessionTime: number,
longestSessionTime: number,
connections: number,
// Other
bounties: Array<any>, // TODO, define bounty object
bountiesLength: number,
}
export const UpdatePlayer = async(
client: DayZR,
player: Player,
interaction: ChatInputCommandInteraction | null = null
): Promise<void> =>
{
/* Wrapping this function in a promise solves some bugs */
return new Promise(resolve => {
client.dbo.collection("players").updateOne(
{ "playerID": player.playerID },
{ $set: { ...player } },
{ upsert: true }, // Create player stat document if it does not exist
(err: string) => {
if (err)
{
if (interaction == null) return client.error(`UpdatePlayer Error: ${err}`);
else return client.sendInternalError(interaction, `UpdatePlayer Error: ${err}`);
} else resolve();
}
);
});
};
// TODO: fix magic NUMBERS!!!
export const getDefaultPlayer = (
gamertag: string,
playerId: string,
nitradoServerId: string
): Player =>
{
return {
// Identifiers
gamertag: gamertag,
playerID: playerId,
discordID: "",
nitradoServerID: nitradoServerId,
// General PVP Stats
KDR: 0.00,
kills: 0,
deaths: 0,
killStreak: 0,
bestKillStreak: 0,
longestKill: 0,
deathStreak: 0,
worstDeathStreak: 0,
// In depth PVP Stats
shotsLanded: 0,
timesShot: 0,
shotsLandedPerBodyPart: copy(DefaultBodyPartStats),
timesShotPerBodyPart: copy(DefaultBodyPartStats),
weaponStats: createWeaponsObject({
kills: 0,
deaths: 0,
shotsLanded: 0,
timesShot: 0,
shotsLandedPerBodyPart: copy(DefaultBodyPartStats),
timesShotPerBodyPart: copy(DefaultBodyPartStats),
}),
combatRating: 800,
highestCombatRating: 800,
lowestCombatRating: 800,
combatRatingHistory: [ 800 ],
// General Session Data
lastConnectionDate: null,
lastDisconnectionDate: null,
lastDamageDate: null,
lastDeathDate: null,
lastHitBy: null,
connected: false,
pos: [],
lastPos: [],
time: null,
lastTime: null,
// Session Stats
totalSessionTime: 0,
lastSessionTime: 0,
longestSessionTime: 0,
connections: 0,
// Other
bounties: [],
bountiesLength: 0,
}
};
export const insertPVPstats = (player: Player): Player =>
{
player.shotsLanded = 0;
player.timesShot = 0;
player.shotsLandedPerBodyPart = copy(DefaultBodyPartStats);
player.timesShotPerBodyPart = copy(DefaultBodyPartStats);
player.weaponStats = createWeaponsObject(
{
kills: 0,
deaths: 0,
shotsLanded: 0,
timesShot: 0,
shotsLandedPerBodyPart: copy(DefaultBodyPartStats),
timesShotPerBodyPart: copy(DefaultBodyPartStats),
});
return player;
};
// If a new weapon is not in the existing weaponStats, this will add it.
export const createWeaponStats = (
player: Player,
weapon: AllWeapons
): Player =>
{
player.weaponStats[weapon] = {
kills: 0,
deaths: 0,
shotsLanded: 0,
timesShot: 0,
shotsLandedPerBodyPart: copy(DefaultBodyPartStats),
timesShotPerBodyPart: copy(DefaultBodyPartStats),
}
return player;
};
-77
View File
@@ -1,77 +0,0 @@
module.exports = {
weapons: {
handguns: {
"CR-75": "https://static.wikia.nocookie.net/dayz_gamepedia/images/4/40/CZ75.png/revision/latest/scale-to-width-down/112?cb=20210505021307",
"Deagle": "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/62/Deagle.png/revision/latest/scale-to-width-down/127?cb=20210512003023",
"Derringer": "https://static.wikia.nocookie.net/dayz_gamepedia/images/9/9f/Derringer_Black.png/revision/latest/scale-to-width-down/105?cb=20220521175445",
"FX-45": "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/fd/FNX45.png/revision/latest/scale-to-width-down/104?cb=20210505025055",
"IJ-70": "https://static.wikia.nocookie.net/dayz_gamepedia/images/2/26/MakarovIJ70.png/revision/latest/scale-to-width-down/92?cb=20210209000551",
"Kolt 1911": "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/f9/Colt1911.png/revision/latest/scale-to-width-down/112?cb=20210505030200",
"Longhorn": "https://static.wikia.nocookie.net/dayz_gamepedia/images/7/79/Longhorn.png/revision/latest/scale-to-width-down/222?cb=20220324214533",
"MK II": "https://static.wikia.nocookie.net/dayz_gamepedia/images/0/0d/MKII.png/revision/latest/scale-to-width-down/171?cb=20210210153348",
"Mlock-91": "https://static.wikia.nocookie.net/dayz_gamepedia/images/9/9b/Glock19.png/revision/latest/scale-to-width-down/121?cb=20210505024259",
"P1": "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/cc/P1.png/revision/latest/scale-to-width-down/120?cb=20220518204515",
"Revolver": "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/6d/Revolver.png/revision/latest/scale-to-width-down/148?cb=20210208232303",
"Signal Pistol": "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/a7/Flaregun.png/revision/latest/scale-to-width-down/107?cb=20210501150913",
},
shotguns: {
"BK-12": "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/cb/Izh18Shotgun.png/revision/latest/scale-to-width-down/256?cb=20220922184507",
"BK-133": "https://static.wikia.nocookie.net/dayz_gamepedia/images/5/5c/MP-133-Shotgun.png/revision/latest/scale-to-width-down/256?cb=20210210190104",
"BK-43": "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c7/Izh43Shotgun.png/revision/latest/scale-to-width-down/256?cb=20210210185835",
"Vaiga": "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c8/Vaiga.png/revision/latest/scale-to-width-down/256?cb=20220220185225",
},
subMachineGuns: {
"Bizon": "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/af/PP19.png/revision/latest/scale-to-width-down/251?cb=20220127132305",
"CR-61 Skorpion": "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/63/VZ61Scorpion.png/revision/latest/scale-to-width-down/222?cb=20220518204508",
"SG5-K": "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/fc/MP5-K.png/revision/latest/scale-to-width-down/158?cb=20220221011343",
"USG-45": "https://static.wikia.nocookie.net/dayz_gamepedia/images/d/d7/UMP45.png/revision/latest/scale-to-width-down/153?cb=20220221002354",
},
assaultRifles: {
"AUR A1": "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/e6/AugShort.png/revision/latest/scale-to-width-down/173?cb=20211104175243",
"AUR AX": "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/be/Aug.png/revision/latest/scale-to-width-down/233?cb=20211104182427",
"KA-101": "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/f2/AK101.png/revision/latest/scale-to-width-down/251?cb=20210207040122",
"KA-74": "https://static.wikia.nocookie.net/dayz_gamepedia/images/8/8b/AK74.png/revision/latest/scale-to-width-down/253?cb=20210505013141",
"KAS-74U": "https://static.wikia.nocookie.net/dayz_gamepedia/images/0/0b/AKS74U.png/revision/latest/scale-to-width-down/191?cb=20210505014222",
"KA-M": "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/6c/AKM.png/revision/latest/scale-to-width-down/244?cb=20210505011614",
"LE-MAS": "https://static.wikia.nocookie.net/dayz_gamepedia/images/2/21/FAMAS.png/revision/latest/scale-to-width-down/197?cb=20210902183114",
"M16-A2": "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/b3/M16-A2.png/revision/latest/scale-to-width-down/256?cb=20220221002601",
"M4-A1": "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/a1/M4A1.png/revision/latest/scale-to-width-down/223?cb=20220330014851",
"SVAL": "https://static.wikia.nocookie.net/dayz_gamepedia/images/3/39/ASVAL.png/revision/latest/scale-to-width-down/256?cb=20210208015731",
"Vikhr": "https://static.wikia.nocookie.net/dayz_gamepedia/images/0/0d/Vikhr.png/revision/latest/scale-to-width-down/173?cb=20240116163108"
},
battleRifles: {
"LAR": "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/e9/FAL.png/revision/latest/scale-to-width-down/256?cb=20220221001123",
},
boltActionRifles: {
"CR-527": "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/f0/CR527Wood.png/revision/latest/scale-to-width-down/256?cb=20220518204503 ",
"CR-550 Savanna": "https://static.wikia.nocookie.net/dayz_gamepedia/images/4/44/CR-550_Savanna.png/revision/latest/scale-to-width-down/256?cb=20220518204410",
"M70 Tundra": "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/62/Winchester70.png/revision/latest/scale-to-width-down/256?cb=20220517152918",
"Mosin 91/30": "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/a8/Mosin9130.png/revision/latest/scale-to-width-down/256?cb=20230126021955",
"Pioneer": "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/69/Scout.png/revision/latest/scale-to-width-down/256?cb=20220518204357",
"SSG 82": "https://static.wikia.nocookie.net/dayz_gamepedia/images/1/10/SSG82.png/revision/latest/scale-to-width-down/256?cb=20220922192455",
"VS-89": "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/ea/SV98.png/revision/latest/scale-to-width-down/256?cb=20240424164607",
},
breakActionRifles: {
"BK-18": "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/cb/IZH18_Rifle.png/revision/latest/scale-to-width-down/256?cb=20220517154121",
"Blaze": "https://static.wikia.nocookie.net/dayz_gamepedia/images/8/8a/Blaze_95_Double_Rifle_Wood.png/revision/latest/scale-to-width-down/256?cb=20220517154129",
},
leverActionRifles: {
"Repeater Carbine": "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/ce/Repeater.png/revision/latest/scale-to-width-down/256?cb=20220517154151",
},
marksmanRifles: {
"VSD": "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/a2/SVD_w._PSO-1.png/revision/latest/scale-to-width-down/256?cb=20220220235826",
"VSS": "https://static.wikia.nocookie.net/dayz_gamepedia/images/8/83/VSSVintorez.png/revision/latest/scale-to-width-down/256?cb=20210208202042",
},
semiAutomaticRifles: {
"DMR": "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/b4/M14.png/revision/latest/scale-to-width-down/350?cb=20231005142636",
"SK 59/66": "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/fe/SKS.png/revision/latest/scale-to-width-down/256?cb=20220517154633",
"Sporter 22": "https://static.wikia.nocookie.net/dayz_gamepedia/images/5/5b/Sporter_22_Wood.png/revision/latest/scale-to-width-down/256?cb=20220518204154",
},
other: {
"Crossbow": "https://static.wikia.nocookie.net/dayz_gamepedia/images/7/79/Crossbow.png/revision/latest/scale-to-width-down/212?cb=20180121164101",
"M79": "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/b7/M79.png/revision/latest/scale-to-width-down/256?cb=20220521184052",
},
},
weaponClassOf: (weapon) => Object.keys(module.exports.weapons).filter(c => weapon in module.exports.weapons[c])[0],
}
+149
View File
@@ -0,0 +1,149 @@
export type WeaponCategory =
| "handguns"
| "shotguns"
| "subMachineGuns"
| "assaultRifles"
| "battleRifles"
| "boltActionRifles"
| "breakActionRifles"
| "leverActionRifles"
| "marksmanRifles"
| "semiAutomaticRifles"
| "other";
export type HandgunWeapon =
| "CR-75" | "Deagle" | "Derringer" | "FX-45" | "IJ-70" | "Kolt 1911"
| "Longhorn" | "MK II" | "Mlock-91" | "P1" | "Revolver" | "Signal Pistol";
export type ShotgunWeapon =
| "BK-12" | "BK-133" | "BK-43" | "Vaiga";
export type SubMachineGunWeapon =
| "Bizon" | "CR-61 Skorpion" | "SG5-K" | "USG-45";
export type AssaultRifleWeapon =
| "AUR A1" | "AUR AX" | "KA-101" | "KA-74" | "KAS-74U" | "KA-M"
| "LE-MAS" | "M16-A2" | "M4-A1" | "SVAL" | "Vikhr";
export type BattleRifleWeapon = "LAR";
export type BoltActionRifleWeapon =
| "CR-527" | "CR-550 Savanna" | "M70 Tundra" | "Mosin 91/30"
| "Pioneer" | "SSG 82" | "VS-89";
export type BreakActionRifleWeapon = "BK-18" | "Blaze";
export type LeverActionRifleWeapon = "Repeater Carbine";
export type MarksmanRifleWeapon = "VSD" | "VSS";
export type SemiAutomaticRifleWeapon = "DMR" | "SK 59/66" | "Sporter 22";
export type OtherWeapon = "Crossbow" | "M79";
export interface Weapons
{
handguns: Record<HandgunWeapon, string>;
shotguns: Record<ShotgunWeapon, string>;
subMachineGuns: Record<SubMachineGunWeapon, string>;
assaultRifles: Record<AssaultRifleWeapon, string>;
battleRifles: Record<BattleRifleWeapon, string>;
boltActionRifles: Record<BoltActionRifleWeapon, string>;
breakActionRifles: Record<BreakActionRifleWeapon, string>;
leverActionRifles: Record<LeverActionRifleWeapon, string>;
marksmanRifles: Record<MarksmanRifleWeapon, string>;
semiAutomaticRifles: Record<SemiAutomaticRifleWeapon, string>;
other: Record<OtherWeapon, string>;
}
export type AllWeapons =
| HandgunWeapon
| ShotgunWeapon
| SubMachineGunWeapon
| AssaultRifleWeapon
| BattleRifleWeapon
| BoltActionRifleWeapon
| BreakActionRifleWeapon
| LeverActionRifleWeapon
| MarksmanRifleWeapon
| SemiAutomaticRifleWeapon
| OtherWeapon;
export const weapons: Weapons =
{
handguns: {
"CR-75": "https://static.wikia.nocookie.net/dayz_gamepedia/images/4/40/CZ75.png/revision/latest/scale-to-width-down/112?cb=20210505021307",
"Deagle": "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/62/Deagle.png/revision/latest/scale-to-width-down/127?cb=20210512003023",
"Derringer": "https://static.wikia.nocookie.net/dayz_gamepedia/images/9/9f/Derringer_Black.png/revision/latest/scale-to-width-down/105?cb=20220521175445",
"FX-45": "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/fd/FNX45.png/revision/latest/scale-to-width-down/104?cb=20210505025055",
"IJ-70": "https://static.wikia.nocookie.net/dayz_gamepedia/images/2/26/MakarovIJ70.png/revision/latest/scale-to-width-down/92?cb=20210209000551",
"Kolt 1911": "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/f9/Colt1911.png/revision/latest/scale-to-width-down/112?cb=20210505030200",
"Longhorn": "https://static.wikia.nocookie.net/dayz_gamepedia/images/7/79/Longhorn.png/revision/latest/scale-to-width-down/222?cb=20220324214533",
"MK II": "https://static.wikia.nocookie.net/dayz_gamepedia/images/0/0d/MKII.png/revision/latest/scale-to-width-down/171?cb=20210210153348",
"Mlock-91": "https://static.wikia.nocookie.net/dayz_gamepedia/images/9/9b/Glock19.png/revision/latest/scale-to-width-down/121?cb=20210505024259",
"P1": "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/cc/P1.png/revision/latest/scale-to-width-down/120?cb=20220518204515",
"Revolver": "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/6d/Revolver.png/revision/latest/scale-to-width-down/148?cb=20210208232303",
"Signal Pistol": "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/a7/Flaregun.png/revision/latest/scale-to-width-down/107?cb=20210501150913",
},
shotguns: {
"BK-12": "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/cb/Izh18Shotgun.png/revision/latest/scale-to-width-down/256?cb=20220922184507",
"BK-133": "https://static.wikia.nocookie.net/dayz_gamepedia/images/5/5c/MP-133-Shotgun.png/revision/latest/scale-to-width-down/256?cb=20210210190104",
"BK-43": "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c7/Izh43Shotgun.png/revision/latest/scale-to-width-down/256?cb=20210210185835",
"Vaiga": "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/c8/Vaiga.png/revision/latest/scale-to-width-down/256?cb=20220220185225",
},
subMachineGuns: {
"Bizon": "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/af/PP19.png/revision/latest/scale-to-width-down/251?cb=20220127132305",
"CR-61 Skorpion": "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/63/VZ61Scorpion.png/revision/latest/scale-to-width-down/222?cb=20220518204508",
"SG5-K": "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/fc/MP5-K.png/revision/latest/scale-to-width-down/158?cb=20220221011343",
"USG-45": "https://static.wikia.nocookie.net/dayz_gamepedia/images/d/d7/UMP45.png/revision/latest/scale-to-width-down/153?cb=20220221002354",
},
assaultRifles: {
"AUR A1": "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/e6/AugShort.png/revision/latest/scale-to-width-down/173?cb=20211104175243",
"AUR AX": "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/be/Aug.png/revision/latest/scale-to-width-down/233?cb=20211104182427",
"KA-101": "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/f2/AK101.png/revision/latest/scale-to-width-down/251?cb=20210207040122",
"KA-74": "https://static.wikia.nocookie.net/dayz_gamepedia/images/8/8b/AK74.png/revision/latest/scale-to-width-down/253?cb=20210505013141",
"KAS-74U": "https://static.wikia.nocookie.net/dayz_gamepedia/images/0/0b/AKS74U.png/revision/latest/scale-to-width-down/191?cb=20210505014222",
"KA-M": "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/6c/AKM.png/revision/latest/scale-to-width-down/244?cb=20210505011614",
"LE-MAS": "https://static.wikia.nocookie.net/dayz_gamepedia/images/2/21/FAMAS.png/revision/latest/scale-to-width-down/197?cb=20210902183114",
"M16-A2": "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/b3/M16-A2.png/revision/latest/scale-to-width-down/256?cb=20220221002601",
"M4-A1": "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/a1/M4A1.png/revision/latest/scale-to-width-down/223?cb=20220330014851",
"SVAL": "https://static.wikia.nocookie.net/dayz_gamepedia/images/3/39/ASVAL.png/revision/latest/scale-to-width-down/256?cb=20210208015731",
"Vikhr": "https://static.wikia.nocookie.net/dayz_gamepedia/images/0/0d/Vikhr.png/revision/latest/scale-to-width-down/173?cb=20240116163108",
},
battleRifles: {
"LAR": "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/e9/FAL.png/revision/latest/scale-to-width-down/256?cb=20220221001123",
},
boltActionRifles: {
"CR-527": "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/f0/CR527Wood.png/revision/latest/scale-to-width-down/256?cb=20220518204503",
"CR-550 Savanna": "https://static.wikia.nocookie.net/dayz_gamepedia/images/4/44/CR-550_Savanna.png/revision/latest/scale-to-width-down/256?cb=20220518204410",
"M70 Tundra": "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/62/Winchester70.png/revision/latest/scale-to-width-down/256?cb=20220517152918",
"Mosin 91/30": "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/a8/Mosin9130.png/revision/latest/scale-to-width-down/256?cb=20230126021955",
"Pioneer": "https://static.wikia.nocookie.net/dayz_gamepedia/images/6/69/Scout.png/revision/latest/scale-to-width-down/256?cb=20220518204357",
"SSG 82": "https://static.wikia.nocookie.net/dayz_gamepedia/images/1/10/SSG82.png/revision/latest/scale-to-width-down/256?cb=20220922192455",
"VS-89": "https://static.wikia.nocookie.net/dayz_gamepedia/images/e/ea/SV98.png/revision/latest/scale-to-width-down/256?cb=20240424164607",
},
breakActionRifles: {
"BK-18": "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/cb/IZH18_Rifle.png/revision/latest/scale-to-width-down/256?cb=20220517154121",
"Blaze": "https://static.wikia.nocookie.net/dayz_gamepedia/images/8/8a/Blaze_95_Double_Rifle_Wood.png/revision/latest/scale-to-width-down/256?cb=20220517154129",
},
leverActionRifles: {
"Repeater Carbine": "https://static.wikia.nocookie.net/dayz_gamepedia/images/c/ce/Repeater.png/revision/latest/scale-to-width-down/256?cb=20220517154151",
},
marksmanRifles: {
"VSD": "https://static.wikia.nocookie.net/dayz_gamepedia/images/a/a2/SVD_w._PSO-1.png/revision/latest/scale-to-width-down/256?cb=20220220235826",
"VSS": "https://static.wikia.nocookie.net/dayz_gamepedia/images/8/83/VSSVintorez.png/revision/latest/scale-to-width-down/256?cb=20210208202042",
},
semiAutomaticRifles: {
"DMR": "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/b4/M14.png/revision/latest/scale-to-width-down/350?cb=20231005142636",
"SK 59/66": "https://static.wikia.nocookie.net/dayz_gamepedia/images/f/fe/SKS.png/revision/latest/scale-to-width-down/256?cb=20220517154633",
"Sporter 22": "https://static.wikia.nocookie.net/dayz_gamepedia/images/5/5b/Sporter_22_Wood.png/revision/latest/scale-to-width-down/256?cb=20220518204154",
},
other: {
"Crossbow": "https://static.wikia.nocookie.net/dayz_gamepedia/images/7/79/Crossbow.png/revision/latest/scale-to-width-down/212?cb=20180121164101",
"M79": "https://static.wikia.nocookie.net/dayz_gamepedia/images/b/b7/M79.png/revision/latest/scale-to-width-down/256?cb=20220521184052",
},
};
export const weaponClassOf = (weapon: AllWeapons): WeaponCategory | undefined => {
return (Object.keys(weapons) as WeaponCategory[]).find((category) => weapon in weapons[category]);
}
+1 -1
View File
@@ -1,3 +1,3 @@
module.exports = (client, guild) => { module.exports = (client, guild) => {
require("../util/RegisterSlashCommands").RegisterGuildCommands(client, guild.id); require("../services/RegisterSlashCommands").RegisterGuildCommands(client, guild.id);
}; };
+1 -1
View File
@@ -4,7 +4,7 @@ const { GetGuild } = require("../database/guild");
module.exports = async (client, member) => { module.exports = async (client, member) => {
let GuildDB = await GetGuild(client, member.guild.id); let GuildDB = await GetGuild(client, member.guild.id);
if (!client.exists(GuildDB.welcomeChannel)) return; if (!isDefined(GuildDB.welcomeChannel)) return;
const channel = client.GetChannel(GuildDB.welcomeChannel); const channel = client.GetChannel(GuildDB.welcomeChannel);
if (GuildDB.serverName == "") GuildDB.serverName = "our server!" if (GuildDB.serverName == "") GuildDB.serverName = "our server!"
@@ -1,11 +1,12 @@
const { EmbedBuilder } = require("discord.js"); const { EmbedBuilder } = require("discord.js");
const { nearest } = require("../database/destinations"); const { nearest } = require("../database/destinations");
const { GetWebhook, WebhookSend } = require("./WebhookHandler"); const { GetWebhook, WebhookSend } = require("../services/WebhookService");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
SendConnectionLogs: async (client, guild, data) => { SendConnectionLogs: async (client, guild, data) => {
if (!client.exists(guild.connectionLogsChannel)) return; if (!isDefined(guild.connectionLogsChannel)) return;
const channel = client.GetChannel(guild.connectionLogsChannel); const channel = client.GetChannel(guild.connectionLogsChannel);
if (!channel) return; if (!channel) return;
@@ -27,13 +28,13 @@ module.exports = {
} else connectionLog.addFields({ name: "**Session Time**", value: `**Unknown**`, inline: false }); } else connectionLog.addFields({ name: "**Session Time**", value: `**Unknown**`, inline: false });
} }
// if (client.exists(channel)) await channel.send({ embeds: [connectionLog] }); // if (isDefined(channel)) await channel.send({ embeds: [connectionLog] });
await WebhookSend(client, webhook, { embeds: [connectionLog] }); await WebhookSend(client, webhook, { embeds: [connectionLog] });
}, },
DetectCombatLog: async (client, guild, data) => { DetectCombatLog: async (client, guild, data) => {
if (!client.exists(data.lastDamageDate)) return; if (!isDefined(data.lastDamageDate)) return;
if (!client.exists(guild.connectionLogsChannel)) return; if (!isDefined(guild.connectionLogsChannel)) return;
const channel = client.GetChannel(guild.connectionLogsChannel); const channel = client.GetChannel(guild.connectionLogsChannel);
if (!channel) return; // Ensure channel exists if (!channel) return; // Ensure channel exists
@@ -61,7 +62,7 @@ module.exports = {
const webhook = await GetWebhook(client, NAME, guild.connectionLogsChannel); const webhook = await GetWebhook(client, NAME, guild.connectionLogsChannel);
let content = { embeds: [combatLog] }; let content = { embeds: [combatLog] };
if (client.exists(guild.adminRole)) content.content = `<@&${guild.adminRole}>`; if (isDefined(guild.adminRole)) content.content = `<@&${guild.adminRole}>`;
WebhookSend(client, webhook, content); WebhookSend(client, webhook, content);
// return channel.send({ embeds: [combatLog] }); // return channel.send({ embeds: [combatLog] });
} }
@@ -2,14 +2,15 @@ const { BanPlayer, UnbanPlayer } = require("./NitradoAPI");
const { EmbedBuilder } = require("discord.js"); const { EmbedBuilder } = require("discord.js");
const { nearest } = require("../database/destinations"); const { nearest } = require("../database/destinations");
const { GetGuild } = require("../database/guild"); const { GetGuild } = require("../database/guild");
const { GetWebhook, WebhookSend } = require("./WebhookHandler"); const { GetWebhook, WebhookSend } = require("../services/WebhookService");
const isDefined = require("../util/Validation.js");
// Private functions (only called locally) // Private functions (only called locally)
const ExpireEvent = async (client, guild, e) => { const ExpireEvent = async (client, guild, e) => {
let hasMR = (guild.memberRole != ""); let hasMR = (guild.memberRole != "");
const channel = client.GetChannel(e.channel); const channel = client.GetChannel(e.channel);
if (client.exists(e.channel)) channel.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Default).setDescription(`${hasMR ? `<@&${guild.memberRole}>\n` : ""}**The ${e.name} Event has ended!**`)] }); if (isDefined(e.channel)) channel.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Default).setDescription(`${hasMR ? `<@&${guild.memberRole}>\n` : ""}**The ${e.name} Event has ended!**`)] });
client.dbo.collection("guilds").updateOne({ "server.serverID": guild.serverID }, { client.dbo.collection("guilds").updateOne({ "server.serverID": guild.serverID }, {
$pull: { $pull: {
@@ -21,7 +22,7 @@ const ExpireEvent = async (client, guild, e) => {
} }
const HandlePlayerTrackEvent = async (client, guild, e) => { const HandlePlayerTrackEvent = async (client, guild, e) => {
if (!client.exists(e.channel)) return ExpireEvent(client, guild, e); // Expire event since it has invalid channel. if (!isDefined(e.channel)) return ExpireEvent(client, guild, e); // Expire event since it has invalid channel.
const channel = client.GetChannel(e.channel); const channel = client.GetChannel(e.channel);
if (!channel) return; if (!channel) return;
@@ -40,7 +41,7 @@ const HandlePlayerTrackEvent = async (client, guild, e) => {
const webhook = await GetWebhook(client, NAME, e.channel); const webhook = await GetWebhook(client, NAME, e.channel);
let content = { embeds: [trackEvent] }; let content = { embeds: [trackEvent] };
if (client.exists(guild.adminRole)) content.content = `<@&${e.role}>`; if (isDefined(guild.adminRole)) content.content = `<@&${e.role}>`;
WebhookSend(client, webhook, content); WebhookSend(client, webhook, content);
// if (e.role) channel.send({ content: `<@&${e.role}>`, embeds: [trackEvent] }); // if (e.role) channel.send({ content: `<@&${e.role}>`, embeds: [trackEvent] });
@@ -3,9 +3,10 @@ const { createUser, addUser } = require("../database/user");
const { KillInAlarm } = require("./AlarmsHandler"); const { KillInAlarm } = require("./AlarmsHandler");
const { nearest } = require("../database/destinations"); const { nearest } = require("../database/destinations");
const { getDefaultPlayer, UpdatePlayer } = require("../database/player"); const { getDefaultPlayer, UpdatePlayer } = require("../database/player");
const { calculateNewCombatRating } = require("./CombatRatingHandler"); const { calculateNewCombatRating } = require("../util/CombatRating");
const { weapons, weaponClassOf } = require("../database/weapons"); const { weapons, weaponClassOf } = require("../database/weapons");
const { GetWebhook, WebhookSend } = require("../util/WebhookHandler"); const { GetWebhook, WebhookSend } = require("../util/WebhookHandler");
const isDefined = require("../util/Validation.js");
const Templates = { const Templates = {
Killed: 1, Killed: 1,
@@ -71,7 +72,7 @@ module.exports = {
const newDt = await client.getDateEST(info.time); const newDt = await client.getDateEST(info.time);
let victimStat = await client.dbo.collection("players").findOne({ "playerID": info.playerID }); let victimStat = await client.dbo.collection("players").findOne({ "playerID": info.playerID });
if (!client.exists(victimStat)) victimStat = getDefaultPlayer(info.player, info.playerID, NitradoServerID); if (!isDefined(victimStat)) victimStat = getDefaultPlayer(info.player, info.playerID, NitradoServerID);
victimStat.lastDeathDate = newDt; victimStat.lastDeathDate = newDt;
@@ -126,15 +127,15 @@ module.exports = {
const newDt = await client.getDateEST(info.time); const newDt = await client.getDateEST(info.time);
const unixTime = Math.floor(newDt.getTime() / 1000); const unixTime = Math.floor(newDt.getTime() / 1000);
const showCoords = client.exists(guild.showKillfeedCoords) ? guild.showKillfeedCoords : false; // default to false if no record of configuration. const showCoords = isDefined(guild.showKillfeedCoords) ? guild.showKillfeedCoords : false; // default to false if no record of configuration.
const showWeapon = client.exists(guild.showKillfeedWeapon) ? guild.showKillfeedWeapon : false; // default to false if no record of configuration. const showWeapon = isDefined(guild.showKillfeedWeapon) ? guild.showKillfeedWeapon : false; // default to false if no record of configuration.
const destination = nearest(info.victimPOS, guild.Nitrado.Mission); const destination = nearest(info.victimPOS, guild.Nitrado.Mission);
if ([Templates.LandMine, Templates.Explosion, Templates.Vehicle].includes(killedBy)) if ([Templates.LandMine, Templates.Explosion, Templates.Vehicle].includes(killedBy))
if (killedBy == Templates.LandMine || killedBy == Templates.Explosion || killedBy == Templates.Vehicle) { if (killedBy == Templates.LandMine || killedBy == Templates.Explosion || killedBy == Templates.Vehicle) {
let victimStat = await client.dbo.collection("players").findOne({ "playerID": info.victimID }); let victimStat = await client.dbo.collection("players").findOne({ "playerID": info.victimID });
if (!client.exists(victimStat)) victimStat = getDefaultPlayer(info.victim, info.victimID, NitradoServerID); if (!isDefined(victimStat)) victimStat = getDefaultPlayer(info.victim, info.victimID, NitradoServerID);
victimStat.deaths++; victimStat.deaths++;
victimStat.deathStreak++; victimStat.deathStreak++;
victimStat.worstDeathStreak = victimStat.deathStreak > victimStat.worstDeathStreak ? victimStat.deathStreak : victimStat.worstDeathStreak; victimStat.worstDeathStreak = victimStat.deathStreak > victimStat.worstDeathStreak ? victimStat.deathStreak : victimStat.worstDeathStreak;
@@ -157,18 +158,18 @@ module.exports = {
const webhook = await GetWebhook(client, NAME, guild.killfeedChannel); const webhook = await GetWebhook(client, NAME, guild.killfeedChannel);
WebhookSend(client, webhook, { embeds: [killEvent] }); WebhookSend(client, webhook, { embeds: [killEvent] });
// if (client.exists(channel)) await channel.send({ embeds: [killEvent] }); // if (isDefined(channel)) await channel.send({ embeds: [killEvent] });
return; return;
} }
KillInAlarm(client, guild.serverID, info); // check if kill happened in a no kill zone KillInAlarm(client, guild.serverID, info); // check if kill happened in a no kill zone
if (!client.exists(info.victim) || !client.exists(info.victimID) || !client.exists(info.killer) || !client.exists(info.killerID)) return; if (!isDefined(info.victim) || !isDefined(info.victimID) || !isDefined(info.killer) || !isDefined(info.killerID)) return;
let victimStat = await client.dbo.collection("players").findOne({ "playerID": info.victimID }); let victimStat = await client.dbo.collection("players").findOne({ "playerID": info.victimID });
let killerStat = await client.dbo.collection("players").findOne({ "playerID": info.killerID }); let killerStat = await client.dbo.collection("players").findOne({ "playerID": info.killerID });
if (!client.exists(victimStat)) victimStat = getDefaultPlayer(info.victim, info.victimID, NitradoServerID); if (!isDefined(victimStat)) victimStat = getDefaultPlayer(info.victim, info.victimID, NitradoServerID);
if (!client.exists(killerStat)) killerStat = getDefaultPlayer(info.killer, info.killerID, NitradoServerID); if (!isDefined(killerStat)) killerStat = getDefaultPlayer(info.killer, info.killerID, NitradoServerID);
let weapon = info.weapon.includes("Engraved") ? info.weapon.split("Engraved ")[1] : let weapon = info.weapon.includes("Engraved") ? info.weapon.split("Engraved ")[1] :
info.weapon.includes("Sawed-off") ? info.weapon.split("Sawed-off ")[1] : info.weapon.includes("Sawed-off") ? info.weapon.split("Sawed-off ")[1] :
@@ -181,7 +182,7 @@ module.exports = {
killerStat.KDR = killerStat.kills / (killerStat.deaths == 0 ? 1 : killerStat.deaths); // prevent division by 0 killerStat.KDR = killerStat.kills / (killerStat.deaths == 0 ? 1 : killerStat.deaths); // prevent division by 0
killerStat.longestKill = info.distance > killerStat.longestKill ? info.distance : killerStat.longestKill; killerStat.longestKill = info.distance > killerStat.longestKill ? info.distance : killerStat.longestKill;
killerStat.deathStreak = 0; killerStat.deathStreak = 0;
if (!client.exists(killerStat.weaponStats[weapon].kills)) killerStat.weaponStats[weapon].kills = 0; if (!isDefined(killerStat.weaponStats[weapon].kills)) killerStat.weaponStats[weapon].kills = 0;
killerStat.weaponStats[weapon].kills++; killerStat.weaponStats[weapon].kills++;
// Update victim stats // Update victim stats
@@ -191,21 +192,21 @@ module.exports = {
victimStat.KDR = victimStat.kills / (victimStat.deaths == 0 ? 1 : victimStat.deaths); // prevent division by 0 victimStat.KDR = victimStat.kills / (victimStat.deaths == 0 ? 1 : victimStat.deaths); // prevent division by 0
victimStat.killStreak = 0; victimStat.killStreak = 0;
victimStat.lastDeathDate = newDt; victimStat.lastDeathDate = newDt;
if (!client.exists(victimStat.weaponStats[weapon].deaths)) victimStat.weaponStats[weapon].death = 0; if (!isDefined(victimStat.weaponStats[weapon].deaths)) victimStat.weaponStats[weapon].death = 0;
victimStat.weaponStats[weapon].deaths++; victimStat.weaponStats[weapon].deaths++;
// Create defaults for non-existing ratings // Create defaults for non-existing ratings
if (!client.exists(killerStat.combatRating)) killerStat.combatRating = 800; if (!isDefined(killerStat.combatRating)) killerStat.combatRating = 800;
if (!client.exists(victimStat.combatRating)) victimStat.combatRating = 800; if (!isDefined(victimStat.combatRating)) victimStat.combatRating = 800;
if (!client.exists(killerStat.combatRatingHistory)) killerStat.combatRatingHistory = [800]; if (!isDefined(killerStat.combatRatingHistory)) killerStat.combatRatingHistory = [800];
if (!client.exists(victimStat.combatRatingHistory)) victimStat.combatRatingHistory = [800]; if (!isDefined(victimStat.combatRatingHistory)) victimStat.combatRatingHistory = [800];
if (!client.exists(killerStat.highestCombatRating)) killerStat.highestCombatRating = Math.max(...killerStat.combatRatingHistory); if (!isDefined(killerStat.highestCombatRating)) killerStat.highestCombatRating = Math.max(...killerStat.combatRatingHistory);
if (!client.exists(victimStat.lowestCombatRating)) victimStat.lowestCombatRating = Math.min(...victimStat.combatRatingHistory); if (!isDefined(victimStat.lowestCombatRating)) victimStat.lowestCombatRating = Math.min(...victimStat.combatRatingHistory);
// Calculate new ratings // Calculate new ratings
let killerOldRating = killerStat.combatRating; let killerOldRating = killerStat.combatRating;
let victimOldRating = victimStat.combatRating; let victimOldRating = victimStat.combatRating;
killerStat.combatRating = calculateNewCombatRating(killerStat.combatRating, victimStat.combatRating, client.exists(info.bodyPart) && info.bodyPart.includes("Head") ? 1.25 : 1); killerStat.combatRating = calculateNewCombatRating(killerStat.combatRating, victimStat.combatRating, isDefined(info.bodyPart) && info.bodyPart.includes("Head") ? 1.25 : 1);
victimStat.combatRating = calculateNewCombatRating(victimStat.combatRating, killerStat.combatRating, 0); victimStat.combatRating = calculateNewCombatRating(victimStat.combatRating, killerStat.combatRating, 0);
// Update combat rating records // Update combat rating records
@@ -230,11 +231,11 @@ module.exports = {
if (!banking) { if (!banking) {
banking = await createUser(interaction.member.user.id, guild.serverID, guild.startingBalance, client) banking = await createUser(interaction.member.user.id, guild.serverID, guild.startingBalance, client)
if (!client.exists(banking)) return client.sendInternalError(interaction, err); if (!isDefined(banking)) return client.sendInternalError(interaction, err);
} }
banking = banking.user; banking = banking.user;
if (!client.exists(banking.guilds[guild.serverID])) { if (!isDefined(banking.guilds[guild.serverID])) {
const success = addUser(banking.guilds, guild.serverID, interaction.member.user.id, client, guild.startingBalance); const success = addUser(banking.guilds, guild.serverID, interaction.member.user.id, client, guild.startingBalance);
if (!success) return client.sendInternalError(interaction, "Failed to add bank"); if (!success) return client.sendInternalError(interaction, "Failed to add bank");
} }
@@ -280,10 +281,10 @@ module.exports = {
const webhook = await GetWebhook(client, NAME, guild.killfeedChannel); const webhook = await GetWebhook(client, NAME, guild.killfeedChannel);
WebhookSend(client, webhook, { embeds: [killEvent] }); WebhookSend(client, webhook, { embeds: [killEvent] });
if (client.exists(receivedBounty) && client.exists(channel)) WebhookSend(client, webhook, { content: `<@${killerStat.discordID}>`, embeds: [receivedBounty] }); if (isDefined(receivedBounty) && isDefined(channel)) WebhookSend(client, webhook, { content: `<@${killerStat.discordID}>`, embeds: [receivedBounty] });
// if (client.exists(channel)) await channel.send({ embeds: [killEvent] }); // if (isDefined(channel)) await channel.send({ embeds: [killEvent] });
// if (client.exists(receivedBounty) && client.exists(channel)) await channel.send({ content: `<@${killerStat.discordID}>`, embeds: [receivedBounty] }); // if (isDefined(receivedBounty) && isDefined(channel)) await channel.send({ content: `<@${killerStat.discordID}>`, embeds: [receivedBounty] });
return; return;
} }
@@ -5,7 +5,8 @@ const { getDefaultPlayer } = require("../database/player");
const { FetchServerSettings } = require("./NitradoAPI"); const { FetchServerSettings } = require("./NitradoAPI");
const { UpdatePlayer, insertPVPstats, createWeaponStats } = require("../database/player") const { UpdatePlayer, insertPVPstats, createWeaponStats } = require("../database/player")
const { Missions } = require("../database/destinations"); const { Missions } = require("../database/destinations");
const { GetWebhook, WebhookSend, WebhookMessageEdit } = require("./WebhookHandler"); const { GetWebhook, WebhookSend, WebhookMessageEdit } = require("../services/WebhookService");
const isDefined = require("../util/Validation.js");
module.exports = { module.exports = {
@@ -27,15 +28,15 @@ module.exports = {
playerID: data[3], playerID: data[3],
}; };
if (!client.exists(info.player) || !client.exists(info.playerID)) return; if (!isDefined(info.player) || !isDefined(info.playerID)) return;
let playerStat = await client.dbo.collection("players").findOne({ "playerID": info.playerID }); let playerStat = await client.dbo.collection("players").findOne({ "playerID": info.playerID });
if (!client.exists(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID, NitradoServerID); if (!isDefined(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID, NitradoServerID);
const newDt = await client.getDateEST(info.time); const newDt = await client.getDateEST(info.time);
playerStat.lastConnectionDate = newDt; playerStat.lastConnectionDate = newDt;
playerStat.connected = true; playerStat.connected = true;
if (!client.exists(playerStat.connections)) playerStat.connections = 0; if (!isDefined(playerStat.connections)) playerStat.connections = 0;
playerStat.connections++; playerStat.connections++;
// Track adjusted sessions this instance has handled (e.g. no bot crashes or restarts). // Track adjusted sessions this instance has handled (e.g. no bot crashes or restarts).
@@ -72,10 +73,10 @@ module.exports = {
playerID: data[3], playerID: data[3],
}; };
if (!client.exists(info.player) || !client.exists(info.playerID)) return; if (!isDefined(info.player) || !isDefined(info.playerID)) return;
let playerStat = await client.dbo.collection("players").findOne({ "playerID": info.playerID }); let playerStat = await client.dbo.collection("players").findOne({ "playerID": info.playerID });
if (!client.exists(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID, NitradoServerID); if (!isDefined(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID, NitradoServerID);
let oldUnixTime; let oldUnixTime;
let sessionTimeSeconds; let sessionTimeSeconds;
@@ -85,7 +86,7 @@ module.exports = {
oldUnixTime = Math.round(playerStat.lastConnectionDate.getTime() / 1000); // Seconds oldUnixTime = Math.round(playerStat.lastConnectionDate.getTime() / 1000); // Seconds
sessionTimeSeconds = unixTime - oldUnixTime; sessionTimeSeconds = unixTime - oldUnixTime;
} else sessionTimeSeconds = 0; } else sessionTimeSeconds = 0;
if (!client.exists(playerStat.longestSessionTime)) playerStat.longestSessionTime = 0; if (!isDefined(playerStat.longestSessionTime)) playerStat.longestSessionTime = 0;
playerStat.totalSessionTime = playerStat.totalSessionTime + sessionTimeSeconds; playerStat.totalSessionTime = playerStat.totalSessionTime + sessionTimeSeconds;
playerStat.lastSessionTime = sessionTimeSeconds; playerStat.lastSessionTime = sessionTimeSeconds;
@@ -126,11 +127,11 @@ module.exports = {
pos: data[4].split(", ").map(v => parseFloat(v)) pos: data[4].split(", ").map(v => parseFloat(v))
}; };
if (!client.exists(info.player) || !client.exists(info.playerID)) return; if (!isDefined(info.player) || !isDefined(info.playerID)) return;
let playerStat = await client.dbo.collection("players").findOne({ "playerID": info.playerID }); let playerStat = await client.dbo.collection("players").findOne({ "playerID": info.playerID });
if (!client.exists(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID, NitradoServerID); if (!isDefined(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID, NitradoServerID);
if (!client.exists(playerStat.lastConnectionDate)) playerStat.lastConnectionDate = await client.getDateEST(info.time); if (!isDefined(playerStat.lastConnectionDate)) playerStat.lastConnectionDate = await client.getDateEST(info.time);
playerStat.lastPos = playerStat.pos; playerStat.lastPos = playerStat.pos;
playerStat.pos = info.pos; playerStat.pos = info.pos;
@@ -165,18 +166,18 @@ module.exports = {
weapon: data[12], weapon: data[12],
}; };
if (!client.exists(info.player) || !client.exists(info.playerID) || !client.exists(info.attacker) || !client.exists(info.attackerID)) return; if (!isDefined(info.player) || !isDefined(info.playerID) || !isDefined(info.attacker) || !isDefined(info.attackerID)) return;
let playerStat = await client.dbo.collection("players").findOne({ "playerID": info.playerID }); let playerStat = await client.dbo.collection("players").findOne({ "playerID": info.playerID });
let attackerStat = await client.dbo.collection("players").findOne({ "playerID": info.attackerID }); let attackerStat = await client.dbo.collection("players").findOne({ "playerID": info.attackerID });
if (!client.exists(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID, NitradoServerID); if (!isDefined(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID, NitradoServerID);
if (!client.exists(attackerStat)) attackerStat = getDefaultPlayer(info.attacker, info.attackerID, NitradoServerID); if (!isDefined(attackerStat)) attackerStat = getDefaultPlayer(info.attacker, info.attackerID, NitradoServerID);
playerStat.lastDamageDate = await client.getDateEST(info.time); playerStat.lastDamageDate = await client.getDateEST(info.time);
playerStat.lastHitBy = info.attacker; playerStat.lastHitBy = info.attacker;
if (!client.exists(playerStat.shotsLanded)) playerStat = insertPVPstats(playerStat); if (!isDefined(playerStat.shotsLanded)) playerStat = insertPVPstats(playerStat);
if (!client.exists(attackerStat.shotsLanded)) attackerStat = insertPVPstats(attackerStat); if (!isDefined(attackerStat.shotsLanded)) attackerStat = insertPVPstats(attackerStat);
// Update in depth PVP stats if non Melee weapon // Update in depth PVP stats if non Melee weapon
if (info.weapon.includes("Engraved")) info.weapon = info.weapon.split("Engraved ")[1]; if (info.weapon.includes("Engraved")) info.weapon = info.weapon.split("Engraved ")[1];
@@ -184,13 +185,13 @@ module.exports = {
if (info.weapon in playerStat.weaponStats) { if (info.weapon in playerStat.weaponStats) {
playerStat.timesShot++; playerStat.timesShot++;
playerStat.timesShotPerBodyPart[info.bodyPart]++; playerStat.timesShotPerBodyPart[info.bodyPart]++;
if (!client.exists(playerStat.weaponStats[info.weapon])) playerStat = createWeaponStats(playerStat, info.weapon); if (!isDefined(playerStat.weaponStats[info.weapon])) playerStat = createWeaponStats(playerStat, info.weapon);
playerStat.weaponStats[info.weapon].timesShot++; playerStat.weaponStats[info.weapon].timesShot++;
playerStat.weaponStats[info.weapon].timesShotPerBodyPart[info.bodyPart]++; playerStat.weaponStats[info.weapon].timesShotPerBodyPart[info.bodyPart]++;
attackerStat.shotsLanded++; attackerStat.shotsLanded++;
attackerStat.shotsLandedPerBodyPart[info.bodyPart]++; attackerStat.shotsLandedPerBodyPart[info.bodyPart]++;
if (!client.exists(attackerStat.weaponStats[info.weapon])) attackerStat = createWeaponStats(attackerStat, info.weapon); if (!isDefined(attackerStat.weaponStats[info.weapon])) attackerStat = createWeaponStats(attackerStat, info.weapon);
attackerStat.weaponStats[info.weapon].shotsLanded++; attackerStat.weaponStats[info.weapon].shotsLanded++;
attackerStat.weaponStats[info.weapon].shotsLandedPerBodyPart[info.bodyPart]++; attackerStat.weaponStats[info.weapon].shotsLandedPerBodyPart[info.bodyPart]++;
} }
@@ -205,7 +206,7 @@ module.exports = {
HandleActivePlayersList: async (nitrado_cred, client, guild) => { HandleActivePlayersList: async (nitrado_cred, client, guild) => {
client.activePlayersTick = 0; // reset hour tick client.activePlayersTick = 0; // reset hour tick
if (!client.exists(guild.activePlayersChannel)) return; if (!isDefined(guild.activePlayersChannel)) return;
const channel = client.GetChannel(guild.activePlayersChannel); const channel = client.GetChannel(guild.activePlayersChannel);
if (!channel) return; if (!channel) return;
+1 -1
View File
@@ -1,5 +1,5 @@
import { ShardingManager } from "discord.js"; import { ShardingManager } from "discord.js";
import config from "./config/config"; import { config } from "./config/config";
// ShardingManager spawns node instances and we need to explicitely point to dist/bot.js // ShardingManager spawns node instances and we need to explicitely point to dist/bot.js
const manager: ShardingManager = new ShardingManager("./dist/bot.js", { token: config.Token }); const manager: ShardingManager = new ShardingManager("./dist/bot.js", { token: config.Token });
+17 -13
View File
@@ -1,40 +1,44 @@
const winston = require("winston"); import winston from "winston";
const colors = require("colors"); import colors from "colors";
class Logger { export default class Logger {
constructor(LoggingFile) {
public logger: winston.Logger;
constructor(loggingFile: string)
{
this.logger = winston.createLogger({ this.logger = winston.createLogger({
transports: [new winston.transports.File({ filename: LoggingFile })], transports: [new winston.transports.File({ filename: loggingFile })],
}); });
} }
log(Text) { log(text: string): void
{
let d = new Date(); let d = new Date();
this.logger.log({ this.logger.log({
level: "info", level: "info",
message: message:
`${d.getHours()}:${d.getMinutes()} - ${d.getMonth() + 1}:${d.getDate()}:${d.getFullYear()} | Info: ` + Text `${d.getHours()}:${d.getMinutes()} - ${d.getMonth() + 1}:${d.getDate()}:${d.getFullYear()} | Info: ` + text
}); });
console.log( console.log(
colors.green( colors.green(
`${d.getMonth() + 1}:${d.getDate()}:${d.getFullYear()} - ${d.getHours()}:${d.getMinutes()}` `${d.getMonth() + 1}:${d.getDate()}:${d.getFullYear()} - ${d.getHours()}:${d.getMinutes()}`
) + colors.yellow(" | Info: " + Text) ) + colors.yellow(" | Info: " + text)
); );
} }
error(Text) { error(text: string): void
{
let d = new Date(); let d = new Date();
this.logger.log({ this.logger.log({
level: "error", level: "error",
message: message:
`${d.getHours()}:${d.getMinutes()} - ${d.getMonth() + 1}:${d.getDate()}:${d.getFullYear()} | Error: ` + Text `${d.getHours()}:${d.getMinutes()} - ${d.getMonth() + 1}:${d.getDate()}:${d.getFullYear()} | Error: ` + text
}); });
console.log( console.log(
colors.green( colors.green(
`${d.getMonth() + 1}:${d.getDate()}:${d.getFullYear()} - ${d.getHours()}:${d.getMinutes()}` `${d.getMonth() + 1}:${d.getDate()}:${d.getFullYear()} - ${d.getHours()}:${d.getMinutes()}`
) + colors.yellow(" | Error: ") + colors.red(Text) ) + colors.yellow(" | Error: ") + colors.red(text)
); );
} }
} }
module.exports = Logger;
@@ -3,6 +3,7 @@ const concat = require("concat-stream"); // convert to import ?
import { Readable } from "stream"; import { Readable } from "stream";
import FormData from "form-data"; import FormData from "form-data";
import * as fs from "fs"; import * as fs from "fs";
import isDefined from "../util/Validation";
const MAX_RETRIES = 5; const MAX_RETRIES = 5;
const RETRY_DELAY_MS = 5000; // 5 seconds const RETRY_DELAY_MS = 5000; // 5 seconds
@@ -91,11 +92,11 @@ const HandlePlayerBan = async (nitrado_cred: any, client: any, gamertag: any, ba
} }
} }
const GetRemoteDir = async (nitrado_cred: any, const GetRemoteDir = async (
client: any, nitrado_cred: any,
dir = "") => client: any, dir = "") =>
{ {
const dirParam = client.exists(dir) ? `?dir=${dir}` : ""; const dirParam = isDefined(dir) ? `?dir=${dir}` : "";
for (let retries = 0; retries <= MAX_RETRIES; retries++) for (let retries = 0; retries <= MAX_RETRIES; retries++)
{ {
try try
File renamed without changes.
File renamed without changes.
+23
View File
@@ -0,0 +1,23 @@
import { bgYellow } from "colors";
import "discord.js";
/**
* Type augmentation allows us to add custom functions to the
* ChatInputCommandInteraction without typescript complaining
*/
declare module "discord.js" {
interface ChatInputCommandInteraction {
send(
content: string | { embeds?: (EmbedBuilder | APIEmbed)[]; [key: string]: any }
): Promise<unknown>;
deferReply(
content?: string | { embeds?: (EmbedBuilder | APIEmbed)[]; [key: string]: any }
): Promise<unknown>;
showModal(
content: string | { embeds?: (EmbedBuilder | APIEmbed)[]; [key: string]: any }
): Promise<unknown>;
editReply(
content: string | { embeds?: (EmbedBuilder | APIEmbed)[]; [key: string]: any }
): Promise<unknown>;
}
}
+12
View File
@@ -0,0 +1,12 @@
import { Readable } from "stream";
// cannot get a warning to go away, this is like the only solution
declare module "node:readline" {
import { Interface, ReadLineOptions } from "readline";
interface ReadLineOptionsFixed extends ReadLineOptions {
input: Readable; // 👈 force Node stream
}
export function createInterface(options: ReadLineOptionsFixed): Interface;
}
File renamed without changes.
+11
View File
@@ -0,0 +1,11 @@
/**
* isDefined simply ensures a given input is not
* null, undefined, an empty string or NaN.
*
* @param n to validate
* @returns if this object exists (boolean)
*/
export default function isDefined<T>(n: T | null | undefined | "" | number): n is T
{
return typeof n === "number" ? !isNaN(n) : n !== null && n !== undefined && n !== "";
}
+7 -4
View File
@@ -10,12 +10,15 @@
"resolveJsonModule": true, "resolveJsonModule": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"allowJs": true, "allowJs": true,
"baseUrl": "./src", "lib": ["es2020"],
"types": ["node"],
"moduleResolution": "node",
"baseUrl": ".",
"paths": { "paths": {
"@util/*": ["util/*"], "@util/*": ["src/util/*"],
"@db/*": ["database/*"] "@db/*": ["src/database/*"]
} }
}, },
"include": ["src"], "include": ["src", "src/types"],
"exclude": ["node_modules"] "exclude": ["node_modules"]
} }