From 0bee311e2285e3b2f5dac0414cd16df7205611a1 Mon Sep 17 00:00:00 2001 From: Braeden Sowinski Date: Tue, 7 Mar 2023 17:37:36 -0800 Subject: [PATCH] 5.0.0.1 economy features --- commands/bank.js | 370 +++++++++++++++++++++++++++++++++++++++++++++ commands/money.js | 124 +++++++++++++++ package.json | 2 +- structures/bank.js | 45 ++++++ util/collect.py | 163 -------------------- 5 files changed, 540 insertions(+), 164 deletions(-) create mode 100644 commands/bank.js create mode 100644 commands/money.js create mode 100644 structures/bank.js delete mode 100644 util/collect.py diff --git a/commands/bank.js b/commands/bank.js new file mode 100644 index 0000000..c2f699a --- /dev/null +++ b/commands/bank.js @@ -0,0 +1,370 @@ +const { EmbedBuilder } = require('discord.js'); +const { Bank, addBank } = require('../structures/bank'); + +module.exports = { + name: "bank", + debug: false, + global: false, + description: "Manage your banking", + usage: "[cmd] [opt]", + permissions: { + channel: ["VIEW_CHANNEL", "SEND_MESSAGES", "EMBED_LINKS"], + member: [], + }, + options: [ + { + name: "deposit", + description: "Deposit cash into your bank", + value: "deposit", + type: 1, + options: [{ + name: "amount", + description: "Amount to deposit", + value: "amount", + type: 10, + min_value: 0.01, + required: true, + }] + }, + { + name: "withdraw", + description: "Withdraw cash from you bank", + value: "deposit", + type: 1, + options: [{ + name: "amount", + description: "Amount to withdraw", + value: "amount", + type: 10, + min_value: 0.01, + required: true, + }] + }, + { + name: "balance", + description: "View your bank balance and count your cash", + value: "balance", + type: 1, + options: [{ + name: "user", + description: "User to view ballance", + value: "user", + type: 6, + required: false, + }] + }, + { + name: "give", + description: "Give a user cash", + value: "give", + type: 1, + options: [ + { + name: "user", + description: "User to give cash to", + value: "user", + type: 6, + required: true, + }, + { + name: "amount", + description: "The amount to give", + value: "amount", + type: 10, + min_value: 0.01, + required: true, + }, + ] + }, + { + name: "transfer", + description: "Transfer directly to users bank", + value: "transfer", + type: 1, + options: [ + { + name: "user", + description: "User to transfer to", + value: "user", + type: 6, + required: true, + }, + { + name: "amount", + description: "The amount to transfer", + value: "amount", + type: 10, + min_value: 0.01, + required: true, + }, + ] + } + ], + SlashCommand: { + /** + * + * @param {require("../structures/QuarksBot")} client + * @param {import("discord.js").Message} message + * @param {string[]} args + * @param {*} param3 + */ + run: async (client, interaction, args, { GuildDB }) => { + if (GuildDB.customChannelStatus==true&&!GuildDB.allowedChannels.includes(interaction.channel_id)) { + return interaction.send({ content: `You are not allowed to use the bot in this channel.`, flags: (1 << 6) }); + } + + let banking = await client.dbo.collection("banks").findOne({"banking.userID": interaction.member.user.id}).then(banking => banking); + + if (!banking) { + banking = { + userID: interaction.member.user.id, + guilds: { + [GuildDB.serverID]: { + account: { + balance: GuildDB.startingBalance, + cash: 0.00, + } + } + } + } + + // Register inventory for user + let newBank = new Bank(); + newBank.createBank(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, 0); + newBank.save().catch(err => { + if (err) return client.sendInternalError(interaction, err); + }); + + } else banking = banking.banking; + + if (!client.exists(banking.guilds[GuildDB.serverID])) { + const success = addBank(banking.guilds, GuildDB.serverID, interaction.member.user.id, client, GuildDB.startingBalance); + if (!success) return client.sendInternalError(interaction, 'Failed to add bank'); + } + + if (args[0].name == 'deposit') { + if (banking.guilds[GuildDB.serverID].account.cash.toFixed(2) - args[0].options[0].value < 0) { + const nsf = new EmbedBuilder() + .setDescription('**Bank Notice:** NSF. Non sufficient funds') + .setColor(client.config.Colors.Red); + + return interaction.send({ embeds: [nsf] }); + } + + const newBalance = banking.guilds[GuildDB.serverID].account.balance + args[0].options[0].value; + const newCash = Math.abs(banking.guilds[GuildDB.serverID].account.cash.toFixed(2) - args[0].options[0].value); + + client.dbo.collection("banks").updateOne({ "banking.userID": interaction.member.user.id }, { + $set: { + [`banking.guilds.${GuildDB.serverID}.account.balance`]: newBalance, + [`banking.guilds.${GuildDB.serverID}.account.cash`]: newCash + } + }, function(err, res) { + if (err) return client.sendInternalError(interaction, err); + }); + + const successEmbed = new EmbedBuilder() + .setTitle('Bank Notice:') + .setDescription(`Successfully deposited **$${args[0].options[0].value.toFixed(2)}**\nUse \`/bank balance\` to view your balance`) + .setColor(client.config.Colors.Green); + + return interaction.send({ embeds: [successEmbed] }); + + } else if (args[0].name == 'withdraw') { + if (args[0].options[0].value > banking.guilds[GuildDB.serverID].account.balance) { + let nsf = new EmbedBuilder() + .setDescription('**Bank Notice:** NSF. Non sufficient funds') + .setColor(client.config.Colors.Red); + + return interaction.send({ embeds: [nsf] }); + } + + const newBalance = banking.guilds[GuildDB.serverID].account.balance - args[0].options[0].value; + const newCash = banking.guilds[GuildDB.serverID].account.cash + args[0].options[0].value; + + client.dbo.collection("banks").updateOne({ "banking.userID": interaction.member.user.id }, { + $set: { + [`banking.guilds.${GuildDB.serverID}.account.balance`]: newBalance, + [`banking.guilds.${GuildDB.serverID}.account.cash`]: newCash + } + }, function(err, res) { + if (err) return client.sendInternalError(interaction, err); + }); + + const successEmbed = new EmbedBuilder() + .setTitle('Bank Notice:') + .setDescription(`Successfully withdrew **$${args[0].options[0].value.toFixed(2)}**\nUse \`/bank balance\` or \`/inventory wallet\` to view your cash balance`) + .setColor(client.config.Colors.Green); + + return interaction.send({ embeds: [successEmbed] }); + + } else if (args[0].name == 'balance') { + let balanceEmbed = new EmbedBuilder() + .setColor(client.config.Colors.Default); + + if (args[0].options&&args[0].options[0]) { + // Show target users balance + + let targetUserID = args[0].options[0].value.replace('<@!', '').replace('>', ''); + let targetUserBanking = await client.dbo.collection("banks").findOne({"banking.userID": targetUserID}).then(banking => banking); + + if (!targetUserBanking) { + targetUserBanking = { + userID: targetUserID, + guilds: { + [GuildDB.serverID]: { + account: { + balance: GuildDB.startingBalance, + cash: 0.00, + } + } + } + } + + // Register inventory for user + let newBank = new Bank(); + newBank.createBank(targetUserID, GuildDB.serverID, GuildDB.startingBalance, 0); + newBank.save().catch(err => { + if (err) return client.sendInternalError(interaction, err); + }); + + } else targetUserBanking = targetUserBanking.banking; + + if (!client.exists(targetUserBanking.guilds[GuildDB.serverID])) { + const success = addBank(targetUserBanking.guilds, GuildDB.serverID, targetUserID, client, GuildDB.startingBalance); + if (!success) return client.sendInternalError(interaction, 'Failed to add bank'); + } + + // This lame line of code to get username without ping on discord + const User = client.users.cache.get(targetUserID); + + balanceEmbed.setTitle(`${User.tag}'s Bank Records`); + balanceEmbed.addFields( + { name: '**Bank**', value: `$${targetUserBanking.guilds[GuildDB.serverID].account.balance}`, inline: true }, + { name: '**Cash**', value: `$${targetUserBanking.guilds[GuildDB.serverID].account.cash}`, inline: true }); + + } else { + // Show command authors balance + + balanceEmbed.setTitle('Personal Bank Records'); + balanceEmbed.addFields( + { name: '**Bank**', value: `$${banking.guilds[GuildDB.serverID].account.balance.toFixed(2)}`, inline: true }, + { name: '**Cash**', value: `$${banking.guilds[GuildDB.serverID].account.cash.toFixed(2)}`, inline: true }, + { name: '**Total**', value: `$${(banking.guilds[GuildDB.serverID].account.balance + banking.guilds[GuildDB.serverID].account.cash).toFixed(2)}`, inline: true }); + } + + return interaction.send({ embeds: [balanceEmbed] }); + + } else if (args[0].name == 'give') { + // send money from wallet + + if (banking.guilds[GuildDB.serverID].account.cash.toFixed(2) - args[0].options[1].value < 0) { + let embed = new EmbedBuilder() + .setTitle('Non sufficient funds! Withdraw more cash') + .setColor(client.config.Colors.Red); + + return interaction.send({ embeds: [embed] }); + } + + const newCash = banking.guilds[GuildDB.serverID].account.cash - args[0].options[1].value; + + client.dbo.collection("banks").updateOne({ "banking.userID": interaction.member.user.id }, { + $set: { + [`banking.guilds.${GuildDB.serverID}.account.cash`]: newCash + } + }, function(err, res) { + if (err) return client.sendInternalError(interaction, err); + }); + + const targetUserID = args[0].options[0].value.replace('<@!', '').replace('>', ''); + let targetUserBanking = await client.dbo.collection("banks").findOne({"banking.userID": targetUserID}).then(banking => banking); + + let newTargetCash = targetUserBanking.guilds[GuildDB.serverID].account.cash + args[0].options[1].value; + + if (!targetUserBanking) { + targetUserBanking = { + userID: targetUserID, + guilds: { + [GuildDB.serverID]: { + account: { + balance: GuildDB.startingBalance, + cash: newTargetCash, + } + } + } + } + + // Register inventory for user + let newBank = new Bank(); + newBank.createBank(targetUserID, GuildDB.serverID, GuildDB.startingBalance, newTargetCash); + newBank.save().catch(err => { + if (err) return client.sendInternalError(interaction, err); + }); + } else targetUserBanking = targetUserBanking.banking; + + if (!client.exists(targetUserBanking.guilds[GuildDB.serverID])) { + const success = addBank(targetUserBanking.guilds, GuildDB.serverID, targetUserID, client, GuildDB.startingBalance); + if (!success) return client.sendInternalError(interaction, 'Failed to add bank'); + } + + const successEmbed = new EmbedBuilder() + .setTitle('Success') + .setDescription(`Successfully gave <@${targetUserID}> $${args[0].options[1].value.toFixed(2)}`) + .setColor(client.config.Colors.Green); + + return interaction.send({ embeds: [successEmbed] }); + + } else if (args[0].name == 'transfer') { + // send money from bank + + if (banking.guilds[GuildDB.serverID].account.balance.toFixed(2) - args[0].options[1].value < 0) { + let embed = new EmbedBuilder() + .setTitle('Non sufficient funds! Withdraw more cash') + .setColor(client.config.Colors.Red); + + return interaction.send({ embeds: [embed] }); + } + + const newBalance = banking.guilds[GuildDB.serverID].account.balance - args[0].options[1].value; + + client.dbo.collection("banks").updateOne({"banking.userID":interaction.member.user.id},{$set:{[`banking.guilds.${GuildDB.serverID}.account.balance`]:newBalance}}, function(err, res) { + if (err) return client.sendInternalError(interaction, err); + }); + + const targetUserID = args[0].options[0].value.replace('<@!', '').replace('>', ''); + let targetUserBanking = await client.dbo.collection("banks").findOne({"banking.userID": targetUserID}).then(banking => banking); + + if (!targetUserBanking) { + targetUserBanking = { + userID: targetUserID, + guilds: { + [GuildDB.serverID]: { + account: { + balance: (GuildDB.startingBalance + args[0].options[1].value), + cash: 0.00, + } + } + } + } + + client.dbo.collection("banks").insertOne(targetUserBanking, function(err, res) { + if (err) return client.sendInternalError(interaction, err); + }); + } else targetUserBanking = targetUserBanking.banking; + + const newTargetBalance = targetUserBanking.guilds[GuildDB.serverID].account.balance + args[0].options[1].value; + + client.dbo.collection("banks").updateOne({"banking.userID":targetUserID},{$set:{[`banking.guilds.${GuildDB.serverID}.account.balance`]:newTargetBalance}}, function(err, res) { + if (err) return client.sendInternalError(interaction, err); + }); + + const successEmbed = new EmbedBuilder() + .setTitle('Bank Notice:') + .setDescription(`Successfully transfered <@${targetUserID}> $${args[0].options[1].value.toFixed(2)}`) + .setColor(client.config.Colors.Green); + + return interaction.send({ embeds: [successEmbed] }); + } + }, + }, +} \ No newline at end of file diff --git a/commands/money.js b/commands/money.js new file mode 100644 index 0000000..c3b0f6d --- /dev/null +++ b/commands/money.js @@ -0,0 +1,124 @@ +const { EmbedBuilder } = require('discord.js'); +const { Bank, addBank } = require('../structures/bank'); +const bitfieldCalculator = require('discord-bitfield-calculator'); + +module.exports = { + name: "money", + debug: false, + global: false, + description: "add/remove money from user", + usage: "[opt.] [user] [amount]", + permissions: { + channel: ["VIEW_CHANNEL", "SEND_MESSAGES", "EMBED_LINKS"], + member: ["MANAGE_GUILD"], + }, + options: [ + { + name: "add", + description: "Add money to user", + value: "add", + type: 1, + options: [ + { + name: "amount", + description: "The amount to add to balance", + value: "amount", + type: 10, + min_value: 0.01, + required: true, + }, + { + name: "to", + description: "User to alter balance", + value: "to", + type: 6, + required: true, + }, + ] + }, + { + name: "remove", + description: "Remove or remove money from a user", + value: "remove", + type: 1, + options: [ + { + name: "amount", + description: "The amount to add to balance", + value: "amount", + type: 10, + min_value: 0.01, + required: true, + }, + { + name: "from", + description: "User to alter balance", + value: "from", + type: 6, + required: true, + }, + ] + }, + ], + SlashCommand: { + /** + * + * @param {require("../structures/QuarksBot")} client + * @param {import("discord.js").Message} message + * @param {string[]} args + * @param {*} param3 + */ + run: async (client, interaction, args, { GuildDB }) => { + const permissions = bitfieldCalculator.permissions(interaction.member.permissions); + let canUseCommand = false; + + if (permissions.includes("MANAGE_GUILD")) canUseCommand = true; + if (client.exists(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.' }); + + const targetUserID = args[0].options[1].value.replace('<@!', '').replace('>', ''); + let banking = await client.dbo.collection("banks").findOne({"banking.userID": targetUserID}).then(banking => banking); + + if (!banking) { + banking = { + userID: targetUserID, + guilds: { + [GuildDB.serverID]: { + account: { + balance: GuildDB.startingBalance, + cash: 0.00, + } + } + } + } + + // Register inventory for user + let newBank = new Bank(); + newBank.createBank(targetUserID, GuildDB.serverID, GuildDB.startingBalance, 0); + newBank.save().catch(err => { + if (err) return client.sendInternalError(interaction, err); + }); + + } else banking = banking.banking; + + if (!client.exists(banking.guilds[GuildDB.serverID])) { + const success = addBank(banking.guilds, GuildDB.serverID, targetUserID, client, GuildDB.startingBalance); + if (!success) return client.sendInternalError(interaction, 'Failed to add bank'); + } + + let newBalance = args[0].name == 'add' + ? banking.guilds[GuildDB.serverID].account.balance + args[0].options[0].value + : banking.guilds[GuildDB.serverID].account.balance - args[0].options[0].value; + + client.dbo.collection("banks").updateOne({"banking.userID":targetUserID},{$set:{[`banking.guilds.${GuildDB.serverID}.account.balance`]:newBalance}}, function(err, res) { + if (err) return client.sendInternalError(interaction, err); + }); + + const successEmbed = new EmbedBuilder() + .setDescription(`Successfully ${args[0] == 'add' ? 'added' : 'removed'} $${args[0].options[0].value.toFixed(2)} ${args[0] == 'add' ? 'to' : 'from'} <@${targetUserID}>'s balance`) + .setColor(client.config.Colors.Green); + + return interaction.send({ embeds: [successEmbed] }); + }, + }, +} \ No newline at end of file diff --git a/package.json b/package.json index 046c6cf..cd2bf5d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dayz-armbands", - "version": "4.7.2.1", + "version": "5.0.0.1", "description": "A General Purpose Discord Bot for DayZ Servers.", "main": "index.js", "nodemonConfig": { diff --git a/structures/bank.js b/structures/bank.js new file mode 100644 index 0000000..357e4a9 --- /dev/null +++ b/structures/bank.js @@ -0,0 +1,45 @@ +const mongoose = require('mongoose'); + +let bankSchema = mongoose.Schema({ + banking: { + userID: String, + guilds: {} + } +}); + +bankSchema.methods.createBank = function (userID, guildID, startingBalance, cash) { + this.banking.userID = userID; + this.banking.guilds = {}; + this.banking.guilds[guildID] = { + account: { + balance: startingBalance, + cash: cash, + } + };; +}; + +/* + This function is to add a new guild specific bank to an already existing + bank document + or + can be used to reset a data back to default +*/ +function addBank(guilds, guildID, userID, client, startingBalance) { + let updatedGuilds = guilds; + updatedGuilds[guildID] = { + account: { + balance: startingBalance, + cash: 0.00, + } + } + + client.dbo.collection("banks").updateOne({"banking.userID":userID}, {$set: {"banking.guilds": updatedGuilds}}, function(err, res) { + if (err) return false + }) + return true +} + +module.exports = { + Bank: mongoose.model('Bank', bankSchema), + addBank: addBank, +}; diff --git a/util/collect.py b/util/collect.py deleted file mode 100644 index a8807ed..0000000 --- a/util/collect.py +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/env python3 - -import requests -import urllib -import json -import os -import re -from enum import Enum -from dotenv import load_dotenv - -load_dotenv() -AUTH_KEY: str = os.getenv('AUTH_KEY') -SERVER_ID: str = os.getenv('SERVER_ID') -USER_ID: str = os.getenv('USER_ID') - -AUTH_KEY: str = 'nrBQHGnTMMzQZbInit-C-DLYBtywLc-15GHLw9Zjj_K87V8L589BqAIPW8d9vh7Zc-NtyyL798YO9V9o2GT7gpug0GiiKR8wrE-b' -SERVER_ID: str = '12215784' -USER_ID: str = 'ni8434545_1' - -class LogTemplates(Enum): - pos: str = '$time | Player "$gamertag" (id=$playerID pos=<$pos>)' - damage: str = '$time | Player "$gamertag" (DEAD) (id=$playerID pos=<3$pos>)[HP: 0] hit by Player "$killer" (id=$killerID pos=<$killerPOS>) into $areaHit for $damageVal damage ($bullet_type) with $weapon from $distance meters' - killed: str = '$time | Player "$gamertag" (DEAD) (id=$playerID pos=<3$pos>) killed by Player "$killer" (id=$killerID pos=<$killerPOS>) with $weapon from $distance meters' - connect: str = '$time | Player "$gamertag" is connected (id=$playerID)' - disconnect: str = '$time | Player "$gamertag" (id=$playerID pos=<$pos>) has been disconnected' - -logFlags = [ - "disconnected", - ") placed ", - "connected", - "hit by", - "regained consciousne", - "is unconscious", - "killed by", - ")Built ", - ") folded", - ")Player SurvivorBase", - ") died.", - ") committed suicide", - ")Dismantled", - ") bled" -] -players = { - 'players': [] -} - -# Download Raw Logs off Nitrado -def getRawLogs(): - data = requests.get( - f"https://api.nitrado.net/services/{SERVER_ID}/gameservers/file_server/download?file=/games/{USER_ID}/noftp/dayzxb/config/DayZServer_X1_x64.ADM", - headers={ - "Authorization": AUTH_KEY - }).json() - - print(data) - - # url = data['data']['token']['url'] - # if not os.path.exists('output'): os.mkdir('output') - # urllib.request.urlretrieve(url, "./output/logs.ADM") - - -# Convert Raw Logs into cleaned logs (only positional data logs) -def cleanLogs(): - with open("./output/logs.ADM", "r") as logs: - lines = logs.readlines() - # Isolate Player logs (Removes Connect, Disconnect, place, hit) - with open("./output/clean.txt", "w") as logs: - for line in lines: - if not any(flag in line for flag in logFlags) and "| Player" in line.strip("\n"): - logs.write(line) - - -# Generate List of player names, id's and positions -def collectPlayerData(): - with open('./output/clean.txt', 'r') as logs: - cleanLines = logs.readlines() - for line in cleanLines: - pattern = re.escape(LogTemplates.pos) - pattern = re.sub(r'\\\$(\w+)', r'(?P<\1>.*)', pattern) - data = re.match(pattern, line) - if data is None: break - - query = { - 'gamertag': data.groupdict()['gamertag'], - 'playerID': data.groupdict()['playerID'], - 'time': data.groupdict()['time']+' EST', - 'pos': data.groupdict()['pos'].split(", "), - 'posHistory': [] - } - - if len(players['players'])==0: players['players'].append(query) - else: - for i in range(len(players['players'])): - if players['players'][i]['gamertag']==data.groupdict()['gamertag']: - # Updates existing player data - for j in range(len(players['players'][i]['posHistory'])): - query['posHistory'].append({ - 'time': players['players'][i]['posHistory'][j]['time'], - 'pos': players['players'][i]['posHistory'][j]['pos'] - }) - - query['posHistory'].append({ - 'time': players['players'][i]['time'], - 'pos': players['players'][i]['pos'] - }) - - players['players'].remove(players['players'][i]) - break - - # Logs new player data - players['players'].append(query) - - -# Search Logs for Connected and Disconnected messages -def activeStatus(): - with open("./output/logs.ADM", "r") as logs: - lines = logs.readlines() - for line in lines: - status = "" - update = False - if "\" is connected" in line.strip("\n") and "| Player" in line.strip("\n"): - status = "Online" - update = True - elif ") has been disconnected" in line.strip("\n") and "| Player" in line.strip("\n"): - status = "Offline" - update = True - - if update: - beginPlayer = 19 # Player names always start here - if status=="Online": endPlayer = line.strip("\n").find("\" is") - if status=="Offline": endPlayer = line.strip("\n").find("\"(id=") - playerName = line.strip("\n")[beginPlayer:endPlayer] - - playerFoundAndUpdated = False - for i in range(len(players['players'])): - if players['players'][i]['gamertag']==playerName: - players['players'][i]['connectionStatus'] = status - playerFoundAndUpdated = True - - if not playerFoundAndUpdated: - # Get player ID - beginID = line.strip("\n").find('(id=')+4 - endID = line.strip("\n").find(")") - playerID = line.strip("\n")[beginID:endID] - query = { - "gamertag": playerName, - "playerID": playerID, - "time": None, - "pos": [], - "posHistory": [], - "connectionStatus": "Online" - } - # Logs new player data - players["players"].append(query) - -if __name__ == '__main__': - getRawLogs() - cleanLogs() - collectPlayerData() - activeStatus() - - with open("./output/players.json", "w") as playerJSON: - json.dump(players, playerJSON, ensure_ascii=False, indent=2)