@@ -17,6 +17,25 @@
[DBM Mods](https://discord.gg/djcvWRpgHm) is a community driven open source project meant to modify, extend, and improve [Discord Bot Maker](https://store.steampowered.com/app/682130/Discord_Bot_Maker/).
+## Compatibility
+
+- **Node.js:** 22.x+ (`package.json` engines: `>=22 <27`; CI runs on **22**, **24** (LTS), and **25** (Current); Node **26** is omitted from CI until `actions/setup-node` provides it reliably)
+- **DBM Versions:** 1.7, 2.2.0
+- **Discord.js Version:** 14.26.2
+- **Total Actions:** 515
+- **Total Events:** 47
+- **Total Extensions:** Includes dashboard, command info, server prefixes, topgg, pastebin, and more
+
+### Dashboard leaderboard database (MySQL / MariaDB)
+
+If you use the **dashboard** extension with the **leaderboard** feature, create the tables from [`sql/leveling_system_schema.sql`](sql/leveling_system_schema.sql):
+
+1. Copy `sql/leveling_system_schema.sql` to your **DBM bot project root** (next to `bot.js`), keeping the path `sql/leveling_system_schema.sql`.
+2. In `extensions/dashboard_EXT/config.json`, set `leaderboard.database` (`host`, `user`, `password`, `database`). Do not commit real credentials.
+3. In the dashboard admin UI, use the leaderboard database setup (or run the SQL manually in MySQL).
+
+This repository has been fully updated to support Discord.js v14.26.2 with all deprecated methods replaced (EmbedBuilder, ButtonBuilder, ActionRowBuilder, PermissionFlagsBits, etc.). All files are English-only and follow DBM best practices.
+
# Downloads
This repository is not meant to be downloaded or cloned. Please follow the installation guide below.
diff --git a/actions/aaa_wrexmods_dependencies_MOD.js b/actions/aaa_wrexmods_dependencies_MOD.js
new file mode 100644
index 000000000..54558b55e
--- /dev/null
+++ b/actions/aaa_wrexmods_dependencies_MOD.js
@@ -0,0 +1,567 @@
+// ---------------------------------------------------------------------
+// WrexMODS - for Discord Bot Maker
+// Contains functions for actions using WrexMODS
+// ---------------------------------------------------------------------
+const WrexMODS = {};
+
+WrexMODS.API = {};
+
+WrexMODS.DBM = null;
+
+WrexMODS.Version = '2.0.5';
+
+WrexMODS.latest_changes = 'The module installer WORKS NOW';
+
+// Changelog
+// Lasse - 1.9:
+// Merged custom_methods into wrexmods
+
+// wrex - 2.0.5
+// wrex - FIXED THE DAMN MODULE INSTALLER
+
+// rigid - 2.0.6
+// rigid - fixed the **damn** module installer (from v12)
+
+WrexMODS.CheckAndInstallNodeModule = function (moduleName) {
+ try {
+ require('child_process').execSync(`npm i ${moduleName}`, { stdio: 'ignore' });
+ return true;
+ } catch (e) {
+ console.log(`Failed to Install ${moduleName}, please re-try or install manually with "npm i ${moduleName}"`);
+ return false;
+ }
+};
+
+WrexMODS.require = function (moduleName) {
+ try {
+ return require(moduleName);
+ } catch (e) {
+ this.CheckAndInstallNodeModule(moduleName);
+ try {
+ return require(moduleName);
+ } catch (e2) {
+ return null;
+ }
+ }
+};
+
+WrexMODS.checkURL = function (url) {
+ // / Checks if the provided URL is valid.
+ // / The URL to check.
+ // / True if valid.
+ return !url ? false : this.validUrl().isUri(url) ? true : false;
+};
+
+WrexMODS.runPostJson = function (url, json, returnJson = true, callback) {
+ // / Runs a Request to return JSON Data
+ // / The URL to post the JSON to.
+ // / The json to post
+ // / True if the response should be in JSON format. False if not
+ // / The callback function, args: error, statusCode, data
+ const axios = this.require('axios');
+ axios
+ .post(url, json, { headers: { 'Content-Type': 'application/json' } })
+ .then(function (res) {
+ const statusCode = res && res.status ? res.status : 200;
+ const data = res && res.data !== undefined ? res.data : res;
+ if (callback && typeof callback === 'function') {
+ callback(null, statusCode, data);
+ }
+ })
+ .catch(function (err) {
+ const statusCode = err.response && err.response.status ? err.response.status : 500;
+ const data = err.response && err.response.data !== undefined ? err.response.data : null;
+ if (callback && typeof callback === 'function') {
+ callback(err, statusCode, data);
+ }
+ });
+};
+
+/*
+ var json = {
+ "permission_overwrites": [],
+ "name": tempVars("myChannel"),
+ "parent_id": null,
+ "nsfw": false,
+ "position": 0,
+ "guild_id": msg.guild.id,
+ "type": 4
+ }
+*/
+
+// this.getWrexMods().executeDiscordJSON("POST", "guilds/" + msg.guild.id + "/channels", json ,this.getDBM(), cache)
+
+WrexMODS.executeDiscordJSON = function (type, urlPath, json, DBM, cache, callback) {
+ return new Promise((resolve, reject) => {
+ const axios = this.require('axios');
+ const url = `https://discord.com/api/v10/${urlPath}`;
+ const config = {
+ headers: { Authorization: `Bot ${DBM.Files.data.settings.token}` },
+ method: type,
+ url,
+ data: json,
+ };
+ axios(config)
+ .then(function (res) {
+ const statusCode = res && res.status ? res.status : 200;
+ const data = res && res.data !== undefined ? res.data : res;
+ resolve({ err: null, statusCode, data });
+ if (callback && typeof callback === 'function') {
+ callback(null, statusCode, data);
+ }
+ })
+ .catch(function (err) {
+ const statusCode = err.response && err.response.status ? err.response.status : 500;
+ const data = err.response && err.response.data !== undefined ? err.response.data : null;
+ const rejErr = err instanceof Error ? err : new Error(String(err?.message || 'Discord JSON request failed'));
+ rejErr.statusCode = statusCode;
+ rejErr.data = data;
+ reject(rejErr);
+ if (callback && typeof callback === 'function') {
+ callback(err, statusCode, data);
+ }
+ });
+ });
+};
+
+WrexMODS.runPublicRequest = function (url, returnJson = false, callback, token, user, pass) {
+ // / Runs a Request to return JSON Data
+ // / The URL to get JSON from.
+ // / True if the response should be in JSON format. False if not
+ // / The callback function, args: error, statusCode, data
+ const axios = this.require('axios');
+ const config = { url, headers: { 'User-Agent': 'Other' }, responseType: returnJson ? 'json' : undefined };
+ if (token) config.headers['Authorization'] = `Bearer ${token}`;
+ if (user !== null && user !== undefined && pass !== null && pass !== undefined) {
+ config.auth = { username: user, password: pass };
+ }
+ axios
+ .get(url, config)
+ .then(function (res) {
+ const statusCode = res && res.status ? res.status : 200;
+ const data = res && res.data !== undefined ? res.data : res;
+ if (callback && typeof callback === 'function') {
+ callback(null, statusCode, data);
+ }
+ })
+ .catch(function (err) {
+ const statusCode = err.response && err.response.status ? err.response.status : 500;
+ const data = err.response && err.response.data !== undefined ? err.response.data : null;
+ if (callback && typeof callback === 'function') {
+ callback(err, statusCode, data);
+ }
+ });
+};
+
+WrexMODS.runBearerTokenRequest = function (url, returnJson = false, bearerToken, callback) {
+ // / Runs a Request to return HTML Data using a bearer Token.
+ // / The URL to get JSON from.
+ // / True if the response should be in JSON format. False if not
+ // / The token to run the request with.
+ // / The callback function, args: error, statusCode, data
+ const axios = this.require('axios');
+ const config = {
+ url,
+ headers: { 'User-Agent': 'Other', Authorization: `Bearer ${bearerToken}` },
+ responseType: returnJson ? 'json' : undefined,
+ };
+ axios
+ .get(url, config)
+ .then(function (res) {
+ const statusCode = res && res.status ? res.status : 200;
+ const data = res && res.data !== undefined ? res.data : res;
+ if (callback && typeof callback === 'function') {
+ callback(null, statusCode, data);
+ }
+ })
+ .catch(function (err) {
+ const statusCode = err.response && err.response.status ? err.response.status : 500;
+ const data = err.response && err.response.data !== undefined ? err.response.data : null;
+ if (callback && typeof callback === 'function') {
+ callback(err, statusCode, data);
+ }
+ });
+};
+
+WrexMODS.runBasicAuthRequest = function (url, returnJson = false, username, password, callback) {
+ // / Runs a Request to return HTML Data
+ // / The URL to get JSON from.
+ // / True if the response should be in JSON format. False if not
+ // / The username for the request
+ // / The password for the request
+ // / The callback function, args: error, statusCode, data
+ const axios = this.require('axios');
+ const config = {
+ url,
+ headers: { 'User-Agent': 'Other' },
+ auth: { username, password },
+ responseType: returnJson ? 'json' : undefined,
+ };
+ axios
+ .get(url, config)
+ .then(function (res) {
+ const statusCode = res && res.status ? res.status : 200;
+ const data = res && res.data !== undefined ? res.data : res;
+ if (callback && typeof callback === 'function') {
+ callback(null, statusCode, data);
+ }
+ })
+ .catch(function (err) {
+ const statusCode = err.response && err.response.status ? err.response.status : 500;
+ const data = err.response && err.response.data !== undefined ? err.response.data : null;
+ if (callback && typeof callback === 'function') {
+ callback(err, statusCode, data);
+ }
+ });
+};
+
+WrexMODS.jsonPath = function (obj, expr, arg) {
+ // JSONPath 0.8.0 - XPath for JSON
+ // JSONPath Expressions: http://goessner.net/articles/JsonPath/index.html#e2
+ // http://jsonpath.com/
+ // function jsonPath(obj, expr, arg)
+ // Copyright (c) 2007 Stefan Goessner (goessner.net)
+ // Licensed under the MIT (MIT-LICENSE.txt) licence.
+ const $ = obj;
+ const P = {
+ resultType: (arg && arg.resultType) || 'VALUE',
+ result: [],
+ normalize(expr) {
+ const subx = [];
+ return expr
+ .replace(/[\['](\??\(.*?\))[\]']/g, function ($0, $1) {
+ return `[#${subx.push($1) - 1}]`;
+ })
+ .replace(/'?\.'?|\['?/g, ';')
+ .replace(/;;;|;;/g, ';..;')
+ .replace(/;$|'?\]|'$/g, '')
+ .replace(/#([0-9]+)/g, function ($0, $1) {
+ return subx[$1];
+ });
+ },
+ asPath(path) {
+ const x = path.split(';');
+ let p = '$';
+ for (let i = 1, n = x.length; i < n; i++) p += /^[0-9*]+$/.test(x[i]) ? `[${x[i]}]` : `['${x[i]}']`;
+ return p;
+ },
+ store(p, v) {
+ if (p) P.result[P.result.length] = P.resultType === 'PATH' ? P.asPath(p) : v;
+ return Boolean(p);
+ },
+ trace(expr, val, path) {
+ if (expr) {
+ let x = expr.split(';');
+ const loc = x.shift();
+ x = x.join(';');
+ if (val && val.hasOwnProperty(loc)) P.trace(x, val[loc], `${path};${loc}`);
+ else if (loc === '*')
+ P.walk(loc, x, val, path, function (m, l, x, v, p) {
+ P.trace(`${m};${x}`, v, p);
+ });
+ else if (loc === '..') {
+ P.trace(x, val, path);
+ P.walk(loc, x, val, path, function (m, l, x, v, p) {
+ typeof v[m] === 'object' && P.trace(`..;${x}`, v[m], `${p};${m}`);
+ });
+ } else if (/,/.test(loc)) {
+ // [name1,name2,...]
+ for (let s = loc.split(/'?,'?/), i = 0, n = s.length; i < n; i++) P.trace(`${s[i]};${x}`, val, path);
+ } else if (/^\(.*?\)$/.test(loc))
+ // [(expr)]
+ P.trace(`${P.eval(loc, val, path.substr(path.lastIndexOf(';') + 1))};${x}`, val, path);
+ else if (/^\?\(.*?\)$/.test(loc))
+ // [?(expr)]
+ P.walk(loc, x, val, path, function (m, l, x, v, p) {
+ if (P.eval(l.replace(/^\?\((.*?)\)$/, '$1'), v[m], m)) P.trace(`${m};${x}`, v, p);
+ });
+ else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc))
+ // [start:end:step] phyton slice syntax
+ P.slice(loc, x, val, path);
+ } else P.store(path, val);
+ },
+ walk(loc, expr, val, path, f) {
+ if (val instanceof Array) {
+ for (let i = 0, n = val.length; i < n; i++) if (i in val) f(i, loc, expr, val, path);
+ } else if (typeof val === 'object') {
+ for (const m in val) if (val.hasOwnProperty(m)) f(m, loc, expr, val, path);
+ }
+ },
+ slice(loc, expr, val, path) {
+ if (val instanceof Array) {
+ const len = val.length;
+ let start = 0;
+ let end = len;
+ let step = 1;
+ loc.replace(/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g, function ($0, $1, $2, $3) {
+ start = parseInt($1 || start, 10);
+ end = parseInt($2 || end, 10);
+ step = parseInt($3 || step, 10);
+ });
+ start = start < 0 ? Math.max(0, start + len) : Math.min(len, start);
+ end = end < 0 ? Math.max(0, end + len) : Math.min(len, end);
+ for (let i = start; i < end; i += step) P.trace(`${i};${expr}`, val, path);
+ }
+ },
+ eval(x, _v, _vname) {
+ try {
+ return $ && _v && eval(x.replace(/@/g, '_v'));
+ } catch (e) {
+ throw new SyntaxError(`jsonPath: ${e.message}: ${x.replace(/@/g, '_v').replace(/\^/g, '_a')}`);
+ }
+ },
+ };
+
+ if (expr && obj && (P.resultType === 'VALUE' || P.resultType === 'PATH')) {
+ P.trace(P.normalize(expr).replace(/^\$;/, ''), obj, '$');
+ return P.result.length ? P.result : false;
+ }
+};
+
+WrexMODS.validUrl = function () {
+ // converted to function from NPM module valid-url: https://www.npmjs.com/package/valid-url
+ const splitUri = function (uri) {
+ const splitted = uri.match(/(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/);
+ return splitted;
+ };
+
+ function is_iri(value) {
+ if (!value) {
+ return;
+ }
+
+ // check for illegal characters
+ if (/[^a-z0-9\:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\.\-\_\~\%]/i.test(value)) return;
+
+ // check for hex escapes that aren't complete
+ if (/%[^0-9a-f]/i.test(value)) return;
+ if (/%[0-9a-f](:?[^0-9a-f]|$)/i.test(value)) return;
+
+ let splitted = [];
+ let scheme = '';
+ let authority = '';
+ let path = '';
+ let query = '';
+ let fragment = '';
+ let out = '';
+
+ // from RFC 3986
+ splitted = splitUri(value);
+ scheme = splitted[1];
+ authority = splitted[2];
+ path = splitted[3];
+ query = splitted[4];
+ fragment = splitted[5];
+
+ // scheme and path are required, though the path can be empty
+ if (!(scheme && scheme.length && path.length >= 0)) return;
+
+ // if authority is present, the path must be empty or begin with a /
+ if (authority && authority.length) {
+ if (!(path.length === 0 || /^\//.test(path))) return;
+ } else if (/^\/\//.test(path)) {
+ // if authority is not present, the path must not start with //
+ return;
+ }
+
+ // scheme must begin with a letter, then consist of letters, digits, +, ., or -
+ if (!/^[a-z][a-z0-9\+\-\.]*$/.test(scheme.toLowerCase())) return;
+
+ // re-assemble the URL per section 5.3 in RFC 3986
+ out += `${scheme}:`;
+ if (authority && authority.length) {
+ out += `//${authority}`;
+ }
+
+ out += path;
+
+ if (query && query.length) {
+ out += `?${query}`;
+ }
+
+ if (fragment && fragment.length) {
+ out += `#${fragment}`;
+ }
+
+ return out;
+ }
+
+ function is_http_iri(value, allowHttps) {
+ if (!is_iri(value)) {
+ return;
+ }
+
+ let splitted = [];
+ let scheme = '';
+ let authority = '';
+ let path = '';
+ let port = '';
+ let query = '';
+ let fragment = '';
+ let out = '';
+
+ // from RFC 3986
+ splitted = splitUri(value);
+ scheme = splitted[1];
+ authority = splitted[2];
+ path = splitted[3];
+ query = splitted[4];
+ fragment = splitted[5];
+
+ if (!scheme) return;
+
+ if (allowHttps) {
+ if (scheme.toLowerCase() !== 'https') return;
+ } else if (scheme.toLowerCase() !== 'http') {
+ return;
+ }
+
+ // fully-qualified URIs must have an authority section that is
+ // a valid host
+ if (!authority) {
+ return;
+ }
+
+ // enable port component
+ if (/:(\d+)$/.test(authority)) {
+ port = authority.match(/:(\d+)$/)[0];
+ authority = authority.replace(/:\d+$/, '');
+ }
+
+ out += `${scheme}:`;
+ out += `//${authority}`;
+
+ if (port) {
+ out += port;
+ }
+
+ out += path;
+
+ if (query && query.length) {
+ out += `?${query}`;
+ }
+
+ if (fragment && fragment.length) {
+ out += `#${fragment}`;
+ }
+
+ return out;
+ }
+
+ function is_https_iri(value) {
+ return is_http_iri(value, true);
+ }
+
+ function is_web_iri(value) {
+ return is_http_iri(value) || is_https_iri(value);
+ }
+
+ const module = {};
+ module.exports = {};
+ module.exports.is_uri = is_iri;
+ module.exports.is_http_uri = is_http_iri;
+ module.exports.is_https_uri = is_https_iri;
+ module.exports.is_web_uri = is_web_iri;
+ // Create aliases
+ module.exports.isUri = is_iri;
+ module.exports.isHttpUri = is_http_iri;
+ module.exports.isHttpsUri = is_https_iri;
+ module.exports.isWebUri = is_web_iri;
+
+ return module.exports;
+};
+
+WrexMODS.getWebhook = function (type, varName, cache) {
+ const server = cache.server;
+ switch (type) {
+ case 1:
+ return cache.temp[varName];
+ case 2:
+ if (server && this.server[server.id]) {
+ return this.server[server.id][varName];
+ }
+ break;
+ case 3:
+ return this.global[varName];
+ default:
+ break;
+ }
+ return false;
+};
+
+WrexMODS.getReaction = function (type, varName, cache) {
+ const server = cache.server;
+ switch (type) {
+ case 1:
+ return cache.temp[varName];
+ case 2:
+ if (server && this.server[server.id]) {
+ return this.server[server.id][varName];
+ }
+ break;
+ case 3:
+ return this.global[varName];
+ default:
+ break;
+ }
+ return false;
+};
+
+WrexMODS.getEmoji = function (type, varName, cache) {
+ const server = cache.server;
+ switch (type) {
+ case 1:
+ return cache.temp[varName];
+ case 2:
+ if (server && this.server[server.id]) {
+ return this.server[server.id][varName];
+ }
+ break;
+ case 3:
+ return this.global[varName];
+ default:
+ break;
+ }
+ return false;
+};
+
+// This function is called by DBM when the bot is started
+const customaction = {};
+customaction.name = 'WrexMODS';
+customaction.section = 'JSON Things';
+customaction.author = 'General Wrex';
+customaction.version = '1.8.3';
+customaction.short_description = 'Required for some mods. Does nothing';
+
+customaction.html = function () {
+ return `
+
+
+ Wrexmods Dependencies:
+ This isn't an action, but it is required for the actions under this category.
+ Create action wont do anything
+
+
`;
+};
+
+customaction.getWrexMods = function () {
+ return WrexMODS;
+};
+
+customaction.mod = function (DBM) {
+ WrexMODS.DBM = DBM;
+
+ // Avoid running `npm i` on every bot start. Only install if missing.
+ try {
+ require.resolve('axios');
+ } catch (e) {
+ WrexMODS.CheckAndInstallNodeModule('axios');
+ }
+ // WrexMODS.CheckAndInstallNodeModule("extend");
+ // WrexMODS.CheckAndInstallNodeModule("valid-url");
+
+ DBM.Actions.getWrexMods = function () {
+ return WrexMODS;
+ };
+};
+module.exports = customaction;
diff --git a/actions/abb_custom_methods_MOD.js b/actions/abb_custom_methods_MOD.js
new file mode 100644
index 000000000..df7b0abd9
--- /dev/null
+++ b/actions/abb_custom_methods_MOD.js
@@ -0,0 +1,96 @@
+// ---------------------------------------------------------------------
+// custommethods - for Discord Bot Maker
+// Contains functions for actions using custommethods
+// Stolen from Wrex :troll: ~ Lasse
+// ---------------------------------------------------------------------
+// Changelog:
+// 2.1.6 - Lasse
+// - Use WrexMods instead
+// 1.0.1 - Lasse
+// - Added getReaction()
+//
+// 1.0.0 - Lasse
+// - Added getWebhook()
+//
+// ---------------------------------------------------------------------
+
+const custommethods = {};
+
+custommethods.API = {};
+
+custommethods.DBM = null;
+
+custommethods.Version = '2.1.6';
+
+// Methods:
+
+custommethods.getWebhook = function (type, varName, cache) {
+ const server = cache.server;
+ console.log('Please update WrexMods, Store Reaction Info and the webhook actions! Go to #support for more help :D');
+ switch (type) {
+ case 1:
+ return cache.temp[varName];
+ case 2:
+ if (server && this.server[server.id]) {
+ return this.server[server.id][varName];
+ }
+ break;
+ case 3:
+ return this.global[varName];
+ default:
+ break;
+ }
+ return false;
+};
+
+custommethods.getReaction = function (type, varName, cache) {
+ const server = cache.server;
+ console.log('Please update WrexMods, Store Reaction Info and the webhook actions! Go to #support for more help :D');
+ switch (type) {
+ case 1:
+ return cache.temp[varName];
+ case 2:
+ if (server && this.server[server.id]) {
+ return this.server[server.id][varName];
+ }
+ break;
+ case 3:
+ return this.global[varName];
+ default:
+ break;
+ }
+ return false;
+};
+
+// ---------------------------------------------------------------------
+
+// This function is called by DBM when the bot is started
+const customaction = {};
+customaction.name = 'custommethods';
+customaction.section = 'Deprecated';
+customaction.author = 'DBM Mods'; // Init.: Lasse
+customaction.version = '2.1.6'; // Added in 1.8.7 - Changelog at the top!
+customaction.short_description = 'Required for some mods. Does nothing';
+
+customaction.html = function () {
+ return `
+
+
+ Custom Methods:
+ Please delete this file from your actions folder. We merged this with WrexMods!
+
+
`;
+};
+
+customaction.getcustommethods = function () {
+ return custommethods;
+};
+
+customaction.mod = function (DBM) {
+ custommethods.DBM = DBM;
+
+ DBM.Actions.getcustommethods = function () {
+ return custommethods;
+ };
+};
+module.exports = customaction;
diff --git a/actions/action_anchor.js b/actions/action_anchor.js
new file mode 100644
index 000000000..fc68c60a4
--- /dev/null
+++ b/actions/action_anchor.js
@@ -0,0 +1,119 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Action Anchor',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.anchorName}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['anchorName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+Anchor Name
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data, customData, index) {
+ if (!customData.anchors) {
+ customData.anchors = {};
+ }
+ customData.anchors[data.anchorName] = index;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/action_anchor_MOD.js b/actions/action_anchor_MOD.js
new file mode 100644
index 000000000..dc7853dd2
--- /dev/null
+++ b/actions/action_anchor_MOD.js
@@ -0,0 +1,141 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Action Anchor',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return data.description
+ ? `${data.description}`
+ : `Create ${
+ data.anchor_id
+ ? `the "${data.anchorName}" anchor at the current position!`
+ : 'an anchor!'
+ }`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.7',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/end_if_ended.js',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['anchorName', 'color', 'description'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+Anchor Name
+
+
+ Anchor Color:
+
+
+
+
+ Description:
+
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data, customData, index) {
+ if (!customData.anchors) {
+ customData.anchors = {};
+ }
+ customData.anchors[data.anchorName] = index;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/action_container.js b/actions/action_container.js
new file mode 100644
index 000000000..1fd307b01
--- /dev/null
+++ b/actions/action_container.js
@@ -0,0 +1,124 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Action Container',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.comment}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['comment', 'actions'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Comment
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const actions = data.actions;
+ this.executeSubActionsThenNextAction(actions, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.actions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/action_container_color_comment_MOD.js b/actions/action_container_color_comment_MOD.js
new file mode 100644
index 000000000..ff04385e1
--- /dev/null
+++ b/actions/action_container_color_comment_MOD.js
@@ -0,0 +1,137 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Action Container',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.comment}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/action_container_color_comment_MOD.js',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding Ids in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['comment', 'actions', 'color'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Text Color:
+
+ Comment
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const actions = data.actions;
+ this.executeSubActionsThenNextAction(actions, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.actions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/add_blank_field_MOD.js b/actions/add_blank_field_MOD.js
new file mode 100644
index 000000000..66d6c18c8
--- /dev/null
+++ b/actions/add_blank_field_MOD.js
@@ -0,0 +1,42 @@
+module.exports = {
+ name: 'Add Blank Embed Field',
+ section: 'Embed Message',
+
+ subtitle(data) {
+ const info = ['.', 'Temp Variable', 'Server Variable', 'Global Variable'];
+ return `${info[parseInt(data.storage, 10)]}: ${data.varName}`;
+ },
+
+ fields: ['storage', 'varName'],
+
+ html(isEvent, data) {
+ return `
+
Note:
+ This mod adds commas to a number for every 1000.
+
+
+
+
+ Number to Add Commas
+
+
+
+
+
+
+
+
+
+
+
Example: 1000000 will be converted to 1,000,000
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer');
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const number = this.evalMessage(data.number, cache);
+
+ // Use regex to add commas to the number
+ const numberWithCommas = number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
+
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(numberWithCommas, storage, varName, cache);
+
+ this.callNextAction(cache);
+ },
+};
diff --git a/actions/add_embed_field.js b/actions/add_embed_field.js
new file mode 100644
index 000000000..eb507a126
--- /dev/null
+++ b/actions/add_embed_field.js
@@ -0,0 +1,137 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Add Embed Field',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Embed Message',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.message}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'fieldName', 'message', 'inline'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Field Name
+
+
+
+ Display Inline
+
+
+
+
+
+
+
+
+
+
+
+ Field Description
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ let embed = this.getVariable(storage, varName, cache);
+ const name = this.evalMessage(data.fieldName, cache);
+ const message = this.evalMessage(data.message, cache);
+ const inline = data.inline === '0';
+
+ const { EmbedBuilder } = this.getDBM().DiscordJS;
+ embed = EmbedBuilder.from(embed).addFields({ name, value: message, inline });
+
+ this.storeValue(embed, storage, varName, cache);
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/add_embed_to_message_data.js b/actions/add_embed_to_message_data.js
new file mode 100644
index 000000000..f9a25d0bf
--- /dev/null
+++ b/actions/add_embed_to_message_data.js
@@ -0,0 +1,123 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Add Embed to Message Data',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Embed Message',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Store ${presets.getVariableText(data.storage, data.varName)} in ${presets.getVariableText(
+ data.editMessage,
+ data.editMessageVarName,
+ )}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'editMessage', 'editMessageVarName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const embed = this.getVariable(storage, varName, cache);
+
+ if (embed) {
+ const editMessage = parseInt(data.editMessage, 10);
+ if (typeof editMessage === 'number' && editMessage >= 0) {
+ const editVarName = this.evalMessage(data.editMessageVarName, cache);
+ const editObject = this.getVariable(editMessage, editVarName, cache);
+ if (Array.isArray(editObject.embeds)) {
+ editObject.embeds.push(embed);
+ } else {
+ editObject.embeds = [embed];
+ }
+ }
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/add_forum_tag.js b/actions/add_forum_tag.js
new file mode 100644
index 000000000..208847e72
--- /dev/null
+++ b/actions/add_forum_tag.js
@@ -0,0 +1,154 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Add Forum Tag',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Add tag: ${data.tagName || 'Unnamed Tag'}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: null,
+ authorUrl: 'https://github.com/master3395/dbm-mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['forumChannel', 'varName', 'tagName', 'emoji', 'moderated'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Tag Name
+
+
+
+
+
+
+ Emoji (optional, leave blank for none)
+
+
+
+
+
+
+ Moderated Tag (only moderators can use)
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const DBM = this.getDBM();
+ const DiscordJS = DBM.DiscordJS;
+ const isV14 = DBM.isDiscordJSv14 ? DBM.isDiscordJSv14() : parseInt(DiscordJS.version.split('.')[0], 10) >= 14;
+
+ const channel = await this.getChannelFromData(data.forumChannel, data.varName, cache);
+
+ if (!channel) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ // Check if channel is a forum channel
+ const ChannelType = DBM.getChannelType ? DBM.getChannelType() : DiscordJS.ChannelType || {};
+ const isForum = isV14
+ ? channel.type === ChannelType.GuildForum || channel.type === 15
+ : channel.type === 'GUILD_FORUM' || channel.type === 15;
+
+ if (!isForum) {
+ this.displayError(data, cache, new Error('Channel must be a forum channel'));
+ return;
+ }
+
+ try {
+ const tagName = this.evalMessage(data.tagName, cache);
+ const emojiInput = this.evalMessage(data.emoji, cache);
+ const moderated = data.moderated === 'true';
+
+ if (!tagName || !tagName.trim()) {
+ this.displayError(data, cache, new Error('Tag name is required'));
+ return;
+ }
+
+ // Prepare tag data
+ const tagData = {
+ name: tagName.trim(),
+ moderated,
+ };
+
+ // Add emoji if provided
+ if (emojiInput && emojiInput.trim()) {
+ // Try to resolve emoji (could be unicode or custom emoji ID)
+ const emoji = emojiInput.trim();
+ if (emoji.match(/^\d+$/)) {
+ // Custom emoji ID
+ tagData.emojiId = emoji;
+ } else {
+ // Unicode emoji or custom emoji format
+ tagData.emojiName = emoji;
+ }
+ }
+
+ // Add tag to forum channel
+ // v13 and v14 use the same API
+ const currentTags = channel.availableTags || [];
+ const updatedTags = [...currentTags, tagData];
+
+ await channel.setAvailableTags(updatedTags);
+
+ this.callNextAction(cache);
+ } catch (err) {
+ this.displayError(data, cache, err);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/add_item_to_list.js b/actions/add_item_to_list.js
new file mode 100644
index 000000000..75268cc8e
--- /dev/null
+++ b/actions/add_item_to_list.js
@@ -0,0 +1,169 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Add Item to List',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Lists and Loops',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storage = presets.variables;
+ return `Add "${data.value}" to ${storage[parseInt(data.storage, 10)]} (${data.varName})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'addType', 'position', 'value'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Add Type
+
+
+
+ Position
+
+
+
+
+
+
+
+ Value
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChange1 = function (event) {
+ const value = parseInt(event.value, 10);
+ const dom = document.getElementById('positionHolder');
+ if (value < 2) {
+ dom.style.display = 'none';
+ } else {
+ dom.style.display = null;
+ }
+ };
+
+ glob.onChange1(document.getElementById('addType'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const list = this.getVariable(storage, varName, cache);
+
+ const type = parseInt(data.addType, 10);
+ let val = this.evalMessage(data.value, cache);
+ try {
+ val = this.eval(val, cache);
+ } catch (e) {
+ this.displayError(data, cache, e);
+ }
+
+ switch (type) {
+ case 0:
+ list.push(val);
+ break;
+ case 1:
+ list.unshift(val);
+ break;
+ case 2:
+ const position = parseInt(this.evalMessage(data.position), 10);
+ if (position < 0) {
+ list.unshift(val);
+ } else if (position >= list.length) {
+ list.push(val);
+ } else {
+ list.splice(position, 0, val);
+ }
+ break;
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/add_item_to_object_MOD.js b/actions/add_item_to_object_MOD.js
new file mode 100644
index 000000000..14774b062
--- /dev/null
+++ b/actions/add_item_to_object_MOD.js
@@ -0,0 +1,137 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Add Item to Object',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'JSON Things',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storage = presets.variables;
+ if (!data.value) return `Clear key "${data.key}" in ${storage[parseInt(data.storage, 10)]} (${data.varName})`;
+ return `Add "${data.value}" to key "${data.key}" in ${storage[parseInt(data.storage, 10)]} (${data.varName})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'key', 'value'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Key
+
+
+
+ Value
+
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const key = this.evalMessage(data.key, cache);
+ const list = this.getVariable(storage, varName, cache);
+
+ let val = this.evalMessage(data.value, cache);
+ if (!val) {
+ delete list[key];
+ } else {
+ try {
+ val = this.eval(val, cache);
+ } catch (e) {
+ this.displayError(data, cache, e);
+ }
+ list[key] = val;
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/add_items_to_object_MOD.js b/actions/add_items_to_object_MOD.js
new file mode 100644
index 000000000..b5cece8ca
--- /dev/null
+++ b/actions/add_items_to_object_MOD.js
@@ -0,0 +1,147 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Add Items to Object',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'JSON Things',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storage = presets.variables;
+ return `Add ${Object.entries(data.entriess).length} item${
+ Object.entries(data.entriess).length === 1 ? '' : 's'
+ } entries to ${storage[parseInt(data.storage, 10)]} (${data.varName})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'entriess'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+ Key
+
+
+
+ Value
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const list = this.getVariable(storage, varName, cache);
+
+ for (let i = 0; i < data.entriess.length; i++) {
+ const key = this.evalMessage(data.entriess[i].key, cache);
+ let val = this.evalMessage(data.entriess[i].value, cache);
+ if (!key) continue;
+ if (!val) {
+ delete list[key];
+ continue;
+ } else {
+ try {
+ val = this.eval(val, cache);
+ } catch (e) {
+ this.displayError(data, cache, e);
+ }
+ list[key] = val;
+ }
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/add_member_role.js b/actions/add_member_role.js
new file mode 100644
index 000000000..0e9122c11
--- /dev/null
+++ b/actions/add_member_role.js
@@ -0,0 +1,128 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Add Member Role',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName2)} - ${presets.getRoleText(data.role, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName2', 'role', 'varName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const role = await this.getRoleFromData(data.role, data.varName, cache);
+ const member = await this.getMemberFromData(data.member, data.varName2, cache);
+ const reason = this.evalMessage(data.reason, cache);
+ if (Array.isArray(member)) {
+ this.callListFunc(
+ member.map((m) => m.roles),
+ 'add',
+ [role, reason],
+ )
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else if (member?.roles) {
+ member.roles
+ .add(role, reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/add_member_to_thread_MOD.js b/actions/add_member_to_thread_MOD.js
new file mode 100644
index 000000000..7df93cc9d
--- /dev/null
+++ b/actions/add_member_to_thread_MOD.js
@@ -0,0 +1,45 @@
+module.exports = {
+ name: 'Add Member to Thread',
+ section: 'Channel Control',
+ meta: {
+ version: '2.1.7',
+ preciseCheck: false,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods/blob/master/actions/add_member_to_thread_MOD.js',
+ },
+
+ subtitle(data, presets) {
+ const storeTypes = presets.variables;
+
+ return `${storeTypes[parseInt(data.storage, 10)]} (${data.varName})`;
+ },
+
+ fields: ['storage', 'varName', 'member', 'varName2'],
+
+ html() {
+ return `
+
+
+
+
+ `;
+ },
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ let duration = this.evalMessage(data.addtime, cache);
+
+ if (duration.includes('s')) {
+ duration = duration.split('s')[0] * 1000;
+ } else if (duration.includes('m')) {
+ duration = duration.split('m')[0] * 60000;
+ } else if (duration.includes('h')) {
+ duration = duration.split('h')[0] * 3600000;
+ } else if (duration.includes('d')) {
+ duration = duration.split('d')[0] * 86400000;
+ } else {
+ duration *= 1000;
+ }
+ const result = new Date().getTime() + duration;
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/add_reaction.js b/actions/add_reaction.js
new file mode 100644
index 000000000..d8d289a36
--- /dev/null
+++ b/actions/add_reaction.js
@@ -0,0 +1,167 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Add Reaction',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Add Reaction to ${presets.getMessageText(data.storage, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'emoji', 'varName2', 'varName3'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Source Emoji
+
+
+
+ Emoji (right-click -> Insert Emoji)
+
+
+
+ Variable Name
+
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChange1 = function (event) {
+ const value = parseInt(event.value, 10);
+ const varNameInput = document.getElementById('extName');
+ if (value === 0) {
+ varNameInput.innerHTML = 'Emoji Name';
+ document.getElementById('varNameContainer3').style.display = 'none';
+ document.getElementById('varNameContainer2').style.display = null;
+ } else if (value === 4) {
+ varNameInput.innerHTML = 'Emoji (right-click -> Insert Emoji)';
+ document.getElementById('varNameContainer3').style.display = 'none';
+ document.getElementById('varNameContainer2').style.display = null;
+ } else {
+ glob.onChangeBasic(event, 'varNameContainer3');
+ document.getElementById('varNameContainer3').style.display = null;
+ document.getElementById('varNameContainer2').style.display = 'none';
+ }
+ };
+
+ glob.onChange1(document.getElementById('emoji'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const message = await this.getMessageFromData(data.storage, data.varName, cache);
+
+ const type = parseInt(data.emoji, 10);
+ let emoji;
+ if (type === 4) {
+ emoji = this.evalMessage(data.varName2, cache);
+ } else if (type === 0) {
+ emoji = this.getDBM().Bot.bot.emojis.cache.find((e) => e.name === this.evalMessage(data.varName2, cache));
+ } else {
+ emoji = this.getVariable(type, this.evalMessage(data.varName3, cache), cache);
+ }
+
+ if (Array.isArray(message)) {
+ this.callListFunc(message, 'react', [emoji])
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else if (emoji && message?.react) {
+ message
+ .react(emoji)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/add_time_to_timestamp.js b/actions/add_time_to_timestamp.js
new file mode 100644
index 000000000..0d041dbd0
--- /dev/null
+++ b/actions/add_time_to_timestamp.js
@@ -0,0 +1,89 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Add Time To Timestamp',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ const dataType = 'New Timestamp';
+ return [data.varName2, dataType];
+ },
+
+ subtitle(data, presets) {
+ return `Added time ${data.addtime} to new timestamp!`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Gotowka',
+ authorUrl: 'https://github.com/Gotowka',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['addtime', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
`;
+ },
+
+ init() {},
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const regex = /(\.)|(-)|(\/)|(\\)|(,)|(:)|(;)|(')|(°)/gi;
+ const replDOB = this.evalMessage(data.DOB, cache).replace(regex, ' ');
+ // ['12', '23', '1990']
+ const dateArr = replDOB.split(' ');
+ const monthsArr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+ const INFO = parseInt(data.info, 10);
+ let result;
+ let converttoformat;
+ let converttodateformat;
+ let calcDOB;
+ switch (INFO) {
+ case 0:
+ // MM/DD/YYYY selected format
+ // convert to DD/MM/YYYY so calc can work
+ // INPUT: ['12', '23', '1990']
+ converttoformat = `${dateArr[1]} ${monthsArr[parseInt(dateArr[0], 10) - 1]} ${dateArr[2]}`;
+ converttodateformat = new Date(converttoformat);
+
+ calcDOB = parseInt((new Date() - converttodateformat) / 60 / 60 / 24 / 365.242214 / 1000, 10); // Precise num of days in year, not 365 or 365.25
+
+ if (calcDOB < 0) {
+ result = 'unborn';
+ } else if (calcDOB === 0) {
+ result = 'newborn';
+ } else {
+ result = calcDOB;
+ }
+ break;
+
+ case 1:
+ // DD/MM/YYYY selected format
+ // convert to DD/MM/YYYY so calc can work
+ // INPUT: ['12', '23', '1990']
+ converttoformat = `${dateArr[0]} ${monthsArr[parseInt(dateArr[1], 10) - 1]} ${dateArr[2]}`;
+ converttodateformat = new Date(converttoformat);
+
+ calcDOB = parseInt((new Date() - converttodateformat) / 60 / 60 / 24 / 365.242214 / 1000, 10); // Precise num of days in year, not 365 or 365.25
+
+ if (calcDOB < 0) {
+ result = 'unborn';
+ } else if (calcDOB === 0) {
+ result = 'newborn';
+ } else {
+ result = calcDOB;
+ }
+ break;
+
+ case 2:
+ // MM/YYYY/DD selected format
+ // convert to DD/MM/YYYY so calc can work
+ // INPUT: ['12', '1990', '23']
+ converttoformat = `${dateArr[2]} ${monthsArr[parseInt(dateArr[0], 10) - 1]} ${dateArr[1]}`;
+ converttodateformat = new Date(converttoformat);
+
+ calcDOB = parseInt((new Date() - converttodateformat) / 60 / 60 / 24 / 365.242214 / 1000, 10); // Precise num of days in year, not 365 or 365.25
+
+ if (calcDOB < 0) {
+ result = 'unborn';
+ } else if (calcDOB === 0) {
+ result = 'newborn';
+ } else {
+ result = calcDOB;
+ }
+ break;
+ case 3:
+ // DD/YYYY/MM selected format
+ // convert to DD/MM/YYYY so calc can work
+ // INPUT: ['12', '1990', '23']
+ converttoformat = `${dateArr[0]} ${monthsArr[parseInt(dateArr[2], 10) - 1]} ${dateArr[1]}`;
+ converttodateformat = new Date(converttoformat);
+
+ calcDOB = parseInt((new Date() - converttodateformat) / 60 / 60 / 24 / 365.242214 / 1000, 10); // Precise num of days in year, not 365 or 365.25
+
+ if (calcDOB < 0) {
+ result = 'unborn';
+ } else if (calcDOB === 0) {
+ result = 'newborn';
+ } else {
+ result = calcDOB;
+ }
+ break;
+
+ case 4:
+ // YYYY/MM/DD selected format
+ // convert to DD/MM/YYYY so calc can work
+ // INPUT: ['1990', '12', '23']
+ converttoformat = `${dateArr[2]} ${monthsArr[parseInt(dateArr[1], 10) - 1]} ${dateArr[0]}`;
+ converttodateformat = new Date(converttoformat);
+
+ calcDOB = parseInt((new Date() - converttodateformat) / 60 / 60 / 24 / 365.242214 / 1000, 10); // Precise num of days in year, not 365 or 365.25
+
+ if (calcDOB < 0) {
+ result = 'unborn';
+ } else if (calcDOB === 0) {
+ result = 'newborn';
+ } else {
+ result = calcDOB;
+ }
+ break;
+
+ case 5:
+ // YYYY/DD/MM selected format
+ // convert to DD/MM/YYYY so calc can work
+ // INPUT: ['1990', '23', '12']
+ converttoformat = `${dateArr[1]} ${monthsArr[parseInt(dateArr[2], 10) - 1]} ${dateArr[0]}`;
+ converttodateformat = new Date(converttoformat);
+
+ calcDOB = parseInt((new Date() - converttodateformat) / 60 / 60 / 24 / 365.242214 / 1000, 10); // Precise num of days in year, not 365 or 365.25
+
+ if (calcDOB < 0) {
+ result = 'unborn';
+ } else if (calcDOB === 0) {
+ result = 'newborn';
+ } else {
+ result = calcDOB;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/aiden_mod_info_MOD.js b/actions/aiden_mod_info_MOD.js
new file mode 100644
index 000000000..6848c55b7
--- /dev/null
+++ b/actions/aiden_mod_info_MOD.js
@@ -0,0 +1,281 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Translation of Info',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: '#Info Translation',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data) {
+ const info = [
+ 'DBMEX Mod Pack',
+ 'DBMEX Mod Pack',
+ 'DBMEX Mod Pack',
+ 'DBMEX Mod Pack',
+ 'DBMEX Mod Pack',
+ 'DBMEX Mod Pack',
+ ];
+ return `${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // DBM Mods Manager Variables (Optional but nice to have!)
+ //
+ // These are variables that DBM Mods Manager uses to show information
+ // about the mods for people to see in the list.
+ // ---------------------------------------------------------------------
+
+ // Who made the mod (If not set, defaults to "DBM Mods")
+ author: 'Giingu',
+
+ // The version of the mod (Defaults to 1.0.0)
+ version: '2.1.6', // Added in 2.1.6
+
+ // A short description to show on the mod line for this mod (Must be on a single line)
+ short_description: 'DBMEX Mod Pack Information.',
+
+ long_description: '2D > 3D',
+
+ // If it depends on any other mods by name, ex: WrexMODS if the mod uses something from WrexMods
+
+ // ---------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Credits';
+ break;
+ case 1:
+ dataType = 'DBMEX';
+ break;
+ }
+ return [data.varName, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['serverip', 'gametype', 'info', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editting actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Translation information Created by DBM Extended
+ You will find the updates here Version: 2.1.1 for Mods version: 2.1.6
+
+
+ `;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer');
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existance.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const _this = this; // To fix error
+ const data = cache.actions[cache.index];
+ const info = parseInt(data.info, 10);
+ const gametype = _this.evalMessage(data.gametype, cache);
+ const host = _this.evalMessage(data.serverip, cache);
+
+ // Main code:
+ const WrexMODS = _this.getWrexMods(); // as always.
+ WrexMODS.CheckAndInstallNodeModule('game-server-query');
+ const query = WrexMODS.require('game-server-query');
+
+ query(
+ {
+ type: `${gametype}`,
+ host: `${host}`,
+ },
+ function (state) {
+ if (state.error) {
+ console.log('[Store Game Server Info Mod] Server is offline.');
+ } else {
+ let result;
+ switch (info) {
+ case 0:
+ result = state.name;
+ break;
+ case 1:
+ result = state.map;
+ break;
+ case 2:
+ result = state.raw.numplayers;
+ break;
+ case 3:
+ result = state.maxplayers;
+ break;
+ case 4:
+ result = state.raw.tags;
+ break;
+ case 5:
+ result = state.password;
+ break;
+ default:
+ break;
+ }
+
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = _this.evalMessage(data.varName, cache);
+ _this.storeValue(result, storage, varName2, cache);
+ _this.callNextAction(cache);
+ } else {
+ _this.callNextAction(cache);
+ }
+ }
+ },
+ );
+ },
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflictions between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {},
+}; // End of module
diff --git a/actions/anchor_jump_MOD.js b/actions/anchor_jump_MOD.js
index a4a0825d5..ef63d7590 100644
--- a/actions/anchor_jump_MOD.js
+++ b/actions/anchor_jump_MOD.js
@@ -53,19 +53,27 @@ module.exports = {
},
mod(DBM) {
+ function resolveAnchorIndex(actions, id) {
+ return actions.findIndex((a) => {
+ if (a.name === 'Create Anchor' && a.anchor_id === id) return true;
+ if (a.name === 'Action Anchor' && a.anchorName === id) return true;
+ return false;
+ });
+ }
+
DBM.Actions.anchorJump = function anchorJump(id, cache) {
- const anchorIndex = cache.actions.findIndex((a) => a.name === 'Create Anchor' && a.anchor_id === id);
- if (anchorIndex === -1) throw new Error('There was not an anchor found with that exact anchor ID!');
+ const anchorIndex = resolveAnchorIndex(cache.actions, id);
+ if (anchorIndex === -1) {
+ console.warn(`[Jump to Anchor] No anchor found for ID: "${id}". Continuing to next action.`);
+ this.callNextAction(cache);
+ return;
+ }
cache.index = anchorIndex - 1;
this.callNextAction(cache);
};
DBM.Actions.anchorExist = function anchorExist(id, cache) {
- const anchorIndex = cache.actions.findIndex((a) => a.name === 'Create Anchor' && a.anchor_id === id);
- if (anchorIndex === -1) {
- return false;
- }
- return true;
+ return resolveAnchorIndex(cache.actions, id) !== -1;
};
},
};
diff --git a/actions/archive_thread.js b/actions/archive_thread.js
new file mode 100644
index 000000000..c47a7e0ae
--- /dev/null
+++ b/actions/archive_thread.js
@@ -0,0 +1,130 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Archive Thread',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.archive === 'true' ? 'Archive' : 'Unarchive'} Thread: "${presets.getChannelText(
+ data.thread,
+ data.threadVarName,
+ )}"`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['thread', 'threadVarName', 'archive'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ New Thread State
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const thread = await this.getChannelFromData(data.thread, data.threadVarName, cache);
+
+ const reason = this.evalMessage(data.reason, cache);
+ const archive = data.archive === 'true';
+
+ if (Array.isArray(thread)) {
+ this.callListFunc(thread, 'setArchived', [archive, reason]).then(() => this.callNextAction(cache));
+ } else if (thread?.setArchived) {
+ thread
+ .setArchived(archive, reason)
+ .then((threadChannel) => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/await_interaction_MOD.js b/actions/await_interaction_MOD.js
new file mode 100644
index 000000000..0f948d33f
--- /dev/null
+++ b/actions/await_interaction_MOD.js
@@ -0,0 +1,306 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Await Interaction',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'DBM-Extended',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ if (data.time >= 1) {
+ return `Await Interaction For ${data.time / 1000} Seconds`;
+ }
+ return `Await Interaction For 60 Seconds (Default)`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Unknown Type'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['type', 'msgvar', 'msgvarname', 'time', 'code', 'timeout', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
How To Use:
+ ● Put This Action After Your Send Message.
+ ● If Await Time Runs Out, Result Will Be timeout by "Default"
+
+
+
+ Interaction Type
+
+
+
+ Source Message (ID ONLY)
+
+
+
+
+ Await Time (Miliseconds)
+
+
+
+ Await Timeout Value
+
+
+
+
+
+
+
+
+
+ A DBM-E Modification | Install DBM-E`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+
+ const msgvar = this.evalMessage(data.msgvar, cache) || 0;
+ {
+ if (isNaN(msgvar)) {
+ console.log(
+ `------------ DBME ERROR ------------\n-> \"${msgvar}\" Is not a Message's ID!\n--------- Await Interaction --------\n`,
+ );
+ return;
+ }
+ }
+ let time = this.evalMessage(data.time, cache) || 60000;
+ const timeout = this.evalMessage(data.timeout, cache) || 'timeout';
+ const varName = this.evalMessage(data.varName, cache);
+ const storage = parseInt(data.storage, 10);
+
+ if (msgvar === 0) {
+ var path = `last-interaction`;
+ } else {
+ var path = `${msgvar}-interaction`;
+ }
+
+ const member = await this.getMemberFromData(1, undefined, cache);
+ (async () => {
+ const sleep = require('sleep-promise');
+ member.setData(path, undefined);
+ do {
+ await sleep(500);
+ time -= 500;
+ if (time < 500) {
+ this.storeValue(timeout, storage, varName, cache);
+ break;
+ }
+ const result = member.data(path);
+ if (Boolean(result)) {
+ member.setData(path, undefined);
+ if (msgvar !== 0) {
+ const path2 = member.data(`message-interaction`);
+ if (Boolean(path2)) member.setData(path2, undefined);
+ }
+ this.storeValue(result, storage, varName, cache);
+ break;
+ } else {
+ continue;
+ }
+ } while (1);
+ this.callNextAction(cache);
+ })();
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/await_message_from_member.js b/actions/await_message_from_member.js
new file mode 100644
index 000000000..a184905d8
--- /dev/null
+++ b/actions/await_message_from_member.js
@@ -0,0 +1,163 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Await Message from Member',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Await message in ${presets.getChannelText(data.channel, data.channelVarName)} from ${presets.getMemberText(
+ data.member,
+ data.memberVarName,
+ )}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.storeInVarName, 'Message'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'channelVarName', 'member', 'memberVarName', 'time', 'count', 'storage', 'storeInVarName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+
+
+ Await Time (in Seconds)
+
+
+
+ Number of Messages to Check
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const channel = await this.getChannelFromData(data.channel, data.channelVarName, cache);
+ const member = await this.getMemberFromData(data.member, data.memberVarName, cache);
+
+ if (!member || !channel?.createMessageCollector) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const maxProcessed = Math.min(parseInt(this.evalMessage(data.count, cache), 10), 200);
+ const time = parseInt(this.evalMessage(data.time, cache) || '5', 10) * 1000;
+ const filter = (m) => m?.author?.id === member.id;
+
+ const collector = channel.createMessageCollector({
+ max: 1,
+ time,
+ filter,
+ maxProcessed,
+ });
+
+ collector.on('end', (collected) => {
+ if (collected && collected.size > 0) {
+ const varName = this.evalMessage(data.storeInVarName, cache);
+ const storage = parseInt(data.storage, 10);
+ this.storeValue(collected.values().next(), storage, varName, cache);
+ }
+
+ this.callNextAction(cache);
+ });
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {},
+};
diff --git a/actions/backup_MOD.js b/actions/backup_MOD.js
new file mode 100644
index 000000000..3be05ff15
--- /dev/null
+++ b/actions/backup_MOD.js
@@ -0,0 +1,81 @@
+module.exports = {
+ name: 'Backup',
+ section: 'Other Stuff',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: '[Tempest - 321400509326032897]',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data) {
+ return `Backup ${data.pastaBackup}`;
+ },
+
+ fields: ['pastaBackup', 'backupNome', 'log', 'nextAction'],
+
+ html(_isEvent, data) {
+ return `
+
+ Folder to Backup
+
+
+
+ Backup Name
+
+
+
+ Console logging
+
+
+
+ Call next action
+
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer');
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const zip = require('zip-local');
+
+ let pastaBackup = this.evalMessage(data.pastaBackup, cache);
+ pastaBackup = `./${pastaBackup.toString().replace('./', '')}`;
+ let backupNome = this.evalMessage(data.backupNome, cache);
+ backupNome = `${backupNome.toString().replace('.zip', '').replace('.rar', '')}.zip`;
+ const log = parseInt(data.log, 10);
+ const nextAction = parseInt(data.nextAction, 10);
+
+ zip.sync.zip(pastaBackup).compress().save(backupNome);
+
+ switch (log) {
+ case 0:
+ console.log('Backup done successfully!');
+ break;
+ case 1:
+ break;
+ }
+
+ switch (nextAction) {
+ case 0:
+ this.callNextAction(cache);
+ break;
+ case 1:
+ this.endActions(cache);
+ break;
+ }
+ },
+
+ mod() {},
+};
diff --git a/actions/ban_member.js b/actions/ban_member.js
new file mode 100644
index 000000000..a34e029b5
--- /dev/null
+++ b/actions/ban_member.js
@@ -0,0 +1,125 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Ban Member',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.1.7', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'reason', 'days'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Reason
+
+
+
+
+ Number of days of messages to delete
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+ const days = parseInt(data.days, 10) || 0;
+ if (Array.isArray(member)) {
+ this.callListFunc(member, 'ban', [{ days, reason }])
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else if (member?.ban) {
+ member
+ .ban({ days, reason })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/ban_member.ts b/actions/ban_member.ts
new file mode 100644
index 000000000..562038095
--- /dev/null
+++ b/actions/ban_member.ts
@@ -0,0 +1,132 @@
+import * as djs from 'discord.js';
+import Action from '../bot.ts';
+
+export default {
+ //---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ //---------------------------------------------------------------------
+
+ name: 'Ban Member',
+
+ //---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ //---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ //---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ //---------------------------------------------------------------------
+
+ subtitle(data: any, presets: any): string {
+ return `${presets.getMemberText(data.member, data.varName)}`;
+ },
+
+ //---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ //---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ //---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ //---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'reason', 'days'],
+
+ //---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //---------------------------------------------------------------------
+
+ html(isEvent: boolean, data: any): string {
+ return `
+
+
+
+
+
+ Reason
+
+
+
+
+ Number of days of messages to delete
+
+
`;
+ },
+
+ //---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ //---------------------------------------------------------------------
+
+ init() {},
+
+ //---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ //---------------------------------------------------------------------
+
+ async action(this: typeof Action, cache: any): Promise {
+ const data: any = cache.actions[cache.index];
+ const member: djs.GuildMember | djs.GuildMember[] | null = await this.getMemberFromData(
+ data.member,
+ data.varName,
+ cache,
+ );
+ const reason: string = this.evalMessage(data.reason, cache);
+ const days: number = parseInt(data.days, 10) || 0;
+ const banOptions: djs.BanOptions = { deleteMessageSeconds: days * 24 * 60 * 60, reason };
+
+ try {
+ if (Array.isArray(member)) {
+ await this.callListFunc(member, 'ban', [banOptions]);
+ } else if (member?.ban) {
+ await member.ban(banOptions);
+ }
+ this.callNextAction(cache);
+ } catch (err: any) {
+ this.displayError(data, cache, err);
+ }
+ },
+
+ //---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ //---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/banscount_MOD.js b/actions/banscount_MOD.js
new file mode 100644
index 000000000..87f4cb19d
--- /dev/null
+++ b/actions/banscount_MOD.js
@@ -0,0 +1,171 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Server Bans Count',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'DBM Extended',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = ['Server Bans Count'];
+ return `${presets.getServerText(data.server, data.varName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 41:
+ dataType = 'Bans Count';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.5',
+ preciseCheck: true,
+ author: 'DBMExtended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadUrl: 'https://github.com/DBM-Extended/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName', 'info', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain Information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Source Info
+
+
+
+
+
+
+ `;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const targetServer = await this.getServerFromData(data.server, data.varName, cache);
+
+ if (!targetServer) {
+ return this.callNextAction(cache);
+ }
+
+ const fetchMembers = async (withPresences = false) => {
+ if (targetServer.memberCount !== targetServer.members.cache.size) {
+ await targetServer.members.fetch({ withPresences });
+ }
+ };
+
+ const info = parseInt(data.info, 10);
+
+ let result;
+ switch (info) {
+ case 1:
+ await fetchMembers();
+ await targetServer.bans.fetch({ cache: true });
+ result = targetServer.bans.cache.size;
+ break;
+ default:
+ break;
+ }
+
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/buscar_um_item_da_lista_MOD.js b/actions/buscar_um_item_da_lista_MOD.js
new file mode 100644
index 000000000..e464a59c4
--- /dev/null
+++ b/actions/buscar_um_item_da_lista_MOD.js
@@ -0,0 +1,163 @@
+module.exports = {
+ name: 'Search a list item',
+ section: 'Lists and Loops',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data) {
+ const info = [
+ 'exactly equal to',
+ 'include',
+ 'matches regex',
+ 'less than',
+ 'less than or equal to',
+ 'greater than',
+ 'greater than or equal to',
+ 'length greater than',
+ 'length less than',
+ 'length equal to',
+ 'begins with',
+ 'ends with',
+ ];
+ return `Search ${info[parseInt(data.fetchedxin, 10)]} "${data.item}" in "${data.varName}"`;
+ },
+
+ variableStorage(data, varType) {
+ const prse2 = parseInt(data.fetchedxin, 10);
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName2, 'Number'[prse2]];
+ },
+
+ fields: ['list', 'varName', 'fetchedxin', 'item', 'storage', 'varName2'],
+
+ html(isEvent, data) {
+ return `
+
+List source:
+
+
+
+Variable name:
+
+
+
+
+Search:
+
+
+
+
+
+
+
+ Store in:
+
+
+
+ Variable name:
+
+
+
+
This action searches for an item in a list and returns the position.
+Note that every list in JavaScript starts at 0
+If not found, it will always return -1
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChange1 = function onChange1(event) {
+ const value = parseInt(event.value, 10);
+ const dom = document.getElementById('positionHolder');
+ if (value < 3) {
+ dom.style.display = 'none';
+ } else {
+ dom.style.display = null;
+ }
+ };
+
+ glob.listChange(document.getElementById('list'), 'varNameContainer');
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.list, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const list = await this.getList(storage, varName, cache);
+ const fetchedxin = parseInt(data.fetchedxin, 10);
+ const item = this.evalMessage(data.item, cache);
+
+ let result;
+
+ switch (fetchedxin) {
+ case 0:
+ result = list.findIndex((i) => i === item);
+ break;
+ case 1:
+ result = list.findIndex((i) => i.includes(item));
+ break;
+ case 2:
+ result = list.findIndex((i) => Boolean(i.match(new RegExp(`^${item}$`, 'i'))));
+ break;
+ case 3:
+ result = list.findIndex((i) => i < item);
+ break;
+ case 4:
+ result = list.findIndex((i) => i <= item);
+ break;
+ case 5:
+ result = list.findIndex((i) => i > item);
+ break;
+ case 6:
+ result = list.findIndex((i) => i >= item);
+ break;
+ case 7:
+ result = list.findIndex((i) => Boolean(i.length > item));
+ break;
+ case 8:
+ result = list.findIndex((i) => Boolean(i.length < item));
+ break;
+ case 9:
+ result = list.findIndex((i) => Boolean(i.length === item));
+ break;
+ case 10:
+ result = list.findIndex((i) => i.startsWith(item));
+ break;
+ case 11:
+ result = list.findIndex((i) => i.endsWith(item));
+ break;
+ }
+
+ if (result !== undefined) {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage2 = parseInt(data.storage, 10);
+ this.storeValue(result, storage2, varName2, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/call_command_or_event.js b/actions/call_command_or_event.js
new file mode 100644
index 000000000..4d1e7ca61
--- /dev/null
+++ b/actions/call_command_or_event.js
@@ -0,0 +1,157 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Call Command/Event',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Call Command/Event ID "${data.source}"`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['source', 'type'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Command/Event
+
+
+
+ Call Type
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ const $cmds = glob.$cmds;
+ const coms = document.getElementById('commands');
+ coms.innerHTML = '';
+ for (let i = 0; i < $cmds.length; i++) {
+ if ($cmds[i]) {
+ coms.innerHTML += `\n`;
+ }
+ }
+
+ const $evts = glob.$evts;
+ const evet = document.getElementById('events');
+ evet.innerHTML = '';
+ for (let i = 0; i < $evts.length; i++) {
+ if ($evts[i]) {
+ evet.innerHTML += `\n`;
+ }
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const Files = this.getDBM().Files;
+
+ const id = data.source;
+ let actions;
+ const allData = Files.data.commands.concat(Files.data.events);
+ for (let i = 0; i < allData.length; i++) {
+ if (allData[i]?._id === id) {
+ actions = allData[i].actions;
+ break;
+ }
+ }
+
+ if (!actions) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const waitForCompletion = data.type === 'true';
+ let callback = null;
+ if (waitForCompletion) {
+ callback = () => this.callNextAction(cache);
+ }
+ this.executeSubActions(actions, cache, callback);
+ if (!waitForCompletion) {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/call_command_or_event_MOD.js b/actions/call_command_or_event_MOD.js
new file mode 100644
index 000000000..eb2a12fc2
--- /dev/null
+++ b/actions/call_command_or_event_MOD.js
@@ -0,0 +1,172 @@
+module.exports = {
+ name: 'Call Command/Event',
+ section: 'Other Stuff',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data) {
+ let source;
+ if (parseInt(data.sourcetype, 10) === 2) {
+ source = `Nome do comando: ${data.source3.toString()}`;
+ }
+ if (parseInt(data.sourcetype, 10) === 1) {
+ source = `ID do comando: ${data.source2.toString()}`;
+ }
+ if (parseInt(data.sourcetype, 10) === 0) {
+ source = `Lista > comando: ${data.source.toString()}`;
+ }
+ return `${source}`;
+ },
+
+ fields: ['sourcetype', 'source', 'source2', 'source3', 'type'],
+
+ html() {
+ return `
+
+Source Type
+
+
+
+Command/Event
+
+
+
+Command/Event ID
+
+
+
+Command/Event Name
+
+
+
+Call type
+
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ const { $cmds } = glob;
+ const coms = document.getElementById('commands');
+ coms.innerHTML = '';
+ for (let i = 0; i < $cmds.length; i++) {
+ if ($cmds[i]) {
+ coms.innerHTML += `\n`;
+ }
+ }
+
+ const { $evts } = glob;
+ const evet = document.getElementById('events');
+ evet.innerHTML = '';
+ for (let i = 0; i < $evts.length; i++) {
+ if ($evts[i]) {
+ evet.innerHTML += `\n`;
+ }
+ }
+
+ glob.onChange1 = function onChange1(event) {
+ const sourceType = parseInt(document.getElementById('sourcetype').value, 10);
+ const info1 = document.getElementById('info1');
+ const info2 = document.getElementById('info2');
+ const info3 = document.getElementById('info3');
+
+ switch (sourceType) {
+ case 0:
+ info1.style.display = null;
+ info2.style.display = 'none';
+ info3.style.display = 'none';
+ break;
+ case 1:
+ info1.style.display = 'none';
+ info2.style.display = null;
+ info3.style.display = 'none';
+ break;
+ case 2:
+ info1.style.display = 'none';
+ info2.style.display = 'none';
+ info3.style.display = null;
+ break;
+ default:
+ break;
+ }
+ };
+
+ glob.onChange1(document.getElementById('sourcetype'));
+ },
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const { Files } = this.getDBM();
+
+ let id;
+ if (parseInt(data.sourcetype, 10) === 1) {
+ id = this.evalMessage(data.source2, cache);
+ } else {
+ id = data.source;
+ }
+ if (!id) return console.log('Enter a Command/Event ID!');
+
+ let name;
+ if (parseInt(data.sourcetype, 10) === 2) {
+ name = this.evalMessage(data.source3, cache);
+ } else {
+ name = data.source;
+ }
+ if (!name) return console.log('Enter a Command/Event name!');
+
+ let actions;
+ const allData = Files.data.commands.concat(Files.data.events);
+ for (let i = 0; i < allData.length; i++) {
+ if (parseInt(data.sourcetype, 10) === 0) {
+ if (allData[i] && allData[i]._id === id) {
+ actions = allData[i].actions;
+ break;
+ }
+ }
+ if (parseInt(data.sourcetype, 10) === 1) {
+ if (allData[i] && allData[i]._id === id) {
+ actions = allData[i].actions;
+ break;
+ }
+ }
+ if (parseInt(data.sourcetype, 10) === 2) {
+ if (allData[i] && allData[i].name === name) {
+ actions = allData[i].actions;
+ break;
+ }
+ }
+ }
+ if (!actions) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const waitForCompletion = data.type === 'true';
+ let callback = null;
+ if (waitForCompletion) {
+ callback = () => this.callNextAction(cache);
+ }
+ this.executeSubActions(actions, cache, callback);
+ if (!waitForCompletion) {
+ this.callNextAction(cache);
+ }
+ },
+
+ mod() {},
+};
diff --git a/actions/canvas_create_primitive_MOD.js b/actions/canvas_create_primitive_MOD.js
new file mode 100644
index 000000000..27ba37851
--- /dev/null
+++ b/actions/canvas_create_primitive_MOD.js
@@ -0,0 +1,189 @@
+module.exports = {
+ name: 'Canvas Create Shape',
+ section: 'Image Editing',
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ subtitle(data) {
+ const info = parseInt(data.info, 10);
+ switch (info) {
+ case 0:
+ return data.color ? `Create Circle with Color ${data.color}` : 'No color circle has been created';
+ case 1:
+ return data.color ? `Create Rectangle with Color ${data.color}` : 'No color rectangle has been created';
+ case 2:
+ return data.color ? `Create Triangle with Color ${data.color}` : 'No color triangle has been created';
+ case 3:
+ return data.color ? `Create Hexagon with Color ${data.color}` : 'No color hexagon has been created';
+ case 4:
+ return data.color ? `Create Pentagon with Color ${data.color}` : 'No color pentagon has been created';
+ case 5:
+ return data.color ? `Create Ellipse with Color ${data.color}` : 'No color ellipse has been created';
+ case 6:
+ return data.color ? `Create Star with Color ${data.color}` : 'No color star has been created';
+ default:
+ return '';
+ }
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, 'Image'];
+ },
+
+ fields: ['shapeType', 'width', 'height', 'color', 'storage', 'varName'],
+
+ html() {
+ return `
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // region Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // region Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const prefix = this.evalMessage(data.newPrefix, cache) || '!';
+
+ if (prefix) {
+ this.getDBM().Files.data.settings.tag = prefix;
+ this.getDBM().Files.saveData('settings');
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // region Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/change_server.js b/actions/change_server.js
new file mode 100644
index 000000000..8c0030809
--- /dev/null
+++ b/actions/change_server.js
@@ -0,0 +1,102 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Change Server',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Server Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getServerText(data.server, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return ``;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = await this.getServerFromData(data.server, data.varName, cache);
+ if (server) {
+ cache.server = server;
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/channel_command_restriction_MOD.js b/actions/channel_command_restriction_MOD.js
new file mode 100644
index 000000000..0cb4637e7
--- /dev/null
+++ b/actions/channel_command_restriction_MOD.js
@@ -0,0 +1,85 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Channel Command Restriction',
+ displayName: 'Channel Restriction',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Moderation',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getChannelText(data.channel, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'varName', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ `;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const fs = require('fs');
+ const data = cache.actions[cache.index];
+
+ const filePath = this.evalMessage(data.filePath, cache);
+
+ const fileExists = fs.existsSync(filePath);
+
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(filePath, storage, varName, cache);
+
+ this.executeResults(fileExists, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/check_if_member_has_role.js b/actions/check_if_member_has_role.js
new file mode 100644
index 000000000..56581b7aa
--- /dev/null
+++ b/actions/check_if_member_has_role.js
@@ -0,0 +1,154 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Check If Member has Role',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Conditions',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'role', 'varName2', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ //
+ // Before the fields from existing data in this action are applied
+ // to the user interface, this function is called if it exists.
+ // The existing data is provided, and a modified version can be
+ // returned. The returned version will be used if provided.
+ // This is to help provide compatibility with older versions of the action.
+ //
+ // The "formatters" argument contains built-in functions for formatting
+ // the data required for official DBM action compatibility.
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ const role = await this.getRoleFromData(data.role, data.varName2, cache);
+
+ let result = false;
+ if (role) {
+ if (Array.isArray(member)) {
+ result = member.every((mem) => mem?.roles?.cache.has(role.id) ?? false);
+ } else if (member?.roles) {
+ result = member.roles.cache.has(role.id);
+ }
+ }
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/check_if_member_has_role_MOD.js b/actions/check_if_member_has_role_MOD.js
new file mode 100644
index 000000000..dcb3af1f6
--- /dev/null
+++ b/actions/check_if_member_has_role_MOD.js
@@ -0,0 +1,147 @@
+module.exports = {
+ name: 'Check If Member has Role MOD',
+ displayName: 'Check If Member has Role',
+ section: 'Conditions',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data) {
+ const results = [
+ 'Continue Actions',
+ 'Stop Action Sequence',
+ 'Jump To Action',
+ 'Jump Forward Actions',
+ 'Jump to Anchor',
+ ];
+ return `If True: ${results[parseInt(data.iftrue, 10)]} ~ If False: ${results[parseInt(data.iffalse, 10)]}`;
+ },
+
+ fields: ['member', 'varName', 'role', 'varName2', 'iftrue', 'iftrueVal', 'iffalse', 'iffalseVal'],
+
+ html(isEvent, data) {
+ return `
+
`;
+ },
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onComparisonChanged = function (event) {
+ if (event.value === '0') {
+ document.getElementById('directValue').style.display = 'none';
+ document.getElementById('containerxin').style.display = 'none';
+ } else {
+ document.getElementById('directValue').style.display = null;
+ document.getElementById('containerxin').style.display = 'none';
+ }
+ if (event.value === '15') {
+ document.getElementById('directValue').style.display = null;
+ document.getElementById('containerxin').style.display = null;
+ document.getElementById('containerxin2').style.display = 'none';
+ }
+ if (
+ event.value === '16' ||
+ event.value === '19' ||
+ event.value === '20' ||
+ event.value === '21' ||
+ event.value === '22' ||
+ event.value === '23' ||
+ event.value === '24' ||
+ event.value === '25'
+ ) {
+ document.getElementById('directValue').style.display = 'none';
+ document.getElementById('containerxin').style.display = 'none';
+ }
+ };
+
+ glob.onComparisonChanged(document.getElementById('comparison'));
+ },
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const val1 = this.evalMessage(data.storage, cache);
+ let result = false;
+ const compare = parseInt(data.comparison, 10);
+ let val2 = data.value;
+ const val3 = data.value2;
+ if (compare !== 6) val2 = this.evalIfPossible(val2, cache);
+ switch (compare) {
+ case 0:
+ result = val1 !== undefined;
+ break;
+ case 1:
+ result = val1 === val2;
+ break;
+ case 2:
+ result = val1 === val2;
+ break;
+ case 3:
+ result = val1 < val2;
+ break;
+ case 4:
+ result = val1 > val2;
+ break;
+ case 5:
+ if (typeof val1?.toString().includes === 'function') {
+ result = val1.toString().includes(val2);
+ }
+ break;
+ case 6:
+ result = Boolean(val1.toString().match(new RegExp(`^${val2}$`, 'i')));
+ break;
+ case 7:
+ result = Boolean(val1.toString().length > val2);
+ break;
+ case 8:
+ result = Boolean(val1.toString().length < val2);
+ break;
+ case 9:
+ result = Boolean(val1.toString().length === val2);
+ break;
+ case 10:
+ result = val1.toString().startsWith(val2);
+ break;
+ case 11:
+ result = val1.toString().endsWith(val2);
+ break;
+ case 12:
+ result = Boolean(val1 >= val2);
+ break;
+ case 13:
+ result = Boolean(val1 <= val2);
+ break;
+ case 14:
+ result = Boolean(val1.toString().match(new RegExp(val2)));
+ break;
+ case 15:
+ var numberj = val1.toString();
+ if (numberj >= val2 && val1 <= val3) {
+ result = numberj;
+ }
+ break;
+ case 16:
+ const conditions = [
+ 'Ä',
+ 'Å',
+ 'Á',
+ 'Â',
+ 'À',
+ 'Ã',
+ 'Ā',
+ 'Ă',
+ 'Ą',
+ 'ā',
+ 'ă',
+ 'ą',
+ 'ä',
+ 'á',
+ 'â',
+ 'à',
+ 'ã',
+ 'É',
+ 'Ê',
+ 'Ë',
+ 'È',
+ 'Ė',
+ 'Ę',
+ 'Ě',
+ 'Ĕ',
+ 'Ē',
+ 'ė',
+ 'ę',
+ 'ě',
+ 'ĕ',
+ 'ē',
+ 'é',
+ 'ê',
+ 'ë',
+ 'è',
+ 'Í',
+ 'Î',
+ 'Ï',
+ 'Ì',
+ 'İ',
+ 'Į',
+ 'Ī',
+ 'ı',
+ 'į',
+ 'ī',
+ 'í',
+ 'î',
+ 'ï',
+ 'ì',
+ 'Ö',
+ 'Ó',
+ 'Ô',
+ 'Ò',
+ 'Õ',
+ 'Ő',
+ 'Ō',
+ 'ő',
+ 'ō',
+ 'ö',
+ 'ó',
+ 'ô',
+ 'ò',
+ 'õ',
+ 'Ü',
+ 'Ú',
+ 'Û',
+ 'Ų',
+ 'Ű',
+ 'Ů',
+ 'Ū',
+ 'ų',
+ 'ű',
+ 'ů',
+ 'ū',
+ 'ü',
+ 'ú',
+ 'û',
+ 'ù',
+ 'Ç',
+ 'Ć',
+ 'Č',
+ 'ç',
+ 'ć',
+ 'č',
+ 'Ñ',
+ 'Ň',
+ 'Ņ',
+ 'Ń',
+ 'ñ',
+ 'ň',
+ 'ņ',
+ 'ń',
+ 'Ÿ',
+ 'Ý',
+ 'ý',
+ 'Ź',
+ 'Ż',
+ 'Ž',
+ 'ź',
+ 'ż',
+ 'ž',
+ 'Ł',
+ 'Ľ',
+ 'Ļ',
+ 'Ĺ',
+ 'ł',
+ 'ľ',
+ 'ĺ',
+ 'Ķ',
+ 'ķ',
+ 'Ģ',
+ 'Ğ',
+ 'ģ',
+ 'ğ',
+ 'Ď',
+ 'ď',
+ 'Ś',
+ 'Š',
+ 'Ş',
+ 'ś',
+ 'š',
+ 'ş',
+ 'Ť',
+ 'Ț',
+ 'Ţ',
+ 'ť',
+ 'ț',
+ 'ţ',
+ 'Ŕ',
+ 'Ř',
+ 'ŕ',
+ 'ř',
+ ];
+ result = conditions.some((el) => val1.includes(el));
+ break;
+ case 17:
+ const conditionsX = val2;
+ result = conditionsX.some((els) => val1.includes(els));
+ break;
+ case 18:
+ const conditionsZ = val2;
+ result = conditionsZ.some((elz) => val1 === elz);
+ break;
+ case 19:
+ result = val1 % 2 === 0;
+ break;
+ case 20:
+ result = val1 % 2 === 1;
+ break;
+ case 21:
+ result = Boolean(!isNaN(parseFloat(val1.toString().replace(',', '.'))));
+ break;
+ case 22:
+ result = Boolean(Array.isArray(val1));
+ break;
+ case 23:
+ const isImageUrl = require('is-image-url');
+ result = isImageUrl(val1);
+ break;
+ case 24:
+ result = typeof val1 === 'string';
+ break;
+ case 25:
+ const isUrl = require('is-url');
+ result = isUrl(val1);
+ }
+
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ mod() {},
+};
diff --git a/actions/check_is_bot_in_voice_channel.js b/actions/check_is_bot_in_voice_channel.js
new file mode 100644
index 000000000..68f7e2de9
--- /dev/null
+++ b/actions/check_is_bot_in_voice_channel.js
@@ -0,0 +1,135 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Check is Bot in Voice Channel',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Conditions',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.1.7', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return ``;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ //
+ // Before the fields from existing data in this action are applied
+ // to the user interface, this function is called if it exists.
+ // The existing data is provided, and a modified version can be
+ // returned. The returned version will be used if provided.
+ // This is to help provide compatibility with older versions of the action.
+ //
+ // The "formatters" argument contains built-in functions for formatting
+ // the data required for official DBM action compatibility.
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const Audio = this.getDBM().Audio;
+ const result = cache.server ? Audio.getSubscription(cache.server) : false;
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/check_is_bot_in_voice_channel.ts b/actions/check_is_bot_in_voice_channel.ts
new file mode 100644
index 000000000..21077f301
--- /dev/null
+++ b/actions/check_is_bot_in_voice_channel.ts
@@ -0,0 +1,144 @@
+import { Bot, Actions, ActionsCache } from '../bot.ts';
+import Audio from '../bot_audio.ts';
+import { Action, ActionMod } from '../types.ts';
+
+export default {
+ //---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ //---------------------------------------------------------------------
+
+ name: 'Check is Bot in Voice Channel',
+
+ //---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ //---------------------------------------------------------------------
+
+ section: 'Conditions',
+
+ //---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ //---------------------------------------------------------------------
+
+ subtitle(data: any, presets: any) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ //---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ //---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ //---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ //---------------------------------------------------------------------
+
+ fields: ['branch'],
+
+ //---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //---------------------------------------------------------------------
+
+ html(isEvent: boolean, data: any) {
+ return ``;
+ },
+
+ //---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ //
+ // Before the fields from existing data in this action are applied
+ // to the user interface, this function is called if it exists.
+ // The existing data is provided, and a modified version can be
+ // returned. The returned version will be used if provided.
+ // This is to help provide compatibility with older versions of the action.
+ //
+ // The "formatters" argument contains built-in functions for formatting
+ // the data required for official DBM action compatibility.
+ //---------------------------------------------------------------------
+
+ preInit(data: any, formatters: any) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ //---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ //---------------------------------------------------------------------
+
+ init() {},
+
+ //---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ //---------------------------------------------------------------------
+
+ async action(this: typeof Actions, cache: ActionsCache) {
+ const data = cache.actions[cache.index] as Action & { branch: any };
+ let result: boolean = false;
+ if (cache.server) {
+ result = (await Audio.getSubscription(cache.server)) !== null;
+ if (!result) {
+ result = !!cache.server.members.me?.voice.channelId;
+ }
+ }
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ //---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ //---------------------------------------------------------------------
+
+ modInit(this: typeof Bot, data: any) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ //---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ //---------------------------------------------------------------------
+
+ mod() {},
+} satisfies ActionMod;
diff --git a/actions/check_member_data.js b/actions/check_member_data.js
new file mode 100644
index 000000000..bf0e243eb
--- /dev/null
+++ b/actions/check_member_data.js
@@ -0,0 +1,212 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Check Member Data',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Data',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'dataName', 'comparison', 'value', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Data Name
+
+
+
+ Comparison Type
+
+
+
+
+
+
+
+ Value to Compare to
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ //
+ // Before the fields from existing data in this action are applied
+ // to the user interface, this function is called if it exists.
+ // The existing data is provided, and a modified version can be
+ // returned. The returned version will be used if provided.
+ // This is to help provide compatibility with older versions of the action.
+ //
+ // The "formatters" argument contains built-in functions for formatting
+ // the data required for official DBM action compatibility.
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ let result = false;
+ if (member?.data) {
+ const dataName = this.evalMessage(data.dataName, cache);
+ const val1 = member.data(dataName);
+ const compare = parseInt(data.comparison, 10);
+ let val2 = this.evalMessage(data.value, cache);
+ if (compare !== 6) val2 = this.eval(val2, cache);
+ if (val2 === false) val2 = this.evalMessage(data.value, cache);
+ switch (compare) {
+ case 0:
+ result = val1 !== undefined;
+ break;
+ case 1:
+ result = val1 === val2;
+ break;
+ case 2:
+ result = val1 === val2;
+ break;
+ case 3:
+ result = val1 < val2;
+ break;
+ case 4:
+ result = val1 > val2;
+ break;
+ case 5:
+ if (typeof val1.includes === 'function') {
+ result = val1.includes(val2);
+ }
+ break;
+ case 6:
+ result = Boolean(val1.match(new RegExp(`^${val2}$`, 'i')));
+ break;
+ case 7:
+ result = val1 >= val2;
+ break;
+ case 8:
+ result = val1 <= val2;
+ break;
+ }
+ }
+
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/check_member_level_MOD.js b/actions/check_member_level_MOD.js
new file mode 100644
index 000000000..4555bc2a0
--- /dev/null
+++ b/actions/check_member_level_MOD.js
@@ -0,0 +1,161 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Check Member Level',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Economy',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'dataName', 'comparison', 'value', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ `;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ let result = false;
+ if (member?.data) {
+ const dataName = this.evalMessage(data.dataName, cache);
+ const val1 = member.data(dataName);
+ const compare = parseInt(data.comparison, 10);
+ let val2 = this.evalMessage(data.value, cache);
+ if (compare !== 6) val2 = this.eval(val2, cache);
+ if (val2 === false) val2 = this.evalMessage(data.value, cache);
+ switch (compare) {
+ case 0:
+ result = val1 !== undefined;
+ break;
+ case 1:
+ result = val1 === val2;
+ break;
+ case 2:
+ result = val1 === val2;
+ break;
+ case 3:
+ result = val1 < val2;
+ break;
+ case 4:
+ result = val1 > val2;
+ break;
+ case 5:
+ if (typeof val1.includes === 'function') {
+ result = val1.includes(val2);
+ }
+ break;
+ case 6:
+ result = Boolean(val1.match(new RegExp(`^${val2}$`, 'i')));
+ break;
+ }
+ }
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/check_member_permissions.js b/actions/check_member_permissions.js
new file mode 100644
index 000000000..545441a4b
--- /dev/null
+++ b/actions/check_member_permissions.js
@@ -0,0 +1,156 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Check Member Permissions',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Conditions',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'permission', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Permission
+
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ //
+ // Before the fields from existing data in this action are applied
+ // to the user interface, this function is called if it exists.
+ // The existing data is provided, and a modified version can be
+ // returned. The returned version will be used if provided.
+ // This is to help provide compatibility with older versions of the action.
+ //
+ // The "formatters" argument contains built-in functions for formatting
+ // the data required for official DBM action compatibility.
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ let result = false;
+ if (member) {
+ result = member.permissions.has([data.permission]);
+ }
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/check_member_perms_MOD.js b/actions/check_member_perms_MOD.js
new file mode 100644
index 000000000..35c9e30fb
--- /dev/null
+++ b/actions/check_member_perms_MOD.js
@@ -0,0 +1,210 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Check Member Permissions',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Conditions',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'permission', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ //
+ // Before the fields from existing data in this action are applied
+ // to the user interface, this function is called if it exists.
+ // The existing data is provided, and a modified version can be
+ // returned. The returned version will be used if provided.
+ // This is to help provide compatibility with older versions of the action.
+ //
+ // The "formatters" argument contains built-in functions for formatting
+ // the data required for official DBM action compatibility.
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ let result = false;
+ if (member) {
+ result = member.permissions.has([data.permission]);
+ }
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/check_member_warnings.js b/actions/check_member_warnings.js
new file mode 100644
index 000000000..704a44f51
--- /dev/null
+++ b/actions/check_member_warnings.js
@@ -0,0 +1,139 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Check Member Warnings',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Conditions',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)} - ${data.comparison} ${data.warningCount}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: null,
+ authorUrl: 'https://github.com/master3395/dbm-mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'comparison', 'warningCount', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Comparison
+
+
+
+
+ Warning Count
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const member = this.getMemberFromData(data.member, data.varName, cache);
+
+ if (!member) {
+ this.executeResults(false, data?.branch ?? data, cache);
+ return;
+ }
+
+ const memberData = this.getMemberData(member, cache.server);
+ const warningCount = memberData.warnings ? memberData.warnings.length : 0;
+ const compare = parseInt(this.evalMessage(data.warningCount, cache), 10) || 0;
+ const comparison = parseInt(data.comparison, 10);
+
+ let result = false;
+ switch (comparison) {
+ case 0:
+ result = warningCount === compare;
+ break;
+ case 1:
+ result = warningCount > compare;
+ break;
+ case 2:
+ result = warningCount < compare;
+ break;
+ case 3:
+ result = warningCount >= compare;
+ break;
+ case 4:
+ result = warningCount <= compare;
+ break;
+ }
+
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/check_message_data.js b/actions/check_message_data.js
new file mode 100644
index 000000000..daecbe15a
--- /dev/null
+++ b/actions/check_message_data.js
@@ -0,0 +1,196 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Check Message Data',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Data',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['message', 'varName', 'dataName', 'comparison', 'value', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Data Name
+
+
+
+ Comparison Type
+
+
+
+
+
+
+
+ Value to Compare to
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const message = await this.getMessageFromData(data.message, data.varName, cache);
+
+ let result = false;
+ if (message?.data) {
+ const dataName = this.evalMessage(data.dataName, cache);
+ const val1 = message.data(dataName);
+ const compare = parseInt(data.comparison, 10);
+ let val2 = this.evalMessage(data.value, cache);
+ if (compare !== 6) val2 = this.eval(val2, cache);
+ if (val2 === false) val2 = this.evalMessage(data.value, cache);
+ switch (compare) {
+ case 0:
+ result = val1 !== undefined;
+ break;
+ case 1:
+ result = val1 === val2;
+ break;
+ case 2:
+ result = val1 === val2;
+ break;
+ case 3:
+ result = val1 < val2;
+ break;
+ case 4:
+ result = val1 > val2;
+ break;
+ case 5:
+ if (typeof val1.includes === 'function') {
+ result = val1.includes(val2);
+ }
+ break;
+ case 6:
+ result = Boolean(val1.match(new RegExp(`^${val2}$`, 'i')));
+ break;
+ case 7:
+ result = val1 >= val2;
+ break;
+ case 8:
+ result = val1 <= val2;
+ break;
+ }
+ }
+
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/check_parameters.js b/actions/check_parameters.js
new file mode 100644
index 000000000..82fba7428
--- /dev/null
+++ b/actions/check_parameters.js
@@ -0,0 +1,205 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Command Only
+ //
+ // If this is 'true', then this will only be available for commands.
+ // ---------------------------------------------------------------------
+
+ commandOnly: true,
+
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Check Parameters',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Conditions',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['condition', 'comparison', 'value', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Condition
+
+
+
+ Comparison
+
+
+
+ Number
+
+
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ //
+ // Before the fields from existing data in this action are applied
+ // to the user interface, this function is called if it exists.
+ // The existing data is provided, and a modified version can be
+ // returned. The returned version will be used if provided.
+ // This is to help provide compatibility with older versions of the action.
+ //
+ // The "formatters" argument contains built-in functions for formatting
+ // the data required for official DBM action compatibility.
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const msg = cache.msg;
+ let result = false;
+ if (msg && msg.content.length > 0) {
+ const condition = parseInt(data.condition, 10);
+ let value = 0;
+ switch (condition) {
+ case 0:
+ value = msg.content.split(/\s+/).length - 1;
+ break;
+ case 1:
+ value = msg.mentions.members.size;
+ break;
+ case 2:
+ value = msg.mentions.channels.size;
+ break;
+ case 3:
+ value = msg.mentions.roles.size;
+ break;
+ }
+ const comparison = parseInt(data.comparison, 10);
+ const value2 = parseInt(data.value, 10);
+ switch (comparison) {
+ case 0:
+ result = value === value2;
+ break;
+ case 1:
+ result = value < value2;
+ break;
+ case 2:
+ result = value > value2;
+ break;
+ }
+ }
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/check_parameters_MOD.js b/actions/check_parameters_MOD.js
new file mode 100644
index 000000000..a9c2a58c7
--- /dev/null
+++ b/actions/check_parameters_MOD.js
@@ -0,0 +1,219 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Command Only
+ //
+ // If this is 'true', then this will only be available for commands.
+ // ---------------------------------------------------------------------
+
+ commandOnly: true,
+
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Check Parameters MOD',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Conditions',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/check_parameters_MOD.js',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['condition', 'comparison', 'value', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Condition
+
+
+
+ Comparison
+
+
+
+ Number
+
+
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ //
+ // Before the fields from existing data in this action are applied
+ // to the user interface, this function is called if it exists.
+ // The existing data is provided, and a modified version can be
+ // returned. The returned version will be used if provided.
+ // This is to help provide compatibility with older versions of the action.
+ //
+ // The "formatters" argument contains built-in functions for formatting
+ // the data required for official DBM action compatibility.
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const msg = cache.msg;
+ let result = false;
+ if (msg && msg.content.length > 0) {
+ const condition = parseInt(data.condition, 10);
+ let value = 0;
+ switch (condition) {
+ case 0:
+ value = msg.content.split(/\s+/).length - 1;
+ break;
+ case 1:
+ value = msg.mentions.members.size;
+ break;
+ case 2:
+ value = msg.mentions.channels.size;
+ break;
+ case 3:
+ value = msg.mentions.roles.size;
+ break;
+ }
+ const comparison = parseInt(data.comparison, 10);
+ const value2 = parseInt(data.value, 10);
+ switch (comparison) {
+ case 0:
+ result = value === value2;
+ break;
+ case 1:
+ result = value < value2;
+ break;
+ case 2:
+ result = value > value2;
+ break;
+ case 3:
+ result = value <= value2;
+ break;
+ case 4:
+ result = value >= value2;
+ break;
+ }
+ }
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/check_role_perms_MOD.js b/actions/check_role_perms_MOD.js
new file mode 100644
index 000000000..4dd39421a
--- /dev/null
+++ b/actions/check_role_perms_MOD.js
@@ -0,0 +1,164 @@
+module.exports = {
+ name: 'Check Role Permissions',
+ section: 'Conditions',
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ subtitle(data, presets) {
+ return `${presets.getRoleText(data.role, data.varName)} has ${data.permission}?`;
+ },
+
+ fields: ['role', 'varName', 'permission', 'branch'],
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ////////////////////////////
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ //
+ // Before the fields from existing data in this action are applied
+ // to the user interface, this function is called if it exists.
+ // The existing data is provided, and a modified version can be
+ // returned. The returned version will be used if provided.
+ // This is to help provide compatibility with older versions of the action.
+ //
+ // The "formatters" argument contains built-in functions for formatting
+ // the data required for official DBM action compatibility.
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const role = await this.getRoleFromData(data.role, data.varName, cache);
+ let result = false;
+ if (role) {
+ result = role.permissions.has([data.permission]);
+ }
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ // ////////////////////////////
+
+ mod() {},
+};
diff --git a/actions/check_server_data.js b/actions/check_server_data.js
new file mode 100644
index 000000000..cdff688db
--- /dev/null
+++ b/actions/check_server_data.js
@@ -0,0 +1,213 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Check Server Data',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Data',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName', 'dataName', 'comparison', 'value', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Data Name
+
+
+
+ Comparison Type
+
+
+
+
+
+
+
+ Value to Compare to
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ //
+ // Before the fields from existing data in this action are applied
+ // to the user interface, this function is called if it exists.
+ // The existing data is provided, and a modified version can be
+ // returned. The returned version will be used if provided.
+ // This is to help provide compatibility with older versions of the action.
+ //
+ // The "formatters" argument contains built-in functions for formatting
+ // the data required for official DBM action compatibility.
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = await this.getServerFromData(data.server, data.varName, cache);
+
+ let result = false;
+ if (server?.data) {
+ const dataName = this.evalMessage(data.dataName, cache);
+ const val1 = server.data(dataName);
+ const compare = parseInt(data.comparison, 10);
+ let val2 = this.evalMessage(data.value, cache);
+ if (compare !== 6) val2 = this.eval(val2, cache);
+ if (val2 === false) val2 = this.evalMessage(data.value, cache);
+ switch (compare) {
+ case 0:
+ result = val1 !== undefined;
+ break;
+ case 1:
+ result = val1 === val2;
+ break;
+ case 2:
+ result = val1 === val2;
+ break;
+ case 3:
+ result = val1 < val2;
+ break;
+ case 4:
+ result = val1 > val2;
+ break;
+ case 5:
+ if (typeof val1.includes === 'function') {
+ result = val1.includes(val2);
+ }
+ break;
+ case 6:
+ result = Boolean(val1.match(new RegExp(`^${val2}$`, 'i')));
+ break;
+ case 7:
+ result = val1 >= val2;
+ break;
+ case 8:
+ result = val1 <= val2;
+ break;
+ }
+ }
+
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/check_variable.js b/actions/check_variable.js
new file mode 100644
index 000000000..9b99c5c08
--- /dev/null
+++ b/actions/check_variable.js
@@ -0,0 +1,242 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Check Variable',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Conditions',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'comparison', 'value', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Comparison Type
+
+
+
+ Value to Compare to
+
+
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ //
+ // Before the fields from existing data in this action are applied
+ // to the user interface, this function is called if it exists.
+ // The existing data is provided, and a modified version can be
+ // returned. The returned version will be used if provided.
+ // This is to help provide compatibility with older versions of the action.
+ //
+ // The "formatters" argument contains built-in functions for formatting
+ // the data required for official DBM action compatibility.
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onComparisonChanged = function (event) {
+ if (event.value === '0') {
+ document.getElementById('directValue').style.display = 'none';
+ } else {
+ document.getElementById('directValue').style.display = null;
+ }
+ };
+
+ glob.onComparisonChanged(document.getElementById('comparison'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const type = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const variable = this.getVariable(type, varName, cache);
+ let result = false;
+
+ const val1 = variable;
+ const compare = parseInt(data.comparison, 10);
+ let val2 = data.value;
+ if (compare !== 6) val2 = this.evalIfPossible(val2, cache);
+ switch (compare) {
+ case 0:
+ result = val1 !== undefined;
+ break;
+ case 1:
+ result = val1 === val2;
+ break;
+ case 2:
+ result = val1 === val2;
+ break;
+ case 3:
+ result = val1 < val2;
+ break;
+ case 4:
+ result = val1 > val2;
+ break;
+ case 5:
+ if (typeof val1?.includes === 'function') {
+ result = val1.includes(val2);
+ }
+ break;
+ case 6:
+ if (typeof val1?.match === 'function') {
+ result = Boolean(val1.match(new RegExp(`^${val2}$`, 'i')));
+ }
+ break;
+ case 7:
+ if (typeof val1?.startsWith === 'function') {
+ result = Boolean(val1.startsWith(val2));
+ }
+ break;
+ case 8:
+ if (typeof val1?.endsWith === 'function') {
+ result = Boolean(val1.endsWith(val2));
+ }
+ break;
+ case 9:
+ if (typeof val1?.length === 'number') {
+ result = Boolean(val1.length === val2);
+ }
+ break;
+ case 10:
+ if (typeof val1?.length === 'number') {
+ result = Boolean(val1.length > val2);
+ }
+ break;
+ case 11:
+ if (typeof val1?.length === 'number') {
+ result = Boolean(val1.length < val2);
+ }
+ break;
+ }
+
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/check_variable_MOD.js b/actions/check_variable_MOD.js
new file mode 100644
index 000000000..245166e5a
--- /dev/null
+++ b/actions/check_variable_MOD.js
@@ -0,0 +1,357 @@
+module.exports = {
+ name: 'Check Variable MOD',
+ section: 'Conditions',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data, presets) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ fields: ['storage', 'varName', 'comparison', 'value', 'value2', 'branch'],
+
+ html(isEvent, data) {
+ return `
+
Version 1.4
+
DBM-Extended
+
+
+
+
+
+
+ Type of comparison
+
+
+
+ Value to compare
+
+
+ and
+
+
+
+
+
+
+
+
+
+
+
`;
+ },
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onComparisonChanged = function (event) {
+ if (event.value === '0') {
+ document.getElementById('directValue').style.display = 'none';
+ document.getElementById('containerxin').style.display = 'none';
+ } else {
+ document.getElementById('directValue').style.display = null;
+ document.getElementById('containerxin').style.display = 'none';
+ }
+ if (event.value === '15') {
+ document.getElementById('directValue').style.display = null;
+ document.getElementById('containerxin').style.display = null;
+ }
+ if (
+ event.value === '16' ||
+ event.value === '19' ||
+ event.value === '20' ||
+ event.value === '21' ||
+ event.value === '22' ||
+ event.value === '23' ||
+ event.value === '24' ||
+ event.value === '25'
+ ) {
+ document.getElementById('directValue').style.display = 'none';
+ document.getElementById('containerxin').style.display = 'none';
+ }
+ };
+
+ glob.onComparisonChanged(document.getElementById('comparison'));
+ },
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const type = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const variable = this.getVariable(type, varName, cache);
+ let result = false;
+
+ const val1 = variable;
+ const compare = parseInt(data.comparison, 10);
+ let val2 = this.evalMessage(data.value, cache);
+ const val3 = this.evalMessage(data.value2, cache);
+ if (compare !== 6) val2 = this.evalIfPossible(val2, cache);
+ switch (compare) {
+ case 0:
+ result = val1 !== undefined;
+ break;
+ case 1:
+ result = val1 === val2;
+ break;
+ case 2:
+ result = val1 === val2;
+ break;
+ case 3:
+ result = val1 < val2;
+ break;
+ case 4:
+ result = val1 > val2;
+ break;
+ case 5:
+ if (typeof val1?.toString().includes === 'function') {
+ result = val1.toString().includes(val2);
+ }
+ break;
+ case 6:
+ result = Boolean(val1.toString().match(new RegExp(`^${val2}$`, 'i')));
+ break;
+ case 7:
+ result = Boolean(val1.toString().length > val2);
+ break;
+ case 8:
+ result = Boolean(val1.toString().length < val2);
+ break;
+ case 9:
+ result = Boolean(val1.toString().length === val2);
+ break;
+ case 10:
+ result = val1.toString().startsWith(val2);
+ break;
+ case 11:
+ result = val1.toString().endsWith(val2);
+ break;
+ case 12:
+ result = Boolean(val1 >= val2);
+ break;
+ case 13:
+ result = Boolean(val1 <= val2);
+ break;
+ case 14:
+ result = Boolean(val1.toString().match(new RegExp(val2)));
+ break;
+ case 15:
+ var numberj = val1.toString();
+ if (numberj >= val2 && val1 <= val3) {
+ result = numberj;
+ }
+ break;
+ case 16:
+ const conditions = [
+ 'Ä',
+ 'Å',
+ 'Á',
+ 'Â',
+ 'À',
+ 'Ã',
+ 'Ā',
+ 'Ă',
+ 'Ą',
+ 'ā',
+ 'ă',
+ 'ą',
+ 'ä',
+ 'á',
+ 'â',
+ 'à',
+ 'ã',
+ 'É',
+ 'Ê',
+ 'Ë',
+ 'È',
+ 'Ė',
+ 'Ę',
+ 'Ě',
+ 'Ĕ',
+ 'Ē',
+ 'ė',
+ 'ę',
+ 'ě',
+ 'ĕ',
+ 'ē',
+ 'é',
+ 'ê',
+ 'ë',
+ 'è',
+ 'Í',
+ 'Î',
+ 'Ï',
+ 'Ì',
+ 'İ',
+ 'Į',
+ 'Ī',
+ 'ı',
+ 'į',
+ 'ī',
+ 'í',
+ 'î',
+ 'ï',
+ 'ì',
+ 'Ö',
+ 'Ó',
+ 'Ô',
+ 'Ò',
+ 'Õ',
+ 'Ő',
+ 'Ō',
+ 'ő',
+ 'ō',
+ 'ö',
+ 'ó',
+ 'ô',
+ 'ò',
+ 'õ',
+ 'Ü',
+ 'Ú',
+ 'Û',
+ 'Ų',
+ 'Ű',
+ 'Ů',
+ 'Ū',
+ 'ų',
+ 'ű',
+ 'ů',
+ 'ū',
+ 'ü',
+ 'ú',
+ 'û',
+ 'ù',
+ 'Ç',
+ 'Ć',
+ 'Č',
+ 'ç',
+ 'ć',
+ 'č',
+ 'Ñ',
+ 'Ň',
+ 'Ņ',
+ 'Ń',
+ 'ñ',
+ 'ň',
+ 'ņ',
+ 'ń',
+ 'Ÿ',
+ 'Ý',
+ 'ý',
+ 'Ź',
+ 'Ż',
+ 'Ž',
+ 'ź',
+ 'ż',
+ 'ž',
+ 'Ł',
+ 'Ľ',
+ 'Ļ',
+ 'Ĺ',
+ 'ł',
+ 'ľ',
+ 'ĺ',
+ 'Ķ',
+ 'ķ',
+ 'Ģ',
+ 'Ğ',
+ 'ģ',
+ 'ğ',
+ 'Ď',
+ 'ď',
+ 'Ś',
+ 'Š',
+ 'Ş',
+ 'ś',
+ 'š',
+ 'ş',
+ 'Ť',
+ 'Ț',
+ 'Ţ',
+ 'ť',
+ 'ț',
+ 'ţ',
+ 'Ŕ',
+ 'Ř',
+ 'ŕ',
+ 'ř',
+ ];
+ result = conditions.some((el) => val1.includes(el));
+ break;
+ case 17:
+ const conditionsX = val2;
+ result = conditionsX.some((els) => val1.includes(els));
+ break;
+ case 18:
+ const conditionsZ = val2;
+ result = conditionsZ.some((elz) => val1 === elz);
+ break;
+ case 19:
+ result = val1 % 2 === 0;
+ break;
+ case 20:
+ result = val1 % 2 === 1;
+ break;
+ case 21:
+ result = Boolean(!isNaN(parseFloat(val1.toString().replace(',', '.'))));
+ break;
+ case 22:
+ result = Boolean(Array.isArray(val1));
+ break;
+ case 23:
+ const isImageUrl = require('is-image-url');
+ result = isImageUrl(val1);
+ break;
+ case 24:
+ result = typeof val1 === 'string';
+ break;
+ case 25:
+ const isUrl = require('is-url');
+ result = isUrl(val1);
+ }
+
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ mod() {},
+};
diff --git a/actions/check_variable_type.js b/actions/check_variable_type.js
new file mode 100644
index 000000000..3494a34bc
--- /dev/null
+++ b/actions/check_variable_type.js
@@ -0,0 +1,209 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Check Variable Type',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Conditions',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getConditionsText(data)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'comparison', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Variable Type to Check
+
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ //
+ // Before the fields from existing data in this action are applied
+ // to the user interface, this function is called if it exists.
+ // The existing data is provided, and a modified version can be
+ // returned. The returned version will be used if provided.
+ // This is to help provide compatibility with older versions of the action.
+ //
+ // The "formatters" argument contains built-in functions for formatting
+ // the data required for official DBM action compatibility.
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const type = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const variable = this.getVariable(type, varName, cache);
+ let result = false;
+ if (variable) {
+ const DiscordJS = this.getDBM().DiscordJS;
+ const compare = parseInt(data.comparison, 10);
+ switch (compare) {
+ case 0:
+ result = typeof variable === 'number';
+ break;
+ case 1:
+ result = typeof variable === 'string';
+ break;
+ case 2:
+ result = this.getDBM().Images.isImage(variable);
+ break;
+ case 3:
+ result = variable instanceof DiscordJS.GuildMember;
+ break;
+ case 4:
+ result = variable instanceof DiscordJS.Message;
+ break;
+ case 5:
+ result = variable instanceof DiscordJS.TextChannel || variable instanceof DiscordJS.NewsChannel;
+ break;
+ case 6:
+ result = variable instanceof DiscordJS.VoiceChannel;
+ break;
+ case 7:
+ result = variable instanceof DiscordJS.Role;
+ break;
+ case 8:
+ result = variable instanceof DiscordJS.Guild;
+ break;
+ case 9:
+ result = variable instanceof DiscordJS.Emoji || variable instanceof DiscordJS.GuildEmoji;
+ break;
+ case 10:
+ result = variable instanceof DiscordJS.Sticker;
+ break;
+ case 11:
+ result = variable instanceof DiscordJS.ThreadChannel;
+ break;
+ }
+ }
+
+ this.executeResults(result, data?.branch ?? data, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.branch?.iftrueActions);
+ this.prepareActions(data.branch?.iffalseActions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/classificar_lista_MOD.js b/actions/classificar_lista_MOD.js
new file mode 100644
index 000000000..9eee39d86
--- /dev/null
+++ b/actions/classificar_lista_MOD.js
@@ -0,0 +1,125 @@
+module.exports = {
+ name: 'Classificar lista',
+ section: 'Lists and Loops',
+ short_description: 'Classifica uma lista',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data) {
+ const list = ['', 'Temporal Variable', 'Server Variable', 'Global Variable'];
+ const classic = [
+ 'Ascending order [0-9]',
+ 'Descending order [9-0]',
+ 'Alphabetical order [A-Z]',
+ 'Reverse alphabetical order [Z-A]',
+ 'Length [ascending order]',
+ 'Length [descending order]',
+ ];
+ return `(${classic[parseInt(data.sorte, 10)]}) ${list[parseInt(data.list, 10)]} (${data.varName}) to ${
+ list[parseInt(data.storage, 10)]
+ } (${data.varName2})`;
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName2, 'List'];
+ },
+
+ fields: ['list', 'varName', 'storage', 'varName2', 'sorte'],
+
+ html(isEvent, data) {
+ return `
+
+
+ Warning: This will clear all warnings for the selected member.
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const member = this.getMemberFromData(data.member, data.varName, cache);
+
+ if (!member) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ try {
+ const memberData = this.getMemberData(member, cache.server);
+ memberData.warnings = [];
+ this.setMemberData(member, cache.server, memberData);
+ this.callNextAction(cache);
+ } catch (err) {
+ this.displayError(data, cache, err);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/clear_queue.js b/actions/clear_queue.js
new file mode 100644
index 000000000..e014a190a
--- /dev/null
+++ b/actions/clear_queue.js
@@ -0,0 +1,103 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Clear Queue',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return 'The queue is cleared.';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.1.7', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: [],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return '';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const { Audio } = this.getDBM();
+ const server = cache.server;
+ if (server) {
+ const subscription = Audio.subscriptions.get(server.id);
+ if (subscription) subscription.queue = [];
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/clear_queue.ts b/actions/clear_queue.ts
new file mode 100644
index 000000000..9794c0eae
--- /dev/null
+++ b/actions/clear_queue.ts
@@ -0,0 +1,102 @@
+import { Actions, ActionsCache } from '../bot.ts';
+import Audio from '../bot_audio.ts';
+import { ActionMod } from '../types.ts';
+
+export default {
+ //---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ //---------------------------------------------------------------------
+
+ name: 'Clear Queue',
+
+ //---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ //---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ //---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ //---------------------------------------------------------------------
+
+ subtitle(data: {}, presets: any) {
+ return 'The queue is cleared.';
+ },
+
+ //---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ //---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ //---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ //---------------------------------------------------------------------
+
+ fields: [],
+
+ //---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //---------------------------------------------------------------------
+
+ html() {
+ return '';
+ },
+
+ //---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ //---------------------------------------------------------------------
+
+ init() {},
+
+ //---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ //---------------------------------------------------------------------
+
+ async action(this: typeof Actions, cache: ActionsCache) {
+ await Audio.clearQueue(cache);
+ this.callNextAction(cache);
+ },
+
+ //---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ //---------------------------------------------------------------------
+
+ mod() {},
+} satisfies ActionMod;
diff --git a/actions/comment_MOD.js b/actions/comment_MOD.js
new file mode 100644
index 000000000..34b66730b
--- /dev/null
+++ b/actions/comment_MOD.js
@@ -0,0 +1,87 @@
+module.exports = {
+ name: 'Comment',
+ section: 'Other Stuff',
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ subtitle(data) {
+ let styles = '';
+
+ if (data.bold === 'true') styles += 'font-weight: bold; ';
+ if (data.italic === 'true') styles += 'font-style: italic; ';
+ if (data.underline === 'true') styles += 'text-decoration: underline; ';
+ if (data.strikethrough === 'true') styles += 'text-decoration: line-through; ';
+
+ return `${data.comment}`;
+ },
+
+ fields: ['comment', 'color', 'bold', 'italic', 'underline', 'strikethrough'],
+
+ html() {
+ return `
+
`;
+ },
+ init() {},
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const consoleInputVar = this.evalMessage(data.consoleInputVar, cache);
+ const separator = this.evalMessage(data.separator, cache);
+ const partIndex = parseInt(this.evalMessage(data.partIndex, cache), 10) - 1;
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+
+ const consoleInput = this.getVariable(1, consoleInputVar, cache);
+ if (!consoleInput) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const parts = consoleInput.split(separator);
+ const result = parts[partIndex] ? parts[partIndex].trim() : '';
+
+ this.storeValue(result, storage, varName, cache);
+ this.callNextAction(cache);
+ },
+ mod() {},
+};
diff --git a/actions/control_audio.js b/actions/control_audio.js
new file mode 100644
index 000000000..b734cd86c
--- /dev/null
+++ b/actions/control_audio.js
@@ -0,0 +1,127 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Control Audio',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const actions = ['Stop Playing', 'Pause Audio', 'Resume Audio'];
+ return `${actions[parseInt(data.action, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['action'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Audio Action
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const { Audio } = this.getDBM();
+ const server = cache.server;
+ const subscription = server && Audio.subscriptions.get(server.id);
+ if (!subscription) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const action = parseInt(data.action, 10);
+ switch (action) {
+ case 0:
+ subscription.stop();
+ break;
+ case 1:
+ subscription.audioPlayer.pause();
+ break;
+ case 2:
+ subscription.audioPlayer.unpause();
+ break;
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/control_channel_data_MOD.js b/actions/control_channel_data_MOD.js
new file mode 100644
index 000000000..5e1f69577
--- /dev/null
+++ b/actions/control_channel_data_MOD.js
@@ -0,0 +1,102 @@
+module.exports = {
+ name: 'Control Channel Data',
+ section: 'Data',
+
+ subtitle(data, presets) {
+ let symbol = '=';
+ if (data.changeType === '1') symbol = '+=';
+ else if (data.changeType === '2') symbol = '-=';
+ return `${presets.getChannelText(data.channel, data.varName)} (${data.dataName}) ${symbol} ${data.value}`;
+ },
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ fields: ['channel', 'varName', 'dataName', 'changeType', 'value'],
+
+ html(isEvent, data) {
+ return `
+
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ if (member?.setData) {
+ const dataName = this.evalMessage(data.dataName, cache);
+ let val = this.evalMessage(data.value, cache);
+ try {
+ val = this.eval(val, cache);
+ } catch (e) {
+ this.displayError(data, cache, e);
+ }
+ if (val !== undefined) {
+ if (Array.isArray(member)) {
+ member.forEach(function (mem) {
+ if (data.changeType === '1') {
+ if (mem?.addData) mem.addData(dataName, val);
+ } else if (data.changeType === '2') {
+ if (mem?.addData) mem.addData(dataName, -val);
+ } else if (mem?.setData) mem.setData(dataName, val);
+ });
+ } else if (data.changeType === '1') {
+ member.addData(dataName, val);
+ } else if (data.changeType === '2') {
+ member.addData(dataName, -val);
+ } else {
+ member.setData(dataName, val);
+ }
+ }
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/control_message_data.js b/actions/control_message_data.js
new file mode 100644
index 000000000..17c86de53
--- /dev/null
+++ b/actions/control_message_data.js
@@ -0,0 +1,143 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Control Message Data',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Data',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMessageText(data.message, data.varName)} (${data.dataName}) ${
+ data.changeType === '1' ? '+=' : '='
+ } ${data.value}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['message', 'varName', 'dataName', 'changeType', 'value'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Data Name
+
+
+
+ Control Type
+
+
+
+
+
+
+
+ Value
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const message = await this.getMessageFromData(data.message, data.varName, cache);
+
+ if (message?.setData) {
+ const dataName = this.evalMessage(data.dataName, cache);
+ const isAdd = data.changeType === '1';
+ let val = this.evalMessage(data.value, cache);
+ try {
+ val = this.eval(val, cache);
+ } catch (e) {
+ this.displayError(data, cache, e);
+ }
+ if (val !== undefined) {
+ if (isAdd) {
+ message.addData(dataName, val);
+ } else {
+ message.setData(dataName, val);
+ }
+ }
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/control_permissons_MOD.js b/actions/control_permissons_MOD.js
index 05ec9c526..825265372 100644
--- a/actions/control_permissons_MOD.js
+++ b/actions/control_permissons_MOD.js
@@ -55,7 +55,6 @@ module.exports = {
'READ_MESSAGE_HISTORY',
'MENTION_EVERYONE',
'USE_EXTERNAL_EMOJIS',
- 'VIEW_GUILD_INSIGHT',
'CONNECT',
'SPEAK',
'MUTE_MEMBERS',
@@ -69,14 +68,23 @@ module.exports = {
'MANAGE_EMOJIS',
],
- html() {
+ html(isEvent, data) {
return `
-
+
-
+
+ Source Permissions
+
+
+
+ Variable Name
+
+
-
+
@@ -85,8 +93,7 @@ module.exports = {
},
init() {
- const { document } = this;
- const checkbox = document.getElementById('checkbox');
+ const { glob, document } = this;
const permissionsName = {
ADMINISTRATOR: 'Administrator',
@@ -246,63 +253,61 @@ module.exports = {
'Voice Channel Permissions': voicePermissions,
};
- const varName = document.getElementById('varName');
- const list = document.getElementById('variableList');
-
- varName.oninput = function oninput() {
- if (list.children.length === 0) return;
- let dataType;
+ function resolveDataType(doc) {
+ const varNameEl = doc.getElementById('varName');
+ const list = doc.getElementById('variableList');
+ if (!varNameEl || !list || list.children.length === 0) {
+ return 'All Permissions';
+ }
+ const { value } = varNameEl;
for (let i = 0; i < list.children.length; i++) {
- if (varName.value && list.children[i].value === varName.value) {
- dataType = list.children[i].innerHTML;
- break;
+ if (value && list.children[i].value === value) {
+ return list.children[i].innerHTML;
}
}
- if (!dataType) dataType = 'All Permissions';
- checkbox.innerHTML = '';
- permissionsList[dataType].forEach((Permission) => {
- const dom = document.createElement('select');
- checkbox.innerHTML += `${permissionsName[Permission]}: `;
- dom.id = Permission;
+ return 'All Permissions';
+ }
+
+ glob.controlPermsRebuild = function controlPermsRebuild() {
+ const doc = document;
+ const checkbox = doc.getElementById('checkbox');
+ const varNameEl = doc.getElementById('varName');
+ if (!checkbox || !varNameEl) return;
+
+ while (checkbox.firstChild) {
+ checkbox.removeChild(checkbox.firstChild);
+ }
+
+ const dataType = resolveDataType(doc);
+ const permKeys = permissionsList[dataType] || permissionsList['All Permissions'];
+ const useRoleOptions = dataType === 'Role Permissions';
+ const optionSet = useRoleOptions ? options2 : options;
+
+ permKeys.forEach((permissionKey) => {
+ const label = doc.createElement('div');
+ label.style.marginTop = '4px';
+ label.textContent = `${permissionsName[permissionKey] || permissionKey}:`;
+ checkbox.appendChild(label);
+
+ const dom = doc.createElement('select');
+ dom.id = permissionKey;
dom.className = 'round';
- let option = options;
- if (dataType === 'Role Permissions') option = options2;
- option.forEach((option) => {
- const op = document.createElement('option');
- op.innerHTML = option;
- op.value = option;
- dom.add(op);
+ optionSet.forEach((opt) => {
+ const op = doc.createElement('option');
+ op.textContent = opt;
+ op.value = opt;
+ dom.appendChild(op);
});
checkbox.appendChild(dom);
- checkbox.innerHTML += ' ';
+
+ const br = doc.createElement('br');
+ checkbox.appendChild(br);
});
};
- let dataType;
- if (list.children.length !== 0) {
- for (let i = 0; i < list.children.length; i++) {
- if (list.children[i].value === varName.value) {
- dataType = list.children[i].innerHTML;
- break;
- }
- }
- }
- if (!dataType) dataType = 'All Permissions';
- checkbox.innerHTML = '';
- permissionsList[dataType].forEach((Permission) => {
- const dom = document.createElement('select');
- checkbox.innerHTML += `${permissionsName[Permission]}: `;
- dom.id = Permission;
- dom.className = 'round';
- options.forEach((option) => {
- const op = document.createElement('option');
- op.innerHTML = option;
- op.value = option;
- dom.add(op);
- });
- checkbox.appendChild(dom);
- checkbox.innerHTML += ' ';
- });
+ setTimeout(() => {
+ glob.controlPermsRebuild();
+ }, 100);
},
async action(cache) {
@@ -311,10 +316,43 @@ module.exports = {
const storage = parseInt(data.storage, 10);
const varName = this.evalMessage(data.varName, cache);
let permissions = this.getVariable(storage, varName, cache);
- if (permissions.bitfield) {
- const temp = permissions;
- permissions = { allow: temp };
+
+ if (permissions === undefined || permissions === null) {
+ this.displayError(
+ data,
+ cache,
+ new Error(
+ 'Control Permissions: source variable is undefined. Set the variable before this action (e.g. Create Permissions / Store Channel Permissions) and ensure the name matches (dbm-network/mods#652).',
+ ),
+ );
+ return;
}
+
+ try {
+ if (typeof permissions === 'bigint' || (typeof permissions === 'number' && !Number.isNaN(permissions))) {
+ permissions = { allow: new Permissions(permissions) };
+ } else if (
+ permissions &&
+ typeof permissions === 'object' &&
+ Object.prototype.hasOwnProperty.call(permissions, 'bitfield') &&
+ permissions.allow === undefined &&
+ permissions.disallow === undefined
+ ) {
+ const temp = permissions;
+ permissions = { allow: temp };
+ } else if (typeof permissions !== 'object') {
+ this.displayError(
+ data,
+ cache,
+ new Error('Control Permissions: source variable must be a permissions object or a bitfield value.'),
+ );
+ return;
+ }
+ } catch (err) {
+ this.displayError(data, cache, err);
+ return;
+ }
+
const permsArray = [
'ADMINISTRATOR',
'CREATE_INSTANT_INVITE',
@@ -366,12 +404,12 @@ module.exports = {
if (permissions.inherit && permissions.inherit.includes(perms))
permissions.inherit.splice(permissions.inherit.indexOf(perms), 1);
} else if (data[perms] === 'Inherit') {
- if (!permissions.inherit || !permissions.inherit.has(perms)) {
+ if (!permissions.inherit || !permissions.inherit.includes(perms)) {
if (!permissions.inherit) permissions.inherit = [];
permissions.inherit.push(perms);
}
- if (permissions.disallow.has(perms)) permissions.disallow.remove(perms);
- if (permissions.allow.has(perms)) permissions.allow.remove(perms);
+ if (permissions.disallow && permissions.disallow.has(perms)) permissions.disallow.remove(perms);
+ if (permissions.allow && permissions.allow.has(perms)) permissions.allow.remove(perms);
}
});
this.storeValue(permissions, storage, varName, cache);
diff --git a/actions/control_server_data.js b/actions/control_server_data.js
new file mode 100644
index 000000000..0eddfcbab
--- /dev/null
+++ b/actions/control_server_data.js
@@ -0,0 +1,160 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Control Server Data',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Data',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ let type;
+ switch (data.changeType) {
+ case '0':
+ type = '=';
+ break;
+ case '1':
+ type = '+=';
+ break;
+ case '2':
+ type = '-';
+ break;
+ }
+ return `${presets.getServerText(data.server, data.varName)} (${data.dataName}) ${type} ${data.value}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName', 'dataName', 'changeType', 'value'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Data Name
+
+
+
+ Control Type
+
+
+
+
+
+
+
+ Value
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = await this.getServerFromData(data.server, data.varName, cache);
+
+ if (server?.setData) {
+ const dataName = this.evalMessage(data.dataName, cache);
+ const isAdd = data.changeType === '1';
+ const isSub = data.changeType === '2';
+ let val = this.evalMessage(data.value, cache);
+
+ try {
+ val = this.eval(val, cache);
+ } catch (e) {
+ this.displayError(data, cache, e);
+ }
+
+ if (val !== undefined) {
+ if (isAdd) {
+ server.addData(dataName, val);
+ } else if (isSub) {
+ server.subData(dataName, val);
+ } else {
+ server.setData(dataName, val);
+ }
+ }
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/control_variable.js b/actions/control_variable.js
new file mode 100644
index 000000000..bf9cd2a5c
--- /dev/null
+++ b/actions/control_variable.js
@@ -0,0 +1,166 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Control Variable',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storage = presets.variables;
+ return `${storage[parseInt(data.storage, 10)]} (${data.varName}) ${data.changeType === '1' ? '+=' : '='} ${
+ data.value
+ }`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Unknown Type'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'changeType', 'value'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Control Type
+
+
+
+ Value
+
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const type = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const storage = this.getVariable(type, varName, cache);
+ const isAdd = data.changeType === '1';
+ const isSub = data.changeType === '2';
+ let val = this.evalMessage(data.value, cache);
+
+ try {
+ val = this.eval(val, cache);
+ } catch (e) {
+ this.displayError(data, cache, e);
+ }
+
+ if (val !== undefined) {
+ if (isAdd) {
+ let result;
+ if (storage === undefined) {
+ result = val;
+ } else {
+ result = storage + val;
+ }
+ this.storeValue(result, type, varName, cache);
+ } else if (isSub) {
+ let result;
+ if (storage === undefined) {
+ result = val;
+ } else {
+ result = storage - val;
+ }
+ this.storeValue(result, type, varName, cache);
+ } else {
+ this.storeValue(val, type, varName, cache);
+ }
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/control_variable_MOD.js b/actions/control_variable_MOD.js
new file mode 100644
index 000000000..3a856e9bf
--- /dev/null
+++ b/actions/control_variable_MOD.js
@@ -0,0 +1,82 @@
+module.exports = {
+ name: 'Control Variable',
+ section: 'Other Stuff',
+ meta: {
+ version: '2.1.7',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data, presets) {
+ const storage = presets.variables;
+ return `${storage[parseInt(data.storage, 10)]} (${data.varName}) ${data.changeType === '1' ? '+=' : '='} ${
+ data.value
+ }`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Unknown Type'];
+ },
+
+ fields: ['storage', 'varName', 'changeType', 'value'],
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Control Type
+
+
+
+
+
+
+ Value
+
+
+`;
+ },
+
+ init() {},
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const type = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const storage = this.getVariable(type, varName, cache);
+ const isAdd = data.changeType === '1';
+ let val = this.evalMessage(data.value, cache);
+ try {
+ val = this.eval(val, cache);
+ } catch (e) {
+ this.displayError(data, cache, e);
+ }
+ if (val !== undefined) {
+ if (isAdd) {
+ let result;
+ if (storage === undefined) {
+ result = val;
+ } else {
+ result = storage + val;
+ }
+ this.storeValue(result, type, varName, cache);
+ } else {
+ this.storeValue(val, type, varName, cache);
+ }
+ }
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/convert_color_MOD.js b/actions/convert_color_MOD.js
new file mode 100644
index 000000000..5c8726057
--- /dev/null
+++ b/actions/convert_color_MOD.js
@@ -0,0 +1,279 @@
+module.exports = {
+ name: 'Convert Color',
+ section: 'Conversions',
+ meta: {
+ version: '2.2.0',
+ preciseCheck: false,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ subtitle(data) {
+ let from = data.InputColor.toUpperCase();
+ if (from === 'AUTO') from = 'Auto Detect';
+ if (from === 'CSS') from = 'Keyword';
+ if (from === 'DECIMAL') from = 'Decimal';
+
+ let to = data.OutputColor.toUpperCase();
+ if (to === 'CSS') to = 'Keyword';
+ if (to === 'DECIMAL') to = 'Decimal';
+ return `Convert Color from ${from} to ${to}`;
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.Storage, 10) !== varType) return;
+ return [data.VarName, 'Color'];
+ },
+
+ fields: ['InputColor', 'InputText', 'OutputColor', 'Storage', 'VarName'],
+
+ html() {
+ return `
+
Note:
+ You can convert ISO 8601 date to Unix Timestamp with this mod.
+
+
+
+
+ ISO 8601 Date to Convert
+
+
+
+
+
+
+
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer');
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const isoDate = this.evalMessage(data.isoDate, cache);
+
+ const timestamp = Date.parse(isoDate);
+
+ if (!isNaN(timestamp)) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(timestamp, storage, varName, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+};
diff --git a/actions/convert_list_to_text.js b/actions/convert_list_to_text.js
new file mode 100644
index 000000000..69b989d14
--- /dev/null
+++ b/actions/convert_list_to_text.js
@@ -0,0 +1,169 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Convert List to Text',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Lists and Loops',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const list = presets.lists;
+ return `Convert ${list[parseInt(data.list, 10)]} to Text`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Text'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['list', 'varName', 'start', 'middle', 'end', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source List
+
+
+
+ Variable Name
+
+
+
+
+
+
+
+
+ Start Characters
+
+
+
+ Middle Characters
+
+
+
+ End Characters
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.listChange(document.getElementById('list'), 'varNameContainer');
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const list = (await this.getListFromData(data.list, data.varName, cache)) ?? [];
+
+ const start = this.evalMessage(data.start, cache).replace('\\n', '\n');
+ const middle = this.evalMessage(data.middle, cache).replace('\\n', '\n');
+ const end = this.evalMessage(data.end, cache).replace('\\n', '\n');
+ let result = '';
+
+ for (let i = 0; i < list.length; i++) {
+ if (i === 0) {
+ result += start + String(list[i]) + end;
+ } else {
+ result += start + middle + String(list[i]) + end;
+ }
+ }
+
+ if (typeof result === 'string') {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage2 = parseInt(data.storage, 10);
+ this.storeValue(result, storage2, varName2, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/convert_secounds_to_timestamp_MOD.js b/actions/convert_secounds_to_timestamp_MOD.js
new file mode 100644
index 000000000..90086038a
--- /dev/null
+++ b/actions/convert_secounds_to_timestamp_MOD.js
@@ -0,0 +1,60 @@
+module.exports = {
+ name: 'Convert Seconds To Timestamp',
+ section: 'Other Stuff',
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ subtitle(data) {
+ return `Convert ${data.time}`;
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, 'String'];
+ },
+
+ fields: ['time', 'storage', 'varName'],
+
+ html() {
+ return `
+
+ `;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const time = this.evalMessage(data.time, cache);
+
+ if (isNaN(time)) return this.callNextAction(cache);
+
+ const futureTimestamp = Math.floor(Date.now() / 1000) + parseInt(time, 10);
+
+ const discordTimestamp = ``; // Format Discorda:
+
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(discordTimestamp, storage, varName, cache);
+
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/convert_time_MOD.js b/actions/convert_time_MOD.js
new file mode 100644
index 000000000..6aeafbbca
--- /dev/null
+++ b/actions/convert_time_MOD.js
@@ -0,0 +1,243 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Convert Time',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data) {
+ const convertFroms = ['Miliseconds', 'Seconds', 'Minutes', 'Hours'];
+ const convertTos = ['Miliseconds', 'Seconds', 'Minutes', 'Hours'];
+ return `Convert ${data.time} ${convertFroms[parseInt(data.convertFrom, 10)]} to ${
+ convertTos[parseInt(data.convertTo, 10)]
+ }`;
+ },
+
+ // ---------------------------------------------------------------------
+ // DBM Mods Manager Variables (Optional but nice to have!)
+ //
+ // These are variables that DBM Mods Manager uses to show information
+ // about the mods for people to see in the list.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: null,
+ authorUrl: 'https://github.com/master3395/dbm-mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const dataType = 'Number';
+ return [data.varName, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['time', 'convertFrom', 'convertTo', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editting actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
Made by ZockerNico
+
+
+ Convert from:
+
+
+
+ Amount:
+
+
+
+ Convert to:
+
+
+
+ Store In:
+
+
+
+ Variable Name:
+
+
+
+
Sample: 1 minute as input will give you 0.016666666666666666 hours as output.
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existance.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const amount = parseInt(this.evalMessage(data.time, cache), 10);
+ const convFrom = parseFloat(data.convertFrom);
+ const convTo = parseFloat(data.convertTo);
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+
+ let result = undefined;
+ function Converter(from, to, amount) {
+ switch (from) {
+ case 0: // From miliseconds
+ switch (to) {
+ case 0:
+ result = parseFloat(amount); // Same
+ break;
+ case 1:
+ result = parseFloat(amount / 1000); // To seconds
+ break;
+ case 2:
+ result = parseFloat(amount / 60000); // To minutes
+ break;
+ case 3:
+ result = parseFloat(amount / 3600000); // To hours
+ break;
+ }
+ break;
+ case 1: // From seconds
+ switch (to) {
+ case 0:
+ result = parseFloat(amount * 1000); // To miliseconds
+ break;
+ case 1:
+ result = parseFloat(amount); // Same
+ break;
+ case 2:
+ result = parseFloat(amount / 60); // To minutes
+ break;
+ case 3:
+ result = parseFloat(amount / 3600); // To hours
+ break;
+ }
+ break;
+ case 2: // From minutes
+ switch (to) {
+ case 0:
+ result = parseFloat(amount * 60000); // To miliseconds
+ break;
+ case 1:
+ result = parseFloat(amount * 60); // To seconds
+ break;
+ case 2:
+ result = parseFloat(amount); // Same
+ break;
+ case 3:
+ result = parseFloat(amount / 60); // To hours
+ break;
+ }
+ break;
+ case 3: // From hours
+ switch (to) {
+ case 0:
+ result = parseFloat(amount * 6000000); // To miliseconds
+ break;
+ case 1:
+ result = parseFloat(amount * 3600); // To seconds
+ break;
+ case 2:
+ result = parseFloat(amount * 60); // To minutes
+ break;
+ case 3:
+ result = parseFloat(amount); // Same
+ break;
+ }
+ break;
+ }
+ }
+ Converter(convFrom, convTo, amount);
+
+ this.storeValue(result, storage, varName, cache);
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflictions between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {},
+}; // End of module
diff --git a/actions/converter_MOD.js b/actions/converter_MOD.js
new file mode 100644
index 000000000..39474f892
--- /dev/null
+++ b/actions/converter_MOD.js
@@ -0,0 +1,266 @@
+module.exports = {
+ name: 'Converter',
+ section: 'Other Stuff',
+ short_description: 'Convert an information to text, number or format',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data) {
+ const info = [
+ 'Whole number (Rounded)',
+ 'Whole number (Up)',
+ 'Whole number (Down)',
+ 'Text',
+ 'Uppercase text',
+ 'Small text',
+ 'Text without spaces',
+ 'Text (Without spaces on both sides)',
+ 'Number with punctuation',
+ 'Short number',
+ 'R$ money format',
+ 'U$ money format',
+ '€ money format',
+ 'Text without accents',
+ 'Text starting with capital letter',
+ 'Spaced text',
+ ];
+ const prse = parseInt(data.into, 10);
+ return `Convert "${data.vAria}" to ${info[prse]}`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ const prse2 = parseInt(data.into, 10);
+ const info2 = [
+ 'Number',
+ 'Number',
+ 'Number',
+ 'Text',
+ 'Text',
+ 'Text',
+ 'Text',
+ 'Text',
+ 'Number',
+ 'Number',
+ 'Money',
+ 'Money',
+ 'Money ',
+ 'Text',
+ 'Text',
+ 'Text',
+ ];
+ if (type !== varType) return;
+ return [data.varName2, info2[prse2]];
+ },
+
+ fields: ['into', 'vAria', 'storage', 'varName2'],
+
+ html(isEvent, data) {
+ return `
+
+
+
+ Information
+
+
+
+ Convert to
+
+
+
+
+ Store in
+
+
+
+
+
+
+
+
+
+
+
+ `;
+ },
+
+ init() {},
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const theVar = this.evalMessage(data.vAria, cache);
+ const INTO = parseInt(data.into, 10);
+ let result;
+
+ switch (INTO) {
+ case 0:
+ result = Math.round(theVar.toString().replace(',', '.'));
+ break;
+ case 1:
+ result = Math.ceil(theVar.toString().replace(',', '.'));
+ break;
+ case 2:
+ result = parseInt(theVar, 10);
+ break;
+ case 3:
+ result = theVar.toString();
+ break;
+ case 4:
+ result = theVar.toString().toUpperCase();
+ break;
+ case 5:
+ result = theVar.toString().toLowerCase();
+ break;
+ case 6:
+ result = theVar.toString().split(' ').join('');
+ break;
+ case 7:
+ result = theVar.toString().trim();
+ break;
+ case 8:
+ if (isNaN(parseFloat(theVar))) {
+ result = theVar;
+ } else {
+ result = parseFloat(theVar).toLocaleString('pt-BR');
+ }
+ break;
+ case 9:
+ var number = parseInt(this.evalMessage(theVar, cache), 10);
+
+ if (number >= 1000 && number <= 999999) {
+ number = `${number.toString().slice(0, -3)}k`;
+ }
+
+ if (number >= 1e6 && number <= 1e8) {
+ number = `${number.toString().slice(0, -6)}m`;
+ }
+
+ if (number >= 1e9 && number <= 1e11) {
+ number = `${number.toString().slice(0, -9)}b`;
+ }
+
+ if (number >= 1e12 && number <= 1e14) {
+ number = `${number.toString().slice(0, -12)}t`;
+ }
+ if (number >= 1e15 && number <= 1e17) {
+ number = `${number.toString().slice(0, -15)}q`;
+ }
+ if (number >= 1e18 && number <= 1e20) {
+ number = `${number.toString().slice(0, -18)}sx`;
+ }
+ if (number >= 1e21 && number <= 1e23) {
+ number = `${number.toString().slice(0, -4)}sp`;
+ }
+ if (number >= 1e24 && number <= 1e26) {
+ number = `${number.toString().slice(0, -4)}o`;
+ }
+ if (number >= 1e27 && number <= 1e29) {
+ number = `${number.toString().slice(0, -4)}n`;
+ }
+ if (number >= 1e30 && number <= 1e32) {
+ number = `${number.toString().slice(0, -4)}d`;
+ }
+ if (number >= 1e33 && number <= 1e35) {
+ number = `${number.toString().slice(0, -4)}u`;
+ }
+ if (number >= 1e36 && number <= 1e38) {
+ number = `${number.toString().slice(0, -4)}du`;
+ }
+ if (number >= 1e39) {
+ number = `${number.toString().slice(0, -4)}tr`;
+ }
+ result = number;
+ break;
+ case 10:
+ const money = Intl.NumberFormat('pt-BR', {
+ style: 'currency',
+ currency: 'BRL',
+ });
+ result = money.format(theVar.toString().replace(',', '.'));
+ break;
+ case 11:
+ const money2 = Intl.NumberFormat('en-US', {
+ style: 'currency',
+ currency: 'USD',
+ });
+ result = money2.format(theVar.toString().replace(',', '.'));
+ break;
+ case 12:
+ const money3 = Intl.NumberFormat('de-DE', {
+ style: 'currency',
+ currency: 'EUR',
+ });
+ result = money3.format(theVar.toString().replace(',', '.'));
+ break;
+ case 13:
+ const comAcentos =
+ 'ÄÅÁÂÀÃĀĂĄāăąäáâàãÉÊËÈĖĘĚĔĒėęěĕēéêëèÍÎÏÌİĮĪıįīíîïìÖÓÔÒÕŐŌőōöóôòõÜÚÛŲŰŮŪųűůūüúûùÇĆČçćčÑŇŅŃñňņńŸÝÿýŹŻŽźżžŁĽĻĹłľļĺĶķĢĞģğĎďŚŠŞśšşŤȚŢťțţŔŘŕř';
+ const semAcentos =
+ 'AAAAAAAAAaaaaaaaaEEEEEEEEEeeeeeeeeeIIIIIIIiiiiiiiOOOOOOOoooooooUUUUUUUuuuuuuuuCCCcccNNNNnnnnYYyyZZZzzzLLLLllllKkGGggDdSSSsssTTTtttRRrr';
+
+ result = theVar.toString();
+
+ for (let i = 0; i <= comAcentos.length; i++) {
+ result = result.replaceAll(comAcentos[i], semAcentos[i]);
+ }
+ break;
+ case 14:
+ const convertor = theVar[0].toUpperCase() + theVar.substring(1);
+ result = convertor;
+ break;
+ case 15:
+ result = theVar.toString().replaceAll('', ' ');
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ mod(DBM) {},
+};
diff --git a/actions/converter_segundos_MOD.js b/actions/converter_segundos_MOD.js
new file mode 100644
index 000000000..d61f015e3
--- /dev/null
+++ b/actions/converter_segundos_MOD.js
@@ -0,0 +1,109 @@
+module.exports = {
+ name: 'Convert seconds to Y/D/H/M/S',
+ section: 'Other Stuff',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ short_description: 'Convert seconds to years, months, days, hours, minutes and seconds.',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data) {
+ return `Convert ${data.time}`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Date'];
+ },
+
+ fields: ['time', 'storage', 'varName'],
+
+ html(isEvent, data) {
+ return `
+
+
Convert seconds into years, days, hours, minutes and seconds.
+
+
+
+ Convert seconds:
+
+
+
+ Result in:
+
+
+
+ Variable name:
+
+
+
+
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer');
+ },
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const time = this.evalMessage(data.time, cache);
+ var _this = this;
+
+ let d;
+ let h;
+ let m;
+ let s;
+ let a;
+ let mes;
+ let result;
+
+ if (isNaN(time)) {
+ result = 'Invalid date';
+ console.log('Please enter a number');
+ } else {
+ s = Number(time);
+
+ m = Math.floor(s / 60);
+ s %= 60;
+ h = Math.floor(m / 60);
+ m %= 60;
+ a = Math.floor(time / 60 / 60 / 24 / 365.242214);
+ mes = Math.floor(time / 60 / 60 / 24 / 30.43685116666667 - a * 12);
+ d = Math.floor(h / 24 - a * 365.242214 - 30.43685116666667 * mes);
+ h %= 24;
+
+ result =
+ (a > 1 ? `${String(a)} years ` : '') +
+ (a === 1 ? `${String(a)} year ` : '') +
+ (mes > 1 ? `${String(mes)} months ` : '') +
+ (mes === 1 ? `${String(mes)} month ` : '') +
+ (d > 1 ? `${d} days ` : '') +
+ (d === 1 ? `${String(d)} day ` : '') +
+ (h > 1 ? `${h} hours ` : '') +
+ (h === 1 ? `${String(h)} hour ` : '') +
+ (m > 0 ? `${m} min ` : '') +
+ (s > 0 ? `${s} sec ` : '');
+ }
+
+ if (result === 'Invalid date') result = undefined;
+
+ // Storage.
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ mod(DBM) {},
+};
diff --git a/actions/create_channel.js b/actions/create_channel.js
new file mode 100644
index 000000000..4536ae906
--- /dev/null
+++ b/actions/create_channel.js
@@ -0,0 +1,167 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Create Text Channel',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.channelName}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Channel'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channelName', 'topic', 'position', 'storage', 'varName', 'categoryID', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+Name
+
+
+
+Category ID
+
+
+
+
+ Topic
+
+
+
+ Position
+
+
+
+
+
+
+
+
+
+ Reason
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const server = cache.server;
+ if (!server?.channels?.create) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const channelData = {
+ reason: this.evalMessage(data.reason, cache),
+ name: this.evalMessage(data.channelName, cache),
+ };
+ if (data.topic) {
+ channelData.topic = this.evalMessage(data.topic, cache);
+ }
+ if (data.position) {
+ channelData.position = parseInt(this.evalMessage(data.position, cache), 10);
+ }
+ if (data.categoryID) {
+ channelData.parent = this.evalMessage(data.categoryID, cache);
+ }
+
+ server.channels
+ .create(channelData)
+ .then((channel) => {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(channel, storage, varName, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/create_custom_data.js b/actions/create_custom_data.js
new file mode 100644
index 000000000..dffc75832
--- /dev/null
+++ b/actions/create_custom_data.js
@@ -0,0 +1,68 @@
+module.exports = {
+ name: 'Create Custom Data File',
+ section: 'Data',
+ fields: ['filePath', 'fileName', 'varName', 'storage'],
+
+ meta: {
+ version: '2.1.2',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/create_custom_data.js',
+ },
+
+ subtitle(data) {
+ if (data.filePath && data.fileName) {
+ return `Create ${data.filePath}${data.fileName}.json`;
+ }
+ return `Nothing to create (error)`;
+ },
+
+ variableStorage(data, varType) {
+ if (data.filePath && data.fileName) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, 'Data Path'];
+ }
+ },
+
+ html() {
+ return `
+
+
+
+ `;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const Mods = this.getMods();
+ const fs = Mods.require('fs-extra');
+
+ const result =
+ data.filePath && data.fileName ? `${data.filePath}${data.fileName}.json` : `Nothing to create (error)`;
+ const varName = this.evalMessage(data.varName, cache);
+ const storage = parseInt(data.storage, 10);
+ this.storeValue(result, storage, varName, cache);
+
+ if (data.filePath && data.fileName) {
+ fs.pathExistsSync(`${data.filePath}/${data.fileName}.json`)
+ ? console.log('File already exists!')
+ : fs.writeFileSync(`${data.filePath}/${data.fileName}.json`, '{}');
+ }
+
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/create_embed_message.js b/actions/create_embed_message.js
new file mode 100644
index 000000000..130702c80
--- /dev/null
+++ b/actions/create_embed_message.js
@@ -0,0 +1,171 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Create Embed Message',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Embed Message',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.title}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Embed Message Data'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['title', 'author', 'color', 'timestamp', 'url', 'authorIcon', 'imageUrl', 'thumbUrl', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Title
+
+ Author
+
+ Color
+
+ Use Timestamp
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const { EmbedBuilder } = this.getDBM().DiscordJS;
+ const embed = new EmbedBuilder();
+ if (data.title) {
+ embed.setTitle(this.evalMessage(data.title, cache));
+ }
+ if (data.url) {
+ embed.setURL(this.evalMessage(data.url, cache));
+ }
+ if (data.author && data.authorIcon) {
+ embed.setAuthor({
+ name: this.evalMessage(data.author, cache),
+ iconURL: this.evalMessage(data.authorIcon, cache),
+ });
+ }
+ if (data.color) {
+ embed.setColor(this.evalMessage(data.color, cache));
+ }
+ if (data.imageUrl) {
+ embed.setImage(this.evalMessage(data.imageUrl, cache));
+ }
+ if (data.thumbUrl) {
+ embed.setThumbnail(this.evalMessage(data.thumbUrl, cache));
+ }
+ if (data.timestamp === 'true') {
+ embed.setTimestamp();
+ }
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(embed, storage, varName, cache);
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {},
+};
diff --git a/actions/create_emoji.js b/actions/create_emoji.js
new file mode 100644
index 000000000..1ab1dc35d
--- /dev/null
+++ b/actions/create_emoji.js
@@ -0,0 +1,149 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Create Emoji',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Emoji/Sticker Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.emojiName}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage2, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Emoji'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['emojiName', 'storage', 'varName', 'storage2', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Emoji Name
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = cache.server;
+ if (!server?.emojis) return this.callNextAction(cache);
+
+ const type = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const image = this.getVariable(type, varName, cache);
+ const { Images } = this.getDBM();
+
+ let buffer;
+ try {
+ buffer = Images.createBuffer(image);
+ } catch {
+ return this.displayError(data, cache);
+ }
+
+ server.emojis
+ .create({ attachment: buffer, name: this.evalMessage(data.emojiName, cache) })
+ .then((emoji) => {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage = parseInt(data.storage, 10);
+ this.storeValue(emoji, storage, varName2, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/create_emoji_url_MOD.js b/actions/create_emoji_url_MOD.js
new file mode 100644
index 000000000..13bc90c0f
--- /dev/null
+++ b/actions/create_emoji_url_MOD.js
@@ -0,0 +1,102 @@
+module.exports = {
+ name: 'Create Emoji URL',
+ section: 'Emoji/Sticker Control',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data, presets) {
+ return `${data.emojiName}`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage2, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Emoji'];
+ },
+
+ fields: ['emojiName', 'storage', 'varName', 'storage2', 'varName2'],
+
+ html(isEvent, data) {
+ return `
+
+ Emoji name
+
+
+
+
+
+
+
+ Image Url
+
+
+
+ Variable name
+
+
+
+
+
+
+
+
+
+
+
+
+ Store in
+
+
+
+ Variable name
+
+
+
+
+`;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onComparisonChanged = function (event) {
+ if (event.value === '0') {
+ document.getElementById('varNameContainer2').style.display = 'none';
+ } else {
+ document.getElementById('varNameContainer2').style.display = null;
+ }
+ };
+
+ glob.onComparisonChanged(document.getElementById('storage2'));
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = cache.server;
+ if (!server?.emojis) return this.callNextAction(cache);
+
+ const type = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const image = this.getVariable(type, varName, cache);
+ server.emojis
+ .create(image, this.evalMessage(data.emojiName, cache))
+ .then((emoji) => {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage = parseInt(data.storage, 10);
+ this.storeValue(emoji, storage, varName2, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ mod() {},
+};
diff --git a/actions/create_forum_channel.js b/actions/create_forum_channel.js
new file mode 100644
index 000000000..fe20137ed
--- /dev/null
+++ b/actions/create_forum_channel.js
@@ -0,0 +1,310 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Create Forum Channel',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data) {
+ return `${data.channelName}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadURL: null },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Channel'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channelName', 'topic', 'position', 'storage', 'varName', 'categoryID', 'options'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html() {
+ return `
+
+
+ Name
+
+
+
+
+ Guidelines
+
+
+
+
+
+ Category ID
+
+
+
+
+ Position
+
+
+
+
+
+
+
+ Extra Options
+
+
+
+ Default Sort Type
+
+
+
+
+ Default Layout Type
+
+
+
+
+ Rate Limit Per User
+
+
+
+
+ Auto-Archive Duration
+
+
+
+
+ Reason
+
+
+
+
+
+ Name
+
+
+
+
+ Moderated
+
+
+
+
+ Emoji
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const { server } = cache;
+
+ if (!server) {
+ this.callNextAction();
+ return;
+ }
+
+ const channelData = {
+ name: this.evalMessage(data.channelName, cache),
+ type: this.getDBM().DiscordJS.ChannelType.GuildForum,
+ };
+
+ if (data.topic) {
+ channelData.topic = this.evalMessage(data.topic, cache);
+ }
+ if (data.position) {
+ channelData.position = parseInt(this.evalMessage(data.position, cache), 10);
+ }
+ if (data.categoryID) {
+ channelData.parent = this.evalMessage(data.categoryID, cache);
+ }
+ if (data.options.rateLimitPerUser) {
+ channelData.rateLimitPerUser = parseInt(this.evalMessage(data.options.rateLimitPerUser, cache), 10);
+ }
+ if (data.options.reason) {
+ channelData.reason = this.evalMessage(data.options.reason, cache);
+ }
+
+ // ThreadAutoArchiveDuration
+ // https://discord-api-types.dev/api/discord-api-types-v10/enum/ThreadAutoArchiveDuration
+ channelData.autoArchiveDuration =
+ data.options.autoArchiveDuration === 'max' ? 10080 : parseInt(data.autoArchiveDuration, 10);
+
+ // SortOrderType
+ // https://discord-api-types.dev/api/discord-api-types-v10/enum/SortOrderType
+ channelData.defaultSortOrder = parseInt(data.options.defaultSortType, 10);
+
+ // ForumLayoutType
+ // https://discord-api-types.dev/api/discord-api-types-v10/enum/ForumLayoutType
+ channelData.defaultForumLayout = parseInt(data.options.defaultForumLayout, 10);
+
+ // GuildForumTagData
+ // https://discord.js.org/#/docs/discord.js/main/typedef/GuildForumTagData
+ if (data.options.tags.length > 0) {
+ channelData.availableTags = data.options.tags.map((tagData) => {
+ const result = {
+ name: this.evalMessage(tagData.name, cache),
+ moderated: tagData.moderated === 'yes',
+ };
+ if (tagData.emoji) {
+ result.emoji = this.evalMessage(tagData.emoji, cache);
+ }
+ return result;
+ });
+ }
+
+ server.channels
+ .create(channelData)
+ .then((channel) => {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(channel, storage, varName, cache);
+ this.executeResults(true, data?.branch ?? data, cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/create_forum_post.js b/actions/create_forum_post.js
new file mode 100644
index 000000000..c6a760855
--- /dev/null
+++ b/actions/create_forum_post.js
@@ -0,0 +1,156 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Create Forum Post',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.postName || 'Unnamed Post'}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Forum Post'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: null,
+ authorUrl: 'https://github.com/master3395/dbm-mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['forumChannel', 'varName', 'postName', 'message', 'tags', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Post Name
+
+
+
+
+
+
+ Message Content
+
+
+
+
+
+
+ Tags (comma-separated tag IDs, leave blank for none)
+
+
`;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const targetServer = await this.getServerFromData(data.server, data.varName, cache);
+ const name = this.evalMessage(data.name2, cache);
+ const description = this.evalMessage(data.description, cache);
+ targetServer
+ .createTemplate(name, description)
+ .then((template) => {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(template.url, storage, varName2, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ mod() {},
+};
diff --git a/actions/create_image.js b/actions/create_image.js
new file mode 100644
index 000000000..e43344325
--- /dev/null
+++ b/actions/create_image.js
@@ -0,0 +1,124 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Create Image',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Image Editing',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.url}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Image'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['url', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Local/Web URL
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const Images = this.getDBM().Images;
+ Images.getImage(this.evalMessage(data.url, cache))
+ .then((image) => {
+ const varName = this.evalMessage(data.varName, cache);
+ const storage = parseInt(data.storage, 10);
+ this.storeValue(image, storage, varName, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/create_image_from_avatar.js b/actions/create_image_from_avatar.js
new file mode 100644
index 000000000..4a2b60da5
--- /dev/null
+++ b/actions/create_image_from_avatar.js
@@ -0,0 +1,124 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Create Image from Avatar',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Image Editing',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Image'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ const Images = this.getDBM().Images;
+ Images.getImage(member.user.displayAvatarURL({ forceStatic: true, extension: 'png', size: 4096 }))
+ .then((image) => {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage = parseInt(data.storage, 10);
+ this.storeValue(image, storage, varName2, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/create_invite.js b/actions/create_invite.js
new file mode 100644
index 000000000..d3e8d4334
--- /dev/null
+++ b/actions/create_invite.js
@@ -0,0 +1,187 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Create Invite',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Invite to ${presets.getChannelText(data.channel, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Text'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'varName', 'maxUses', 'lifetime', 'tempInvite', 'unique', 'storage', 'varName2', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Max Uses
+
+ Invite Lifetime (in seconds)
+
+
+
+ Temporary Invite
+
+ Is Unique
+
+
+
+
+
+
+
+
+
+
+
+ Reason
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const channel = await this.getChannelFromData(data.channel, data.varName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+
+ const options = {};
+ if (data.maxUses) {
+ options.maxUses = parseInt(this.evalMessage(data.maxUses, cache), 10);
+ } else {
+ options.maxUses = 0;
+ }
+ if (data.lifetime) {
+ options.maxAge = parseInt(this.evalMessage(data.lifetime, cache), 10);
+ } else {
+ options.maxAge = 0;
+ }
+ if (options.maxAge > 86400) options.maxAge = 86400;
+ if (reason) options.reason = reason;
+ options.temporary = data.temporary === 'true';
+ options.unique = data.unique === 'true';
+
+ if (Array.isArray(channel)) {
+ this.callListFunc(channel, 'createInvite', [options]).then((invite) => {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage2 = parseInt(data.storage, 10);
+ this.storeValue(invite.map((i) => i.url).join('\n'), storage2, varName2, cache);
+ this.callNextAction(cache);
+ });
+ } else if (channel?.createInvite) {
+ channel
+ .createInvite(options)
+ .then((invite) => {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage2 = parseInt(data.storage, 10);
+ this.storeValue(invite.url, storage2, varName2, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/create_json_file_MOD.js b/actions/create_json_file_MOD.js
new file mode 100644
index 000000000..8b014310d
--- /dev/null
+++ b/actions/create_json_file_MOD.js
@@ -0,0 +1,122 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Create Json File',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Json Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const fileName = data.fileName || 'file';
+ const finalFileName = fileName.toLowerCase().endsWith('.json') ? fileName : `${fileName}.json`;
+ return `Create ${finalFileName}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'File Path'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['fileName', 'filePath', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ File Name
+
+
+
+
+ File Path
+
+
+
+
+
+
+ `;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const fs = require('fs');
+ const path = require('path');
+ const data = cache.actions[cache.index];
+
+ let fileName = this.evalMessage(data.fileName, cache);
+ if (!fileName) fileName = 'file';
+
+ const finalFileName = fileName.toLowerCase().endsWith('.json') ? fileName : `${fileName}.json`;
+
+ const filePath = this.evalMessage(data.filePath, cache);
+ const fullPath = path.join(filePath, finalFileName);
+
+ const directoryPath = path.dirname(fullPath);
+ if (!fs.existsSync(directoryPath)) {
+ fs.mkdirSync(directoryPath, { recursive: true });
+ }
+
+ if (!fs.existsSync(fullPath)) {
+ fs.writeFileSync(fullPath, JSON.stringify({}, null, 2), 'utf8');
+ }
+
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(fullPath, storage, varName, cache);
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/create_list.js b/actions/create_list.js
new file mode 100644
index 000000000..8cfc481b9
--- /dev/null
+++ b/actions/create_list.js
@@ -0,0 +1,114 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Create List',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Lists and Loops',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storage = presets.variables;
+ return `${storage[parseInt(data.storage, 10)]} (${data.varName})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'List'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return ``;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const varName = this.evalMessage(data.varName, cache);
+ const storage = parseInt(data.storage, 10);
+ this.storeValue([], storage, varName, cache);
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/create_object_MOD.js b/actions/create_object_MOD.js
new file mode 100644
index 000000000..b18bb45d1
--- /dev/null
+++ b/actions/create_object_MOD.js
@@ -0,0 +1,82 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Create Object',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'JSON Things',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storage = presets.variables;
+ return `${storage[parseInt(data.storage, 10)]} (${data.varName})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Object'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return ``;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const varName = this.evalMessage(data.varName, cache);
+ const storage = parseInt(data.storage, 10);
+ this.storeValue({}, storage, varName, cache);
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/create_private_thread_MOD.js b/actions/create_private_thread_MOD.js
new file mode 100644
index 000000000..fad268098
--- /dev/null
+++ b/actions/create_private_thread_MOD.js
@@ -0,0 +1,85 @@
+module.exports = {
+ name: 'Create Private Thread',
+ section: 'Channel Control',
+ meta: {
+ version: '2.1.7',
+ preciseCheck: true,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods/blob/master/actions/create_private_thread_MOD.js',
+ },
+ fields: ['channel', 'channelVarName', 'threadName', 'autoArchiveDuration', 'reason', 'storage', 'storageVarName'],
+
+ subtitle(data, presets) {
+ return `Create Private Thread In ${presets.getChannelText(data.channel ?? 0, data.channelVarName)}`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.storageVarName, 'Channel'];
+ },
+
+ html() {
+ return `
+
+
+
+
+
+
+ Thread Name
+
+
+
+
+
+ Auto-Archive Duration
+
+
+
+
+
+
+
+
+
+
+
+ Reason
+
+
+
+
+
+ `;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const channel = await this.getChannelFromData(data.channel, data.channelVarName, cache);
+
+ const thread = await channel.threads.create({
+ name: this.evalMessage(data.threadName, cache),
+ autoArchiveDuration: data.autoArchiveDuration === 'max' ? 10080 : parseInt(data.autoArchiveDuration, 10),
+ type: 'PrivateThread',
+ reason: this.evalMessage(data.reason, cache) || null,
+ });
+
+ const storage = parseInt(data.storage, 10);
+ const storageVarName = this.evalMessage(data.storageVarName, cache);
+ this.storeValue(thread, storage, storageVarName, cache);
+
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/create_role.js b/actions/create_role.js
new file mode 100644
index 000000000..056a506bf
--- /dev/null
+++ b/actions/create_role.js
@@ -0,0 +1,184 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Create Role',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Role Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.roleName}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, 'Role'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['roleName', 'hoist', 'mentionable', 'color', 'position', 'storage', 'varName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+Name
+
+
+
+
+
+ Display Separately
+
+
+
+
+ Mentionable
+
+
+
+ Color
+
+
+
+
+ Position
+
+
+
+
+
+
+
+
+
+
+ Reason
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const server = cache.server;
+ if (!server) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ /** @type {import('discord.js').CreateRoleOptions} */
+ const roleData = {};
+ if (data.roleName) {
+ roleData.name = this.evalMessage(data.roleName, cache);
+ }
+ if (data.color) {
+ roleData.color = this.evalMessage(data.color, cache);
+ }
+ if (data.position) {
+ roleData.position = parseInt(this.evalMessage(data.position, cache), 10);
+ }
+ if (data.reason) {
+ roleData.reason = this.evalMessage(data.reason, cache);
+ }
+ roleData.hoist = data.hoist === 'true';
+ roleData.mentionable = data.mentionable === 'true';
+
+ server.roles
+ .create(roleData)
+ .then((role) => {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(role, storage, varName, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/create_server_template_MOD.js b/actions/create_server_template_MOD.js
new file mode 100644
index 000000000..67f1ba27f
--- /dev/null
+++ b/actions/create_server_template_MOD.js
@@ -0,0 +1,80 @@
+module.exports = {
+ name: 'Create Server Template MOD',
+ section: 'Server Control',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data) {
+ return `${data.templatename}`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'URL'];
+ },
+
+ fields: ['server', 'varName', 'templatename', 'templatedescricao', 'storage', 'varName2'],
+
+ html(isEvent, data) {
+ return `
+
Version 0.2
+
DBM-Extended
+
+
+
+
+Template Name
+
+
+
+
+Description
+
+ Maximum 120 characters
+
+
+
+
+ Store in
+
+
+
+ Variable Name
+
+
+
`;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const targetServer = await this.getServerFromData(data.server, data.varName, cache);
+ if (!targetServer) {
+ return this.callNextAction(cache);
+ }
+ const templatename = this.evalMessage(data.templatename, cache);
+ const templatedescricao = this.evalMessage(data.templatedescricao, cache);
+ let result = targetServer.createTemplate(templatename, templatedescricao).catch((err) => {
+ console.log('A template already exists on the server');
+ console.error(err);
+ });
+
+ if ((result = `https://discord.new/${(await targetServer.fetchTemplates()).map((v) => v.code)}`)) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ this.callNextAction(cache);
+ }
+ },
+
+ mod() {},
+};
diff --git a/actions/create_sticker.js b/actions/create_sticker.js
new file mode 100644
index 000000000..11b386142
--- /dev/null
+++ b/actions/create_sticker.js
@@ -0,0 +1,168 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Create Sticker',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Emoji/Sticker Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.stickerName}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage2, 10) !== varType) return;
+ return [data.varName2, 'Sticker'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['stickerName', 'description', 'tag', 'storage', 'varName', 'storage2', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Sticker Name
+
+
+
+
+
+
+
+
+
+
+ Sticker Tag
+
+
+
+
+
+
+ Sticker Description
+
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = cache.server;
+ if (!server) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const stickerData = { name: this.evalMessage(data.stickerName, cache) };
+
+ const varName = this.evalMessage(data.varName, cache);
+ const image = this.getVariable(parseInt(data.storage, 10), varName, cache);
+ const { Images } = this.getDBM();
+
+ try {
+ stickerData.file = Images.createBuffer(image);
+ } catch {
+ return this.displayError(data, cache);
+ }
+
+ stickerData.tag = this.evalMessage(data.tag, cache);
+ stickerData.description = this.evalMessage(data.description, cache);
+
+ server.stickers
+ .create(stickerData)
+ .then((sticker) => {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage = parseInt(data.storage, 10);
+ this.storeValue(sticker, storage, varName2, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/create_thread.js b/actions/create_thread.js
new file mode 100644
index 000000000..55c9429c5
--- /dev/null
+++ b/actions/create_thread.js
@@ -0,0 +1,216 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Create Thread',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Create Thread Named "${data.threadName}" from ${
+ data.fromTarget._index === 0
+ ? presets.getChannelText(data.fromTarget?.channel ?? 0, data.fromTarget?.channelVarName)
+ : presets.getMessageText(data.fromTarget?.message ?? 0, data.fromTarget?.messageVarName)
+ }`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.storageVarName, 'Thread Channel'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['fromTarget', 'threadName', 'autoArchiveDuration', 'reason', 'storage', 'storageVarName', 'threadType'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Thread Name
+
+
+
+ Auto-Archive Duration
+
+
+
+
+
+ Thread Type
+
+
+
+
+
+
+
+
+ Reason
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+
+ let messageOrChannel = null;
+
+ if (data.fromTarget._index === 0) {
+ messageOrChannel = await this.getChannelFromData(data.fromTarget.channel, data.fromTarget.channelVarName, cache);
+ } else {
+ messageOrChannel = await this.getMessageFromData(data.fromTarget.message, data.fromTarget.messageVarName, cache);
+ }
+
+ let type = this.getDBM().DiscordJS.ChannelType.PublicThread;
+ switch (data.threadType) {
+ case '0':
+ type = this.getDBM().DiscordJS.ChannelType.PublicThread;
+ break;
+ case '1':
+ type = this.getDBM().DiscordJS.ChannelType.PrivateThread;
+ break;
+ }
+
+ // ThreadAutoArchiveDuration
+ // https://discord-api-types.dev/api/discord-api-types-v10/enum/ThreadAutoArchiveDuration
+ const threadOptions = {
+ name: this.evalMessage(data.threadName, cache),
+ autoArchiveDuration: data.autoArchiveDuration === 'max' ? 10080 : parseInt(data.autoArchiveDuration, 10),
+ type,
+ };
+
+ if (data.reason) {
+ const reason = this.evalMessage(data.reason, cache);
+ threadOptions.reason = reason;
+ }
+
+ if (messageOrChannel !== null) {
+ if (Array.isArray(messageOrChannel)) {
+ this.callListFunc(messageOrChannel, 'startThread', [threadOptions]).then(() => this.callNextAction(cache));
+ } else if (messageOrChannel?.startThread) {
+ messageOrChannel
+ .startThread(threadOptions)
+ .then((threadChannel) => {
+ const storage = parseInt(data.storage, 10);
+ const storageVarName = this.evalMessage(data.storageVarName, cache);
+ this.storeValue(threadChannel, storage, storageVarName, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ }
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/create_timestamp_discord_MOD.js b/actions/create_timestamp_discord_MOD.js
new file mode 100644
index 000000000..64ce837d7
--- /dev/null
+++ b/actions/create_timestamp_discord_MOD.js
@@ -0,0 +1,119 @@
+module.exports = {
+ name: 'Create Timestamp Discord',
+ section: 'Other Stuff',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data) {
+ const info = [
+ 'Short time',
+ 'Very long',
+ 'Short date',
+ 'Long date',
+ 'Long date with short time',
+ 'Long date with day of week and short time',
+ 'Relative',
+ ];
+ const prse = parseInt(data.saida, 10);
+ return `${info[prse]}`;
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, 'Date'];
+ },
+
+ fields: ['date', 'saida', 'storage', 'varName'],
+
+ html(_isEvent, data) {
+ return `
+
+ Data
+
+
+
+
+ Output
+
+
+
+
+ Store in
+
+
+
+ Variable name
+
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer');
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const moment = require('moment');
+ const saida = parseInt(data.saida, 10);
+ let result;
+
+ let date = moment(Date.parse(this.evalMessage(data.date, cache)));
+
+ if (isNaN(date)) {
+ console.error('Action Create Discord Timestamp: Invalid date format!');
+ result = 'Invalid date format!';
+ } else {
+ date += '-';
+ date = date.replace('000-', '');
+ date = date.toString();
+
+ switch (saida) {
+ case 0:
+ result = ``;
+ break;
+ case 1:
+ result = ``;
+ break;
+ case 2:
+ result = ``;
+ break;
+ case 3:
+ result = ``;
+ break;
+ case 4:
+ result = ``;
+ break;
+ case 5:
+ result = ``;
+ break;
+ case 6:
+ result = ``;
+ break;
+ }
+ }
+
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/create_together_MOD.js b/actions/create_together_MOD.js
new file mode 100644
index 000000000..3349bc6be
--- /dev/null
+++ b/actions/create_together_MOD.js
@@ -0,0 +1,133 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Create Together',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'DBM Extended',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Action created by DBM Extended`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.1.5', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['together'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain Information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source Together
+
+
+
+
+
Zmiena = \${tempVars("GameInvite")}
+ `;
+ },
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ // Use DBM's DiscordJS for version compatibility (supports both v13 and v14)
+ const { MessageEmbed } = this.getDBM().DiscordJS;
+ const client = this.getDBM().Bot.bot;
+ const { interaction } = cache;
+ const { DiscordTogether } = require('discord-together');
+
+ client.discordTogether = new DiscordTogether(client);
+
+ if (interaction.member.voice.channel) {
+ client.discordTogether.createTogetherCode(interaction.member.voice.channelId, data.together).then((invite) => {
+ const result = invite.code;
+ this.storeValue(result, 1, 'GameInvite', cache);
+ this.callNextAction(cache);
+ });
+ } else {
+ const embederror = new MessageEmbed()
+ .setTitle(`Error!`)
+ .setColor(0xff0000) // Red color as number for v14 compatibility
+ .setTimestamp()
+ .setDescription(
+ `
+
+ > ** Join the voice channel **
+
+ `,
+ )
+ .setFooter({
+ text: `${interaction.member.user.username} (${interaction.member.user.id})`,
+ iconURL: `${interaction.member.user.displayAvatarURL({ dynamic: true })}`,
+ });
+ interaction.reply({ embeds: [embederror], ephemeral: true });
+ }
+ },
+
+ mod() {},
+};
diff --git a/actions/create_transcript_MOD.js b/actions/create_transcript_MOD.js
new file mode 100644
index 000000000..9a60ac0c2
--- /dev/null
+++ b/actions/create_transcript_MOD.js
@@ -0,0 +1,205 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Create Transcript',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Gets a Transcript from a Channel: ${presets.getChannelText(data.channel, data.varName1)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, storage) {
+ const type = parseInt(data.storage, 10);
+ if (type !== storage) return;
+ return [data.varName2, 'Transcript (HTML)'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: [
+ 'fileName',
+ 'saveImages',
+ 'useSSR',
+ 'channel',
+ 'storage',
+ 'varName1',
+ 'varName2',
+ 'footerText',
+ 'poweredBy',
+ 'messageLimit',
+ ],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html() {
+ return `
+
+
+
+ `;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+
+ const variableValue = this.evalMessage(data.variableValue, cache);
+ const variableType = parseInt(data.variableType, 10);
+ let value;
+
+ switch (variableType) {
+ case 0: // String
+ value = String(variableValue);
+ break;
+ case 1: // Number
+ value = Number(variableValue);
+ break;
+ case 2: // Boolean
+ if (typeof variableValue === 'string') {
+ const lower = variableValue.toLowerCase().trim();
+ if (lower === 'true' || lower === '1') {
+ value = true;
+ } else if (lower === 'false' || lower === '0') {
+ value = false;
+ } else {
+ value = lower.length > 0;
+ }
+ } else {
+ value = Boolean(variableValue);
+ }
+ break;
+
+ case 3: // Undefined
+ value = undefined;
+ break;
+ case 4: // Null
+ value = null;
+ break;
+ default:
+ value = variableValue;
+ }
+
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage = parseInt(data.storage, 10);
+ this.storeValue(value, storage, varName2, cache);
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/create_voice_channel.js b/actions/create_voice_channel.js
new file mode 100644
index 000000000..2091c0609
--- /dev/null
+++ b/actions/create_voice_channel.js
@@ -0,0 +1,173 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Create Voice Channel',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.channelName}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Voice Channel'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channelName', 'bitrate', 'userLimit', 'storage', 'varName', 'categoryID', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+Name
+
+
+
+
+Category ID
+
+
+
+
+
+ Bitrate
+
+
+
+ User Limit
+
+
+
+
+
+
+
+
+
+
+ Reason
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const server = cache.server;
+ if (!server?.channels) return this.callNextAction(cache);
+
+ const name = this.evalMessage(data.channelName, cache);
+ const storage = parseInt(data.storage, 10);
+ const reason = this.evalMessage(data.reason, cache);
+
+ /** @type {import('discord.js').GuildChannelCreateOptions} */
+ const channelData = {
+ name,
+ reason,
+ type: this.getDBM().DiscordJS.ChannelType.GuildVoice,
+ };
+ if (data.bitrate) {
+ channelData.bitrate = parseInt(this.evalMessage(data.bitrate, cache), 10) * 1000;
+ }
+ if (data.userLimit) {
+ channelData.userLimit = parseInt(this.evalMessage(data.userLimit, cache), 10);
+ }
+ if (data.categoryID) {
+ channelData.parent = server.channels.cache.get(this.evalMessage(data.categoryID, cache));
+ }
+
+ server.channels
+ .create(channelData)
+ .then((channel) => {
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(channel, storage, varName, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/crosspost_message_MOD.js b/actions/crosspost_message_MOD.js
index 35e78e0a7..9d22ae1da 100644
--- a/actions/crosspost_message_MOD.js
+++ b/actions/crosspost_message_MOD.js
@@ -36,7 +36,7 @@ module.exports = {
async action(cache) {
const data = cache.actions[cache.index];
- const message = await this.getMessageFromData(data.mssage, data.varName, cache);
+ const message = await this.getMessageFromData(data.message, data.varName, cache);
if (!message) return this.callNextAction(cache);
diff --git a/actions/defer_interaction.js b/actions/defer_interaction.js
new file mode 100644
index 000000000..3cc3de4dd
--- /dev/null
+++ b/actions/defer_interaction.js
@@ -0,0 +1,113 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Defer Interaction',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const deferType = data.deferType === 'update' ? 'Update' : 'Reply';
+ const ephemeral = data.ephemeral ? ' (Ephemeral)' : '';
+ return `Defer ${deferType}${ephemeral}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: null,
+ authorUrl: 'https://github.com/master3395/dbm-mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['deferType', 'ephemeral'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Defer Type
+
+
+
+
+
+
+ Ephemeral (Only for Reply)
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const interaction = cache.interaction;
+
+ if (!interaction) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ try {
+ if (data.deferType === 'update') {
+ // Defer update for buttons/select menus
+ if (interaction.deferred || interaction.replied) {
+ this.callNextAction(cache);
+ return;
+ }
+ await interaction.deferUpdate();
+ } else {
+ // Defer reply for slash commands
+ if (interaction.deferred || interaction.replied) {
+ this.callNextAction(cache);
+ return;
+ }
+ await interaction.deferReply({ ephemeral: data.ephemeral === 'true' });
+ }
+ this.callNextAction(cache);
+ } catch (err) {
+ this.displayError(data, cache, err);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/delete_bulk_messages.js b/actions/delete_bulk_messages.js
new file mode 100644
index 000000000..767905922
--- /dev/null
+++ b/actions/delete_bulk_messages.js
@@ -0,0 +1,182 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Delete Bulk Messages',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Delete ${data.count} messages from ${presets.getChannelText(data.channel, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'count', 'condition', 'custom', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Amount to Delete
+
+
+
+
+ Delete Condition
+
+
+
+ Code
+
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChange2 = function (event) {
+ const value = parseInt(event.value, 10);
+ const varNameInput = document.getElementById('varNameContainer2');
+ if (value === 0) {
+ varNameInput.style.display = 'none';
+ } else {
+ varNameInput.style.display = null;
+ }
+ };
+
+ glob.onChange2(document.getElementById('condition'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const source = await this.getChannelFromData(data.channel, data.varName, cache);
+
+ if (!source?.messages) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const count = Math.min(parseInt(this.evalMessage(data.count, cache), 10), 100);
+ const options = {
+ limit: count,
+ };
+
+ if (cache.msg) {
+ options.before = cache.msg.id;
+ }
+
+ source.messages
+ .fetch(options)
+ .then((messages) => {
+ const condition = parseInt(data.condition, 10);
+ if (condition === 1) {
+ let author;
+ try {
+ author = this.eval(data.custom, cache);
+ } catch (e) {
+ this.displayError(data, cache, e);
+ author = null;
+ }
+ if (author?.id) {
+ messages = messages.filter((m) => m.author.id === author.id);
+ }
+ } else if (condition === 2) {
+ const cond = data.custom;
+ messages = messages.filter((message) => {
+ let result = false;
+ try {
+ result = Boolean(this.eval(cond, cache));
+ } catch (e) {
+ this.displayError(data, cache, `Error with custom eval:\n${e.stack}`);
+ }
+ return result;
+ });
+ }
+ source
+ .bulkDelete(messages, true)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {},
+};
diff --git a/actions/delete_bulk_messages_MOD.js b/actions/delete_bulk_messages_MOD.js
new file mode 100644
index 000000000..0f2bcd213
--- /dev/null
+++ b/actions/delete_bulk_messages_MOD.js
@@ -0,0 +1,325 @@
+/* eslint-disable no-unused-vars */
+/* eslint-disable no-empty */
+
+module.exports = {
+ name: 'Delete Bulk Messages MOD',
+ displayName: 'Delete Bulk Messages',
+ section: 'Messaging',
+
+ subtitle(data) {
+ const channels = [
+ 'Same Channel',
+ 'Mentioned Channel',
+ '1st Server Channel',
+ 'Temp Variable',
+ 'Server Variable',
+ 'Global Variable',
+ ];
+ return `Delete ${data.count} messages from ${channels[parseInt(data.channel, 10)] || 'Nothing'}`;
+ },
+
+ fields: [
+ 'channel',
+ 'varName',
+ 'count',
+ 'type',
+ 'option',
+ 'msgid',
+ 'Con0',
+ 'Con1',
+ 'Con2',
+ 'Con3',
+ 'Con4',
+ 'Con5',
+ 'iffalse',
+ 'iffalseVal',
+ 'storage',
+ 'varName2',
+ ],
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName2, 'Message List'];
+ },
+
+ html(isEvent, data) {
+ return `
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+ document.getElementById('link').onclick = function onclick() {
+ require('child_process').execSync('start https://gist.github.com/LeonZ2019/336a20a85f8c37e5d9273d0c690040e6');
+ };
+
+ glob.onChangeFalse = function onChangeFalse(event) {
+ switch (parseInt(event.value, 10)) {
+ case 0:
+ case 1:
+ document.getElementById('iffalseContainer').style.display = 'none';
+ break;
+ case 2:
+ document.getElementById('iffalseName').innerHTML = 'Action Number';
+ document.getElementById('iffalseContainer').style.display = null;
+ break;
+ case 3:
+ document.getElementById('iffalseName').innerHTML = 'Number of Actions to Skip';
+ document.getElementById('iffalseContainer').style.display = null;
+ break;
+ case 4:
+ document.getElementById('iffalseName').innerHTML = 'Anchor ID';
+ document.getElementById('iffalseContainer').style.display = null;
+ break;
+ default:
+ break;
+ }
+ };
+ glob.onChange1 = function onChange1(type) {
+ const value = parseInt(type.value, 10);
+ const placeholder = document.getElementById('filterPlaceHolder');
+ const placeholder2 = document.getElementById('filterPlaceHolder2');
+ const placeholder3 = document.getElementById('filterPlaceHolder3');
+ if (value === 0) {
+ placeholder.style.display = 'none';
+ placeholder2.style.display = 'none';
+ placeholder3.style.display = 'none';
+ } else {
+ placeholder.style.display = null;
+ placeholder2.style.display = null;
+ placeholder3.style.display = null;
+ }
+ };
+ glob.onChange2 = function onChange2(event) {
+ const value = parseInt(event.value, 10);
+ const varNameInput = document.getElementById('varNameContainer2');
+ if (value === 0) {
+ varNameInput.style.display = 'none';
+ } else {
+ varNameInput.style.display = null;
+ }
+ };
+ glob.channelChange(document.getElementById('channel'), 'varNameContainer');
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer3');
+ glob.onChange1(document.getElementById('type'));
+ glob.onChange2(document.getElementById('option'));
+ glob.onChangeFalse(document.getElementById('iffalse'));
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const channel = parseInt(data.channel, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const source = this.getChannel(channel, varName, cache);
+
+ if (!source) {
+ this.displayError(data, cache, 'Channel does not exist!');
+ return this.callNextAction(cache);
+ }
+
+ const options = {};
+ const msgid = parseInt(this.evalMessage(data.msgid, cache), 10);
+ switch (parseInt(data.option, 10)) {
+ case 1:
+ options.before = msgid;
+ break;
+ case 2:
+ options.after = msgid;
+ break;
+ case 3:
+ options.around = msgid;
+ break;
+ default:
+ break;
+ }
+
+ options.limit = 100;
+ const limit = Math.min(parseInt(this.evalMessage(data.count, cache), 10), 100);
+ if (source?.messages?.fetch) {
+ try {
+ const Con0 = this.evalMessage(data.Con0, cache);
+ const Con1 = this.evalMessage(data.Con1, cache);
+ const Con2 = this.evalMessage(data.Con2, cache);
+ const Con3 = this.evalMessage(data.Con3, cache);
+ const Con4 = this.evalMessage(data.Con4, cache);
+ const Con5 = this.evalMessage(data.Con5, cache);
+ const { Collection } = this.getDBM().DiscordJS;
+ let messagesFound = new Collection();
+ let lastId;
+ let times = 0;
+ while (times === 0 || (messagesFound && messagesFound.size < limit)) {
+ times++;
+ if (times === 10) throw Error('Looping for 10 times. Stop searching messages.');
+ let messages;
+ if (lastId && (messagesFound.length || messagesFound.size) < limit) {
+ options.before = lastId;
+ messages = await source.messages.fetch(options);
+ } else {
+ messages = await source.messages.fetch(options);
+ lastId = messages.lastKey();
+ }
+ let filtered = messages;
+ if (Con0) filtered = filtered.filter((e) => e.author.id !== Con0.replace(/\D/g, ''));
+ if (Con1) filtered = (filtered || messages).filter((e) => e.author.id === Con1.replace(/\D/g, ''));
+ if (Con2 !== '0') {
+ filtered = (filtered || messages).filter((e) =>
+ Con2 === '1' ? e.embeds.length === 0 : e.embeds.length !== 0,
+ );
+ }
+ if (Con3) filtered = (filtered || messages).filter((e) => e.content.includes(Con3));
+ if (Con4) {
+ filtered = (filtered || messages).filter((message) => {
+ let result = false;
+ try {
+ result = Boolean(eval(Con4));
+ } catch {}
+ return result;
+ });
+ }
+ if (Con5 !== '0') {
+ filtered = (filtered || messages).filter((e) =>
+ Con5 === '1' ? e.attachments.size === 0 : e.attachments.size !== 0,
+ );
+ }
+ messagesFound = messagesFound.concat(filtered);
+ }
+ if (messagesFound.array) messagesFound = messagesFound.array();
+ if (messagesFound.length > limit) {
+ messagesFound.splice(limit);
+ }
+ const deleted = await source.bulkDelete(messagesFound);
+ const storage = parseInt(data.storage, 10);
+ if (storage !== 0 && deleted) {
+ let result = deleted.array ? deleted.array() : deleted;
+ if (deleted.length === 1) result = deleted[0];
+ const varName = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ } catch (err) {
+ if (
+ [
+ 'You can only bulk delete messages that are under 14 days old.',
+ 'Looping for 10 times. Stop searching messages.',
+ ].includes(err.message)
+ ) {
+ this.executeResults(false, data, cache);
+ } else {
+ this.displayError(data, cache, err);
+ }
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ mod() {},
+};
diff --git a/actions/delete_channel.js b/actions/delete_channel.js
new file mode 100644
index 000000000..800c7f2fc
--- /dev/null
+++ b/actions/delete_channel.js
@@ -0,0 +1,117 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Delete Channel',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getChannelText(data.storage, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const channel = await this.getChannelFromData(data.storage, data.varName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+ if (Array.isArray(channel)) {
+ this.callListFunc(channel, 'delete', [reason]).then(() => this.callNextAction(cache));
+ } else if (channel?.delete) {
+ channel
+ .delete(reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/delete_emoji.js b/actions/delete_emoji.js
new file mode 100644
index 000000000..39507de36
--- /dev/null
+++ b/actions/delete_emoji.js
@@ -0,0 +1,157 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Delete Emoji',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Emoji/Sticker Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const inputTypes = ['Specific Emoji', 'Temp Variable', 'Server Variable', 'Global Variable'];
+ return `${inputTypes[parseInt(data.emoji, 10)]} (${data.varName})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['emoji', 'varName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source Emoji
+
+
+
+ Emoji Name
+
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChange1 = function (event) {
+ const value = parseInt(event.value, 10);
+ const varNameInput = document.getElementById('extName');
+ if (value === 0) {
+ varNameInput.innerHTML = 'Emoji Name';
+ } else {
+ varNameInput.innerHTML = 'Variable Name';
+ }
+ };
+
+ glob.onChange1(document.getElementById('emoji'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const server = cache.server;
+ const type = parseInt(data.emoji, 10);
+ const reason = this.evalMessage(data.reason, cache);
+ const varName = this.evalMessage(data.varName, cache);
+ let emoji;
+ if (type === 0) {
+ emoji = server.emojis.cache.find((e) => e.name === varName);
+ } else {
+ emoji = this.getVariable(type, varName, cache);
+ }
+ if (!emoji) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ if (emoji?.delete) {
+ emoji
+ .delete(reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/delete_guild_scheduled_event_MOD.js b/actions/delete_guild_scheduled_event_MOD.js
new file mode 100644
index 000000000..25b2c4730
--- /dev/null
+++ b/actions/delete_guild_scheduled_event_MOD.js
@@ -0,0 +1,108 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Delete Guild Scheduled Event',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Guild Scheduled Events',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Delete Guild Event: ${data.name || 'No Name'}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ const dataName = this.evalMessage(data.dataName, cache);
+
+ member.delData(dataName);
+ this.callNextAction(cache);
+ },
+
+ mod(DBM) {
+ Reflect.defineProperty(DBM.DiscordJS.GuildMember.prototype, 'delData', {
+ value(name) {
+ const { players } = DBM.Files.data;
+
+ if (name && players[this.id]?.[name]) {
+ delete players[this.id][name];
+ DBM.Files.saveData('players');
+ } else if (!name) {
+ delete players[this.id];
+ DBM.Files.saveData('players');
+ }
+ },
+ });
+
+ Reflect.defineProperty(DBM.DiscordJS.User.prototype, 'delData', {
+ value(name) {
+ const { players } = DBM.Files.data;
+
+ if (name && players[this.id]?.[name]) {
+ delete players[this.id][name];
+ DBM.Files.saveData('players');
+ } else if (!name) {
+ delete players[this.id];
+ DBM.Files.saveData('players');
+ }
+ },
+ });
+ },
+};
diff --git a/actions/delete_message.js b/actions/delete_message.js
new file mode 100644
index 000000000..e3ff27d25
--- /dev/null
+++ b/actions/delete_message.js
@@ -0,0 +1,126 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Delete Message',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMessageText(data.storage, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const message = await this.getMessageFromData(data.storage, data.varName, cache);
+
+ const reason = this.evalMessage(data.reason, cache);
+ const resolveDeleteError = (err) => {
+ const code = err && (err.code ?? err.rawError?.code);
+ if (code === 10008) {
+ this.callNextAction(cache);
+ return;
+ }
+ this.displayError(data, cache, err);
+ };
+ if (Array.isArray(message)) {
+ this.callListFunc(message, 'delete', [{ reason }])
+ .then(() => this.callNextAction(cache))
+ .catch((err) => resolveDeleteError(err));
+ } else if (message?.delete) {
+ message
+ .delete({ reason })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => resolveDeleteError(err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/delete_role.js b/actions/delete_role.js
new file mode 100644
index 000000000..18d3e73d8
--- /dev/null
+++ b/actions/delete_role.js
@@ -0,0 +1,117 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Delete Role',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Role Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getRoleText(data.storage, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const role = await this.getRoleFromData(data.storage, data.varName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+ if (Array.isArray(role)) {
+ this.callListFunc(role, 'delete', [reason]).then(() => this.callNextAction(cache));
+ } else if (role?.delete) {
+ role
+ .delete(reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/delete_sticker.js b/actions/delete_sticker.js
new file mode 100644
index 000000000..1de9dbdf2
--- /dev/null
+++ b/actions/delete_sticker.js
@@ -0,0 +1,157 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Delete Sticker',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Emoji/Sticker Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const inputTypes = ['Specific Sticker', 'Temp Variable', 'Server Variable', 'Global Variable'];
+ return `${inputTypes[parseInt(data.sticker, 10)]} (${data.varName})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['sticker', 'varName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source Emoji
+
+
+
+ Sticker Name
+
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChange1 = function (event) {
+ const value = parseInt(event.value, 10);
+ const varNameInput = document.getElementById('extName');
+ if (value === 0) {
+ varNameInput.innerHTML = 'Sticker Name';
+ } else {
+ varNameInput.innerHTML = 'Variable Name';
+ }
+ };
+
+ glob.onChange1(document.getElementById('sticker'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const server = cache.server;
+ const type = parseInt(data.sticker, 10);
+ const reason = this.evalMessage(data.reason, cache);
+ const varName = this.evalMessage(data.varName, cache);
+ let sticker;
+ if (type === 0) {
+ sticker = server.stickers.cache.find((e) => e.name === varName);
+ } else {
+ sticker = this.getVariable(type, varName, cache);
+ }
+ if (!sticker) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ if (sticker?.delete) {
+ sticker
+ .delete(reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/delete_thread_MOD.js b/actions/delete_thread_MOD.js
new file mode 100644
index 000000000..e93358616
--- /dev/null
+++ b/actions/delete_thread_MOD.js
@@ -0,0 +1,37 @@
+module.exports = {
+ name: 'Delete Thread',
+ section: 'Channel Control',
+ subtitle(data, presets) {
+ return `Delete Thread: "${presets.getChannelText(data.thread, data.threadVarName)}"`;
+ },
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+ fields: ['thread', 'threadVarName', 'reason'],
+ html() {
+ return `
+
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer');
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const moment = require('moment');
+
+ const date = this.evalMessage(data.date, cache);
+ const date2 = this.evalMessage(data.date2, cache);
+ const saida = parseInt(data.saida, 10);
+
+ let d1 = date;
+ let d2 = date2;
+
+ if (d1 === 'new') {
+ d1 = new Date();
+ }
+
+ if (d2 === 'new') {
+ d2 = new Date();
+ }
+
+ let result = moment(d2, 'DD/MM/YYYY HH:mm:ss').diff(moment(d1, 'DD/MM/YYYY HH:mm:ss'), 'seconds');
+
+ switch (saida) {
+ case 0:
+ if (isNaN(result) || result === 'Invalid date') {
+ result = 'Invalid date!';
+ } else {
+ let s = result;
+ let m = Math.floor(s / 60);
+ s %= 60;
+ let h = Math.floor(m / 60);
+ m %= 60;
+ const d = Math.floor(h / 24);
+ h %= 24;
+
+ result = `${d}d ${h}h ${m}m ${s}s`;
+ }
+ break;
+ case 1:
+ if (isNaN(result) || result === 'Invalid date') {
+ result = 'Invalid date!';
+ }
+ break;
+ }
+
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/disable_buttons_select.js b/actions/disable_buttons_select.js
new file mode 100644
index 000000000..9fc6197d0
--- /dev/null
+++ b/actions/disable_buttons_select.js
@@ -0,0 +1,239 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Disable Buttons and Selects',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMessageText(data.storage, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'type', 'disable', 'searchValue'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Components to Disable
+
+
+
+
+ Disable or Re-enable
+
+
+
+
+
+
+ Component Label/ID
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob } = this;
+
+ glob.onButtonSelectTypeChange = function (event) {
+ const input = document.getElementById('nameContainer');
+ input.style.display = event.value === 'findButton' || event.value === 'findSelect' ? null : 'none';
+ };
+
+ glob.onButtonSelectTypeChange(document.getElementById('type'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const message = await this.getMessageFromData(data.storage, data.varName, cache);
+
+ const type = data.type;
+
+ let sourceButton = null;
+ if (cache.interaction.isButton()) {
+ sourceButton = cache.interaction.customId;
+ }
+
+ let sourceSelect = null;
+ if (cache.interaction.isStringSelectMenu()) {
+ sourceSelect = cache.interaction.customId;
+ }
+
+ const disable = (data.disable ?? 'disable') === 'disable';
+ let components = null;
+ let searchValue = null;
+
+ if (message?.components) {
+ const { ActionRowBuilder, ComponentType, Component } = this.getDBM().DiscordJS;
+ const oldComponents = message.components;
+ const newComponents = [];
+
+ for (let i = 0; i < oldComponents.length; i++) {
+ const compData = oldComponents[i];
+ const rowComps = compData instanceof ActionRowBuilder ? compData.toJSON() : compData;
+ const newRowComps = [];
+
+ for (let j = 0; j < rowComps.components.length; j++) {
+ const compStructure = rowComps.components[j];
+ const comp = compStructure instanceof Component ? compStructure.toJSON() : compStructure;
+ const id = comp.custom_id ?? comp.customId;
+
+ switch (type) {
+ case 'all': {
+ comp.disabled = disable;
+ break;
+ }
+ case 'allButtons': {
+ if (comp.type === 2 || comp.type === ComponentType.Button) comp.disabled = disable;
+ break;
+ }
+ case 'allSelects': {
+ if (comp.type === 3 || comp.type === ComponentType.SelectMenu) comp.disabled = disable;
+ break;
+ }
+ case 'sourceButton': {
+ if (id === sourceButton) comp.disabled = disable;
+ break;
+ }
+ case 'sourceSelect': {
+ if (id === sourceSelect) comp.disabled = disable;
+ break;
+ }
+ case 'findButton':
+ case 'findSelect': {
+ if (searchValue === null) searchValue = this.evalMessage(data.searchValue, cache);
+ if (id === searchValue || comp.label === searchValue) comp.disabled = disable;
+ break;
+ }
+ }
+
+ newRowComps.push(comp);
+ }
+
+ newComponents.push(
+ ActionRowBuilder.from({
+ data: oldComponents.data,
+ components: newRowComps,
+ }),
+ );
+ }
+
+ components = newComponents;
+ }
+
+ if (components) {
+ if (Array.isArray(message)) {
+ this.callListFunc(message, 'edit', [{ components }]).then(() => this.callNextAction(cache));
+ } else if (
+ cache.interaction?.message?.id === message?.id &&
+ cache.interaction?.update &&
+ !cache.interaction?.replied
+ ) {
+ cache.interaction
+ .update({ components })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else if (message?.edit) {
+ message
+ .edit({ components })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ if (message.components) {
+ message.components = components;
+ }
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/disable_command.js b/actions/disable_command.js
new file mode 100644
index 000000000..b60a86e85
--- /dev/null
+++ b/actions/disable_command.js
@@ -0,0 +1,204 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Disable Command',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.disable === 'disable' ? 'Disable' : 'Re-enable'} "${data.command}"`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['fromTarget', 'command', 'disable'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Command
+
+
+
+
+
+
+ Disable or Re-enable
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ const $cmds = glob.$cmds;
+ const coms = document.getElementById('command');
+ let innerHTML = '';
+ for (let i = 0; i < $cmds.length; i++) {
+ if ($cmds[i] && $cmds[i].comType >= 4 && $cmds[i].comType <= 6) {
+ innerHTML += `\n`;
+ }
+ }
+ coms.innerHTML = innerHTML;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const { Bot, Files } = this.getDBM();
+
+ const id = data.command;
+
+ let name;
+ const allData = Files.data.commands;
+ for (let i = 0; i < allData.length; i++) {
+ if (allData[i]?._id === id) {
+ name = allData[i].name;
+ break;
+ }
+ }
+
+ const names = Bot.validateSlashCommandName(name);
+ if (!names || names.length < 1 || !names[0]) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ name = names[0];
+
+ const { ApplicationCommandPermissionType } = this.getDBM().DiscordJS;
+
+ let memberOrRole = null;
+ let resolvedType;
+ if (data.fromTarget._index === 0) {
+ memberOrRole = await this.getMemberFromData(data.fromTarget.member, data.fromTarget.memberVarName, cache);
+ resolvedType = ApplicationCommandPermissionType.User;
+ } else {
+ memberOrRole = await this.getRoleFromData(data.fromTarget.role, data.fromTarget.roleVarName, cache);
+ resolvedType = ApplicationCommandPermissionType.Role;
+ }
+
+ if (!memberOrRole) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const resolvedId = memberOrRole?.id;
+
+ const disable = data.disable === 'disable';
+
+ let command = Bot.bot.application.commands.cache.find((com) => com.name === name);
+ if (!command) {
+ command = cache.server.commands.cache.find((com) => com.name === name);
+ }
+
+ if (command) {
+ const permissions = [
+ {
+ id: resolvedId,
+ type: resolvedType,
+ permission: !disable,
+ },
+ ];
+
+ command.permissions
+ .add({ permissions })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/disconnect_user_MOD.js b/actions/disconnect_user_MOD.js
new file mode 100644
index 000000000..a046cbb1a
--- /dev/null
+++ b/actions/disconnect_user_MOD.js
@@ -0,0 +1,134 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Disconnect Member',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Mods',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/disconnect_user_MOD.js',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const type = parseInt(data.member, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const member = this.getMember(type, varName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+ if (Array.isArray(member)) {
+ this.callListFunc(
+ member.map((m) => m.voice),
+ 'disconnect',
+ [reason],
+ ).then(() => this.callNextAction(cache));
+ } else if (member?.voice.disconnect) {
+ member.voice
+ .disconnect(reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/draw_image.js b/actions/draw_image.js
new file mode 100644
index 000000000..02de1c9dd
--- /dev/null
+++ b/actions/draw_image.js
@@ -0,0 +1,157 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Draw Image on Image',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Image Editing',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storeTypes = presets.variables;
+ return `${storeTypes[parseInt(data.storage2, 10)]} (${data.varName2}) -> ${
+ storeTypes[parseInt(data.storage, 10)]
+ } (${data.varName})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'storage2', 'varName2', 'x', 'y', 'mask'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+
+
+ X Position
+
+
+
+ Y Position
+
+
+
+
+
+
+
+ Draw Effect
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const image = this.getVariable(storage, varName, cache);
+ if (!image || !image.composite) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const storage2 = parseInt(data.storage2, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const image2 = this.getVariable(storage2, varName2, cache);
+ if (!image2) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const x = parseInt(this.evalMessage(data.x, cache), 10);
+ const y = parseInt(this.evalMessage(data.y, cache), 10);
+ const mask = data.mask;
+
+ if (mask === '2') {
+ image.mask(image2, x, y);
+ } else if (mask === '1') {
+ this.getDBM().Images.drawImageOnImage(image, image2, x, y);
+ } else {
+ image.composite(image2, x, y);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/draw_text.js b/actions/draw_text.js
new file mode 100644
index 000000000..f2bd65350
--- /dev/null
+++ b/actions/draw_text.js
@@ -0,0 +1,147 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Draw Text on Image',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Image Editing',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.text}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'x', 'y', 'font', 'width', 'text'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Local Font URL (.fnt)
+
+ X Position
+
+
+
+ Max Width
+
+ Y Position
+
+
+
+
+
+
+ Text
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const Images = this.getDBM().Images;
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const image = this.getVariable(storage, varName, cache);
+ if (!image) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const fontName = this.evalMessage(data.font, cache);
+ const x = parseInt(this.evalMessage(data.x, cache), 10);
+ const y = parseInt(this.evalMessage(data.y, cache), 10);
+ const width = data.width ? parseInt(this.evalMessage(data.width, cache), 10) : null;
+ const text = this.evalMessage(data.text, cache);
+
+ Images.getFont(fontName)
+ .then(
+ function (font) {
+ if (width) {
+ image.print(font, x, y, text, width);
+ } else {
+ image.print(font, x, y, text);
+ }
+ this.callNextAction(cache);
+ }.bind(this),
+ )
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/edit_button_MOD.js b/actions/edit_button_MOD.js
new file mode 100644
index 000000000..634764626
--- /dev/null
+++ b/actions/edit_button_MOD.js
@@ -0,0 +1,290 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Edit Button',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Message Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data) {
+ if (data.sourceButton === 'current') {
+ return 'Edit Current Button';
+ } else if (data.sourceButton === 'byId') {
+ return `Edit Button by ID (${data.buttonId || 'No ID'})`;
+ }
+ return 'Edit button';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['sourceButton', 'buttonId', 'newLabel', 'newStyle', 'newEmoji', 'newURL', 'disabled'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+ Change name to
+
+
+
+
+ Change emoji to
+
+
+
+
+
+Change the type to
+
+PRIMARY (Blue)
+SECONDARY (Grey)
+SUCCESS (Green)
+DANGER (Red)
+Or use a variable, example \${tempVars("color")}
+`;
+ },
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_0_iftruefalse_to_branch(data);
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onButtonSelectTypeChange = function (event) {
+ const input = document.getElementById('nameContainer');
+ input.style.display = event.value === 'findButton' || event.value === 'findSelect' ? null : 'none';
+ };
+
+ glob.onButtonSelectTypeChange(document.getElementById('type'));
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const alterartype = this.evalMessage(data.alterartype, cache);
+ const alteraremoji = this.evalMessage(data.alteraremoji, cache);
+ const alterarnome = this.evalMessage(data.alterarnome, cache);
+ const message = await this.getMessageFromData(data.storage, data.varName, cache);
+
+ const type = data.type;
+
+ let sourceButton = null;
+ if (cache.interaction.isButton()) {
+ sourceButton = cache.interaction.customId;
+ }
+
+ if (cache.interaction.isSelectMenu()) {
+ const _sourceSelect = cache.interaction.customId;
+ }
+
+ let components = null;
+ let searchValue = null;
+
+ if (message?.components) {
+ const { MessageActionRow } = this.getDBM().DiscolordJS;
+ const oldComponents = message.components;
+ const newComponents = [];
+
+ for (let i = 0; i < oldComponents.length; i++) {
+ const compData = oldComponents[i];
+ const comps = compData instanceof MessageActionRow ? compData.toJSON() : compData;
+
+ for (let j = 0; j < comps.components.length; j++) {
+ const comp = comps.components[j];
+ const id = comp.custom_id ?? comp.customId;
+
+ switch (type) {
+ case 'all': {
+ comp.style = alterartype;
+ comp.label = alterarnome;
+ comp.emoji = alteraremoji;
+ break;
+ }
+ case 'sourceButton': {
+ if (id === sourceButton) comp.style = alterartype;
+ if (id === sourceButton) comp.label = alterarnome;
+ if (id === sourceButton) comp.emoji = alteraremoji;
+ break;
+ }
+ case 'findButton': {
+ if (searchValue === null) searchValue = this.evalMessage(data.searchValue, cache);
+ if (id === searchValue || comp.style === searchValue) comp.style = alterartype;
+ if (id === searchValue || comp.label === searchValue) comp.label = alterarnome;
+ if (id === searchValue || comp.emoji === searchValue) comp.emoji = alteraremoji;
+ break;
+ }
+ }
+ }
+
+ newComponents.push(comps);
+ }
+
+ components = newComponents;
+ }
+
+ if (components) {
+ if (Array.isArray(message)) {
+ this.callListFunc(message, 'edit', [{ components }]).then(() => this.callNextAction(cache));
+ } else if (
+ cache.interaction?.message?.id === message?.id &&
+ cache.interaction?.update &&
+ !cache.interaction?.replied
+ ) {
+ cache.interaction
+ .update({ components })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else if (message?.edit) {
+ message
+ .edit({ components })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ if (message.components) {
+ message.components = components;
+ }
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ mod() {},
+};
diff --git a/actions/edit_channel.js b/actions/edit_channel.js
new file mode 100644
index 000000000..0f1594f5b
--- /dev/null
+++ b/actions/edit_channel.js
@@ -0,0 +1,304 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Edit Any Channel',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const channelTypes = ['Text Channel', 'Voice Channel', 'Thread Channel'];
+ return `Edit ${presets.getChannelText(data.channel, data.channelVarName)} as a ${
+ channelTypes[data.channelEdits._index ?? 0]
+ }`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'channelVarName', 'channelName', 'reason', 'channelEdits'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+ Tags (comma-separated tag IDs, leave blank to keep current)
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const thread = await this.getThreadFromData(data.post, data.varName, cache);
+
+ if (!thread) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ try {
+ const editData = {};
+
+ // Update name if provided
+ const postName = this.evalMessage(data.postName, cache);
+ if (postName && postName.trim()) {
+ editData.name = postName.trim();
+ }
+
+ // Update tags if provided
+ const tagsInput = this.evalMessage(data.tags, cache);
+ if (tagsInput && tagsInput.trim()) {
+ editData.appliedTags = tagsInput
+ .split(',')
+ .map((tag) => tag.trim())
+ .filter((tag) => tag);
+ }
+
+ // Only edit if there's something to change
+ if (Object.keys(editData).length > 0) {
+ await thread.edit(editData);
+ }
+
+ this.callNextAction(cache);
+ } catch (err) {
+ this.displayError(data, cache, err);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/edit_message.js b/actions/edit_message.js
new file mode 100644
index 000000000..dfc0253ce
--- /dev/null
+++ b/actions/edit_message.js
@@ -0,0 +1,128 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Edit Message',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMessageText(data.storage, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'message'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Note:
+ Bots are only able to edit their own messages.
+
+
+
+
+
+
+
+
+
+
+ Edited Message Content
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const message = await this.getMessageFromData(data.storage, data.varName, cache);
+
+ if (Array.isArray(message)) {
+ const content = this.evalMessage(data.message, cache);
+ this.callListFunc(message, 'edit', [content]).then(() => this.callNextAction(cache));
+ } else if (message?.edit) {
+ const content = this.evalMessage(data.message, cache);
+ message
+ .edit(content)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/edit_role.js b/actions/edit_role.js
new file mode 100644
index 000000000..053c4a3be
--- /dev/null
+++ b/actions/edit_role.js
@@ -0,0 +1,173 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Edit Role',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Role Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getRoleText(data.storage, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['roleName', 'hoist', 'mentionable', 'color', 'position', 'storage', 'varName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Name
+
+
+
+
+
+
+ Display Separately
+
+ Mentionable
+
+
+
+
+ Color
+
+ Position
+
+
+
+
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+
+ const roleData = {};
+ if (data.roleName) {
+ roleData.name = this.evalMessage(data.roleName, cache);
+ }
+ if (data.color) {
+ roleData.color = this.evalMessage(data.color, cache);
+ }
+ if (data.position) {
+ roleData.position = parseInt(this.evalMessage(data.position, cache), 10);
+ }
+ if (data.hoist !== 'none') {
+ roleData.hoist = data.hoist === 'true';
+ }
+ if (data.mentionable !== 'none') {
+ roleData.mentionable = data.mentionable === 'true';
+ }
+ if (data.reason) {
+ roleData.reason = this.evalMessage(data.reason, cache);
+ }
+
+ const role = await this.getRoleFromData(data.storage, data.varName, cache);
+
+ if (Array.isArray(role)) {
+ this.callListFunc(role, 'edit', [{ roleData }]).then(() => this.callNextAction(cache));
+ } else if (role?.edit) {
+ role
+ .edit(roleData)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/edit_select_options.js b/actions/edit_select_options.js
new file mode 100644
index 000000000..cf206a29f
--- /dev/null
+++ b/actions/edit_select_options.js
@@ -0,0 +1,306 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Edit Select Menu Options',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const optionChange = data.optionChange ?? {};
+ if (optionChange._index === 0) {
+ return `Add Option Labeled "${optionChange.label}"`;
+ } else if (optionChange.type === 'value') {
+ return `Remove Option with Value "${optionChange.value}"`;
+ }
+ return `Remove Option with Label "${optionChange.value}"`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['message', 'messageVarName', 'type', 'searchValue', 'optionChange'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Components to Edit
+
+
+
+
+
+ Select Menu Label/ID
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+
+
+ Value
+
+
+
+ Description
+
+
+
+
+ Emoji
+
+
+
+
+
+
+
+
+
+
+ Remove Type
+
+
+
+ Option Value to Remove
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob } = this;
+
+ glob.onButtonSelectTypeChange = function (event) {
+ const input = document.getElementById('nameContainer');
+ input.style.display = event.value === 'findSelect' ? null : 'none';
+ };
+
+ glob.onButtonSelectTypeChange(document.getElementById('type'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const message = await this.getMessageFromData(data.message, data.messageVarName, cache);
+
+ const type = data.type;
+
+ let sourceSelect = null;
+ if (cache.interaction.isStringSelectMenu()) {
+ sourceSelect = cache.interaction.customId;
+ }
+
+ const optionChange = data.optionChange;
+
+ let newOptionData = null;
+ let removeOptionValue = null;
+ let removeOptionLabel = null;
+ if (optionChange._index === 0) {
+ newOptionData = {
+ label: this.evalMessage(optionChange.label, cache),
+ value: this.evalMessage(optionChange.value, cache),
+ default: false,
+ };
+ if (optionChange.description) {
+ newOptionData.description = this.evalMessage(optionChange.description, cache);
+ }
+ if (optionChange.emoji) {
+ newOptionData.emoji = this.evalMessage(optionChange.emoji, cache);
+ }
+ } else if (optionChange._index === 1) {
+ if (optionChange.type === 'value') {
+ removeOptionValue = this.evalMessage(optionChange.value, cache);
+ } else if (optionChange.type === 'label') {
+ removeOptionLabel = this.evalMessage(optionChange.value, cache);
+ }
+ }
+
+ const onSelectMenuFound = (select) => {
+ if (select) {
+ if (!select.options) select.options = [];
+ if (newOptionData) {
+ select.addOptions({ ...newOptionData });
+ } else if (removeOptionValue) {
+ select.setOptions(select.options.filter((o) => o.value !== removeOptionValue));
+ } else if (removeOptionLabel) {
+ select.setOptions(select.options.filter((o) => o.label !== removeOptionLabel));
+ }
+ }
+ };
+
+ let components = null;
+ let searchValue = null;
+
+ const { StringSelectMenuBuilder } = this.getDBM().DiscordJS;
+
+ if (message?.components) {
+ const { ActionRowBuilder, ComponentType } = this.getDBM().DiscordJS;
+ const oldComponents = message.components;
+ const newComponents = [];
+
+ for (let i = 0; i < oldComponents.length; i++) {
+ const compData = oldComponents[i];
+ const comps = compData instanceof ActionRowBuilder ? compData.toJSON() : compData;
+ const newComps = [];
+
+ for (let j = 0; j < comps.components.length; j++) {
+ const comp = StringSelectMenuBuilder.from(comps.components[j]);
+ const compData = comp.data;
+
+ switch (type) {
+ case 'allSelects': {
+ if (compData.type === 3 || compData.type === ComponentType.SelectMenu) {
+ onSelectMenuFound(comp);
+ }
+ break;
+ }
+ case 'sourceSelect': {
+ if (compData.custom_id === sourceSelect) {
+ onSelectMenuFound(comp);
+ }
+ break;
+ }
+ case 'findSelect': {
+ if (searchValue === null) {
+ searchValue = this.evalMessage(data.searchValue, cache);
+ }
+ if (
+ compData.custom_id === searchValue ||
+ compData.customId === searchValue ||
+ compData.label === searchValue
+ ) {
+ onSelectMenuFound(comp);
+ }
+ break;
+ }
+ }
+
+ newComps.push(comp);
+ }
+
+ newComponents.push(
+ ActionRowBuilder.from({
+ data: oldComponents.data,
+ components: newComps,
+ }),
+ );
+ }
+
+ components = newComponents;
+ }
+
+ if (components) {
+ if (Array.isArray(message)) {
+ this.callListFunc(message, 'edit', [{ components }]).then(() => this.callNextAction(cache));
+ } else if (message?.edit) {
+ message
+ .edit({ components })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ if (message.components) {
+ message.components = components;
+ }
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/edit_webhook.js b/actions/edit_webhook.js
new file mode 100644
index 000000000..711bb339b
--- /dev/null
+++ b/actions/edit_webhook.js
@@ -0,0 +1,68 @@
+module.exports = {
+ name: 'Edit Webhook',
+ section: 'Webhook Control',
+ meta: {
+ version: '2.1.7',
+ preciseCheck: false,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods/blob/master/actions/edit_webhook',
+ },
+ subtitle(data) {
+ return `${data.webhookName}`;
+ },
+ fields: ['webhookName', 'webhookIcon', 'webhook', 'varName'],
+
+ html(_isEvent, data) {
+ return `
+
`;
+ },
+
+ /* eslint-disable */
+ init() {
+ const { document } = this;
+ const methodSelect = document.getElementById('method');
+ const shiftContainer = document.getElementById('shift-container');
+ const keywordContainer = document.getElementById('keyword-container');
+
+ function toggleContainers() {
+ const method = parseInt(methodSelect.value, 10);
+ shiftContainer.style.display = method === 1 || method === 3 ? 'block' : 'none';
+ keywordContainer.style.display = method === 10 ? 'block' : 'none';
+ }
+
+ methodSelect.addEventListener('change', toggleContainers);
+ toggleContainers();
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const text = this.evalMessage(data.text, cache);
+ const method = parseInt(data.method, 10);
+ const encode = data.encode === 'true';
+ const shift = parseInt(data.shift, 10);
+ const keyword = this.evalMessage(data.keyword, cache);
+ let result;
+
+ switch (method) {
+ case 0: // Binary
+ result = encode
+ ? text
+ .split('')
+ .map((char) => char.charCodeAt(0).toString(2).padStart(8, '0'))
+ .join(' ')
+ : text
+ .split(' ')
+ .map((bin) => String.fromCharCode(parseInt(bin, 2)))
+ .join('');
+ break;
+ case 1: // Keyboard Shift
+ const keyboardShift = (char, shift) => {
+ const qwerty = 'qwertyuiopasdfghjklzxcvbnm';
+ const index = qwerty.indexOf(char.toLowerCase());
+ if (index === -1) return char;
+ const newIndex = (index + shift + qwerty.length) % qwerty.length;
+ return char === char.toUpperCase() ? qwerty[newIndex].toUpperCase() : qwerty[newIndex];
+ };
+ result = text
+ .split('')
+ .map((char) => keyboardShift(char, encode ? shift : -shift))
+ .join('');
+ break;
+ case 2: // Base64
+ result = encode ? Buffer.from(text).toString('base64') : Buffer.from(text, 'base64').toString('utf8');
+ break;
+ case 3: // Caesar Cipher
+ result = text
+ .split('')
+ .map((char) => {
+ if (char.match(/[a-z]/i)) {
+ const code = char.charCodeAt(0);
+ const offset = code >= 65 && code <= 90 ? 65 : 97;
+ return String.fromCharCode(((((code - offset + (encode ? shift : -shift)) % 26) + 26) % 26) + offset);
+ }
+ return char;
+ })
+ .join('');
+ break;
+ case 4: // Enigma Machine (simplified)
+ const enigma = (char, encode) => {
+ const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+ const reflector = 'YRUHQSLDPXNGOKMIEBFZCWVJAT';
+ const rotor1 = 'EKMFLGDQVZNTOWYHXUSPAIBRCJ';
+ const rotor2 = 'AJDKSIRUXBLHWTMCQGZNPYFVOE';
+ const rotor3 = 'BDFHJLCPRTXVZNYEIWGAKMUSQO';
+ const rotors = [rotor1, rotor2, rotor3];
+ const reverse = (rotor) =>
+ rotor.split('').reduce((acc, val, i) => {
+ acc[val] = alphabet[i];
+ return acc;
+ }, {});
+
+ if (!alphabet.includes(char.toUpperCase())) return char;
+ let index = alphabet.indexOf(char.toUpperCase());
+ for (let i = 0; i < rotors.length; i++) {
+ index = alphabet.indexOf(rotors[i][index]);
+ }
+ index = alphabet.indexOf(reflector[index]);
+ for (let i = rotors.length - 1; i >= 0; i--) {
+ index = alphabet.indexOf(reverse(rotors[i])[index]);
+ }
+ return alphabet[index];
+ };
+ result = text
+ .split('')
+ .map((char) => enigma(char, encode))
+ .join('');
+ break;
+ case 5: // Letter to Number
+ result = encode
+ ? text
+ .split('')
+ .map((char) => char.toLowerCase().charCodeAt(0) - 96)
+ .join(' ')
+ : text
+ .split(' ')
+ .map((num) => String.fromCharCode(parseInt(num, 10) + 96))
+ .join('');
+ break;
+ case 6: // Morse Code
+ const morseAlphabet = {
+ a: '.-',
+ b: '-...',
+ c: '-.-.',
+ d: '-..',
+ e: '.',
+ f: '..-.',
+ g: '--.',
+ h: '....',
+ i: '..',
+ j: '.---',
+ k: '-.-',
+ l: '.-..',
+ m: '--',
+ n: '-.',
+ o: '---',
+ p: '.--.',
+ q: '--.-',
+ r: '.-.',
+ s: '...',
+ t: '-',
+ u: '..-',
+ v: '...-',
+ w: '.--',
+ x: '-..-',
+ y: '-.--',
+ z: '--..',
+ 1: '.----',
+ 2: '..---',
+ 3: '...--',
+ 4: '....-',
+ 5: '.....',
+ 6: '-....',
+ 7: '--...',
+ 8: '---..',
+ 9: '----.',
+ 0: '-----',
+ '.': '.-.-.-',
+ '/': '-..-.',
+ ' ': '/',
+ };
+ if (encode) {
+ result = text
+ .toLowerCase()
+ .split('')
+ .map((char) => morseAlphabet[char] || '')
+ .join(' ');
+ } else {
+ const reversedMorseAlphabet = Object.fromEntries(Object.entries(morseAlphabet).map(([k, v]) => [v, k]));
+ result = text
+ .split(' ')
+ .map((code) => reversedMorseAlphabet[code] || '')
+ .join('');
+ }
+ break;
+ case 7: // Hexadecimal
+ result = encode
+ ? text
+ .split('')
+ .map((char) => char.charCodeAt(0).toString(16).padStart(2, '0'))
+ .join(' ')
+ : text
+ .split(' ')
+ .map((hex) => String.fromCharCode(parseInt(hex, 16)))
+ .join('');
+ break;
+ case 8: // URL Encoding
+ result = encode ? encodeURIComponent(text) : decodeURIComponent(text);
+ break;
+ case 9: // ROT13
+ result = text.replace(/[a-z]/gi, (char) => {
+ const offset = char <= 'Z' ? 65 : 97;
+ return String.fromCharCode(((char.charCodeAt(0) - offset + 13) % 26) + offset);
+ });
+ break;
+ case 10: // Vigenère Cipher
+ const vigenere = (text, keyword, encode) => {
+ const alphabet = 'abcdefghijklmnopqrstuvwxyz';
+ const shift = (char, keyChar, encode) => {
+ const charIndex = alphabet.indexOf(char.toLowerCase());
+ const keyIndex = alphabet.indexOf(keyChar.toLowerCase());
+ if (charIndex === -1 || keyIndex === -1) return char;
+ const newIndex = encode ? (charIndex + keyIndex) % 26 : (charIndex - keyIndex + 26) % 26;
+ return char === char.toUpperCase() ? alphabet[newIndex].toUpperCase() : alphabet[newIndex];
+ };
+
+ let keyIndex = 0;
+ return text
+ .split('')
+ .map((char) => {
+ if (alphabet.includes(char.toLowerCase())) {
+ const result = shift(char, keyword[keyIndex], encode);
+ keyIndex = (keyIndex + 1) % keyword.length;
+ return result;
+ }
+ return char;
+ })
+ .join('');
+ };
+
+ result = vigenere(text, keyword, encode);
+ break;
+ }
+
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
+/* eslint-enable */
diff --git a/actions/end_action_container.js b/actions/end_action_container.js
new file mode 100644
index 000000000..8c21a83c9
--- /dev/null
+++ b/actions/end_action_container.js
@@ -0,0 +1,111 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'End Actions Within Container',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'DBM-Enhanced',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return '';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.7',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/end_action_container.js',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding Ids in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: [],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return '';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const member = await this.getMemberFromData(1, undefined, cache);
+ member.setData('end-action-sequence', 1);
+ member.setData('end-stop-master', 1);
+ this.endActions(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/end_action_container_MOD.js b/actions/end_action_container_MOD.js
new file mode 100644
index 000000000..c3b561d57
--- /dev/null
+++ b/actions/end_action_container_MOD.js
@@ -0,0 +1,111 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'End Actions Within Container',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'DBM-Extended',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return '';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.7',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/end_if_ended.js',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding Ids in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: [],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return '';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const member = await this.getMemberFromData(1, undefined, cache);
+ member.setData('end-action-sequence', 1);
+ member.setData('end-stop-master', 1);
+ this.endActions(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/end_action_sequence.js b/actions/end_action_sequence.js
new file mode 100644
index 000000000..1fc85e5c6
--- /dev/null
+++ b/actions/end_action_sequence.js
@@ -0,0 +1,97 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'End Action Sequence',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return '';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: [],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return '';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ this.endActions(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/end_action_sequence_MOD.js b/actions/end_action_sequence_MOD.js
new file mode 100644
index 000000000..0d9dfb1c9
--- /dev/null
+++ b/actions/end_action_sequence_MOD.js
@@ -0,0 +1,108 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'End Action Sequence',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'DBM-Extended',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return '';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.7',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/end_if_ended.js',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding Ids in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: [],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return '';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ this.endActions(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/end_if_ended.js b/actions/end_if_ended.js
new file mode 100644
index 000000000..b44501379
--- /dev/null
+++ b/actions/end_if_ended.js
@@ -0,0 +1,149 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'End If Ended',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'DBM-Enhanced',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return '';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.2',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/end_if_ended.js',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding Ids in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['type', 'type2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Behavior Type
+
+
+
+ Branch Behavior
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const member = await this.getMemberFromData(1, undefined, cache);
+ const data = cache.actions[cache.index];
+ if (member.data('end-action-sequence', 0) === 1) {
+ if (parseInt(data.type, 10) === 0) {
+ member.setData('end-action-sequence', 0);
+ if (member.data('end-stop-master') === 1) {
+ member.setData('end-stop-master', 0);
+ this.endActions(cache);
+ } else {
+ this.callNextAction(cache);
+ }
+ } else if (parseInt(data.type2, 10) === 0) {
+ member.setData('end-stop-master', 1);
+ this.endActions(cache);
+ } else {
+ member.setData('end-stop-master', 0);
+ this.endActions(cache);
+ }
+ } else if (parseInt(data.type, 10) === 0) {
+ if (member.data('end-stop-master') === 1) {
+ member.setData('end-stop-master', 0);
+ this.endActions(cache);
+ } else {
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/end_if_ended_MOD.js b/actions/end_if_ended_MOD.js
new file mode 100644
index 000000000..62c23c20a
--- /dev/null
+++ b/actions/end_if_ended_MOD.js
@@ -0,0 +1,149 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'End If Ended',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'DBM-Extended',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return '';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/end_if_ended.js',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding Ids in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['type', 'type2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Behavior Type
+
+
+
+ Branch Behavior
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const member = await this.getMemberFromData(1, undefined, cache);
+ const data = cache.actions[cache.index];
+ if (member.data('end-action-sequence', 0) === 1) {
+ if (parseInt(data.type, 10) === 0) {
+ member.setData('end-action-sequence', 0);
+ if (member.data('end-stop-master') === 1) {
+ member.setData('end-stop-master', 0);
+ this.endActions(cache);
+ } else {
+ this.callNextAction(cache);
+ }
+ } else if (parseInt(data.type2, 10) === 0) {
+ member.setData('end-stop-master', 1);
+ this.endActions(cache);
+ } else {
+ member.setData('end-stop-master', 0);
+ this.endActions(cache);
+ }
+ } else if (parseInt(data.type, 10) === 0) {
+ if (member.data('end-stop-master') === 1) {
+ member.setData('end-stop-master', 0);
+ this.endActions(cache);
+ } else {
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/fetch_user_MOD.js b/actions/fetch_user_MOD.js
new file mode 100644
index 000000000..0a4886f7d
--- /dev/null
+++ b/actions/fetch_user_MOD.js
@@ -0,0 +1,92 @@
+module.exports = {
+ name: 'Fetch User MOD',
+ section: 'Member Control',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data) {
+ return `${data.User}`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'User'];
+ },
+
+ fields: ['User', 'storage', 'varName', 'iffalse', 'iffalseVal'],
+
+ html(isEvent, data) {
+ return `
+
Version 0.3
+
DBM-Extended
+
+ Search User By ID
+
+
+
+
+
+
+ If the user does not exist
+
+
+
For
+
+
+
+
+ Store in
+
+
+
+ Variable Name
+
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onComparisonChanged = function (event) {
+ if (event.value > '1') {
+ document.getElementById('iffalseContainer').style.display = null;
+ } else {
+ document.getElementById('iffalseContainer').style.display = 'none';
+ }
+ };
+
+ glob.onComparisonChanged(document.getElementById('iffalse'));
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const User = this.evalMessage(data.User, cache);
+ const client = this.getDBM().Bot.bot;
+
+ try {
+ const usuario = await client.users.fetch(User);
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(usuario, storage, varName, cache);
+ this.callNextAction(cache);
+ } catch (err) {
+ this.executeResults(false, data, cache);
+ }
+ },
+
+ mod() {},
+};
diff --git a/actions/find_channel.js b/actions/find_channel.js
new file mode 100644
index 000000000..3c0e3184c
--- /dev/null
+++ b/actions/find_channel.js
@@ -0,0 +1,169 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Find Channel',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = ['Channel ID', 'Channel Name', 'Channel Topic', 'Channel Position', 'Channel Category ID'];
+ return `Find Channel by ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Channel'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['info', 'find', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source Field
+
+
+
+ Search Value
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const server = cache.server;
+ if (!server?.channels) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const data = cache.actions[cache.index];
+ const info = parseInt(data.info, 10);
+ const find = this.evalMessage(data.find, cache);
+ const { ChannelType } = this.getDBM().DiscordJS;
+ const channels = server.channels.cache.filter(
+ (c) => c.type === ChannelType.GuildText || c.type === ChannelType.GuildAnnouncement,
+ );
+ let result;
+ switch (info) {
+ case 0:
+ result = channels.get(find);
+ break;
+ case 1:
+ result = channels.find((c) => c.name === find);
+ break;
+ case 2:
+ result = channels.find((c) => c.topic === find);
+ break;
+ case 3:
+ const position = parseInt(find, 10);
+ result = channels.find((c) => c.position === position);
+ break;
+ case 4:
+ result = channels.find((c) => c.parentId === find);
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/find_emoji.js b/actions/find_emoji.js
new file mode 100644
index 000000000..2f53bf236
--- /dev/null
+++ b/actions/find_emoji.js
@@ -0,0 +1,178 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Find Custom Emoji',
+
+ // ---------------------------------------------------------------------
+ // Action Display Name
+ //
+ // Overrides the name that appears in the editor.
+ // ---------------------------------------------------------------------
+
+ displayName: 'Find Custom Emoji/Sticker',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Emoji/Sticker Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const infoTexts = ['Emoji ID', 'Emoji Name', 'Sticker ID', 'Sticker Name'];
+ const info = parseInt(data.info, 10);
+ return `Find ${info >= 2 ? 'Sticker' : 'Emoji'} by ${infoTexts[info]} (${data.find})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ return [data.varName, info >= 2 ? 'Sticker' : 'Emoji'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['info', 'find', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source Field
+
+
+
+ Search Value
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const bot = this.getDBM().Bot.bot;
+ const server = cache.server;
+
+ const info = parseInt(data.info, 10);
+ const find = this.evalMessage(data.find, cache);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = bot.emojis.cache.get(find);
+ break;
+ case 1:
+ result = bot.emojis.cache.find((e) => e.name === find);
+ break;
+ case 2:
+ if (server) {
+ result = server.stickers.cache.get(find);
+ }
+ if (result === undefined) {
+ try {
+ result = await bot.fetchSticker(find);
+ } catch (err) {
+ this.displayError(data, cache, err);
+ }
+ }
+ case 3:
+ if (server) {
+ result = server.stickers.cache.find((s) => s.name === find);
+ }
+ default:
+ break;
+ }
+
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/find_member.js b/actions/find_member.js
new file mode 100644
index 000000000..2ff97c3fa
--- /dev/null
+++ b/actions/find_member.js
@@ -0,0 +1,167 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Find Member',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = ['Member ID', 'Member Username', 'Member Display Name', 'Member Color', 'Member Tag'];
+ return `Find Member by ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Server Member'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['info', 'find', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source Field
+
+
+
+ Search Value
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const server = cache.server;
+ if (!server?.members) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const data = cache.actions[cache.index];
+ const info = parseInt(data.info, 10);
+ const find = this.evalMessage(data.find, cache);
+ if (server.memberCount !== server.members.cache.size) server.members.fetch();
+ const members = server.members.cache;
+ let result;
+ switch (info) {
+ case 0:
+ result = members.get(find);
+ break;
+ case 1:
+ result = members.find((m) => m.user?.username === find);
+ break;
+ case 2:
+ result = members.find((m) => m.displayName === find);
+ break;
+ case 3:
+ result = members.find((m) => m.displayHexColor === find);
+ break;
+ case 4: // Leave this here until the username update is actually finished.
+ result = members.find((m) => m.user?.tag === find);
+ break;
+ default:
+ break;
+ }
+
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/find_role.js b/actions/find_role.js
new file mode 100644
index 000000000..37ca16588
--- /dev/null
+++ b/actions/find_role.js
@@ -0,0 +1,163 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Find Role',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Role Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = ['Role ID', 'Role Name', 'Role Color', 'Role Position'];
+ return `Find Role by ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Role'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['info', 'find', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source Field
+
+
+
+ Search Value
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const server = cache.server;
+ if (!server || !server.roles) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const data = cache.actions[cache.index];
+ const info = parseInt(data.info, 10);
+ const find = this.evalMessage(data.find, cache);
+ const roles = server.roles.cache;
+ let result;
+
+ switch (info) {
+ case 0:
+ result = roles.get(find);
+ break;
+ case 1:
+ result = roles.find((r) => r.name === find);
+ break;
+ case 2:
+ result = roles.find((r) => r.hexColor === find);
+ break;
+ case 3:
+ const position = parseInt(find, 10);
+ result = roles.find((r) => r.position === position);
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/find_server.js b/actions/find_server.js
new file mode 100644
index 000000000..00dc41ef1
--- /dev/null
+++ b/actions/find_server.js
@@ -0,0 +1,181 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Find Server',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Server Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = [
+ 'Server ID',
+ 'Server Name',
+ 'Server Name Acronym',
+ 'Server Member Count',
+ 'Server Region (Removed)',
+ 'Server Owner ID',
+ 'Server Verification Level',
+ 'Server Is Available',
+ ];
+ return `Find Server by ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Server'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['info', 'find', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source Field
+
+
+
+ Search Value
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const bot = this.getDBM().Bot.bot;
+ const servers = bot.guilds.cache;
+ const data = cache.actions[cache.index];
+ const info = parseInt(data.info, 10);
+ const find = this.evalMessage(data.find, cache);
+ let result;
+
+ switch (info) {
+ case 0:
+ result = servers.get(find);
+ break;
+ case 1:
+ result = servers.find((s) => s.name === find);
+ break;
+ case 2:
+ result = servers.find((s) => s.nameAcronym === find);
+ break;
+ case 3:
+ const memberCount = parseInt(find, 10);
+ result = servers.find((s) => s.memberCount === memberCount);
+ break;
+ case 5:
+ result = servers.find((s) => s.ownerId === find);
+ break;
+ case 6:
+ result = servers.find((s) => s.verificationLevel === find);
+ break;
+ case 7:
+ const available = find === 'true';
+ result = servers.find((s) => s.available === available);
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/find_text_on_image_MOD.js b/actions/find_text_on_image_MOD.js
new file mode 100644
index 000000000..da20ad47f
--- /dev/null
+++ b/actions/find_text_on_image_MOD.js
@@ -0,0 +1,71 @@
+module.exports = {
+ name: 'Get Text From Image',
+
+ section: 'Other Stuff',
+
+ fields: ['image', 'langs', 'storage', 'debug', 'varName'],
+
+ meta: {
+ version: '3.0.0',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data) {
+ return `Take text from ${data.image} and store in ${data.varName}`;
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, 'Text from image'];
+ },
+
+ html(data, isEvent) {
+ return `
+ Image link / File path
+
+ Languages
+
+ Show progress
+
+
+ `;
+ },
+
+ async init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const image = this.evalMessage(data.image, cache);
+ const langs = this.evalMessage(data.langs, cache);
+
+ const { createWorker } = require('tesseract.js');
+
+ const worker = createWorker({
+ logger: (m) => {
+ if (data.debug === '0') {
+ console.log(`${m.status}: ${m.progress}`);
+ }
+ }, // Add logger here
+ });
+
+ (async () => {
+ await worker.load();
+ await worker.loadLanguage(langs);
+ await worker.initialize(langs);
+ await worker.recognize(image).then((text) => {
+ this.storeValue(text.data.text, parseInt(data.storage, 10), data.varName, cache);
+ this.callNextAction(cache);
+ });
+ await worker.terminate();
+ })();
+ },
+
+ // (useless)
+ mod() {},
+};
diff --git a/actions/find_thread.js b/actions/find_thread.js
new file mode 100644
index 000000000..bf0f61ec4
--- /dev/null
+++ b/actions/find_thread.js
@@ -0,0 +1,161 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Find Thread',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = ['Thread ID', 'Thread Name'];
+ return `Find Thread by ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Thread Channel'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'channelVarName', 'info', 'find', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Source Field
+
+
+
+ Search Value
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const server = cache.server;
+ if (!server?.channels) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const data = cache.actions[cache.index];
+ const info = parseInt(data.info, 10);
+ const find = this.evalMessage(data.find, cache);
+
+ const channel = await this.getChannelFromData(data.channel, data.channelVarName, cache);
+
+ const threads = channel.threads.cache;
+ let result;
+ switch (info) {
+ case 0:
+ result = threads.get(find);
+ break;
+ case 1:
+ result = threads.find((c) => c.name === find);
+ break;
+ default:
+ break;
+ }
+
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/find_voice_channel.js b/actions/find_voice_channel.js
new file mode 100644
index 000000000..4fbfcbed3
--- /dev/null
+++ b/actions/find_voice_channel.js
@@ -0,0 +1,181 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Find Voice Channel',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = [
+ 'Voice Channel ID',
+ 'Voice Channel Name',
+ 'Voice Channel Position',
+ 'Voice Channel User Limit',
+ 'Voice Channel Bitrate',
+ 'Voice Channel Category ID',
+ ];
+ return `Find Voice Channel by ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Voice Channel'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['info', 'find', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source Field
+
+
+
+ Search Value
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const server = cache.server;
+ if (!server?.channels) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const data = cache.actions[cache.index];
+ const info = parseInt(data.info, 10);
+ const find = this.evalMessage(data.find, cache);
+ const { ChannelType } = this.getDBM().DiscordJS;
+ const channels = server.channels.cache.filter((c) => c.type === ChannelType.GuildVoice);
+ let result;
+
+ switch (info) {
+ case 0:
+ result = channels.get(find);
+ break;
+ case 1:
+ result = channels.find((c) => c.name === find);
+ break;
+ case 2:
+ const position = parseInt(find, 10);
+ result = channels.find((c) => c.position === position);
+ break;
+ case 3:
+ const userLimit = parseInt(find, 10);
+ result = channels.find((c) => c.userLimit === userLimit);
+ break;
+ case 4:
+ const bitrate = parseInt(find, 10) / 1000;
+ result = channels.find((c) => c.bitrate === bitrate);
+ break;
+ case 5:
+ result = channels.find((c) => c.parentId === find);
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/follow_up_interaction.js b/actions/follow_up_interaction.js
new file mode 100644
index 000000000..3780958d6
--- /dev/null
+++ b/actions/follow_up_interaction.js
@@ -0,0 +1,100 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Follow-Up Interaction',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Send follow-up message to interaction`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: null,
+ authorUrl: 'https://github.com/master3395/dbm-mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['message', 'ephemeral'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChangeType = function (event) {
+ const value = event.value;
+ document.getElementById('passwordSection').style.display = value === 'password' ? null : 'none';
+ document.getElementById('nicknameSection').style.display = value === 'nickname' ? null : 'none';
+ document.getElementById('licenseKeySection').style.display = value === 'licensekey' ? null : 'none';
+ document.getElementById('fullnameSection').style.display = value === 'fullname' ? null : 'none';
+ };
+
+ glob.onChangeType(document.getElementById('type'));
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const type = data.type;
+ const passwordDifficulty = this.evalMessage(data.passwordDifficulty, cache);
+ const min = parseInt(this.evalMessage(data.min, cache), 10);
+ const max = parseInt(this.evalMessage(data.max, cache), 10);
+ const nicknameLanguage = this.evalMessage(data.nicknameLanguage, cache);
+ const fullnameLanguage = this.evalMessage(data.fullnameLanguage, cache);
+ const licenseKeyLength = parseInt(this.evalMessage(data.licenseKeyLength, cache), 10);
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+
+ // Corrected path to generates.json in 'data' folder of the bot
+ const generatesFilePath = path.join(__dirname, '..', 'data', 'generates.json');
+
+ // Check if generates.json exists
+ let generatesData = {};
+ if (!fs.existsSync(generatesFilePath)) {
+ console.log('generates.json not found. Creating a new file with default data.');
+
+ // Default data for generates.json
+ generatesData = {
+ nicknames: {
+ pl: ['SzybkiStrzelec', 'MocnyMati', 'SzybkiGrom'],
+ en: ['VenomousViper', 'IronWulf', 'NightHawkX'],
+ },
+ firstNames: {
+ pl: ['Jan', 'Anna', 'Krzysztof'],
+ en: ['John', 'Emma', 'Chris'],
+ },
+ lastNames: {
+ pl: ['Kowalski', 'Nowak', 'Wiśniewski'],
+ en: ['Smith', 'Johnson', 'Williams'],
+ },
+ };
+
+ // Write default data to generates.json
+ fs.writeFileSync(generatesFilePath, JSON.stringify(generatesData, null, 2), 'utf8');
+ } else {
+ // Read the existing data from generates.json
+ generatesData = JSON.parse(fs.readFileSync(generatesFilePath, 'utf8'));
+ }
+
+ let result = '';
+
+ if (type === 'password') {
+ const charSets = {
+ easy: 'abcdefghijklmnopqrstuvwxyz',
+ medium: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
+ hard: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+[]{}|;:,.<>?',
+ };
+ const chars = charSets[passwordDifficulty];
+ const length = Math.floor(Math.random() * (max - min + 1)) + min;
+ for (let i = 0; i < length; i++) {
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
+ }
+ } else if (type === 'nickname') {
+ const nicknames = generatesData.nicknames[nicknameLanguage];
+ if (nicknames && nicknames.length > 0) {
+ // Correctly picking a random nickname from the list
+ result = nicknames[Math.floor(Math.random() * nicknames.length)];
+ }
+ } else if (type === 'licensekey') {
+ const lengths = [
+ 3, // 3 grupy po 5 znaków
+ 4, // 4 grupy po 5 znaków
+ 5, // 5 grup po 5 znaków
+ 6, // 6 grup po 5 znaków
+ ];
+
+ const numberOfGroups = lengths[licenseKeyLength - 1];
+ let licenseKey = '';
+
+ // Generowanie klucza licencji
+ for (let i = 0; i < numberOfGroups; i++) {
+ const group = Math.random().toString(36).substring(2, 7).toUpperCase(); // 5 znaków w każdej grupie
+ licenseKey += group;
+ if (i < numberOfGroups - 1) {
+ licenseKey += '-'; // Dodajemy myślnik po każdej grupie, z wyjątkiem ostatniej
+ }
+ }
+
+ result = licenseKey; // Przypisujemy wygenerowany klucz licencji
+ } else if (type === 'fullname') {
+ const firstNames = generatesData.firstNames[fullnameLanguage];
+ const lastNames = generatesData.lastNames[fullnameLanguage];
+ if (firstNames && lastNames && firstNames.length > 0 && lastNames.length > 0) {
+ const firstName = firstNames[Math.floor(Math.random() * firstNames.length)];
+ const lastName = lastNames[Math.floor(Math.random() * lastNames.length)];
+ result = `${firstName} ${lastName}`;
+ }
+ }
+
+ if (!result) {
+ console.log('Error: No data found for the selected type and language.');
+ return this.callNextAction(cache);
+ }
+
+ // Store the generated value in the selected variable
+ this.storeValue(result, storage, varName, cache);
+
+ // Proceed to next action
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/generate_random_number.js b/actions/generate_random_number.js
new file mode 100644
index 000000000..63737e31a
--- /dev/null
+++ b/actions/generate_random_number.js
@@ -0,0 +1,131 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Generate Random Number',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storage = presets.variables;
+ return `${storage[parseInt(data.storage, 10)]} (${data.varName}) => [${data.min}, ${data.max}]`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Number'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'min', 'max'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Minimum Range
+
+
+
+ Maximum Range
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const type = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const min = parseInt(this.evalMessage(data.min, cache), 10);
+ const max = parseInt(this.evalMessage(data.max, cache), 10) + 1;
+ const finalVal = Math.floor(Math.random() * (max - min)) + min;
+ this.storeValue(finalVal, type, varName, cache);
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/get_bot_as_member.js b/actions/get_bot_as_member.js
new file mode 100644
index 000000000..2fd4e528f
--- /dev/null
+++ b/actions/get_bot_as_member.js
@@ -0,0 +1,131 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Get Bot as Member',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Bot Client Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getServerText(data.server, data.varName)} ${data.dataName ? ` (${data.dataName})` : ''}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Server Member'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = await this.getServerFromData(data.server, data.varName, cache);
+
+ const callback = (me) => {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(me, storage, varName2, cache);
+ this.callNextAction(cache);
+ };
+
+ if (server?.members?.me) {
+ callback(server.members.me);
+ } else {
+ server?.members
+ ?.fetch?.(this.getDBM().Bot.bot.user.id)
+ .then(callback)
+ .catch((err) => this.displayError(data, cache, err));
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/get_color_MOD.js b/actions/get_color_MOD.js
new file mode 100644
index 000000000..ad56c44a1
--- /dev/null
+++ b/actions/get_color_MOD.js
@@ -0,0 +1,62 @@
+module.exports = {
+ name: 'Get Color',
+ section: 'Other Stuff',
+ eta: {
+ version: '3.2.5',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ subtitle(data) {
+ return `Get color: ${data.color || 'No Color Selected'}`;
+ },
+
+ fields: ['color', 'storage', 'varName2'],
+
+ html() {
+ return `
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const DBM = this.getDBM();
+ const DiscordJS = DBM.DiscordJS;
+ const isV14 = DBM.isDiscordJSv14 ? DBM.isDiscordJSv14() : parseInt(DiscordJS.version.split('.')[0], 10) >= 14;
+
+ const channel = await this.getChannelFromData(data.forumChannel, data.varName, cache);
+
+ if (!channel) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ // Check if channel is a forum channel
+ const ChannelType = DBM.getChannelType ? DBM.getChannelType() : DiscordJS.ChannelType || {};
+ const isForum = isV14
+ ? channel.type === ChannelType.GuildForum || channel.type === 15
+ : channel.type === 'GUILD_FORUM' || channel.type === 15;
+
+ if (!isForum) {
+ this.displayError(data, cache, new Error('Channel must be a forum channel'));
+ return;
+ }
+
+ try {
+ // Get available tags from forum channel
+ // v13 and v14 use the same API
+ const tags = channel.availableTags || [];
+
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(tags, storage, varName2, cache);
+ this.callNextAction(cache);
+ } catch (err) {
+ this.displayError(data, cache, err);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/get_item_from_list.js b/actions/get_item_from_list.js
new file mode 100644
index 000000000..f0b1b34de
--- /dev/null
+++ b/actions/get_item_from_list.js
@@ -0,0 +1,213 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Get Item from List',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Lists and Loops',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const list = presets.lists;
+ return `Get Item from ${list[parseInt(data.list, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const list = parseInt(data.list, 10);
+ let dataType = 'Unknown Type';
+ switch (list) {
+ case 0:
+ dataType = 'Server Member';
+ break;
+ case 1:
+ dataType = 'Channel';
+ break;
+ case 2:
+ case 5:
+ case 6:
+ dataType = 'Role';
+ break;
+ case 3:
+ dataType = 'Emoji';
+ break;
+ case 4:
+ dataType = 'Server';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['list', 'varName', 'getType', 'position', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source List
+
+
+
+ Variable Name
+
+
+
+
+
+
+
+
+ Item to Store
+
+
+
+ Position
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChange1 = function (event) {
+ const value = parseInt(event.value, 10);
+ const dom = document.getElementById('positionHolder');
+ if (value < 3) {
+ dom.style.display = 'none';
+ } else {
+ dom.style.display = null;
+ }
+ };
+
+ glob.listChange(document.getElementById('list'), 'varNameContainer');
+ glob.onChange1(document.getElementById('getType'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const list = (await this.getListFromData(data.list, data.varName, cache)) ?? [];
+
+ const type = parseInt(data.getType, 10);
+ let result;
+ switch (type) {
+ case 0:
+ result = list[0];
+ break;
+ case 1:
+ result = list[list.length - 1];
+ break;
+ case 2:
+ result = list[Math.floor(Math.random() * list.length)];
+ break;
+ case 3:
+ const position = parseInt(this.evalMessage(data.position, cache), 10);
+ if (position < 0) {
+ result = list[0];
+ } else if (position >= list.length) {
+ result = list[list.length - 1];
+ } else {
+ result = list[position];
+ }
+ break;
+ }
+
+ if (result) {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage2 = parseInt(data.storage, 10);
+ this.storeValue(result, storage2, varName2, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/get_item_from_object_MOD.js b/actions/get_item_from_object_MOD.js
new file mode 100644
index 000000000..8f180fa24
--- /dev/null
+++ b/actions/get_item_from_object_MOD.js
@@ -0,0 +1,100 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Get Item from Object',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'JSON Things',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Get Item from ${presets.variables[parseInt(data.storage1, 10)]} (${data.varName})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+
+ return [data.varName2, 'Unknown Type'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['storage1', 'varName', 'key', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Key
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const object = this.getVariable(data.storage1, data.varName, cache);
+
+ const result = object[data.key];
+ if (result) {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage2 = parseInt(data.storage, 10);
+ this.storeValue(result, storage2, varName2, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/get_list_length.js b/actions/get_list_length.js
new file mode 100644
index 000000000..278b21c87
--- /dev/null
+++ b/actions/get_list_length.js
@@ -0,0 +1,136 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Get List Length',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Lists and Loops',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const list = presets.lists;
+ return `Get ${list[parseInt(data.list, 10)]} Length`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Number'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['list', 'varName', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source List
+
+
+
+ Variable Name
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.listChange(document.getElementById('list'), 'varNameContainer');
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const list = await this.getListFromData(data.list, data.varName, cache);
+ if (list?.length) {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage2 = parseInt(data.storage, 10);
+ this.storeValue(list.length, storage2, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/get_list_length_MOD.js b/actions/get_list_length_MOD.js
new file mode 100644
index 000000000..08598904d
--- /dev/null
+++ b/actions/get_list_length_MOD.js
@@ -0,0 +1,68 @@
+module.exports = {
+ name: 'Get List Length MOD',
+ section: 'Lists and Loops',
+
+ subtitle(data, presets) {
+ const list = presets.lists;
+ return `Get ${list[parseInt(data.list, 10)]} Length`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Number'];
+ },
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: null,
+ authorUrl: 'https://github.com/master3395/dbm-mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ fields: ['list', 'varName', 'storage', 'varName2'],
+
+ html(isEvent, data) {
+ return `
+
+ `;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const Mods = this.getMods();
+ const giveawayCommands = Mods.require('./extensions/dashboard_EXT/tools/giveaway_commands');
+ const giveawayUtils = Mods.require('./extensions/dashboard_EXT/tools/giveaway_utils');
+
+ if (!giveawayUtils || !giveawayUtils.isGiveawaySystemAvailable()) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const interaction = await this.getVariableFromData(data.varName, data.varName, cache);
+ if (!interaction || !interaction.isCommand || !interaction.isCommand()) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ // Check if it's the giveaway command
+ if (interaction.commandName !== 'giveaway') {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const subcommand = interaction.options?.getSubcommand(false);
+ const options = interaction.options ? Array.from(interaction.options.data.values()) : [];
+
+ try {
+ const result = await giveawayCommands.executeGiveawayCommand(DBM, interaction, subcommand, options);
+ if (data.varName2) {
+ this.storeValue(result, 1, data.varName2, cache);
+ }
+ } catch (error) {
+ console.error('[Giveaway Slash Command] Error:', error);
+ if (!interaction.replied && !interaction.deferred) {
+ await interaction.reply({ content: 'An error occurred while processing the command.', ephemeral: true });
+ }
+ }
+
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/go_to_anchor.js b/actions/go_to_anchor.js
new file mode 100644
index 000000000..1396acb1d
--- /dev/null
+++ b/actions/go_to_anchor.js
@@ -0,0 +1,101 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Go To Action Anchor',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return data.anchorName;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['anchorName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+Action Anchor Name
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const anchorName = this.evalMessage(data.anchorName, cache);
+ cache.goToAnchor(anchorName);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/go_to_anchor_MOD.js b/actions/go_to_anchor_MOD.js
new file mode 100644
index 000000000..22250918c
--- /dev/null
+++ b/actions/go_to_anchor_MOD.js
@@ -0,0 +1,122 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Go To Action Anchor',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return data.anchorName
+ ? `${data.description}`
+ : `Jump to ${
+ data.jump_to_anchor
+ ? `the "${data.anchorName}" anchor in your command if it exists!`
+ : 'an anchor!'
+ }`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/end_if_ended.js',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['description', 'anchorName', 'color'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+Action Anchor Name
+
+
+
+ Anchor Color:
+
+
+
+ Description:
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const anchorName = this.evalMessage(data.anchorName, cache);
+ cache.goToAnchor(anchorName);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/html_to_image_MOD.js b/actions/html_to_image_MOD.js
new file mode 100644
index 000000000..b1510b644
--- /dev/null
+++ b/actions/html_to_image_MOD.js
@@ -0,0 +1,79 @@
+module.exports = {
+ name: 'HTML to Image',
+
+ section: 'Other Stuff',
+
+ fields: ['html', 'storage', 'height', 'url', 'width', 'varName'],
+
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/blob/main/actions/control_custom_data.js',
+ },
+
+ subtitle(data) {
+ return `Create image in ${data.url}`;
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, 'Image'];
+ },
+
+ html(data, isEvent) {
+ return `
+ HTML
+
+ Save file
+
+
+ Width (px)
+
+
+
+ Height (px)
+
+
+ `;
+ },
+
+ async init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const html = this.evalMessage(data.html, cache);
+ const url = this.evalMessage(data.url, cache);
+ const width = Number(this.evalMessage(data.width, cache));
+ const height = Number(this.evalMessage(data.height, cache));
+
+ const fs = require('node:fs');
+ const puppeteer = require('puppeteer');
+ const browser = await puppeteer.launch();
+ const page = await browser.newPage();
+
+ await page.setContent(html);
+
+ await page.setViewport({
+ width,
+ height,
+ });
+
+ const content = await page.$('body');
+ const imageBuffer = await content.screenshot({ omitBackground: true });
+
+ await page.close();
+ await browser.close();
+
+ fs.writeFileSync(url, imageBuffer);
+
+ // cache.msg.channel.send({content: `${cache.msg.author.username}'s base:\n`, files: [
+ // { attachment: imageBuffer }
+ // ]})
+
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/image_effect.js b/actions/image_effect.js
new file mode 100644
index 000000000..8f3327739
--- /dev/null
+++ b/actions/image_effect.js
@@ -0,0 +1,162 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Apply Image Effect',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Image Editing',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storeTypes = presets.variables;
+ const effect = [
+ 'Greyscale',
+ 'Invert',
+ 'Normalize',
+ 'Remove Transparency',
+ 'Apply Minor Blur',
+ 'Apply Major Blur',
+ 'Apply Sepia',
+ 'Dither',
+ ];
+ return `${storeTypes[parseInt(data.storage, 10)]} (${data.varName}) -> ${effect[parseInt(data.effect, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'effect'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Effect
+
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const image = this.getVariable(storage, varName, cache);
+ if (!image) {
+ this.callNextAction(cache);
+ return;
+ }
+ const effect = parseInt(data.effect, 10);
+ switch (effect) {
+ case 0:
+ image.greyscale();
+ break;
+ case 1:
+ image.invert();
+ break;
+ case 2:
+ image.normalize();
+ break;
+ case 3:
+ image.opaque();
+ break;
+ case 4:
+ image.blur(2);
+ break;
+ case 5:
+ image.blur(10);
+ break;
+ case 6:
+ image.sepia();
+ break;
+ case 7:
+ image.dither565();
+ break;
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/image_slash_MOD.js b/actions/image_slash_MOD.js
new file mode 100644
index 000000000..e3ac38df7
--- /dev/null
+++ b/actions/image_slash_MOD.js
@@ -0,0 +1,59 @@
+module.exports = {
+ name: 'Find Slash Image',
+
+ section: 'Messaging',
+
+ subtitle(data, presets) {
+ return 'Action created by DBM Extended';
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'PhotoUrl'];
+ },
+
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ fields: ['PhotoUrl', 'storage', 'varName'],
+
+ html(isEvent, data) {
+ return `
+
+
+ Nazwa parametru
+
+
+
+
+
+
+
+
+
Jeżeli ci nie działa napisz do mnie w wiadomośći prywatnej!
`;
+ },
+
+ init() {},
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const interaction = cache.interaction;
+ const PhotoUrl = this.evalMessage(data.PhotoUrl, cache);
+ const slashcmd = interaction.options.getAttachment(PhotoUrl);
+ const result = slashcmd.url;
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/join_voice_channel.js b/actions/join_voice_channel.js
new file mode 100644
index 000000000..f64d533db
--- /dev/null
+++ b/actions/join_voice_channel.js
@@ -0,0 +1,113 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Join Voice Channel',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getVoiceChannelText(data.channel, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.1.7', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return ``;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const Audio = this.getDBM().Audio;
+
+ const channel = await this.getVoiceChannelFromData(data.channel, data.varName, cache);
+ if (channel) {
+ Audio.connectToVoice(channel);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Requires Audio Libraries
+ //
+ // If 'true', this action requires audio libraries to run.
+ // ---------------------------------------------------------------------
+
+ requiresAudioLibraries: true,
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/join_voice_channel.ts b/actions/join_voice_channel.ts
new file mode 100644
index 000000000..c19e4c6dc
--- /dev/null
+++ b/actions/join_voice_channel.ts
@@ -0,0 +1,118 @@
+import { Actions, ActionsCache } from '../bot.ts';
+import Audio from '../bot_audio.ts';
+import { Action, ActionMod } from '../types.ts';
+
+type JoinVoiceChannelData = { channel: number; varName: string };
+
+export default {
+ //---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ //---------------------------------------------------------------------
+
+ name: 'Join Voice Channel',
+
+ //---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ //---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ //---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ //---------------------------------------------------------------------
+
+ subtitle(data: JoinVoiceChannelData, presets: any) {
+ return `${presets.getVoiceChannelText(data.channel, data.varName)}`;
+ },
+
+ //---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ //---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ //---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ //---------------------------------------------------------------------
+
+ fields: ['channel', 'varName'],
+
+ //---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //---------------------------------------------------------------------
+
+ html() {
+ return ``;
+ },
+
+ //---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ //---------------------------------------------------------------------
+
+ init() {},
+
+ //---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ //---------------------------------------------------------------------
+
+ async action(this: typeof Actions, cache: ActionsCache) {
+ const data = cache.actions[cache.index] as Action & JoinVoiceChannelData;
+ const channel = await this.getVoiceChannelFromData(data.channel, data.varName, cache);
+
+ if (channel) {
+ await Audio.connectToVoice(channel);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ //---------------------------------------------------------------------
+ // Requires Audio Libraries
+ //
+ // If 'true', this action requires audio libraries to run.
+ //---------------------------------------------------------------------
+
+ requiresAudioLibraries: true,
+
+ //---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ //---------------------------------------------------------------------
+
+ mod() {},
+} satisfies ActionMod;
diff --git a/actions/json_check_MOD.js b/actions/json_check_MOD.js
new file mode 100644
index 000000000..6193ce1f6
--- /dev/null
+++ b/actions/json_check_MOD.js
@@ -0,0 +1,134 @@
+const fs = require('fs');
+const path = require('path');
+
+module.exports = {
+ name: 'Check JSON File',
+
+ section: 'File Stuff',
+
+ subtitle(data) {
+ return `Check JSON file "${data.filepath}"`;
+ },
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: false,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ fields: ['filepath', 'checkType', 'title', 'contentTitle', 'branch'],
+
+ html() {
+ return `
+
+ `;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChangeAction = function onChangeAction(event) {
+ const value = event.value;
+ document.getElementById('titleSection').style.display =
+ value === 'addTitle' || value === 'addContent' || value === 'renameContent' ? 'block' : 'none';
+ document.getElementById('contentSection').style.display = value === 'addContent' ? 'block' : 'none';
+ document.getElementById('renameSection').style.display =
+ value === 'renameContent' || value === 'renameTitle' ? 'block' : 'none';
+ document.getElementById('deleteSection').style.display = value === 'deleteContent' ? 'block' : 'none';
+ };
+
+ glob.onChangeAction(document.getElementById('action'));
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ let filepath = this.evalMessage(data.filepath, cache);
+
+ if (filepath.startsWith('./')) {
+ filepath = path.join(__dirname, '..', filepath.substring(2));
+ }
+
+ const action = data.action;
+ const title = this.evalMessage(data.title, cache);
+ const contentTitle = this.evalMessage(data.contentTitle, cache);
+ const contentText = this.evalMessage(data.contentText, cache);
+ const oldTitle = this.evalMessage(data.oldTitle, cache);
+ const newTitle = this.evalMessage(data.newTitle, cache);
+ const deleteContentTitle = this.evalMessage(data.deleteContentTitle, cache);
+
+ // Load JSON file
+ let jsonData;
+ try {
+ if (fs.existsSync(filepath)) {
+ const fileData = fs.readFileSync(filepath);
+ jsonData = JSON.parse(fileData);
+ } else {
+ jsonData = [];
+ }
+ } catch (error) {
+ console.error(`Error reading JSON file: ${error}`);
+ jsonData = [];
+ }
+
+ let target;
+
+ switch (action) {
+ case 'addTitle':
+ if (title) {
+ jsonData.push({ Title: title });
+ }
+ break;
+ case 'addContent':
+ target = jsonData.find((item) => item.Title === title);
+ if (!target) {
+ target = { Title: title };
+ jsonData.push(target);
+ }
+ if (contentTitle.includes('/')) {
+ const keys = contentTitle.split('/');
+ keys.reduce(function addNestedContent(obj, key, index) {
+ if (index === keys.length - 1) {
+ obj[key] = isNaN(contentText) ? contentText : parseFloat(contentText);
+ } else {
+ obj[key] = obj[key] || {};
+ }
+ return obj[key];
+ }, target);
+ } else {
+ target[contentTitle] = isNaN(contentText) ? contentText : parseFloat(contentText);
+ }
+ break;
+ case 'renameContent':
+ jsonData.forEach((item) => {
+ if (item.Title === title && item[contentTitle]) {
+ item[newTitle] = item[contentTitle];
+ delete item[contentTitle];
+ }
+ });
+ break;
+ case 'renameTitle':
+ jsonData.forEach((item) => {
+ if (item.Title === oldTitle) {
+ item.Title = newTitle;
+ }
+ });
+ break;
+ case 'deleteContent':
+ jsonData.forEach((item) => {
+ if (item.Title === title) {
+ if (deleteContentTitle.includes('/')) {
+ const keys = deleteContentTitle.split('/');
+ keys.reduce(function deleteNestedContent(obj, key, index) {
+ if (index === keys.length - 1) {
+ delete obj[key];
+ } else {
+ return obj[key];
+ }
+ return obj;
+ }, item);
+ } else {
+ delete item[deleteContentTitle];
+ }
+ }
+ });
+ break;
+ case 'deleteTitle':
+ jsonData = jsonData.filter((item) => item.Title !== title);
+ break;
+ }
+
+ // Save JSON file
+ try {
+ fs.writeFileSync(filepath, JSON.stringify(jsonData, null, 2));
+ } catch (error) {
+ console.error(`Error writing JSON file: ${error}`);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/kick_member.js b/actions/kick_member.js
new file mode 100644
index 000000000..c0c906fa6
--- /dev/null
+++ b/actions/kick_member.js
@@ -0,0 +1,117 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Kick Member',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+ if (Array.isArray(member)) {
+ this.callListFunc(member, 'kick', [reason]).then(() => this.callNextAction(cache));
+ } else if (member?.kick) {
+ member
+ .kick(reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/leave_voice_channel.js b/actions/leave_voice_channel.js
new file mode 100644
index 000000000..9c9e14901
--- /dev/null
+++ b/actions/leave_voice_channel.js
@@ -0,0 +1,102 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Leave Voice Channel',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return 'The bot leaves voice channel.';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: [],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return '';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const server = cache.server;
+ const { Audio } = this.getDBM();
+ if (server) {
+ await Audio.disconnectFromVoice(server);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/level_system_MOD.js b/actions/level_system_MOD.js
new file mode 100644
index 000000000..74b3a7c26
--- /dev/null
+++ b/actions/level_system_MOD.js
@@ -0,0 +1,154 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Level System',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Economy',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Level and XP management`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['xpPerMessage', 'xpToLevelUp', 'actions'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Please put the Welcome action into a Bot Initialization event to be able to store the current song!
+
+
`;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const { Audio } = this.getDBM();
+ const targetServer = await this.getServerFromData(data.server, data.varName, cache);
+ if (!targetServer) {
+ return this.callNextAction(cache);
+ }
+
+ const status = parseInt(data.status, 10);
+ const loop = parseInt(data.loop, 10);
+
+ switch (status) {
+ case 0: // Enable
+ switch (loop) {
+ case 0: // Loop Queue
+ Audio.loopQueue[targetServer.id] = true;
+ break;
+ case 1: // Loop Item
+ Audio.loopItem[targetServer.id] = true;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 1: // Disable
+ switch (loop) {
+ case 0: // Loop Queue
+ Audio.loopQueue[targetServer.id] = false;
+ break;
+ case 1: // Loop Item
+ Audio.loopItem[targetServer.id] = false;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/loop_through_all_servers.js b/actions/loop_through_all_servers.js
new file mode 100644
index 000000000..3a490dce1
--- /dev/null
+++ b/actions/loop_through_all_servers.js
@@ -0,0 +1,168 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Loop Through All Servers',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Lists and Loops',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Loop through every server and run ${data.actions?.length ?? 0} actions.`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['type', 'actions'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+Call Type
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Pre-Init Code
+ //
+ // Before the fields from existing data in this action are applied
+ // to the user interface, this function is called if it exists.
+ // The existing data is provided, and a modified version can be
+ // returned. The returned version will be used if provided.
+ // This is to help provide compatibility with older versions of the action.
+ //
+ // The "formatters" argument contains built-in functions for formatting
+ // the data required for official DBM action compatibility.
+ // ---------------------------------------------------------------------
+
+ preInit(data, formatters) {
+ return formatters.compatibility_2_0_3_loopevent_to_actions(data);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const bot = this.getDBM().Bot.bot;
+
+ const actions = data.actions;
+ if (!actions || actions.length <= 0) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const waitForCompletion = data.type === 'true';
+
+ const servers = [...bot.guilds.cache.values()];
+ const act = actions[0];
+ if (act && this.exists(act.name)) {
+ const looper = (i) => {
+ if (!servers[i]) {
+ if (waitForCompletion) this.callNextAction(cache);
+ return;
+ }
+
+ this.executeSubActions(actions, cache, () => looper(i + 1));
+ };
+
+ looper(0);
+
+ if (!waitForCompletion) this.callNextAction(cache);
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.actions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/loop_through_list.js b/actions/loop_through_list.js
new file mode 100644
index 000000000..68e6901bc
--- /dev/null
+++ b/actions/loop_through_list.js
@@ -0,0 +1,252 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Loop Through List',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Lists and Loops',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const list = presets.lists;
+ return `Loop ${list[parseInt(data.list, 10)]} through ${data.actions?.length ?? 0} actions.`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['list', 'varName', 'tempVarName', 'type', 'actions'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Source List
+
+
+
+ Variable Name
+
+
+
+
+
+
+
+
+
+
+ Temp Var. Name (stores member)
+
+
+
+
+ Call Type
+
+
+
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChange1 = function (event) {
+ this.listChange(event, 'varNameContainer');
+ const id = parseInt(event.value, 10);
+ let result = '';
+ switch (id) {
+ case 0:
+ result = 'member';
+ break;
+ case 1:
+ result = 'channel';
+ break;
+ case 4:
+ result = 'server';
+ break;
+ case 2:
+ case 5:
+ case 6:
+ result = 'role';
+ break;
+ case 3:
+ result = 'emoji';
+ break;
+ case 7:
+ case 8:
+ case 9:
+ result = 'item';
+ break;
+ }
+ document.getElementById('tempName').innerHTML = result;
+ };
+
+ glob.onChange1(document.getElementById('list'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+
+ const actions = data.actions;
+ if (!actions) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const list = await this.getListFromData(data.list, data.varName, cache);
+
+ const waitForCompletion = data.type === 'true';
+
+ const act = actions[0];
+ if (list && act && this.exists(act.name)) {
+ const looper = (i) => {
+ if (!list[i]) {
+ if (waitForCompletion) {
+ this.callNextAction(cache);
+ }
+ return;
+ }
+
+ this.storeValue(list[i], 1, data.tempVarName, cache);
+ this.executeSubActions(actions, cache, () => looper(i + 1));
+ };
+
+ looper(0);
+
+ if (!waitForCompletion) {
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.actions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/loop_through_numbers.js b/actions/loop_through_numbers.js
new file mode 100644
index 000000000..f9f08d169
--- /dev/null
+++ b/actions/loop_through_numbers.js
@@ -0,0 +1,244 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Loop Through Numbers',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Lists and Loops',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ if (Math.abs(parseInt(data.increment, 10)) === 1) {
+ return `Call ${data.actions?.length ?? 0} actions ${Math.abs(data.endNum - data.startNum) + 1} times.`;
+ }
+ return `Call ${data.actions?.length ?? 0} actions while counting by ${data.increment}, from ${data.startNum} to ${
+ data.endNum
+ }.`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['startNum', 'endNum', 'increment', 'tempVarName', 'type', 'actions'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Start Number
+
+
+
+
+ End Number
+
+
+
+
+ Increment By
+
+
+
+
+
+
+
+
+
+
+ Temp Var. Name (stores number)
+
+
+
+
+ Call Type
+
+
+
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+
+ const actions = data.actions;
+ if (!actions || actions.length <= 0) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const startNumText = this.evalMessage(data.startNum, cache);
+ const endNumText = this.evalMessage(data.endNum, cache);
+ const incrementText = this.evalMessage(data.increment, cache);
+ const startNum = parseInt(startNumText, 10);
+ const endNum = parseInt(endNumText, 10);
+ const increment = parseInt(incrementText, 10);
+
+ let valid = isNaN(startNum) ? 1 : isNaN(endNum) ? 2 : isNaN(increment) ? 3 : 0;
+ if (valid === 0) {
+ if (increment === 0) {
+ valid = 4;
+ } else if (increment > 0 && startNum > endNum) {
+ valid = 5;
+ } else if (increment < 0 && startNum < endNum) {
+ valid = 6;
+ }
+ }
+
+ switch (valid) {
+ case 1: {
+ this.displayError(data, cache, `Start Number (${startNumText}) is not a valid number.`);
+ break;
+ }
+ case 2: {
+ this.displayError(data, cache, `End Number (${endNumText}) is not a valid number.`);
+ break;
+ }
+ case 3: {
+ this.displayError(data, cache, `Increment (${incrementText}) is not a valid number.`);
+ break;
+ }
+ case 4: {
+ this.displayError(data, cache, `Increment cannot be 0.`);
+ break;
+ }
+ case 5:
+ case 6: {
+ this.displayError(data, cache, `Increment detected to cause infinite loop.`);
+ break;
+ }
+ }
+
+ if (valid !== 0) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const waitForCompletion = data.type === 'true';
+
+ const looper = (i) => {
+ if ((startNum < endNum && i > endNum) || (startNum > endNum && i < endNum)) {
+ if (waitForCompletion) {
+ this.callNextAction(cache);
+ }
+ return;
+ }
+
+ this.storeValue(i, 1, data.tempVarName, cache);
+ this.executeSubActions(actions, cache, () => looper(i + increment));
+ };
+
+ looper(startNum);
+
+ if (!waitForCompletion) {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ this.prepareActions(data.actions);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/math_operation_MOD.js b/actions/math_operation_MOD.js
new file mode 100644
index 000000000..60bd6ce3a
--- /dev/null
+++ b/actions/math_operation_MOD.js
@@ -0,0 +1,129 @@
+module.exports = {
+ name: 'Math Operation',
+ section: 'Other Stuff',
+ meta: {
+ version: '2.1.1',
+ preciseCheck: false,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods/blob/master/actions/math_operation_MOD.js',
+ },
+
+ subtitle(data) {
+ const info = [
+ 'Round',
+ 'Absolute',
+ 'Ceil',
+ 'Floor',
+ 'Sine',
+ 'Cosine',
+ 'Tangent',
+ 'Arc Sine',
+ 'Arc Cosine',
+ 'Arc Tangent',
+ ];
+ return `${info[data.info]}`;
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, 'Number'];
+ },
+
+ fields: ['num', 'info', 'storage', 'varName'],
+
+ html(isEvent, data) {
+ return `
+
`;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const num = parseFloat(this.evalMessage(data.math, cache).replace(/,/g, ''));
+ const info = parseInt(data.info, 10);
+
+ if (!num) return this.callNextAction(cache);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = Math.round(num);
+ break;
+ case 1:
+ result = Math.abs(num);
+ break;
+ case 2:
+ result = Math.ceil(num);
+ break;
+ case 3:
+ result = Math.floor(num);
+ break;
+ case 4:
+ result = Math.sin(num);
+ break;
+ case 5:
+ result = Math.cos(num);
+ break;
+ case 6:
+ result = Math.tan(num);
+ break;
+ case 7:
+ result = Math.asin(num);
+ break;
+ case 8:
+ result = Math.acos(num);
+ break;
+ case 9:
+ result = Math.atan(num);
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/mod_info_MOD.js b/actions/mod_info_MOD.js
index 61e8825a1..1cd8e4916 100644
--- a/actions/mod_info_MOD.js
+++ b/actions/mod_info_MOD.js
@@ -134,7 +134,7 @@ span.discord_code_blocks {
Thank you for using the DBM Mod Collection!
If you want to tell us something, join the Discord Guild below.
And if something doesn't work feel free to create an issue on GitHub
- or open #support and describe your problem.
+ or open #support and describe your problem.
Discord:
Join the Discord Guild to stay updated and be able to suggest things.
diff --git a/actions/mod_info_changelog_MOD.js b/actions/mod_info_changelog_MOD.js
new file mode 100644
index 000000000..f9d322ca3
--- /dev/null
+++ b/actions/mod_info_changelog_MOD.js
@@ -0,0 +1,349 @@
+module.exports = {
+ name: 'Changelog',
+ section: '#Mod Information',
+ meta: {
+ version: '2.0.11',
+ preciseCheck: false,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods/blob/master/actions/mod_info_changelog_MOD.js',
+ },
+
+ subtitle() {
+ return 'Does nothing - Click "Edit" for more information';
+ },
+
+ fields: [],
+
+ html() {
+ return `
+
+
+
+
1.9.7: Bunch of bug fixes and new actions!
+ ● Module Installer now functions as intended.
+ ● Added Set Bot Typing Mod
+ ● Added Get Dominant Color Mod
+ ● Added Clone Channel Mod
+ ● Added Convert Text To List Mod
+ ● Added Delete Member Data Mod
+ ● Added Delete Server Data Mod
+ ● Added Edit Embed Object Mod
+ ● Added Remove From Queue Mod
+ ● Added Shuffle Queue Mod
+ ● Added Store Data List Mod
+ ● Added Store Command Info Mod
+ ● Added Store Date Info Plus Mod
+ ● Added Delete Bulk Messages Mod
+ ● Added Canvas Create Background Mod
+ ● Added Canvas Create Image Mod
+ ● Added Canvas Crop Image Mod
+ ● Added Canvas Draw Image Mod
+ ● Added Canvas Draw Text Mod
+ ● Added Canvas Edit Image Border Mod
+ ● Added Canvas Generate Progress Bar Mod
+ ● Added Canvas Image Filter Mod
+ ● Added Canvas Image Options Mod
+ ● Added Canvas Save Image Mod
+ ● Added Canvas Send Image Mod
+ ● Added Store Audit Log Info Mod
+ ● Added Store Audit Log List Mod
+ ● Added Edit Item From List Mod
+ ● Added Auto Help Menu Mod
+ ● Added Delete WebHook Mod
+ ● Added Send Mail Mod
+ ● Added Attach Image to Embed Mod
+ ● Added Check if Command Exists Mod
+ ● Added Check Role Permissions Mod
+ ● Added Variable Pattern Mod
+ ● Added Repeat String Mod
+ ● Added Add Blank Field
+ ● Added Set Server Owner Mod
+ ● Added Create Server Mod
+ ● Added Delete Server Mod
+ ● Added Set AFK Timeout Mod
+ ● Added Find Invite Mod
+ ● Revised Find Member
+ ● Revised Store Invite Info
+ ● Revised Check Variable
+ ● Revised File Control Mod
+ ● Revised Await Reaction Call Action Mod
+ ● Revised YouTube Info Mod
+ ● Revised Find Text Mod
+ ● Revised Store Message Embed Object
+ ● Revised Set Time Restriction Mod
+ ● Revised Store Server Info
+ ● Fixed DBL to top.gg transition
+ ● Removed AlternativeMods folder
+ ● Removed Node_Modules folder
+
+
+
1.9.6: Almost everything requires beta! WOO!
+ ● Added Check if File Exists Mod
+ ● Added Generate Random Word
+ ● Added Merge Lists Mod
+ ● Added Slice Mod
+ ● Added Play Youtube (Revised default action)
+ ● Added Create Anchor Mod
+ ● Added Jump To Anchor Mod
+ ● Added Inspect List or Object Mod
+ ● Added Filter List or Object Mod
+ ● Revised Check If Member
+ ● Revised Parse From Sored JSON
+ ● Revised Read File
+ ● Revised Store Member Info
+ ● Revised Check Variable
+ ● Revised Check Parameters
+ ● Revised Randomize Letters
+ ● Revised Remove Item From list
+ ● Revised Set Bot Activity
+ ● Revised Store Audio Info Mod
+ ● Revised Youtube Info Mod
+ ● Revised Check If User Reacted Mod
+ ● Revised Convert Seconds To Days Mod
+ ● Revised File Control (V4) Mod
+ ● Revised Game Server Mod
+ ● Revised Add Embed Field
+ ● Revised Set Embed Description
+ ● Revised Send Embed Message
+ ● Revised Send Image Mod
+ ● Revised Send Gif Mod
+ ● Revised Send Log Message
+ ● Revised Find Emoji
+ ● Revised Find Emoji in MSG Server Mod
+ ● Revised Check Variable
+ ● Fixed Create Voice Channel
+ ● Fixed Create Channel
+ ● Fixed Create Category
+ ● Fixed Store Channel Info
+ ● Fixed Send Image
+ ● Fixed Mod Info
+
+
+
1.9.5: We fixed it all and YouTube Playlists are around now!
+ ● Added Store Game Info
+ ● Added Find Item in List
+ ● Added Play YouTube Playlist
+ ● Added Store Twitch Info
+ ● Added Set Time Restriction
+ ● Added Global Data actions
+ ● Revised Store Category Info
+ ● Revised Control Variable
+ ● Revised Store Server Info
+ ● Revised YouTube Search
+ ● Revised Call Command/Event
+ ● Revised Remove Item From List
+ ● Revised Find Member
+ ● Revised Check If Member
+ ● Revised Set Member Voice Channel
+ ● Revised Embed Messaging actions
+ ● Revised Music System actions
+ ● Fixed Transfer Variable
+ ● Fixed Send Embed Message
+ ● Fixed Await Response Call Action
+ ● Fixed Await Reaction Call Action
+ ● Fixed Edit Channel
+ ● Fixed Store Channel Info
+
+
+
1.9.4: owo Is this a release I see? A lot of revised mods.
+ ● Added Convert Seconds to Days
+ ● Added Download File
+ ● Renamed Convert a Variable
+ ● Revised Add Embed Field
+ ● Revised Await Response Call Action
+ ● Revised Check Member Data
+ ● Revised Check Server Data
+ ● Revised Check Variable
+ ● Revised Edit Channel
+ ● Revised Edit Message
+ ● Revised Find Emoji in Message
+ ● Revised Member Data List
+ ● Revised Store Category Info
+ ● Revised Store Message Info
+ ● Revised Youtube Info
+
+
+
1.9.3: Yet another update
+ ● Added RSS actions
+ ● Added Speedtest action
+ ● Added Message URL to Store Message Info
+ ● Added Send Embed to Webhook
+ ● Added Restart Bot
+ ● Added Create Webhook
+ ● Removed Set AFK Timeout
+ ● Fixed Set Category using ID
+ ● Fixed _id of Loop Through List
+ ● Updated Convert Variable
+ ● Updated Set Role Permissions
+ ● Updated Control Variable
+ ● Moved smaller, not always needed mods, to a separated folder
+
+
+
1.9.2: Update Update
+ ● Updated "Send Stats to DBL" - Removed automated success message from the console
+ ● Updated "Convert List To Text" - Added sort option
+ ● Updated "Store Audio Info" - Added current song URL
+ ● Updated "Custom Image Effect"
+ ● Fixed "Find Custom Emoji in Server"
+ ● Fixed "Find Category"
+ ● Fixed "Add Reaction"
+ ● Fixed "Set Role Permissions"
+ ● Fixed "Create Channel" - Set Category ID
+ ● Merged "Store Role Info Things" with "Store Role Info"
+ ● Merged "Store Member Things" with "Store Member Info"
+ ● Added "Set AFK Channel"
+ ● Added "Math Operation Plus"
+ ● Added Donators to the "Welcome" action
+
+
+
1.9.1: Bunch of new mods, and yes, we now have the reaction stuff
+ ● Added Set Role Voice Channel Perms
+ ● Added Set Member Voice Channel Perms
+ ● Added Find Category
+ ● Added Change Prefix
+ ● Added Set Role Permissions
+ ● Added Get Song Lyrics
+ ● Added Get Bot Stats From DBXYZ
+ ● Added Check If User Reacted
+ ● Added Remove Reaction
+ ● Added Find Reaction
+ ● Added Store Game Server Info
+ ● Added Find Custom Emoji In Server
+ ● Merged Send Image MOD with Send Image
+ ● Merged Store Server Things with Store Server Info
+ ● Merged Store Message Things with Store Message Info
+ ● Merged Store Voice Channel Things with Store Voice Channel Info
+ ● Merged Store Voice Channel Things with Store Voice Channel Info
+ ● Merged Store Channel Things with Store Channel Info
+ ● Updated Create Text Channel
+ ● Updated DBL actions
+ ● Updated Create Voice Channel
+ ● Updated Store Reaction Info
+ ● Updated Remove Message Reactions
+ ● Updated Add Reaction
+ ● Fixed Find Member
+ ● Fixed Send To Webhook
+ ● Fixed Send Embed Message
+ ● Fixed Set Bot Activity
+
+
+
1.9: New Mods, Bug fixes and general quality of life improvements!
+ ● Added Store Invite Info
+ ● Added Store Emoji Info
+ ● Added Basic Math Operation
+ ● Added Edit Embed Message
+ ● Better YouTube Search
+ ● Fixes for Parse From Stored JSON
+ ● Fixes for Store Bot Client Info
+ ● Fixes for Set Bot Activity
+ ● Fixes for Store Reaction Info
+ ● Fixes for Run SQL Query
+ ● Fixes for Webhook actions
+ ● Fixes for Get Item from List
+ ● Updated Check If Member
+ ● Merged Send Embed Message MOD with Send Embed Message
+ ● Merged Store Channel Things with Store Channel Info
+ ● Added Await Response (probably not what you are looking for...)
+ ● Many little bug fixes
+
+
+
1.8.9: HUGE fixes for everyone!
+ ● Added Math Operation mod! ~iAmaury
+ ● Added Convert A Variable (to fix the "Add to member data" problem)! ~EliteArtz
+ ● Added a new version of Replace Text! ~iAmaury
+ ● Added Check if Member has voted on DBL! ~Lasse
+ ● Added Get Stats from DBL! ~EGGS>
+ ● Added Send Stats to DBL! ~EGGSY
+ ● Added Store Date Info! ~iAmaury
+ ● Added Loop Through Folder! ~Jakob
+ ● Fixed DBMs problem with find offline members! ~Lasse
+ ● Added A new Run Script mod with a better UI! ~General Wrex
+ ● Added Send Embed Message mod which allows you to store the message object! ~General Wrex
+ ● Multiple UI updates and bug fixes!
+
+
+
1.8.8: Store Reaction Info is now available!
+ ● Added Check If Member (is bot/is kickable/is banable/is in voice channel)
+ ● Added Skip Actions
+ ● Added Store Reaction Info
+ ● Added Urban Dictionary Search modification
+ ● Redesigned a few modifications UI
+ ● MANY bug fixes!
+
+
+
1.8.7: All your wishes except Await Response
+ ● Google & YouTube Search!
+ ● Set the channel category in Edit Channel!
+ ● Webhooks!
+ ● Store the total amount of commands and events!
+ ● Merged "Start & Stop Typing"!
+ ● Added "File Control" which includes "Create", "Write", "Append" and "Delete" File!
+ ● "Find Text" allows it to find a word in a text!
+ ● Convert Timestamp!
+ ● Store Weather Informations!
+ ● Revise and Replace Mods!
+ ● Many bug fixes....
+
+
+
1.8.6: So many small new mods
+ ● Check Variable length
+ ● HTML and Json fixes
+ ● Generate Random Hex Color
+ ● Change images name
+ ● Delete File
+ ● Cleverbot .io & .com support
+ ● Randomize Letters
+ ● Slice variable
+ ● Translate variable
+ ● Store Attachment Info
+ ● Convert YouTube Time
+ ... and much more!
+
+
+
1.8.5: Many new options...
+ ● Store Human & Bot count!
+ ● Json WebAPI with sliders and bug fixes!
+ ● New Mod Information in DBM!
+ ● Little text changes!
+ ● Sorted many action options!
+ ● Find Message!
+ ● Merged Store Role Info!
+ ● Refreshing uptimes (1h:27m:10s or 1:27:10 or...)!
+ ● Store Bots platform OS & Bots directory!
+ ● Store CPU usage in MB & Memory usage in MB!
+ ● Removed deprecated files from 1.8.4!
+ ● Store and parse XML -> You can store data from (nearly) every website!
+
+
+
1.8.4: Set Prefix + Write File + Jump to Action
+ ● Set Voice Channel Permissions
+ ● Write File (Creates a real file like a txt file)
+ ● Set Prefix (Global)
+ ● Jump to Action
+ ● Merged all Store Bot Client Info mods (Check info below)
+ ● Merged all Store Server Things mods (Check info below)
+ ● Reduced file size (We removed some obsolete modules 150 MB -> 330 KB)
+ ● Bug and typo fixes
+ ● Removed the music and discord.js fix because it is in beta fixed
+ The merged actions are still usable but are located in the deprecated section. All functions are copied info the main action.
+
+
+
+
+
+`;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ if (!member) {
+ this.callNextAction(cache);
+ return;
+ }
+ const targetChannel = await this.getVoiceChannelFromData(data.channel, data.varName2, cache);
+ if (!targetChannel) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ member.voice.setChannel(targetChannel.id).catch((err) => {
+ console.log('ERROR');
+ console.ERROR(err);
+ });
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/multi_check_variable.js b/actions/multi_check_variable.js
new file mode 100644
index 000000000..aeb5f1914
--- /dev/null
+++ b/actions/multi_check_variable.js
@@ -0,0 +1,226 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Multi-Check Variable',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Conditions',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Check ${presets.getVariableText(data.storage, data.varName)} with ${data.branches.length} Branches`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'branches'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+ Comparison Type
+
+
+
+ Value to Compare to
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob } = this;
+
+ glob.formatItem = function (data) {
+ let result = '
VAR ';
+ const comp = data.comparison;
+ switch (comp) {
+ case '0':
+ result += 'Exists';
+ break;
+ case '1':
+ result += `= ${data.value}`;
+ break;
+ case '2':
+ result += `= ${data.value}`;
+ break;
+ case '3':
+ result += `< ${data.value}`;
+ break;
+ case '4':
+ result += `> ${data.value}`;
+ break;
+ case '5':
+ result += `Includes ${data.value}`;
+ break;
+ case '6':
+ result += `Matches Regex ${data.value}`;
+ break;
+ }
+ result += `
Call ${data.actions.length} Actions`;
+ return result;
+ };
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const type = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const variable = this.getVariable(type, varName, cache);
+ let result = false;
+ if (variable) {
+ const val1 = variable;
+ const branches = data.branches;
+ for (let i = 0; i < branches.length; i++) {
+ const branch = branches[i];
+ const compare = parseInt(branch.comparison, 10);
+ let val2 = branch.value;
+ if (compare !== 6) val2 = this.evalIfPossible(val2, cache);
+ switch (compare) {
+ case 0:
+ result = val1 !== undefined;
+ break;
+ case 1:
+ result = val1 === val2;
+ break;
+ case 2:
+ result = val1 === val2;
+ break;
+ case 3:
+ result = val1 < val2;
+ break;
+ case 4:
+ result = val1 > val2;
+ break;
+ case 5:
+ if (typeof val1.includes === 'function') {
+ result = val1.includes(val2);
+ }
+ break;
+ case 6:
+ result = Boolean(val1.match(new RegExp(`^${val2}$`, 'i')));
+ break;
+ }
+ if (result) {
+ this.executeSubActionsThenNextAction(branch.actions, cache);
+ break;
+ }
+ }
+ }
+ if (!result) {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ if (Array.isArray(data?.branches)) {
+ for (let i = 0; i < data.branches.length; i++) {
+ const branch = data.branches[i];
+ this.prepareActions(branch.actions);
+ }
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/multi_check_variable_MOD.js b/actions/multi_check_variable_MOD.js
new file mode 100644
index 000000000..9538cd7d9
--- /dev/null
+++ b/actions/multi_check_variable_MOD.js
@@ -0,0 +1,288 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Multi-Check Variable',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Conditions',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Check ${presets.getVariableText(data.storage, data.varName)} with ${data.branches.length} Branches`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'branches'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+ Comparison Type
+
+
+
+ Value to Compare to
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob } = this;
+
+ glob.formatItem = function (data) {
+ let result = '
VAR ';
+ const comp = data.comparison;
+ switch (comp) {
+ case '0':
+ result += 'Exists';
+ break;
+ case '1':
+ result += `= ${data.value}`;
+ break;
+ case '2':
+ result += `= ${data.value}`;
+ break;
+ case '3':
+ result += `< ${data.value}`;
+ break;
+ case '4':
+ result += `> ${data.value}`;
+ break;
+ case '5':
+ result += `Includes ${data.value}`;
+ break;
+ case '6':
+ result += `Matches Regex ${data.value}`;
+ break;
+ case '7':
+ result += `Length is Bigger Than ${data.value}`;
+ break;
+ case '8':
+ result += `Length is Smaller Than ${data.value}`;
+ break;
+ case '9':
+ result += `Length is Equals ${data.value}`;
+ break;
+ case '10':
+ result += `Starts With ${data.value}`;
+ break;
+ case '11':
+ result += `Ends With ${data.value}`;
+ break;
+ case '12':
+ result += `Matches Full Regex ${data.value}`;
+ break;
+ case '13':
+ result += `<=${data.value}`;
+ break;
+ case '14':
+ result += `>= ${data.value}`;
+ break;
+ }
+ result += `
Call ${data.actions.length} Actions`;
+ return result;
+ };
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const type = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const variable = this.getVariable(type, varName, cache);
+ let result = false;
+ if (variable) {
+ const val1 = variable;
+ const branches = data.branches;
+ for (let i = 0; i < branches.length; i++) {
+ const branch = branches[i];
+ const compare = parseInt(branch.comparison, 10);
+ let val2 = branch.value;
+ if (compare !== 6) val2 = this.evalIfPossible(val2, cache);
+ switch (compare) {
+ case 0:
+ result = val1 !== undefined;
+ break;
+ case 1:
+ result = val1 === val2;
+ break;
+ case 2:
+ result = val1 === val2;
+ break;
+ case 3:
+ result = val1 < val2;
+ break;
+ case 4:
+ result = val1 > val2;
+ break;
+ case 5:
+ if (typeof val1.includes === 'function') {
+ result = val1.includes(val2);
+ }
+ break;
+ case 6:
+ result = Boolean(val1.match(new RegExp(`^${val2}$`, 'i')));
+ break;
+ case 7:
+ result = val1.length > val2;
+ break;
+ case 8:
+ result = val1.length < val2;
+ break;
+ case 9:
+ result = val1.length === val2;
+ break;
+ case 10:
+ result = val1.startsWith(val2);
+ break;
+ case 11:
+ result = val1.endsWith(val2);
+ break;
+ case 12:
+ result = Boolean(val1.match(new RegExp(val2)));
+ break;
+ case 13:
+ result = val1 <= val2;
+ break;
+ case 14:
+ result = val1 >= val2;
+ break;
+ }
+ if (result) {
+ this.executeSubActionsThenNextAction(branch.actions, cache);
+ break;
+ }
+ }
+ }
+ if (!result) {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ //
+ // An optional function for action mods. Upon the bot's initialization,
+ // each command/event's actions are iterated through. This is to
+ // initialize responses to interactions created within actions
+ // (e.g. buttons and select menus for Send Message).
+ //
+ // If an action provides inputs for more actions within, be sure
+ // to call the `this.prepareActions` function to ensure all actions are
+ // recursively iterated through.
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ if (Array.isArray(data?.branches)) {
+ for (let i = 0; i < data.branches.length; i++) {
+ const branch = data.branches[i];
+ this.prepareActions(branch.actions);
+ }
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/nt_ai_bridge_MOD.js b/actions/nt_ai_bridge_MOD.js
new file mode 100644
index 000000000..ca854894f
--- /dev/null
+++ b/actions/nt_ai_bridge_MOD.js
@@ -0,0 +1,162 @@
+'use strict';
+
+const path = require('path');
+
+/** Shown in editor footer and meta.version (DBM “Action Out of Date” check). */
+const NT_AI_BRIDGE_MOD_VERSION = '2.2.0';
+
+function normalizeInvokeFrom(v) {
+ const s = String(v == null ? '' : v).toLowerCase();
+ if (s === 'slash' || s === 'prefix') {
+ return s;
+ }
+ return 'both';
+}
+
+module.exports = {
+ name: 'NT AI Bridge MOD',
+ section: 'Other Stuff',
+
+ subtitle(data) {
+ const v = data.promptVarName || 'ntAiPrompt';
+ const d = data.deferSlash === 'false' ? 'no defer' : 'defer';
+ const inv = normalizeInvokeFrom(data.invokeFrom);
+ const invShort = inv === 'both' ? 'slash+prefix' : inv;
+ const ep = data.ephemeralSlash === 'true' ? 'ephemeral' : 'public';
+ return `${v} · ${invShort} · ${d} · ${ep}`;
+ },
+
+ // meta.version is the DBM build this action targets (same field DBM uses for “Action Out of Date”).
+ meta: {
+ version: NT_AI_BRIDGE_MOD_VERSION,
+ preciseCheck: true,
+ author: 'News Targeted',
+ authorUrl: 'https://newstargeted.com',
+ downloadUrl: null,
+ },
+
+ fields: ['promptVarName', 'invokeFrom', 'ephemeralSlash', 'deferSlash', 'behavior'],
+
+ html(isEvent, data) {
+ const pv = String(data.promptVarName != null ? data.promptVarName : 'ntAiPrompt').replace(/"/g, '"');
+ const invokeFrom = normalizeInvokeFrom(data.invokeFrom);
+ const ephemeralSlash = data.ephemeralSlash === 'true' ? 'true' : 'false';
+ const deferSlash = data.deferSlash === 'false' ? 'false' : 'true';
+ const beh = data.behavior === '1' ? '1' : '0';
+ return `
+
+ Invoke from skips the wrong trigger with a short hint (e.g. prefix-only blocks slash). Ephemeral applies to slash interactions; prefix replies stay public in the channel. Match defer to your ephemeral choice (defer uses the same flag). Configure URL/token under Extensions → NT AI Bridge. See ai.newstargeted.com/docs.
+
+
+ Targets DBM 2.2.x / Discord.js v14. No extra npm in nt_ai_bridge_EXT (Node built-ins only); run npm install in your bot project root.
+
+ Helpful Information
+ - To get an api key visit pastebin api page.
+ - To get all the supported formats click here.
+ - To see the paste limit and other information pastebin FAQ.
+ - If you chose file, write down the file location for ex './example.txt'.
+
+
+ API Key:
+
+
+
+ Pastebin Title:
+
+
+
+ Format:
+
+
+
+
+
+
+
+
+
+ Store Pastebin Link In:
+
+
+
+ Variable Name:
+
+
+
+ If Paste Fails:
+
+
+
+ Action Number:
+
+
`;
+ },
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChangeFalse(document.getElementById('iffalse'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existance.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const _this = this;
+ const data = cache.actions[cache.index];
+ const apikey = _this.evalMessage(data.apikey, cache);
+ const title = _this.evalMessage(data.title, cache);
+ const format = _this.evalMessage(data.format, cache);
+ const text = _this.evalMessage(data.text, cache);
+ const type = parseInt(data.type, 10);
+
+ const WrexMODS = _this.getWrexMods();
+ WrexMODS.CheckAndInstallNodeModule('pastebin-js');
+ const PastebinAPI = require('pastebin-js');
+ const pastebin = new PastebinAPI({
+ api_dev_key: apikey,
+ });
+ let result;
+ switch (type) {
+ case 0:
+ result = pastebin.createPaste(text, title);
+ break;
+ case 1:
+ result = pastebin.createPasteFromFile(text, title, format, 1, 'N');
+ break;
+ }
+ result
+ .then(function (pasteData) {
+ console.log(pasteData);
+ const varName = _this.evalMessage(data.varName, cache);
+ const storage = parseInt(data.storage, 10);
+ _this.storeValue(pasteData, storage, varName, cache);
+ _this.callNextAction(cache);
+ })
+ .fail(function (err) {
+ console.log(err);
+ _this.executeResults(false, data, cache);
+ });
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflictions between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {},
+}; // End of module
diff --git a/actions/pin_forum_post.js b/actions/pin_forum_post.js
new file mode 100644
index 000000000..379622888
--- /dev/null
+++ b/actions/pin_forum_post.js
@@ -0,0 +1,97 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Pin Forum Post',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const action = data.action === 'pin' ? 'Pin' : 'Unpin';
+ return `${action} forum post`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: null,
+ authorUrl: 'https://github.com/master3395/dbm-mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['post', 'varName', 'action'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Action
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const thread = await this.getThreadFromData(data.post, data.varName, cache);
+
+ if (!thread) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ try {
+ if (data.action === 'pin') {
+ await thread.setPinned(true);
+ } else {
+ await thread.setPinned(false);
+ }
+
+ this.callNextAction(cache);
+ } catch (err) {
+ this.displayError(data, cache, err);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/pin_message.js b/actions/pin_message.js
new file mode 100644
index 000000000..7fd3a0dbf
--- /dev/null
+++ b/actions/pin_message.js
@@ -0,0 +1,109 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Pin Message',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Pin ${presets.getMessageText(data.storage, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return ``;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const message = await this.getMessageFromData(data.storage, data.varName, cache);
+
+ if (Array.isArray(message)) {
+ this.callListFunc(message, 'pin', []).then(() => this.callNextAction(cache));
+ } else if (message?.pin) {
+ message
+ .pin()
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/play_file.js b/actions/play_file.js
new file mode 100644
index 000000000..a82de9d11
--- /dev/null
+++ b/actions/play_file.js
@@ -0,0 +1,146 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Play File',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ // ---------------------------------------------------------------------
+ // Requires Audio Libraries
+ //
+ // If 'true', this action requires audio libraries to run.
+ // ---------------------------------------------------------------------
+
+ requiresAudioLibraries: true,
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.url}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['url', 'seek', 'volume', 'bitrate', 'type'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Local URL
+
+
+
+ Volume (0 = min; 100 = max)
+
+ Bitrate
+
+
+
+ Seek Position
+
+
+
+
+
+
+ Play Type
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const Audio = this.getDBM().Audio;
+ const options = {};
+ if (data.seek) {
+ options.seek = parseInt(this.evalMessage(data.seek, cache), 10);
+ }
+ if (data.volume) {
+ options.volume = parseInt(this.evalMessage(data.volume, cache), 10) / 100;
+ }
+ if (data.bitrate) {
+ options.bitrate = parseInt(this.evalMessage(data.bitrate, cache), 10);
+ }
+ const url = this.evalMessage(data.url, cache);
+ if (url) {
+ const info = ['file', options, url];
+ await Audio.addAudio(info, cache.server, data.type === '0');
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/play_file_MOD.js b/actions/play_file_MOD.js
new file mode 100644
index 000000000..1bb0bd662
--- /dev/null
+++ b/actions/play_file_MOD.js
@@ -0,0 +1,263 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Play File',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ // ---------------------------------------------------------------------
+ // Requires Audio Libraries
+ //
+ // If 'true', this action requires audio libraries to run.
+ // ---------------------------------------------------------------------
+
+ requiresAudioLibraries: true,
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.url}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'DarkXenei',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['url', 'seek', 'volume', 'bitrate', 'type'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const { createAudioPlayer, createAudioResource, AudioPlayerStatus } = require('@discordjs/voice');
+
+ // Pobranie aktywnego po³¹czenia
+ const connection = this.getVariable(1, 'activeVoiceConnection', cache);
+ if (!connection) {
+ console.error('No active voice connection found.');
+ this.callNextAction(cache);
+ return;
+ }
+
+ const url = this.evalMessage(data.url, cache);
+ if (!url) {
+ console.error('No audio file URL provided.');
+ this.callNextAction(cache);
+ return;
+ }
+
+ const seek = parseInt(this.evalMessage(data.seek, cache), 10) || 0;
+ const volume = parseInt(this.evalMessage(data.volume, cache), 10) || 100;
+ const bitrate = parseInt(this.evalMessage(data.bitrate, cache), 10) || 128000;
+ const type = parseInt(data.type, 10) || 0;
+
+ const player = createAudioPlayer();
+ connection.subscribe(player);
+
+ const resource = createAudioResource(url, {
+ inlineVolume: true,
+ seek,
+ bitrate,
+ });
+
+ resource.volume.setVolume(volume / 100);
+ player.play(resource);
+
+ player.on(AudioPlayerStatus.Idle, () => {
+ if (type === 0) {
+ connection.destroy();
+ this.callNextAction(cache);
+ }
+ });
+
+ player.on('error', (error) => {
+ console.error('Error in audio player:', error);
+ connection.destroy();
+ this.callNextAction(cache);
+ });
+
+ if (type === 1) {
+ this.callNextAction(cache);
+ }
+ },
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/play_url.js b/actions/play_url.js
new file mode 100644
index 000000000..783cb47e6
--- /dev/null
+++ b/actions/play_url.js
@@ -0,0 +1,146 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Play URL',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ // ---------------------------------------------------------------------
+ // Requires Audio Libraries
+ //
+ // If 'true', this action requires audio libraries to run.
+ // ---------------------------------------------------------------------
+
+ requiresAudioLibraries: true,
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.url}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['url', 'seek', 'volume', 'bitrate', 'type'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Web URL
+
+
+
+ Volume (0 = min; 100 = max)
+
+ Bitrate
+
+
+
+ Seek Position
+
+
+
+
+
+
+ Play Type
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const Audio = this.getDBM().Audio;
+ const options = {};
+ if (data.seek) {
+ options.seek = parseInt(this.evalMessage(data.seek, cache), 10);
+ }
+ if (data.volume) {
+ options.volume = parseInt(this.evalMessage(data.volume, cache), 10) / 100;
+ }
+ if (data.bitrate) {
+ options.bitrate = parseInt(this.evalMessage(data.bitrate, cache), 10);
+ }
+ const url = this.evalMessage(data.url, cache);
+ if (url) {
+ const info = ['url', options, url];
+ await Audio.addAudio(info, cache.server, data.type === '0');
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/play_url_MOD.js b/actions/play_url_MOD.js
new file mode 100644
index 000000000..fbfaec286
--- /dev/null
+++ b/actions/play_url_MOD.js
@@ -0,0 +1,112 @@
+module.exports = {
+ name: 'Play URL',
+ section: 'Audio Control',
+ requiresAudioLibraries: true,
+
+ subtitle(data) {
+ return 'Play media from URL';
+ },
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ fields: ['url', 'volume', 'bitrate', 'seek', 'type', 'channel', 'varName'],
+
+ html() {
+ return `
+
+ `;
+ };
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const containers = data.actionContainers;
+ if (!Array.isArray(containers) || containers.length === 0) return this.callNextAction(cache);
+
+ const chances = containers.map((c, i) => {
+ const raw = this.evalMessage(c.chance, cache);
+ const value = parseFloat(raw);
+ if (isNaN(value)) console.warn(`Invalid chance at container ${i}:`, raw);
+ return value || 0;
+ });
+
+ const totalChance = chances.reduce((a, b) => a + b, 0);
+
+ if (totalChance <= 0) {
+ return this.callNextAction(cache);
+ }
+
+ const roll = Math.random() * totalChance;
+
+ let cumulative = 0;
+ for (let i = 0; i < chances.length; i++) {
+ cumulative += chances[i];
+ if (roll <= cumulative) {
+ const branch = containers[i];
+ if (branch && Array.isArray(branch.actions)) {
+ this.executeSubActions(branch.actions, cache);
+ return;
+ }
+ }
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod Init
+ // ---------------------------------------------------------------------
+
+ modInit(data) {
+ if (Array.isArray(data?.actionContainers)) {
+ for (const container of data.actionContainers) {
+ this.prepareActions(container.actions);
+ }
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/remove_buttons_select.js b/actions/remove_buttons_select.js
new file mode 100644
index 000000000..ba2ffdad3
--- /dev/null
+++ b/actions/remove_buttons_select.js
@@ -0,0 +1,231 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Remove Buttons and Selects',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMessageText(data.storage, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'type', 'searchValue'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Components to Remove
+
+
+
+
+ Component Label/ID
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob } = this;
+
+ glob.onButtonSelectTypeChange = function (event) {
+ const input = document.getElementById('nameContainer');
+ input.style.display = event.value === 'findButton' || event.value === 'findSelect' ? null : 'none';
+ };
+
+ glob.onButtonSelectTypeChange(document.getElementById('type'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const message = await this.getMessageFromData(data.storage, data.varName, cache);
+
+ const type = data.type;
+
+ let sourceButton = null;
+ if (cache.interaction.isButton()) {
+ sourceButton = cache.interaction.customId;
+ }
+
+ let sourceSelect = null;
+ if (cache.interaction.isStringSelectMenu()) {
+ sourceSelect = cache.interaction.customId;
+ }
+
+ let components = null;
+
+ let searchValue = null;
+
+ const messageId = message.id;
+ if (type === 'all') {
+ components = [];
+ this.clearAllTemporaryInteractions(messageId);
+ } else if (message?.components) {
+ const { ActionRowBuilder, ComponentType } = this.getDBM().DiscordJS;
+ const oldComponents = message.components;
+ const newComponents = [];
+
+ for (let i = 0; i < oldComponents.length; i++) {
+ const compData = oldComponents[i];
+ const comps = compData instanceof ActionRowBuilder ? compData.toJSON() : compData;
+ const newComps = [];
+
+ for (let j = 0; j < comps.components.length; j++) {
+ const comp = comps.components[j];
+ let deleted = false;
+ const id = comp.custom_id ?? comp.customId;
+
+ switch (type) {
+ case 'allButtons': {
+ if (comp.type !== 2 || comp.type === ComponentType.Button) newComps.push(comp);
+ else deleted = true;
+ break;
+ }
+ case 'allSelects': {
+ if (comp.type !== 3 || comp.type === ComponentType.SelectMenu) newComps.push(comp);
+ else deleted = true;
+ break;
+ }
+ case 'sourceButton': {
+ if (id !== sourceButton) newComps.push(comp);
+ else deleted = true;
+ break;
+ }
+ case 'sourceSelect': {
+ if (id !== sourceSelect) newComps.push(comp);
+ else deleted = true;
+ break;
+ }
+ case 'findButton':
+ case 'findSelect': {
+ if (searchValue === null) searchValue = this.evalMessage(data.searchValue, cache);
+ if (id !== searchValue && comp.label !== searchValue) newComps.push(comp);
+ else deleted = true;
+ break;
+ }
+ }
+
+ if (deleted) {
+ this.clearTemporaryInteraction(messageId, id);
+ }
+ }
+
+ comps.components = newComps;
+ if (newComps.length > 0) newComponents.push(comps);
+ }
+ components = newComponents;
+ }
+
+ if (components) {
+ if (Array.isArray(message)) {
+ this.callListFunc(message, 'edit', [{ components }]).then(() => this.callNextAction(cache));
+ } else if (
+ cache.interaction?.message?.id === message?.id &&
+ cache.interaction?.update &&
+ !cache.interaction?.replied
+ ) {
+ cache.interaction
+ .update({ components })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else if (message?.edit) {
+ message
+ .edit({ components })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ if (message.components) {
+ message.components = components;
+ }
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/remove_item_from_list.js b/actions/remove_item_from_list.js
new file mode 100644
index 000000000..4d8ac9601
--- /dev/null
+++ b/actions/remove_item_from_list.js
@@ -0,0 +1,177 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Remove Item from List',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Lists and Loops',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storage = presets.variables;
+ return `Remove Item from ${storage[parseInt(data.storage, 10)]} (${data.varName})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage2, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Unknown Type'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'removeType', 'position', 'storage2', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Remove Type
+
+
+
+ Position
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChange1 = function (event) {
+ const value = parseInt(event.value, 10);
+ const dom = document.getElementById('positionHolder');
+ if (value < 2) {
+ dom.style.display = 'none';
+ } else {
+ dom.style.display = null;
+ }
+ };
+
+ glob.onChange1(document.getElementById('removeType'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const list = this.getVariable(storage, varName, cache);
+
+ const type = parseInt(data.removeType, 10);
+
+ let result = null;
+ switch (type) {
+ case 0:
+ result = list.pop();
+ break;
+ case 1:
+ result = list.shift();
+ break;
+ case 2:
+ const position = parseInt(this.evalMessage(data.position, cache), 10);
+ if (position < 0) {
+ result = list.shift();
+ } else if (position >= list.length) {
+ result = list.pop();
+ } else {
+ result = list[position];
+ list.splice(position, 1);
+ }
+ break;
+ }
+
+ if (result) {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage2 = parseInt(data.storage2, 10);
+ this.storeValue(result, storage2, varName2, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/remove_member_from_thread_MOD.js b/actions/remove_member_from_thread_MOD.js
new file mode 100644
index 000000000..bd69ec480
--- /dev/null
+++ b/actions/remove_member_from_thread_MOD.js
@@ -0,0 +1,46 @@
+module.exports = {
+ name: 'Remove Member from Thread',
+ section: 'Channel Control',
+ meta: {
+ version: '2.1.7',
+ preciseCheck: false,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods/blob/master/actions/remove_member_from_thread_MOD.js',
+ },
+
+ fields: ['storage', 'varName', 'member', 'varName2', 'iffalse', 'iffalseVal'],
+
+ subtitle(data, presets) {
+ const storeTypes = presets.variables;
+ return `${storeTypes[parseInt(data.storage, 10)]} (${data.varName})`;
+ },
+
+ html() {
+ return `
+
+
+
+
+
+
+ `;
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const th = this.getVariable(storage, varName, cache);
+ const member = await this.getMemberFromData(data.member, data.varName2, cache);
+
+ try {
+ await th.members.remove(member.id);
+ this.callNextAction(cache);
+ } catch {
+ this.executeResults(false, data, cache);
+ }
+ },
+
+ mod() {},
+};
diff --git a/actions/remove_member_role.js b/actions/remove_member_role.js
new file mode 100644
index 000000000..ef0d4d740
--- /dev/null
+++ b/actions/remove_member_role.js
@@ -0,0 +1,126 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Remove Member Role',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName2)} - ${presets.getRoleText(data.role, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName2', 'role', 'varName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const role = await this.getRoleFromData(data.role, data.varName, cache);
+ const member = await this.getMemberFromData(data.member, data.varName2, cache);
+ const reason = this.evalMessage(data.reason, cache);
+ if (Array.isArray(member)) {
+ this.callListFunc(
+ member.map((m) => m.roles),
+ 'remove',
+ [role, reason],
+ ).then(() => this.callNextAction(cache));
+ } else if (member?.roles) {
+ member.roles
+ .remove(role, reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/resize_image.js b/actions/resize_image.js
new file mode 100644
index 000000000..977b5a3d8
--- /dev/null
+++ b/actions/resize_image.js
@@ -0,0 +1,135 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Resize Image',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Image Editing',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storeTypes = presets.variables;
+ return `${storeTypes[parseInt(data.storage, 10)]} (${data.varName}) -> [${data.width}, ${data.height}]`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'width', 'height'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ New Width (direct size or percent)
+
+
+
+ New Height (direct size or percent)
+
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const image = this.getVariable(storage, varName, cache);
+ if (!image) {
+ this.callNextAction(cache);
+ return;
+ }
+ let width = this.evalMessage(data.width, cache);
+ let height = this.evalMessage(data.height, cache);
+ if (width.endsWith('%')) {
+ const percent = width.replace('%', '');
+ width = image.bitmap.width * (parseInt(percent, 10) / 100);
+ } else {
+ width = parseInt(width, 10);
+ }
+ if (height.endsWith('%')) {
+ const percent = height.replace('%', '');
+ height = image.bitmap.height * (parseInt(percent, 10) / 100);
+ } else {
+ height = parseInt(height, 10);
+ }
+ image.resize(width, height);
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/role_command_restriction_MOD.js b/actions/role_command_restriction_MOD.js
new file mode 100644
index 000000000..903cca95e
--- /dev/null
+++ b/actions/role_command_restriction_MOD.js
@@ -0,0 +1,93 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Role Command Restriction',
+ displayName: 'Role Restriction',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Moderation',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Check if ${presets.getMemberText(data.member, data.varName)} has role ${presets.getRoleText(
+ data.role,
+ data.varName2,
+ )}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'role', 'varName2', 'branch'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+ `;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ const role = await this.getRoleFromData(data.role, data.varName2, cache);
+
+ if (!member) {
+ return this.callNextAction(cache);
+ }
+
+ if (!role) {
+ return this.callNextAction(cache);
+ }
+
+ const hasRole = member.roles?.cache?.has?.(role.id);
+
+ this.executeResults(hasRole, data.branch, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/rotate_image.js b/actions/rotate_image.js
new file mode 100644
index 000000000..6540d1813
--- /dev/null
+++ b/actions/rotate_image.js
@@ -0,0 +1,145 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Rotate Image',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Image Editing',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storeTypes = presets.variables;
+ const mirror = ['No Mirror', 'Horizontal Mirror', 'Vertical Mirror', 'Diagonal Mirror'];
+ return `${storeTypes[parseInt(data.storage, 10)]} (${data.varName}) -> [${mirror[parseInt(data.mirror, 10)]} ~ ${
+ data.rotation
+ }°]`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'rotation', 'mirror'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Mirror
+
+
+
+ Rotation (degrees)
+
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const image = this.getVariable(storage, varName, cache);
+ if (!image) {
+ this.callNextAction(cache);
+ return;
+ }
+ const mirror = parseInt(data.mirror, 10);
+ switch (mirror) {
+ case 0:
+ image.mirror(false, false);
+ break;
+ case 1:
+ image.mirror(true, false);
+ break;
+ case 2:
+ image.mirror(false, true);
+ break;
+ case 3:
+ image.mirror(true, true);
+ break;
+ }
+ const rotation = parseInt(data.rotation, 10);
+ image.rotate(rotation);
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/run_command_to_console_MOD.js b/actions/run_command_to_console_MOD.js
new file mode 100644
index 000000000..9eb66958e
--- /dev/null
+++ b/actions/run_command_to_console_MOD.js
@@ -0,0 +1,117 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Run Command to Console',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data) {
+ return `${data.command}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['command'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editting actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Mod Info:
+ Created by MrGold
+ Original Code by NetLuis
+
+
+
+ Command to Run:
+
+
+
+
+ NOTE: This mod will not work if you run your bot on DBM
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existance.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const command = this.evalMessage(data.command, cache);
+ const child = require('child_process');
+ child
+ .execSync(command, { cwd: require('path').dirname(process.argv[1]), stdio: [0, 1, 2] })
+ .catch((e) => console.log(`An error occurred while executing the command: ${e}`));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflictions between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {},
+}; // End of module
diff --git a/actions/run_script.js b/actions/run_script.js
new file mode 100644
index 000000000..d498105a5
--- /dev/null
+++ b/actions/run_script.js
@@ -0,0 +1,149 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Run Script',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.code}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Unknown Type'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['behavior', 'interpretation', 'code', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ End Behavior
+
+
+
+ Interpretation Style
+
+
+
+
+
+
+
+ Custom Code
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ let code;
+ if (data.interpretation === '0') {
+ code = this.evalMessage(data.code, cache);
+ } else {
+ code = data.code;
+ }
+ const result = this.eval(code, cache);
+ const varName = this.evalMessage(data.varName, cache);
+ const storage = parseInt(data.storage, 10);
+ this.storeValue(result, storage, varName, cache);
+ if (data.behavior === '0') {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/run_script_colorable_MOD.js b/actions/run_script_colorable_MOD.js
new file mode 100644
index 000000000..4fbb2c032
--- /dev/null
+++ b/actions/run_script_colorable_MOD.js
@@ -0,0 +1,163 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Run Script Colorable',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.code}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/run_script_colorable_MOD.js',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Unknown Type'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding Ids in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['behavior', 'interpretation', 'code', 'storage', 'varName', 'color'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Text Color:
+
+
+ End Behavior
+
+
+
+ Interpretation Style
+
+
+
+
+
+
+
+ Custom Code
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ let code;
+ if (data.interpretation === '0') {
+ code = this.evalMessage(data.code, cache);
+ } else {
+ code = data.code;
+ }
+ const result = this.eval(code, cache);
+ const varName = this.evalMessage(data.varName, cache);
+ const storage = parseInt(data.storage, 10);
+ this.storeValue(result, storage, varName, cache);
+ if (data.behavior === '0') {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/save_variable.js b/actions/save_variable.js
new file mode 100644
index 000000000..1f4c847b4
--- /dev/null
+++ b/actions/save_variable.js
@@ -0,0 +1,121 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Save Variable',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storage = ['', '', 'Server Variable', 'Global Variable'];
+ return `${storage[parseInt(data.storage, 10)]} (${data.varName})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Save Variable
+
+
+
+ Variable Name
+
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const Files = this.getDBM().Files;
+ const type = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const item = this.getVariable(type, varName, cache);
+ if (data.storage === '3') {
+ Files.saveGlobalVariable(varName, item);
+ } else if (cache.server) {
+ Files.saveServerVariable(cache.server.id, varName, item);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/send_components_v2_MOD.js b/actions/send_components_v2_MOD.js
new file mode 100644
index 000000000..887d4d28d
--- /dev/null
+++ b/actions/send_components_v2_MOD.js
@@ -0,0 +1,2479 @@
+module.exports = {
+ name: 'Send Components V2',
+ section: 'Messaging',
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow & vxed_',
+ authorUrl: 'https://github.com/shadoow051',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ size() {
+ return { width: 640, height: 550 };
+ },
+
+ // ---------------------------------------------------------------------
+ // region 📃 Subtitle Text
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const components = data.components ?? [];
+ const containerDetails = [];
+
+ const selectedType = (components[0]?.componentType || components[0]?.containerComponentType || '').toLowerCase();
+
+ const countComponents = (arr, isNested = false) => {
+ let btn = 0;
+ let sel = 0;
+ let txt = 0;
+ let sec = 0;
+ let img = 0;
+ let sep = 0;
+ let file = 0;
+
+ if (!Array.isArray(arr)) return { btn, sel, txt, sec, img, sep, file };
+
+ for (const comp of arr) {
+ const type = (comp.componentType || comp.containerComponentType || '').toLowerCase();
+
+ const isSingleMode = !isNested && components.length === 1;
+ const isAllowed = !isSingleMode || type === selectedType || type === 'container';
+
+ if (!isAllowed) continue;
+
+ if (type === 'container' && Array.isArray(comp.containerComponents)) {
+ const nested = countComponents(comp.containerComponents, true);
+ containerDetails.push(
+ `Cont: ${[
+ nested.txt ? `${nested.txt} Txt` : null,
+ nested.sec ? `${nested.sec} Sec` : null,
+ nested.img ? `${nested.img} Img` : null,
+ nested.sep ? `${nested.sep} Sep` : null,
+ nested.file ? `${nested.file} File` : null,
+ nested.btn ? `${nested.btn} Btn` : null,
+ nested.sel ? `${nested.sel} Sel` : null,
+ ]
+ .filter(Boolean)
+ .join(' | ')}`,
+ );
+ continue;
+ }
+
+ // Content
+ if (type === 'content') {
+ const msg = comp.message ?? comp.containerMessage;
+ if (typeof msg === 'string' && msg.trim()) txt += 1;
+ }
+
+ // Section
+ if (type === 'section') {
+ const msg = comp.message ?? comp.sectionMessage;
+ if (typeof msg === 'string' && msg.trim()) sec += 1;
+ if (Array.isArray(comp.buttons)) btn += comp.buttons.length;
+ if (Array.isArray(comp.containerButtons)) btn += comp.containerButtons.length;
+ }
+
+ // Images
+ if (type === 'images') {
+ if (Array.isArray(comp.images)) img += comp.images.length;
+ if (Array.isArray(comp.containerImages)) img += comp.containerImages.length;
+ }
+
+ // Files
+ if (type === 'files') {
+ if (Array.isArray(comp.files)) file += comp.files.length;
+ if (Array.isArray(comp.containerFiles)) file += comp.containerFiles.length;
+ }
+
+ // Separators
+ if (type === 'separators') {
+ if (Array.isArray(comp.separators)) sep += comp.separators.length;
+ if (Array.isArray(comp.containerSeparators)) sep += comp.containerSeparators.length;
+ }
+
+ // Buttons
+ if (type === 'buttons') {
+ if (Array.isArray(comp.buttons)) btn += comp.buttons.length;
+ if (Array.isArray(comp.containerButtons)) btn += comp.containerButtons.length;
+ }
+
+ // Select Menus
+ if (type === 'select menus') {
+ if (Array.isArray(comp.selectMenus)) sel += comp.selectMenus.length;
+ if (Array.isArray(comp.containerSelectMenus)) sel += comp.containerSelectMenus.length;
+ }
+ }
+
+ return { btn, sel, txt, sec, img, sep, file };
+ };
+
+ const top = countComponents(components);
+
+ const parts = [];
+ if (top.txt) parts.push(`${top.txt} Txt`);
+ if (top.sec) parts.push(`${top.sec} Sec`);
+ if (top.img) parts.push(`${top.img} Img`);
+ if (top.sep) parts.push(`${top.sep} Sep`);
+ if (top.file) parts.push(`${top.file} File`);
+ if (top.btn) parts.push(`${top.btn} Btn`);
+ if (top.sel) parts.push(`${top.sel} Sel`);
+
+ const allParts = [...parts, ...containerDetails];
+ let defaultText = allParts.length > 0 ? allParts.join(' | ') : 'No components';
+
+ if (data.editMessage && data.editMessage !== '0') {
+ defaultText = `Editing: ${presets.getVariableText(data.editMessage, data.editMessageVarName)}`;
+ }
+
+ if (data.dontReply) {
+ defaultText = `Store: ${defaultText}`;
+ } else {
+ defaultText = `${presets.getSendReplyTargetText(data.channel, data.varName)}: ${defaultText}`;
+ }
+
+ const userDesc = data.actionDescription?.toString().trim();
+ if (userDesc) {
+ const color = data.actionDescriptionColor || '#ffffff';
+ return `${userDesc}`;
+ }
+
+ return defaultText;
+ },
+
+ // ---------------------------------------------------------------------
+ // region 📦 Action Storage
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, data.dontSend ? 'Message Options' : 'Message'];
+ },
+
+ // ---------------------------------------------------------------------
+ // region 🔢 Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: [
+ 'channel',
+ 'varName',
+ 'varName2',
+ 'varNameContainer',
+ 'storage',
+ 'message',
+ 'buttons',
+ 'selectMenus',
+ 'attachments',
+ 'components',
+ 'reply',
+ 'dontReply',
+ 'ephemeral',
+ 'tts',
+ 'overwrite',
+ 'dontSend',
+ 'pinned',
+ 'actionDescription',
+ 'actionDescriptionColor',
+ 'editMessage',
+ 'editMessageVarName',
+ 'allowedMentionEveryone',
+ 'allowedMentionRole',
+ 'allowedMentionMember',
+ ],
+
+ // ---------------------------------------------------------------------
+ // region #️⃣ Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // region 💾 Action Editor Save
+ // ---------------------------------------------------------------------
+
+ onSave(data, helpers) {
+ const genId = () => `msg-button-${helpers.generateUUID().substring(0, 7)}`;
+ const genSelectId = () => `msg-select-${helpers.generateUUID().substring(0, 7)}`;
+
+ if (Array.isArray(data?.components)) {
+ for (const [, comp] of data.components.entries()) {
+ // Główne Buttons (w Containerze)
+ if (Array.isArray(comp.buttons)) {
+ for (const [, btn] of comp.buttons.entries()) {
+ if (!btn.id || btn.id === '0') {
+ btn.id = genId();
+ }
+ }
+ }
+
+ // Główne SelectMenus
+ if (Array.isArray(comp.selectMenus)) {
+ for (const [, sel] of comp.selectMenus.entries()) {
+ if (!sel.id || sel.id === '0') {
+ sel.id = genSelectId();
+ }
+ }
+ }
+
+ // Container Buttons
+ if (Array.isArray(comp.containerButtons)) {
+ for (const [, btn] of comp.containerButtons.entries()) {
+ if (!btn.containerId || btn.containerId === '0') {
+ btn.containerId = genId();
+ }
+ }
+ }
+
+ // Container Select Menus
+ if (Array.isArray(comp.containerSelectMenus)) {
+ for (const [, sel] of comp.containerSelectMenus.entries()) {
+ if (!sel.containerId || sel.containerId === '0') {
+ sel.containerId = genSelectId();
+ }
+ }
+ }
+
+ // Section Buttons (accessories)
+ if (Array.isArray(comp.sectionComponents)) {
+ for (const [, acc] of comp.sectionComponents.entries()) {
+ if (acc.accessoryType === 'button' && (!acc.id || acc.id === '0')) {
+ acc.id = genId();
+ }
+ }
+ }
+
+ // Container Components (zagnieżdżone)
+ if (Array.isArray(comp.containerComponents)) {
+ for (const [, child] of comp.containerComponents.entries()) {
+ // Child Container Buttons
+ if (Array.isArray(child.containerButtons)) {
+ for (const [, btn] of child.containerButtons.entries()) {
+ if (!btn.containerId || btn.containerId === '0') {
+ btn.containerId = genId();
+ }
+ }
+ }
+
+ // Child Container SelectMenus
+ if (Array.isArray(child.containerSelectMenus)) {
+ for (const [, sel] of child.containerSelectMenus.entries()) {
+ if (!sel.containerId || sel.containerId === '0') {
+ sel.containerId = genSelectId();
+ }
+ }
+ }
+
+ // Child SectionComponents (buttons w sekcji)
+ if (Array.isArray(child.sectionComponents)) {
+ for (const [, acc] of child.sectionComponents.entries()) {
+ if (acc.accessoryType === 'button' && (!acc.id || acc.id === '0')) {
+ acc.id = genId();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return data;
+ },
+
+ // ---------------------------------------------------------------------
+ // region ✏️ Action Editor Paste
+ // ---------------------------------------------------------------------
+
+ onPaste(data, helpers) {
+ const genId = () => `msg-button-${helpers.generateUUID().substring(0, 7)}`;
+ const genSelectId = () => `msg-select-${helpers.generateUUID().substring(0, 7)}`;
+
+ if (Array.isArray(data?.components)) {
+ for (const comp of data.components) {
+ // Główne Buttons (w Containerze)
+ if (Array.isArray(comp.buttons)) {
+ for (const btn of comp.buttons) {
+ btn.id = genId();
+ }
+ }
+
+ // Główne SelectMenus
+ if (Array.isArray(comp.selectMenus)) {
+ for (const sel of comp.selectMenus) {
+ sel.id = genSelectId();
+ }
+ }
+
+ // Container Buttons
+ if (Array.isArray(comp.containerButtons)) {
+ for (const btn of comp.containerButtons) {
+ btn.containerId = genId();
+ }
+ }
+
+ // Container Select Menus
+ if (Array.isArray(comp.containerSelectMenus)) {
+ for (const sel of comp.containerSelectMenus) {
+ sel.containerId = genSelectId();
+ }
+ }
+
+ // Section Buttons (accessories)
+ if (Array.isArray(comp.sectionComponents)) {
+ for (const acc of comp.sectionComponents) {
+ if (acc.accessoryType === 'button') {
+ acc.id = genId();
+ }
+ }
+ }
+
+ // Container Components (zagnieżdżone)
+ if (Array.isArray(comp.containerComponents)) {
+ for (const child of comp.containerComponents) {
+ // Child Container Buttons
+ if (Array.isArray(child.containerButtons)) {
+ for (const btn of child.containerButtons) {
+ btn.containerId = genId();
+ }
+ }
+
+ // Child Container SelectMenus
+ if (Array.isArray(child.containerSelectMenus)) {
+ for (const sel of child.containerSelectMenus) {
+ sel.containerId = genSelectId();
+ }
+ }
+
+ // Child SectionComponents (buttons w sekcji)
+ if (Array.isArray(child.sectionComponents)) {
+ for (const acc of child.sectionComponents) {
+ if (acc.accessoryType === 'button') {
+ acc.id = genId();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return data;
+ },
+
+ // ---------------------------------------------------------------------
+ // region 🛠️ Action Functions
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const DBM = this.getDBM();
+ const DiscordJS = DBM.DiscordJS;
+
+ // Version detection for compatibility
+ const version = DiscordJS.version || '0.0.0';
+ const majorVersion = DBM.getDiscordJSMajorVersion
+ ? DBM.getDiscordJSMajorVersion()
+ : parseInt(version.split('.')[0], 10);
+ const isV13 = DBM.isDiscordJSv13 ? DBM.isDiscordJSv13() : majorVersion === 13;
+ const isV14 = DBM.isDiscordJSv14 ? DBM.isDiscordJSv14() : majorVersion === 14;
+
+ // Message Components v2 are only available in v14.24.0+
+ // For v13, we'll provide a helpful error message
+ if (isV13) {
+ console.error(
+ `[Send Components V2] Message Components v2 are only available in Discord.js v14.24.0+. Current version: ${version}`,
+ );
+ this.callNextAction(cache);
+ return;
+ }
+
+ // Check if v2 components are available (v14.24.0+)
+ if (isV14 && !DiscordJS.TextDisplayBuilder) {
+ console.error(
+ `[Send Components V2] Message Components v2 require Discord.js v14.24.0+. Current version: ${version}`,
+ );
+ this.callNextAction(cache);
+ return;
+ }
+
+ const {
+ MessageFlags,
+ ActionRowBuilder,
+ TextDisplayBuilder,
+ SeparatorBuilder,
+ MediaGalleryBuilder,
+ AttachmentBuilder,
+ FileBuilder,
+ SeparatorSpacingSize,
+ ContainerBuilder,
+ SectionBuilder,
+ ButtonStyle,
+ ThumbnailBuilder,
+ ButtonBuilder,
+ StringSelectMenuBuilder,
+ UserSelectMenuBuilder,
+ RoleSelectMenuBuilder,
+ MentionableSelectMenuBuilder,
+ ChannelSelectMenuBuilder,
+ } = DiscordJS;
+ let targetChannel = null;
+ const channelType = data.channel;
+ const varNameRaw = data.varName;
+ const varName = this.evalMessage(varNameRaw, cache);
+
+ const bot = this.getDBM().Bot.bot;
+
+ try {
+ switch (channelType) {
+ case '100': {
+ // User by name
+ if (!cache.server || !varName) break;
+
+ const members = await cache.server.members.fetch({
+ query: varName,
+ limit: 1,
+ });
+ const member = members.first();
+
+ if (member?.user) {
+ targetChannel = await member.user.createDM();
+ } else {
+ console.warn(`[SendComponents] ❌ Nie znaleziono użytkownika o nazwie: ${varName}`);
+ }
+ break;
+ }
+
+ case '101': {
+ // User by ID
+ if (!cache.server || !varName) break;
+
+ try {
+ const member = await cache.server.members.fetch(varName);
+ if (member?.user) {
+ targetChannel = await member.user.createDM();
+ } else {
+ console.warn(`[SendComponents] ❌ Nie znaleziono użytkownika o ID: ${varName}`);
+ }
+ } catch (err) {
+ console.warn(`[SendComponents] ❌ Błąd fetch usera o ID: ${varName}`, err);
+ }
+ break;
+ }
+
+ case '102': {
+ // Channel by name
+ const found = bot.channels.cache.find((ch) => ch.name === varName);
+ if (found) {
+ targetChannel = found;
+ } else {
+ console.warn(`[SendComponents] ❌ Nie znaleziono kanału o nazwie: ${varName}`);
+ }
+ break;
+ }
+
+ case '103': {
+ // Channel by ID (już masz, ale wrzucam dla spójności)
+ try {
+ targetChannel = await bot.channels.fetch(varName);
+ if (targetChannel) {
+ } else {
+ console.warn(`[SendComponents] ❌ Kanał o ID ${varName} zwrócił null!`);
+ }
+ } catch (err) {
+ console.warn(`[SendComponents] ❌ Błąd podczas fetch kanału ID: ${varName}`, err);
+ }
+ break;
+ }
+
+ default: {
+ targetChannel = await this.getChannelFromData(channelType, varNameRaw, cache);
+ if (targetChannel) {
+ } else {
+ console.warn(`[SendComponents] ⚠️ getChannelFromData zwrócił null (type=${channelType})`);
+ }
+ }
+ }
+ } catch (err) {
+ console.warn(`[SendComponents] ❌ Błąd ogólny przy uzyskiwaniu targetChannel (type=${channelType}):`, err);
+ }
+
+ const awaitResponses = [];
+
+ if (!targetChannel) {
+ return this.callNextAction(cache);
+ }
+ const path = require('path');
+ const fs = require('fs/promises');
+
+ const allComponents = Array.isArray(data.components) ? data.components.flat() : [];
+
+ allComponents.forEach((component, index) => {});
+
+ // ////////////////////////////////
+ // region ! CREATE COMP !
+ // ////////////////////////////////
+
+ const attachments = [];
+ const finalComponents = [];
+
+ for (const c of allComponents) {
+ // ////////////////////////////////
+ // region ## Content
+ // ////////////////////////////////
+ if (c.componentType === 'Content' && typeof c.message === 'string' && c.message.trim().length > 0) {
+ const parsed = this.evalMessage(c.message, cache);
+
+ if (typeof parsed === 'string' && parsed.trim().length > 0) {
+ finalComponents.push(new TextDisplayBuilder().setContent(parsed));
+ }
+
+ continue;
+ }
+ // ////////////////////////////////
+ // region ## Separators
+ // ////////////////////////////////
+ if (c.componentType === 'Separators' && Array.isArray(c.separators) && c.separators.length > 0) {
+ for (const separator of c.separators) {
+ const sizeName = separator.separatorSize;
+ const sizeEnum = SeparatorSpacingSize[sizeName];
+ if (sizeEnum === undefined) continue;
+
+ finalComponents.push(new SeparatorBuilder().setSpacing(sizeEnum));
+ }
+ continue;
+ }
+
+ // ////////////////////////////////
+ // region ## Media Gallery
+ // ////////////////////////////////
+ if (c.componentType === 'Images' && Array.isArray(c.images) && c.images.length > 0) {
+ const mediaItems = c.images
+ .map((img) => {
+ const rawUrl = img.imageUrl;
+ const evaluatedUrl = this.evalMessage(rawUrl, cache);
+
+ // WALIDACJA końcowego URL-a
+ if (
+ typeof evaluatedUrl !== 'string' ||
+ !evaluatedUrl.trim().length ||
+ !(
+ evaluatedUrl.startsWith('http://') ||
+ evaluatedUrl.startsWith('https://') ||
+ evaluatedUrl.startsWith('attachment://')
+ )
+ ) {
+ return null; // pomijamy ten item
+ }
+
+ return {
+ media: { url: evaluatedUrl },
+ spoiler: img.imageSpoiler === true,
+ };
+ })
+ .filter((item) => item !== null);
+
+ if (mediaItems.length > 0) {
+ finalComponents.push(new MediaGalleryBuilder().addItems(mediaItems));
+ }
+ continue;
+ }
+
+ // ////////////////////////////////
+ // region ## Files
+ // ////////////////////////////////
+ if (c.componentType === 'Files' && Array.isArray(c.files) && c.files.length > 0) {
+ for (const file of c.files) {
+ const filePath = path.resolve(file.fileUrl);
+ const fileName = path.basename(file.fileName);
+ try {
+ const fileContent = await fs.readFile(filePath);
+ const attachment = new AttachmentBuilder(Buffer.from(fileContent), {
+ name: fileName,
+ });
+ attachments.push(attachment);
+
+ finalComponents.push(new FileBuilder().setURL(`attachment://${fileName}`).setSpoiler(file.fileSpoiler));
+ } catch (err) {
+ console.error(`Błąd odczytu pliku ${filePath}:`, err);
+ }
+ }
+ continue;
+ }
+
+ // ////////////////////////////////
+ // region ## Buttons
+ // ////////////////////////////////
+ if (Array.isArray(c.buttons) && c.buttons.length > 0) {
+ const row = new ActionRowBuilder();
+
+ for (const btn of c.buttons) {
+ let button;
+ const style = Number(btn.type) || 1;
+
+ if (style === 5) {
+ if (!btn.url || typeof btn.url !== 'string' || btn.url.trim() === '') {
+ console.warn(`[SendComponents] Pominięto przycisk typu LINK bez poprawnego URL!`);
+ continue;
+ }
+
+ const label = this.evalMessage(btn.name, cache);
+
+ button = new ButtonBuilder().setStyle(5).setURL(btn.url);
+
+ if (label) {
+ button.setLabel(label);
+ } else if (!btn.emoji) {
+ button.setLabel('Button');
+ }
+ } else {
+ let id = btn.id;
+ if (!id || typeof id !== 'string' || id.trim().length < 1 || id === '0') {
+ id = `msg-button-${Math.random().toString(36).substring(2, 9)}`;
+ btn.id = id;
+ console.warn(`[SendComponents] ⚠️ Brak ID — nadano nowy: ${id}`);
+ }
+
+ const label = this.evalMessage(btn.name, cache);
+
+ button = new ButtonBuilder().setStyle(style).setCustomId(id);
+
+ if (label) {
+ button.setLabel(label);
+ } else if (!btn.emoji) {
+ button.setLabel('Button');
+ }
+
+ const disabled =
+ typeof btn.ButtonDisabled === 'string' ? btn.ButtonDisabled === 'true' : Boolean(btn.ButtonDisabled);
+
+ button.setDisabled(disabled);
+
+ const actions = btn.actions || btn.actionList || btn.actionsList;
+
+ console.log(`[SendComponents] BUTTON "${btn.name || 'Unnamed'}" ID: ${id} Disabled: ${disabled}`);
+
+ if (Array.isArray(actions) && actions.length > 0) {
+ button.actions = actions;
+
+ const mode = btn.mode || 'MULTI';
+ const time = parseInt(btn.time, 10) || 60000;
+ const userId = cache.getUser()?.id;
+
+ btn.actions = actions; // KLUCZOWE!
+
+ if (mode !== 'PERSISTENT') {
+ awaitResponses.push({
+ type: 'BUTTON',
+ time,
+ id,
+ user: mode.endsWith('PERSONAL') ? userId : null,
+ multi: mode.startsWith('MULTI'),
+ data: btn,
+ });
+
+ console.log(`[SendComponents] ⏳ Tymczasowy przycisk "${id}" zapisany do awaitResponses`);
+ } else {
+ const { Bot } = this.getDBM();
+ if (typeof Bot?.$button === 'object' && !Bot.$button[id]) {
+ Bot.$button[id] = { actions };
+ console.log(`[SendComponents] ✅ Persistent button "${id}" zarejestrowany`);
+ } else {
+ console.warn(`[SendComponents] ⚠️ "${id}" już zarejestrowane — pominięto`);
+ }
+ }
+ } else {
+ console.log(`[SendComponents] Brak akcji dla przycisku "${id}"`);
+ }
+ }
+
+ if (btn.emoji) button.setEmoji(btn.emoji);
+ row.addComponents(button);
+ }
+
+ finalComponents.push(row);
+ continue;
+ }
+
+ // ////////////////////////////////
+ // region ## Select menus
+ // ////////////////////////////////
+ if (c.componentType === 'Select Menus' && Array.isArray(c.selectMenus)) {
+ for (const menu of c.selectMenus) {
+ const BuilderMap = {
+ StringSelectMenu: StringSelectMenuBuilder,
+ UserSelectMenu: UserSelectMenuBuilder,
+ RoleSelectMenu: RoleSelectMenuBuilder,
+ MentionableSelectMenu: MentionableSelectMenuBuilder,
+ ChannelSelectMenu: ChannelSelectMenuBuilder,
+ };
+
+ const Builder = BuilderMap[menu.SelectMenuType];
+ if (!Builder) {
+ console.warn(`[SendComponents] Nieznany SelectMenuType: ${menu.SelectMenuType}`);
+ continue;
+ }
+
+ let id = menu.id;
+ if (!id || typeof id !== 'string' || id.trim().length < 1 || id === '0') {
+ id = `msg-select-${Math.random().toString(36).substring(2, 9)}`;
+ menu.id = id;
+ console.warn(`[SendComponents] ⚠️ Brak ID — nadano nowy: ${id}`);
+ }
+
+ const selectMenu = new Builder()
+ .setCustomId(id)
+ .setDisabled(menu.SelectMenuDisabled === 'true')
+ .setPlaceholder(menu.placeholder)
+ .setMinValues(Number(menu.min) || 1)
+ .setMaxValues(Number(menu.max) || 1);
+
+ if (Array.isArray(menu.options) && Builder === StringSelectMenuBuilder) {
+ selectMenu.addOptions(
+ menu.options.map((opt) => ({
+ label: opt.label || 'ㅤ',
+ value: opt.value || '',
+ description: opt.description || undefined,
+ emoji: opt.emoji || undefined,
+ })),
+ );
+ }
+
+ const actions = menu.actions || menu.actionList || menu.actionsList || menu.containerActions; // ← warto zostawić na wypadek fallbacku
+
+ if (Array.isArray(actions) && actions.length > 0) {
+ selectMenu.actions = actions;
+
+ const id = menu.id;
+ const mode = menu.mode || 'MULTI';
+ const time = parseInt(menu.time, 10) || 60000;
+ const userId = cache.getUser()?.id;
+
+ menu.actions = actions; // ⬅️ TO DODAJ
+
+ if (mode !== 'PERSISTENT') {
+ awaitResponses.push({
+ type: 'SELECT',
+ time,
+ id,
+ user: mode.endsWith('PERSONAL') ? userId : null,
+ multi: mode.startsWith('MULTI'),
+ data: menu,
+ });
+ } else {
+ const { Bot } = this.getDBM();
+ if (typeof Bot?.$select === 'object' && !Bot.$select[id]) {
+ Bot.$select[id] = menu;
+ console.log(`[SendComponents 1] ✅ Zarejestrowano PERSISTENT menu ID: ${id}`, menu);
+ }
+ }
+ } else {
+ console.log(`[SendComponents] Brak akcji dla SelectMenu "${id}"`);
+ }
+
+ finalComponents.push(new ActionRowBuilder().addComponents(selectMenu));
+ }
+ continue;
+ }
+
+ // ////////////////////////////////
+ // region ## Sections
+ // ////////////////////////////////
+ if (c.componentType === 'Section' && Array.isArray(c.sectionComponents)) {
+ const content = c.sectionMessage?.trim() || '\u200B';
+
+ for (const sec of c.sectionComponents) {
+ // 1) text display
+ const textComp = new TextDisplayBuilder().setContent(content);
+
+ // 2) SectionBuilder
+ const section = new SectionBuilder().addTextDisplayComponents(textComp);
+
+ // ////////////////////////////////
+ // region ^ Thumbnail accessory
+ // ////////////////////////////////
+ if (sec.accessoryType === 'thumbnail' && sec.thumbnailUrl) {
+ section.setThumbnailAccessory(
+ new ThumbnailBuilder({
+ media: { url: sec.thumbnailUrl },
+ spoiler: sec.thumbnailSpoiler === true,
+ }),
+ );
+ }
+
+ // ////////////////////////////////
+ // region ^ Button accessory
+ // ////////////////////////////////
+ if (sec.accessoryType === 'button') {
+ const style = sec.type === 'link' ? ButtonStyle.Link : Number(sec.type) || ButtonStyle.Primary;
+
+ const label = this.evalMessage(sec.name || 'Button', cache);
+
+ const btnBuilder = new ButtonBuilder().setStyle(style);
+
+ if (label) {
+ btnBuilder.setLabel(label);
+ } else if (!sec.emoji) {
+ btnBuilder.setLabel('Button');
+ }
+
+ if (style === ButtonStyle.Link) {
+ if (!sec.url?.trim()) {
+ console.warn(`[SendComponents] ❌ Pominięto LINK button "${sec.name}" — brak URL`);
+ return;
+ }
+ const url = this.evalMessage(sec.url?.trim(), cache);
+ btnBuilder.setURL(url);
+ } else {
+ let id = sec.id;
+ if (!id || typeof id !== 'string' || id.trim().length < 1 || id === '0') {
+ id = `msg-button-${Math.random().toString(36).substring(2, 9)}`;
+ sec.id = id;
+ }
+
+ btnBuilder.setCustomId(id);
+
+ const disabledRaw =
+ sec.ButtonDisabled ?? sec.containerButtonDisabled ?? sec.ButtonSectionDisabled ?? false;
+
+ const disabled = typeof disabledRaw === 'string' ? disabledRaw === 'true' : Boolean(disabledRaw);
+
+ btnBuilder.setDisabled(disabled);
+
+ const actions = sec.actions || sec.actionList || sec.actionsList || sec.containerActions;
+
+ if (Array.isArray(actions) && actions.length > 0) {
+ btnBuilder.actions = actions;
+
+ const mode = sec.mode || 'MULTI';
+ const time = parseInt(sec.time, 10) || 60000;
+ const userId = cache.getUser()?.id;
+
+ sec.actions = actions;
+
+ if (mode !== 'PERSISTENT') {
+ awaitResponses.push({
+ type: 'BUTTON',
+ time,
+ id,
+ user: mode.endsWith('PERSONAL') ? userId : null,
+ multi: mode.startsWith('MULTI'),
+ data: sec,
+ });
+ } else {
+ const { Bot } = this.getDBM();
+ if (typeof Bot?.$button === 'object' && !Bot.$button[id]) {
+ Bot.$button[id] = { actions };
+ }
+ }
+ }
+ }
+
+ if (sec.emoji) btnBuilder.setEmoji(sec.emoji);
+
+ section.setButtonAccessory(btnBuilder);
+ }
+ console.log(`[SendComponents] 😀 Dodano emoji do buttona: ${sec.emoji}`);
+ console.log(`[SendComponents] 🧱 Section JSON:`, JSON.stringify(section.toJSON(), null, 2));
+ finalComponents.push(section);
+ }
+ continue;
+ }
+
+ // ////////////////////////////////
+ // region ## Container
+ // ////////////////////////////////
+ if (c.componentType === 'Container' && Array.isArray(c.containerComponents) && c.containerComponents.length > 0) {
+ const container = new ContainerBuilder()
+ .setAccentColor(
+ c.useColor && typeof c.containerColor === 'string'
+ ? parseInt(c.containerColor.replace('#', ''), 16)
+ : undefined,
+ )
+ .setSpoiler(c.containerSpoiler);
+
+ for (const child of c.containerComponents) {
+ // ////////////////////////////////
+ // region ^ Content
+ // ////////////////////////////////
+ const parsed = this.evalMessage(child.containerMessage, cache);
+
+ if (typeof parsed === 'string' && parsed.trim().length > 0) {
+ container.addTextDisplayComponents(new TextDisplayBuilder().setContent(parsed));
+ }
+
+ // ////////////////////////////////
+ // region ^ Separators
+ // ////////////////////////////////
+ if (child.containerComponentType === 'Separators' && Array.isArray(child.containerSeparators)) {
+ for (const sep of child.containerSeparators) {
+ const sizeEnum = SeparatorSpacingSize[sep.containerSeparatorSize];
+ if (sizeEnum != null) {
+ container.addSeparatorComponents(new SeparatorBuilder().setSpacing(sizeEnum));
+ }
+ }
+ }
+
+ // ////////////////////////////////
+ // region ^ Images
+ // ////////////////////////////////
+ if (child.containerComponentType === 'Images' && Array.isArray(child.containerImages)) {
+ const items = child.containerImages
+ .map((i) => {
+ const rawUrl = i.containerImageUrl;
+ const evaluatedUrl = this.evalMessage(rawUrl, cache);
+
+ // WALIDACJA końcowego URL-a
+ if (
+ typeof evaluatedUrl !== 'string' ||
+ !evaluatedUrl.trim().length ||
+ !(
+ evaluatedUrl.startsWith('http://') ||
+ evaluatedUrl.startsWith('https://') ||
+ evaluatedUrl.startsWith('attachment://')
+ )
+ ) {
+ return null; // pomijamy ten item
+ }
+
+ return {
+ media: { url: evaluatedUrl },
+ spoiler: i.containerImageSpoiler === true,
+ };
+ })
+ .filter((item) => item !== null);
+
+ if (items.length > 0) {
+ container.addMediaGalleryComponents(new MediaGalleryBuilder().addItems(items));
+ }
+ }
+
+ // ////////////////////////////////
+ // region ^ Files
+ // ////////////////////////////////
+ if (child.containerComponentType === 'Files' && Array.isArray(child.containerFiles)) {
+ for (const f of child.containerFiles) {
+ const filePath = path.resolve(f.containerFileUrl);
+ const fileName = f.containerFileName || path.basename(filePath);
+ try {
+ const buf = await fs.readFile(filePath);
+ const attachment = new AttachmentBuilder(Buffer.from(buf), {
+ name: fileName,
+ });
+ attachments.push(attachment);
+ container.addFileComponents(
+ new FileBuilder().setURL(`attachment://${fileName}`).setSpoiler(f.containerFileSpoiler === true),
+ );
+ } catch (err) {
+ console.error(`Błąd odczytu pliku ${filePath}:`, err);
+ }
+ }
+ }
+
+ // ////////////////////////////////
+ // region ^ Buttons
+ // ////////////////////////////////
+ if (child.containerComponentType === 'Buttons' && Array.isArray(child.containerButtons)) {
+ const row = new ActionRowBuilder();
+
+ for (const btn of child.containerButtons) {
+ let button;
+ const style = Number(btn.containerType) || ButtonStyle.Primary;
+
+ if (style === ButtonStyle.Link) {
+ if (!btn.containerUrl?.trim()) {
+ continue;
+ }
+
+ const rawLabel = this.evalMessage(btn.containerName, cache);
+ const label = rawLabel?.trim();
+ const hasLabel = Boolean(label);
+ const hasEmoji = Boolean(btn.containerEmoji);
+
+ const rawUrl = btn.containerUrl?.trim();
+ const url = this.evalMessage(rawUrl, cache);
+
+ if (!/^https?:\/\//i.test(url)) {
+ console.warn(
+ `[SendComponents] ❌ Pominięto LINK button "${btn.containerName}" — brak poprawnego URL:`,
+ url,
+ );
+ continue;
+ }
+
+ button = new ButtonBuilder().setStyle(ButtonStyle.Link).setURL(url);
+
+ if (hasLabel) {
+ button.setLabel(label);
+ } else if (!hasEmoji) {
+ button.setLabel('Button');
+ }
+
+ if (hasEmoji) {
+ button.setEmoji(btn.containerEmoji);
+ }
+ } else {
+ let id = btn.containerId;
+ if (!id || typeof id !== 'string' || id.trim().length < 1) {
+ id = `msg-button-${Math.random().toString(36).substring(2, 9)}`;
+ btn.containerId = id;
+ }
+
+ const rawLabel = this.evalMessage(btn.containerName, cache);
+ const label = rawLabel?.trim();
+
+ button = new ButtonBuilder().setStyle(style).setCustomId(id);
+
+ const hasLabel = Boolean(label);
+ const hasEmoji = Boolean(btn.containerEmoji);
+
+ if (hasLabel) {
+ button.setLabel(label);
+ } else if (!hasEmoji) {
+ // Brak labela i brak emoji — daj domyślny tekst
+ button.setLabel('Button');
+ }
+
+ if (hasEmoji) {
+ button.setEmoji(btn.containerEmoji);
+ }
+
+ const disabled =
+ typeof btn.containerButtonDisabled === 'string'
+ ? btn.containerButtonDisabled === 'true'
+ : Boolean(btn.containerButtonDisabled);
+
+ button.setDisabled(disabled);
+
+ const actions = btn.actions || btn.actionList || btn.actionsList || btn.containerActions;
+
+ if (Array.isArray(actions) && actions.length > 0) {
+ button.actions = actions;
+
+ const id = btn.containerId;
+ const mode = btn.containerMode || 'MULTI';
+ const time = parseInt(btn.containerTime, 10) || 60000;
+ const userId = cache.getUser()?.id;
+
+ btn.actions = actions; // ⬅️ ważne!
+
+ if (mode !== 'PERSISTENT') {
+ awaitResponses.push({
+ type: 'BUTTON',
+ time,
+ id,
+ user: mode.endsWith('PERSONAL') ? userId : null,
+ multi: mode.startsWith('MULTI'),
+ data: btn,
+ });
+ } else {
+ const { Bot } = this.getDBM();
+ if (typeof Bot?.$button === 'object' && !Bot.$button[id]) {
+ Bot.$button[id] = {
+ actions,
+ };
+ }
+ }
+ }
+ }
+
+ if (btn.containerEmoji) button.setEmoji(btn.containerEmoji);
+ row.addComponents(button);
+ }
+
+ container.addActionRowComponents(row);
+ }
+
+ // ////////////////////////////////
+ // region ^ Select Menus
+ // ////////////////////////////////
+ if (child.containerComponentType === 'Select Menus' && Array.isArray(child.containerSelectMenus)) {
+ for (const menu of child.containerSelectMenus) {
+ const BuilderMap = {
+ StringSelectMenu: StringSelectMenuBuilder,
+ UserSelectMenu: UserSelectMenuBuilder,
+ RoleSelectMenu: RoleSelectMenuBuilder,
+ MentionableSelectMenu: MentionableSelectMenuBuilder,
+ ChannelSelectMenu: ChannelSelectMenuBuilder,
+ };
+
+ const Builder = BuilderMap[menu.containerSelectMenuType];
+ if (!Builder) {
+ console.warn(`[SendComponents] Nieznany typ SelectMenu: ${menu.containerSelectMenuType}`);
+ continue;
+ }
+
+ let id = menu.containerId;
+ if (!id || typeof id !== 'string' || id.trim().length < 1 || id === '0') {
+ id = `msg-select-${Math.random().toString(36).substring(2, 9)}`;
+ menu.containerId = id;
+ console.warn(`[SendComponents] ⚠️ Brak ID — nadano nowy: ${id}`);
+ }
+
+ const selectMenu = new Builder()
+ .setCustomId(id)
+ .setDisabled(menu.containerSelectMenuDisabled === 'true')
+ .setPlaceholder(menu.containerPlaceholder)
+ .setMinValues(Number(menu.containerMin) || 1)
+ .setMaxValues(Number(menu.containerMax) || 1);
+
+ if (Array.isArray(menu.containerOptions) && Builder === StringSelectMenuBuilder) {
+ selectMenu.addOptions(
+ menu.containerOptions.map((opt) => ({
+ label: opt.containerLabel || 'ㅤ',
+ value: opt.containerValue || '',
+ description: opt.containerDescription || undefined,
+ emoji: opt.containerEmoji || undefined,
+ default: opt.containerDefault === true,
+ })),
+ );
+ }
+
+ const actions = menu.actions || menu.actionList || menu.actionsList || menu.containerActions; // ← warto zostawić na wypadek fallbacku
+
+ if (Array.isArray(actions) && actions.length > 0) {
+ selectMenu.actions = actions;
+
+ const id = menu.containerId;
+ const mode = menu.containerMode || 'MULTI';
+ const time = parseInt(menu.time, 10) || 60000;
+ const userId = cache.getUser()?.id;
+
+ menu.actions = actions; // ⬅️ TO DODAJ
+ menu.tempVarName = menu.containerTempVarName;
+
+ if (mode !== 'PERSISTENT') {
+ awaitResponses.push({
+ type: 'SELECT',
+ time,
+ id,
+ user: mode.endsWith('PERSONAL') ? userId : null,
+ multi: mode.startsWith('MULTI'),
+ data: menu,
+ });
+ } else {
+ const { Bot } = this.getDBM();
+ if (typeof Bot?.$select === 'object' && !Bot.$select[id]) {
+ Bot.$select[id] = menu;
+ console.log(`[SendComponents 1] ✅ Zarejestrowano PERSISTENT menu ID: ${id}`, menu);
+ }
+ }
+ } else {
+ console.log(`[SendComponents] Brak akcji dla SelectMenu "${id}"`);
+ }
+
+ const row = new ActionRowBuilder().addComponents(selectMenu);
+ container.addActionRowComponents(row);
+ }
+ }
+
+ // ////////////////////////////////
+ // region ^ Section
+ // ////////////////////////////////
+ if (
+ child.containerComponentType === 'Section' &&
+ Array.isArray(child.sectionComponents) &&
+ child.sectionComponents.length > 0
+ ) {
+ const content = this.evalMessage(
+ child.containerSectionMessage?.trim() || child.sectionMessage?.trim() || '\u200B',
+ cache,
+ );
+
+ const textComp = new TextDisplayBuilder().setContent(content);
+ const section = new SectionBuilder().addTextDisplayComponents(textComp);
+
+ for (const sec of child.sectionComponents) {
+ if (sec.accessoryType === 'thumbnail' && sec.thumbnailUrl) {
+ const rawUrl = sec.thumbnailUrl.trim();
+ const evalUrl = this.evalMessage(rawUrl, cache);
+
+ if (!/^https?:\/\//i.test(evalUrl) && !evalUrl.startsWith('attachment://')) {
+ console.warn(`[SendComponentsV2] ❌ Pominięto thumbnail "${rawUrl}" — niepoprawny URL: ${evalUrl}`);
+ continue;
+ }
+
+ section.setThumbnailAccessory(
+ new ThumbnailBuilder({
+ media: { url: evalUrl },
+ spoiler: sec.thumbnailSpoiler === true,
+ }),
+ );
+ }
+
+ if (sec.accessoryType === 'button') {
+ const style = sec.type === 'link' ? ButtonStyle.Link : Number(sec.type) || ButtonStyle.Primary;
+
+ const label = this.evalMessage(sec.name, cache);
+
+ const btnBuilder = new ButtonBuilder()
+ .setStyle(style)
+ .setDisabled(sec.ButtonSectionDisabled === true || sec.ButtonSectionDisabled === 'true');
+
+ if (label) {
+ btnBuilder.setLabel(label);
+ } else if (!sec.emoji) {
+ btnBuilder.setLabel('Button');
+ }
+
+ if (style === ButtonStyle.Link) {
+ if (!sec.url?.trim()) {
+ console.warn(`[SendComponents] ❌ Pominięto LINK button "${sec.name}" — brak URL`);
+ return;
+ }
+ const url = this.evalMessage(sec.url?.trim(), cache);
+ btnBuilder.setURL(url);
+ } else {
+ let id = sec.id;
+ if (!id || typeof id !== 'string' || id.trim().length < 1 || id === '0') {
+ id = `msg-button-${Math.random().toString(36).substring(2, 9)}`;
+ sec.id = id;
+ }
+
+ btnBuilder.setCustomId(id);
+
+ const actions = sec.actions || sec.actionList || sec.actionsList || sec.containerActions;
+
+ if (Array.isArray(actions) && actions.length > 0) {
+ btnBuilder.actions = actions;
+
+ const mode = sec.mode || 'MULTI';
+ const time = parseInt(sec.time, 10) || 60000;
+ const userId = cache.getUser()?.id;
+
+ sec.actions = actions;
+
+ if (mode !== 'PERSISTENT') {
+ awaitResponses.push({
+ type: 'BUTTON',
+ time,
+ id,
+ user: mode.endsWith('PERSONAL') ? userId : null,
+ multi: mode.startsWith('MULTI'),
+ data: sec,
+ });
+ } else {
+ const { Bot } = this.getDBM();
+ if (typeof Bot?.$button === 'object' && !Bot.$button[id]) {
+ Bot.$button[id] = { actions };
+ }
+ }
+ }
+ }
+
+ if (sec.emoji) btnBuilder.setEmoji(sec.emoji);
+
+ section.setButtonAccessory(btnBuilder);
+ }
+ }
+ container.components.push(section);
+ continue;
+ }
+ }
+
+ finalComponents.push(container);
+ continue;
+ }
+ }
+
+ // ////////////////////////////////
+ // region % SENDING MESS
+ // ////////////////////////////////
+
+ const interaction = cache.interaction;
+ const inputChannelId = this.evalMessage(data.varName, cache);
+ const forceTypes = ['100', '101', '102', '103'];
+
+ const forceTargetChannel =
+ forceTypes.includes(data.channel) && (!interaction?.channel || interaction.channel.id !== inputChannelId);
+
+ const allowedMentions = { parse: [] };
+
+ function isChecked(value) {
+ return value === true || value === 'true' || value === '1';
+ }
+
+ if (isChecked(data.allowedMentionEveryone)) {
+ allowedMentions.parse.push('everyone');
+ }
+
+ if (isChecked(data.allowedMentionRole)) {
+ allowedMentions.parse.push('roles');
+ }
+
+ if (isChecked(data.allowedMentionMember)) {
+ allowedMentions.parse.push('users');
+ }
+
+ const messageData = {
+ flags: MessageFlags.IsComponentsV2,
+ components: finalComponents,
+ files: attachments,
+ tts: data.tts === 'true',
+ allowedMentions,
+ };
+
+ if (String(data.ephemeral) === 'true') {
+ messageData.flags |= MessageFlags.Ephemeral;
+ }
+
+ if (data.editMessage !== 'none') {
+ let message;
+
+ if (data.editMessage === 'intUpdate' && interaction?.isMessageComponent?.()) {
+ message = interaction.message;
+ } else {
+ message = this.getVariable(parseInt(data.editMessage, 10), data.editMessageVarName, cache);
+ }
+
+ if (message?.edit) {
+ try {
+ await message.edit(messageData);
+ } catch (err) {
+ console.error('[SendComponentsV3] Failed to edit message:', err);
+ }
+ return this.callNextAction(cache);
+ }
+ }
+
+ if (data.dontSend === 'true') {
+ return this.callNextAction(cache);
+ }
+
+ try {
+ let sentMessage = null;
+
+ const shouldReply = data.reply === true || data.reply === 'true';
+
+ if (!forceTargetChannel && interaction && shouldReply) {
+ const isIntEdit = data.editMessage === 'intUpdate';
+ try {
+ if (isIntEdit) {
+ sentMessage = await interaction.editReply(messageData);
+ } else if (interaction.deferred || interaction.replied) {
+ sentMessage = await interaction.followUp(messageData);
+ } else {
+ await interaction.reply(messageData);
+ sentMessage = await interaction.fetchReply();
+ }
+ } catch (err) {
+ console.error(`[SendComponentsV2] ❌ Błąd interakcji:`, err);
+ }
+ }
+
+ // 👇 JEŚLI mamy targetChannel (np. po channel by ID) i jeszcze nie wysłano
+ if (!sentMessage && targetChannel) {
+ try {
+ sentMessage = await targetChannel.send(messageData);
+ } catch (err) {
+ console.error(`[SendComponentsV2] ❌ Błąd przy .send():`, err);
+ }
+ }
+
+ // ⛔ Fallback tylko jeśli interaction nie zadziałało
+ if (!sentMessage && targetChannel) {
+ sentMessage = await targetChannel.send(messageData);
+ }
+
+ if (data.pinned === 'true' && sentMessage) {
+ try {
+ await sentMessage.pin();
+ } catch (err) {
+ console.warn('[SendComponentsV3] Nie udało się przypiąć wiadomości:', err);
+ }
+ }
+
+ // 🧠 Zapisz wiadomość do zmiennej (Store In)
+ if (sentMessage && data.storage !== 'none') {
+ this.storeValue(sentMessage, parseInt(data.storage, 10), data.varName2, cache);
+ }
+ for (let i = 0; i < awaitResponses.length; i++) {
+ const response = awaitResponses[i];
+ const originalInteraction = cache.interaction?.__originalInteraction ?? cache.interaction;
+ const tempVariables = cache.temp || {};
+
+ this.registerTemporaryInteraction(
+ sentMessage.id,
+ response.time,
+ response.id,
+ response.user,
+ response.multi,
+ (interaction) => {
+ if (response.data) {
+ interaction.__originalInteraction = originalInteraction;
+
+ if (response.type === 'BUTTON') {
+ this.preformActionsFromInteraction(interaction, response.data, cache.meta, tempVariables);
+ } else {
+ if (response.data?.tempVarName) {
+ tempVariables[response.data.tempVarName] =
+ interaction.values?.length === 1 ? interaction.values[0] : interaction.values;
+ }
+
+ this.preformActionsFromSelectInteraction(interaction, response.data, cache.meta, tempVariables);
+ }
+ }
+ },
+ );
+ }
+ } catch (err) {
+ console.error('[SendComponentsV3] Błąd podczas wysyłania komponentów:', err);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ////////////////////////////////
+ // region ! Bot Mod Init !
+ // ////////////////////////////////
+
+ modInit(data) {
+ if (!Array.isArray(data?.components)) return;
+
+ const registerButton = (btn) => {
+ if (!btn || typeof btn !== 'object') return;
+ const id = btn.containerId || btn.id;
+ const mode = btn.containerMode || btn.mode;
+ const actions = btn.actions || btn.containerActions || btn.actionList || btn.actionsList;
+
+ if (id && Array.isArray(actions)) {
+ this.prepareActions?.(actions);
+ if (mode === 'PERSISTENT') {
+ this.registerButtonInteraction(id, { actions, mode });
+ }
+ }
+ };
+
+ const registerSelect = (sel) => {
+ if (!sel || typeof sel !== 'object') return;
+ const id = sel.containerId || sel.id;
+ const mode = sel.containerMode || sel.mode;
+ const actions = sel.actions || sel.containerActions || sel.actionList || sel.actionsList;
+
+ if (id && Array.isArray(actions)) {
+ this.prepareActions?.(actions);
+
+ if (mode === 'PERSISTENT' && typeof this.registerSelectMenuInteraction === 'function') {
+ this.registerSelectMenuInteraction(id, {
+ ...sel,
+ actions,
+ mode,
+ tempVarName: sel.containerTempVarName || sel.tempVarName,
+ });
+ }
+ }
+ };
+
+ const walk = (node) => {
+ if (!node || typeof node !== 'object') return;
+
+ registerButton(node);
+ registerSelect(node);
+
+ const sub = (arr) => (Array.isArray(arr) ? arr : []);
+
+ [...sub(node.buttons), ...sub(node.containerButtons), ...sub(node.sectionComponents)].forEach(registerButton);
+ [...sub(node.selectMenus), ...sub(node.containerSelectMenus), ...sub(node.sectionSelectMenus)].forEach(
+ registerSelect,
+ );
+
+ if (Array.isArray(node.containerComponents)) {
+ node.containerComponents.forEach(walk);
+ }
+ };
+
+ data.components.forEach(walk);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/send_embed_message.js b/actions/send_embed_message.js
new file mode 100644
index 000000000..b3f22ca72
--- /dev/null
+++ b/actions/send_embed_message.js
@@ -0,0 +1,149 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Send Embed Message',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Embed Message',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getSendTargetText(data.channel, data.varName2)}: ${data.varName}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'channel', 'varName2', 'storage3', 'varName3'],
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage3, 10);
+ if (type !== varType) return;
+ return [data.varName3, 'Message'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const embed = this.getVariable(storage, varName, cache);
+ if (!embed) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const target = await this.getSendTargetFromData(data.channel, data.varName2, cache);
+
+ const varName3 = this.evalMessage(data.varName3, cache);
+ const storage3 = parseInt(data.storage3, 10);
+
+ if (Array.isArray(target)) {
+ this.callListFunc(target, 'send', [{ embeds: [embed] }]).then(() => this.callNextAction(cache));
+ } else if (target?.send) {
+ target
+ .send({ embeds: [embed] })
+ .then((msg) => {
+ if (varName3) this.storeValue(msg, storage3, varName3, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/send_file.js b/actions/send_file.js
new file mode 100644
index 000000000..2ee67dfb2
--- /dev/null
+++ b/actions/send_file.js
@@ -0,0 +1,133 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Send File',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const channels = presets.sendTargets;
+ return `${channels[parseInt(data.channel, 10)]}: "${data.message.replace(/[\n\r]+/, '')}"`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'varName', 'file', 'message'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Local File URL
+
+
+
+
+ Message
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const { DiscordJS } = this.getDBM();
+ const message = data.message;
+ if (!data.channel || !message) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const target = await this.getSendTargetFromData(data.channel, data.varName, cache);
+
+ const file = new DiscordJS.AttachmentBuilder(this.getLocalFile(this.evalMessage(data.file, cache)));
+ const options = { content: this.evalMessage(message, cache), files: [file] };
+
+ if (Array.isArray(target)) {
+ this.callListFunc(target, 'send', [options]).then(() => this.callNextAction(cache));
+ } else if (target?.send) {
+ target
+ .send(options)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/send_gmail_MOD.js b/actions/send_gmail_MOD.js
new file mode 100644
index 000000000..73afdc334
--- /dev/null
+++ b/actions/send_gmail_MOD.js
@@ -0,0 +1,204 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Send Gmail',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data) {
+ return `from:"${data.username}" to: "${data.mailto}"`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'Unknown Type'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['username', 'password', 'mailto', 'subject', 'type', 'text', 'iffalse', 'iffalseVal'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editting actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
`;
+ },
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChangeFalse(document.getElementById('iffalse'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existance.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const _this = this;
+ const data = cache.actions[cache.index];
+ const username = this.evalMessage(data.username, cache);
+ const password = this.evalMessage(data.password, cache);
+ const mailto = this.evalMessage(data.mailto, cache);
+ const subjectvalue = this.evalMessage(data.subject, cache);
+ const textvalue = this.evalMessage(data.text, cache);
+ const typevalue = parseInt(data.type, 10);
+
+ const WrexMODS = _this.getWrexMods();
+ WrexMODS.CheckAndInstallNodeModule('nodemailer');
+
+ // Big thank to W3schools.com for this code.
+ const nodemailer = WrexMODS.require('nodemailer');
+
+ const transporter = nodemailer.createTransport({
+ service: 'gmail',
+ auth: {
+ user: username,
+ pass: password,
+ },
+ });
+ switch (typevalue) {
+ case 0: {
+ var mailOptions = {
+ from: username,
+ to: mailto,
+ subject: subjectvalue,
+ text: textvalue,
+ };
+ }
+ case 1:
+ var mailOptions = {
+ from: username,
+ to: mailto,
+ subject: subjectvalue,
+ html: textvalue,
+ };
+ }
+
+ transporter.sendMail(mailOptions, function (error, info) {
+ if (error) {
+ console.log(error);
+ _this.executeResults(false, data, cache);
+ } else {
+ console.log(`Email successfully sent to: ${mailto}`);
+ _this.callNextAction(cache);
+ }
+ });
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflictions between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {},
+}; // End of module
diff --git a/actions/send_image.js b/actions/send_image.js
new file mode 100644
index 000000000..95d9fcbc1
--- /dev/null
+++ b/actions/send_image.js
@@ -0,0 +1,173 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Send Image',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Image Editing',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getSendTargetText(data.channel, data.varName2)}: ${data.varName}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'channel', 'varName2', 'message', 'storage2', 'varName3'],
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function << added
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage2, 10);
+ if (type !== varType) return;
+ return [data.varName3, 'Message'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+
+ Message
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const { DiscordJS, Images } = this.getDBM();
+
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const image = this.getVariable(storage, varName, cache);
+ if (!image) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const target = await this.getSendTargetFromData(data.channel, data.varName2, cache);
+
+ const varName3 = this.evalMessage(data.varName3, cache);
+ const storage2 = parseInt(data.storage2, 10);
+
+ if (!Array.isArray(target) && !target?.send) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ Images.createBuffer(image)
+ .then((buffer) => {
+ const obj = {
+ files: [new DiscordJS.AttachmentBuilder(buffer, { name: 'image.png' })],
+ };
+
+ if (data.message) {
+ obj.content = this.evalMessage(data.message, cache);
+ }
+
+ if (Array.isArray(target)) {
+ this.callListFunc(target, 'send', [obj])
+ .then((msgList) => {
+ this.storeValue(msgList, storage2, varName3, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ } else if (target?.send) {
+ target
+ .send(obj)
+ .then((msg) => {
+ this.storeValue(msg, storage2, varName3, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ }
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/send_image_MOD.js b/actions/send_image_MOD.js
new file mode 100644
index 000000000..3d3aca351
--- /dev/null
+++ b/actions/send_image_MOD.js
@@ -0,0 +1,153 @@
+module.exports = {
+ name: 'Send Image MOD',
+ section: 'Image Editing',
+
+ subtitle(data) {
+ const channels = [
+ 'Same Channel',
+ 'Command Author',
+ 'Mentioned User',
+ 'Mentioned Channel',
+ 'Default Channel (Top Channel)',
+ 'Temp Variable',
+ 'Server Variable',
+ 'Global Variable',
+ ];
+ return `${channels[parseInt(data.channel, 10)]}`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage2, 10);
+ if (type !== varType) return;
+ return [data.varName3, 'Message'];
+ },
+
+ fields: ['storage', 'varName', 'channel', 'varName2', 'message', 'imageName', 'imageFormat', 'storage2', 'varName3'],
+
+ html(isEvent, data) {
+ return `
+
+
+ Source Image:
+
+
+
+ Variable Name:
+
+
+
+
+
+ Send To:
+
+
+
+ Variable Name:
+
+
+
+
+ Message:
+
+
+
+ Image Format:
+
+
+
+ Image Name:
+
+
+
+
+ Store In:
+
+
+
+ Variable Name:
+
+
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.refreshVariableList(document.getElementById('storage'));
+ glob.variableChange(document.getElementById('storage2'), 'varNameContainer3'); // Fix the varname container poofing ~TheMonDon
+ glob.sendTargetChange(document.getElementById('channel'), 'varNameContainer2');
+ },
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const image = this.getVariable(storage, varName, cache);
+ if (!image) {
+ this.callNextAction(cache);
+ return;
+ }
+ const channel = parseInt(data.channel, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const target = this.getSendTarget(channel, varName2, cache);
+ const fileName = this.evalMessage(data.imageName, cache);
+ if (Array.isArray(target)) {
+ const { Images } = this.getDBM();
+ Images.createBuffer(image)
+ .then((buffer) => {
+ this.callListFunc(target, 'send', [
+ this.evalMessage(data.message, cache),
+ {
+ files: [
+ {
+ attachment: buffer,
+ name: `${fileName}${data.imageFormat}`,
+ },
+ ],
+ },
+ ]).then((resultMsg) => {
+ const varName3 = this.evalMessage(data.varName3, cache);
+ const storage2 = parseInt(data.storage2, 10);
+ this.storeValue(resultMsg, storage2, varName3, cache);
+ this.callNextAction(cache);
+ });
+ })
+ .catch(this.displayError.bind(this, data, cache));
+ } else if (target && target.send) {
+ const { Images } = this.getDBM();
+ Images.createBuffer(image)
+ .then((buffer) => {
+ const varName3 = this.evalMessage(data.varName3, cache);
+ const storage2 = parseInt(data.storage2, 10);
+ target
+ .send(this.evalMessage(data.message, cache), {
+ files: [
+ {
+ attachment: buffer,
+ name: `${fileName}${data.imageFormat}`,
+ },
+ ],
+ })
+ .then((resultMsg) => {
+ this.storeValue(resultMsg, storage2, varName3, cache);
+ this.callNextAction(cache);
+ })
+ .catch(this.displayError.bind(this, data, cache));
+ })
+ .catch(this.displayError.bind(this, data, cache));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ mod() {},
+};
diff --git a/actions/send_json_to_webapi_MOD.js b/actions/send_json_to_webapi_MOD.js
index a1ff47958..603e0edb8 100644
--- a/actions/send_json_to_webapi_MOD.js
+++ b/actions/send_json_to_webapi_MOD.js
@@ -1,3 +1,11 @@
+const _getFetch = () => {
+ if (typeof globalThis.fetch === 'function') return globalThis.fetch;
+ try {
+ const nf = require('node-fetch');
+ return nf.default || nf;
+ } catch (_) {}
+ return null;
+};
module.exports = {
name: 'Send Json to WebAPI',
section: 'JSON Things',
@@ -164,7 +172,6 @@ module.exports = {
const { Actions } = this.getDBM();
const Mods = this.getMods();
- const fetch = require('node-fetch');
let url = this.evalMessage(data.postUrl, cache);
const method = this.evalMessage(data.method, cache);
@@ -220,7 +227,13 @@ module.exports = {
const value = header[1] || 'Unknown';
setHeaders[key] = value;
- if (debugMode) console.log(`Applied Header: ${lines[i]}`);
+ if (debugMode) {
+ const line = String(lines[i]);
+ const idx = line.indexOf(':');
+ const key = idx === -1 ? '' : line.slice(0, idx).trim().toLowerCase();
+ const safeLine = key === 'authorization' ? `${line.slice(0, idx + 1)} [REDACTED]` : line;
+ console.log(`Applied Header: ${safeLine}`);
+ }
} else if (debugMode)
console.error(
`WebAPI: Error: Custom Header line ${lines[i]} is wrongly formatted. You must split the key from the value with a colon (:)`,
@@ -228,7 +241,38 @@ module.exports = {
}
}
- const jsonData = await fetch(url, { method, body: postJson, headers: setHeaders }).then((r) => r.json());
+ const fetchFn = _getFetch();
+ if (!fetchFn)
+ throw new Error('Send Json to WebAPI: fetch is not available. Use Node 18+ or install node-fetch.');
+ let jsonData;
+ try {
+ const res = await fetchFn(url, { method, body: postJson, headers: setHeaders });
+ const text = typeof res.text === 'function' ? await res.text() : '';
+ if (!text || !String(text).trim()) {
+ jsonData = null;
+ } else {
+ try {
+ jsonData = JSON.parse(text);
+ } catch (parseErr) {
+ const errJson = JSON.stringify({
+ error: parseErr.message || String(parseErr),
+ statusCode: res.status || 0,
+ success: false,
+ rawPreview: String(text).slice(0, 200),
+ });
+ if (debugMode) console.error('WebAPI: Response was not valid JSON:', parseErr.message || parseErr);
+ return this.storeValue(errJson, storage, varName, cache);
+ }
+ }
+ } catch (netErr) {
+ const errJson = JSON.stringify({
+ error: netErr.message || String(netErr),
+ statusCode: 0,
+ success: false,
+ });
+ if (debugMode) console.error(netErr.stack || netErr);
+ return this.storeValue(errJson, storage, varName, cache);
+ }
try {
if (jsonData) {
diff --git a/actions/send_message.js b/actions/send_message.js
new file mode 100644
index 000000000..6c86410ba
--- /dev/null
+++ b/actions/send_message.js
@@ -0,0 +1,931 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Send Message',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ let text = '';
+ if (data.message) {
+ text = `"${data.message.replace(/[\n\r]+/, ' ↲ ')}"`;
+ } else if (data.embeds?.length > 0) {
+ text = `${data.embeds.length} Embeds`;
+ } else if (data.attachments?.length > 0) {
+ text = `${data.attachments.length} Attachments`;
+ } else if (data.buttons?.length > 0 || data.selectMenus?.length > 0) {
+ text = `${data.buttons.length} Buttons and ${data.selectMenus.length} Select Menus`;
+ } else if (data.editMessage && data.editMessage !== '0') {
+ text = `Message Options - ${presets.getVariableText(data.editMessage, data.editMessageVarName)}`;
+ } else {
+ text = `Nothing (might cause error)`;
+ }
+ if (data.dontSend) {
+ return `Store Data: ${text}`;
+ }
+ return `${presets.getSendReplyTargetText(data.channel, data.varName)}: ${text}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, data.dontSend ? 'Message Options' : 'Message'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: [
+ 'channel',
+ 'varName',
+ 'message',
+ 'buttons',
+ 'selectMenus',
+ 'attachments',
+ 'embeds',
+ 'reply',
+ 'ephemeral',
+ 'tts',
+ 'overwrite',
+ 'dontSend',
+ 'editMessage',
+ 'editMessageVarName',
+ 'storage',
+ 'varName2',
+ ],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ `;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const interaction = cache.interaction?.__originalInteraction ?? cache.interaction;
+
+ const targetServer = await this.getServerFromData(data.server, data.varName, cache);
+
+ if (!interaction) {
+ return this.callNextAction(cache);
+ }
+
+ if (!targetServer) {
+ return this.callNextAction(cache);
+ }
+
+ const interactionServerId = interaction.guild?.id;
+ const targetServerId = targetServer.id;
+
+ const sameServer = interactionServerId === targetServerId;
+
+ this.executeResults(sameServer, data.branch, cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_audio_volume.js b/actions/set_audio_volume.js
new file mode 100644
index 000000000..42f223bbe
--- /dev/null
+++ b/actions/set_audio_volume.js
@@ -0,0 +1,108 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Audio Volume',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Set Volume to ${data.volume}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.1.7', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['volume'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Volume (0 = min; 100 = max):
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const Audio = this.getDBM().Audio;
+ const server = cache.server;
+ if (server) {
+ const volume = parseInt(this.evalMessage(data.volume, cache), 10) / 100;
+ Audio.setVolume(volume, server);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_audio_volume.ts b/actions/set_audio_volume.ts
new file mode 100644
index 000000000..30bab140a
--- /dev/null
+++ b/actions/set_audio_volume.ts
@@ -0,0 +1,114 @@
+import * as djs from 'discord.js';
+import { Actions, ActionsCache } from '../bot.ts';
+import Audio from '../bot_audio.ts';
+import { Action, ActionMod } from '../types.ts';
+
+type SetAudioVolume = { volume: string };
+
+module.exports = {
+ //---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ //---------------------------------------------------------------------
+
+ name: 'Set Audio Volume',
+
+ //---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ //---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ //---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ //---------------------------------------------------------------------
+
+ subtitle(data: SetAudioVolume, presets: any) {
+ return `Set Volume to ${data.volume}`;
+ },
+
+ //---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ //---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ //---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ //---------------------------------------------------------------------
+
+ fields: ['volume'],
+
+ //---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //---------------------------------------------------------------------
+
+ html(isEvent: boolean, data: any) {
+ return `
+
+ Volume (min: 0; max: 100)
+
+
`;
+ },
+
+ //---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ //---------------------------------------------------------------------
+
+ init() {},
+
+ //---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ //---------------------------------------------------------------------
+
+ async action(this: typeof Actions, cache: ActionsCache) {
+ const data = cache.actions[cache.index] as Action & SetAudioVolume;
+ const server: djs.Guild = cache.server;
+ if (server) {
+ const volume: number = parseInt(this.evalMessage(data.volume, cache), 10);
+ await Audio.setVolume(volume, server);
+ }
+ this.callNextAction(cache);
+ },
+
+ //---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ //---------------------------------------------------------------------
+
+ mod() {},
+} satisfies ActionMod;
diff --git a/actions/set_bot_activity_MOD.js b/actions/set_bot_activity_MOD.js
new file mode 100644
index 000000000..b9a43b2e8
--- /dev/null
+++ b/actions/set_bot_activity_MOD.js
@@ -0,0 +1,195 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // region # Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Set Bot Activity',
+ displayName: 'Set Bot Activity',
+
+ // ---------------------------------------------------------------------
+ // region # Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Bot Client Control',
+
+ // ---------------------------------------------------------------------
+ // region # Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // region # Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data) {
+ const activities = ['Playing', 'Streaming', 'Listening', 'Watching', 'Custom', 'Competing'];
+ const statusMap = {
+ online: 'Online',
+ idle: 'Idle',
+ dnd: 'Do Not Disturb',
+ invisible: 'Invisible',
+ };
+ const statusText = statusMap[data.status] || 'Unknown';
+ const activityText = activities[Number(data.activityType)] || 'Unknown';
+ const isCustom = (activityText || '').toLowerCase() === 'custom';
+ const text = isCustom ? data.stateText || 'Unknown' : data.nameText || data.stateText || 'Unknown';
+ const suffix = isCustom || !data.stateText ? '' : ` (${data.stateText})`;
+ return `Status: ${statusText} - ${activityText}: ${text}${suffix}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // region # Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['activityType', 'status', 'nameText', 'stateText', 'url'],
+
+ // ---------------------------------------------------------------------
+ // region # Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent) {
+ return `
+
+ `;
+ },
+
+ // ---------------------------------------------------------------------
+ // region # Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onComparisonChanged = function (event) {
+ const value = parseInt(event.value, 10);
+
+ const urlElem = document.getElementById('url');
+ const nameElem = document.getElementById('nameText');
+ const stateElem = document.getElementById('stateText');
+
+ const urlField = urlElem ? urlElem.parentElement : null;
+ const nameField = nameElem ? nameElem.parentElement : null;
+ const stateField = stateElem ? stateElem.parentElement : null;
+
+ if (urlField) {
+ urlField.style.display = value === 1 ? 'block' : 'none';
+ }
+
+ if (value === 4) {
+ if (nameField) {
+ nameField.style.display = 'none';
+ }
+ if (stateField) {
+ stateField.style.display = 'block';
+ stateField.style.float = 'none';
+ stateField.style.width = '100%';
+ stateField.style.paddingTop = stateField.style.paddingTop || '10px';
+ }
+ } else {
+ if (nameField) {
+ nameField.style.display = 'inline-block';
+ nameField.style.float = 'left';
+ nameField.style.width = '49%';
+ nameField.style.paddingTop = nameField.style.paddingTop || '10px';
+ }
+ if (stateField) {
+ stateField.style.display = 'inline-block';
+ stateField.style.float = 'right';
+ stateField.style.width = '49%';
+ stateField.style.paddingTop = stateField.style.paddingTop || '10px';
+ }
+ }
+ };
+
+ const select = document.getElementById('activityType');
+ if (select) glob.onComparisonChanged(select);
+ },
+
+ // ---------------------------------------------------------------------
+ // region # Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const client = this.getDBM().Bot.bot;
+
+ const status = this.evalMessage(data.status, cache);
+ const activityType = Number(this.evalMessage(data.activityType, cache));
+ const nameText = this.evalMessage(data.nameText, cache);
+ const stateText = this.evalMessage(data.stateText, cache);
+ const url = this.evalMessage(data.url, cache);
+
+ const preload = {
+ status, // online, idle, dnd, invisible
+ activities: [
+ {
+ name: nameText,
+ state: stateText,
+ type: activityType, // 0-Playing, 1-Streaming, 2-Listening, 3-Watching, 4-Custom, 5-Competing
+ },
+ ],
+ };
+
+ if (url) {
+ preload.activities[0].url = url;
+ }
+
+ client.user.setPresence(preload);
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // region # Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_bot_afk.js b/actions/set_bot_afk.js
new file mode 100644
index 000000000..454da8ffd
--- /dev/null
+++ b/actions/set_bot_afk.js
@@ -0,0 +1,114 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Bot AFK Status',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Bot Client Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.afk === '0' ? 'AFK' : 'Not AFK'}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['afk'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ AFK Status
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const botClient = this.getDBM().Bot.bot.user;
+ const data = cache.actions[cache.index];
+ const afk = parseInt(data.afk, 10);
+ if (botClient?.setAFK) {
+ botClient
+ .setAFK(afk === 0)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_bot_avatar.js b/actions/set_bot_avatar.js
new file mode 100644
index 000000000..ff5772878
--- /dev/null
+++ b/actions/set_bot_avatar.js
@@ -0,0 +1,115 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Bot Avatar',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Bot Client Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storeTypes = presets.variables;
+ return `${storeTypes[parseInt(data.storage, 10)]} (${data.varName})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return ``;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const botClient = this.getDBM().Bot.bot.user;
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const image = this.getVariable(storage, varName, cache);
+ if (botClient?.setAvatar) {
+ const Images = this.getDBM().Images;
+ Images.createBuffer(image)
+ .then((buffer) => {
+ botClient
+ .setAvatar(buffer)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_bot_game.js b/actions/set_bot_game.js
new file mode 100644
index 000000000..08cb2b176
--- /dev/null
+++ b/actions/set_bot_game.js
@@ -0,0 +1,157 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Bot Game',
+
+ // ---------------------------------------------------------------------
+ // Action Display Name
+ //
+ // Overrides the name that appears in the editor.
+ // ---------------------------------------------------------------------
+
+ displayName: 'Set Bot Activity',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Bot Client Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const activityPrefix = {
+ PLAYING: 'Playing',
+ STREAMING: 'Streaming',
+ LISTENING: 'Listening to',
+ WATCHING: 'Watching',
+ COMPETING: 'Competing in',
+ };
+ return `${activityPrefix[data.activityType]} ${data.gameName}${data.gameLink ? ` [${data.gameLink}]` : ''}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['gameName', 'gameLink', 'activityType'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+Game Name
+
+
+
+
+Twitch Stream Link
+
+
+
+
+Activity Type
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const botClient = this.getDBM().Bot.bot.user;
+ const data = cache.actions[cache.index];
+ const name = this.evalMessage(data.gameName, cache);
+ const url = this.evalMessage(data.gameLink, cache);
+
+ const { ActivityType } = this.getDBM().DiscordJS;
+
+ if (url) {
+ botClient.setActivity(name, { type: ActivityType.Streaming, url });
+ } else {
+ let type = ActivityType.Playing;
+ switch (data.activityType) {
+ case 'PLAYING':
+ type = ActivityType.Playing;
+ case 'STREAMING':
+ type = ActivityType.Streaming;
+ case 'LISTENING':
+ type = ActivityType.Listening;
+ case 'WATCHING':
+ type = ActivityType.Watching;
+ case 'COMPETING':
+ type = ActivityType.Competing;
+ }
+
+ botClient.setActivity(name, { type });
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_bot_nickname.js b/actions/set_bot_nickname.js
new file mode 100644
index 000000000..6aafacaf2
--- /dev/null
+++ b/actions/set_bot_nickname.js
@@ -0,0 +1,124 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Bot Nickname',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Bot Client Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.nickname}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName', 'nickname', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Nickname
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = await this.getServerFromData(data.server, data.varName, cache);
+ const nickname = this.evalMessage(data.nickname, cache) || null;
+ const reason = this.evalMessage(data.reason, cache);
+ const botMember = server.members.me;
+ if (botMember?.setNickname) {
+ botMember
+ .setNickname(nickname, reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_bot_status.js b/actions/set_bot_status.js
new file mode 100644
index 000000000..6f18231ea
--- /dev/null
+++ b/actions/set_bot_status.js
@@ -0,0 +1,113 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Bot Status',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Bot Client Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const statuses = ['Online', 'Idle', 'Invisible', 'Do Not Disturb'];
+ return `${statuses[data.status]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['status'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Status
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const botClient = this.getDBM().Bot.bot.user;
+ const data = cache.actions[cache.index];
+ const status = ['online', 'idle', 'invisible', 'dnd'][parseInt(data.status, 10)];
+ if (status) {
+ botClient.setStatus(status);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_bot_typing_MOD.js b/actions/set_bot_typing_MOD.js
new file mode 100644
index 000000000..a2d30be6a
--- /dev/null
+++ b/actions/set_bot_typing_MOD.js
@@ -0,0 +1,160 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Bot Typing',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Bot Client Control',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data) {
+ const names = [
+ 'Same Channel',
+ 'Mentioned Channel',
+ 'Default Channel',
+ 'Temp Variable',
+ 'Server Variable',
+ 'Global Variable',
+ ];
+ const names2 = ['Starts Typing', 'Stops Typing'];
+ const index2 = parseInt(data.type, 10);
+ const index = parseInt(data.storage, 10);
+ return index < 3 ? `${names[index]} - ${names2[index2]}` : `${names[index]} - ${data.varName} - ${names2[index2]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'type'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editting actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Mod Info:
+ Created by Lasse! (merged by EliteArtz and fixed by iAmaury)
+
+
+
+
+ Typing Option:
+
+
+
+
+
+ Channel to start typing in:
+
+
+
+ Variable Name:
+
+
+
+
+
+ You can stop the typing with Stop Typing
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.channelChange(document.getElementById('storage'), 'varNameContainer');
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existance.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const channel = this.getChannel(storage, varName, cache);
+
+ try {
+ // This "Try and Catch" Function is really useful for when it's coming up an error, it will log it in your logs.
+ if (data.type === '0') {
+ // "If and else" Function is for looking if the result of them equals what you wan't.
+ channel.startTyping(); // Starts the Typing
+ } else {
+ channel.stopTyping(true); // Stops the Typing
+ }
+ } catch (e) {
+ console.error(`ERROR!${e}${e.stack}`); // Here it's gonna log if an error occured.
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflictions between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {},
+}; // End of module
diff --git a/actions/set_bot_username.js b/actions/set_bot_username.js
new file mode 100644
index 000000000..3a13451b9
--- /dev/null
+++ b/actions/set_bot_username.js
@@ -0,0 +1,109 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Bot Username',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Bot Client Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.username}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['username'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
Changing usernames in Discord is heavily rate limited, with only 2 requests every hour. Use this sparingly!
+
+
+ Username
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const botClient = this.getDBM().Bot.bot.user;
+ const data = cache.actions[cache.index];
+ const username = this.evalMessage(data.username, cache);
+ botClient
+ .setUsername(username)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_channel_category_MOD.js b/actions/set_channel_category_MOD.js
new file mode 100644
index 000000000..21f70c392
--- /dev/null
+++ b/actions/set_channel_category_MOD.js
@@ -0,0 +1,119 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Set Channel Category',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const channelText = presets.getChannelText(data.channel, data.varName1);
+ const categoryText = data.categoryId || '';
+ const posText = data.position ? ` at position ${data.position}` : '';
+ const syncText = data.syncPermissions ? ' (sync permissions)' : '';
+ return `Move ${channelText} → Category: ${categoryText}${posText}${syncText}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'varName1', 'categoryId', 'position', 'syncPermissions'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html() {
+ return `
+
+
+
+
+
+ `;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+
+ const channel = await this.getChannelFromData(data.channel, data.varName1, cache);
+ if (!channel) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const syncPermissions = data.syncPermissions;
+
+ const posInput = data.position ? parseInt(this.evalMessage(data.position, cache), 10) : null;
+
+ const categoryId = this.evalMessage(data.categoryId, cache);
+
+ try {
+ await channel.setParent(categoryId, { lockPermissions: syncPermissions });
+ if (posInput !== null && !isNaN(posInput)) {
+ const targetPosition = Math.max(posInput - 1, 0);
+ await channel.setPosition(targetPosition);
+ }
+ } catch (error) {
+ console.error('[Set Channel Category] Error moving channel:', error);
+ this.callNextAction(cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_channel_permissions.js b/actions/set_channel_permissions.js
new file mode 100644
index 000000000..e06d501c0
--- /dev/null
+++ b/actions/set_channel_permissions.js
@@ -0,0 +1,147 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Channel Permissions',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getChannelText(data.storage, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'permission', 'state', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Permission
+
+
+
+ Change To
+
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = cache.server;
+ if (!server) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const channel = await this.getChannelFromData(data.storage, data.varName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+ const options = { [data.permission]: [true, false, null][parseInt(data.state, 10)] };
+ const role = server.roles.cache.get(server.id);
+
+ if (Array.isArray(channel)) {
+ this.callListFunc(channel.permissionOverwrites, 'edit', [role, options, { reason, type: 0 }]).then(() =>
+ this.callNextAction(cache),
+ );
+ } else if (channel?.permissionOverwrites) {
+ channel.permissionOverwrites
+ .edit(role, options, { reason, type: 0 })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_channel_perms_MOD.js b/actions/set_channel_perms_MOD.js
new file mode 100644
index 000000000..7fe420e08
--- /dev/null
+++ b/actions/set_channel_perms_MOD.js
@@ -0,0 +1,182 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Channel Permissions',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getChannelText(data.storage, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'permission', 'state', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = cache.server;
+ if (!server) {
+ this.callNextAction(cache);
+ return;
+ }
+ const channel = await this.getChannelFromData(data.storage, data.varName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+ const options = {
+ [data.permission]: [true, false, null][parseInt(data.state, 10)],
+ };
+
+ if (Array.isArray(channel)) {
+ this.callListFunc(channel.permissionOverwrites, 'edit', [server.id, options, { reason, type: 0 }]).then(() =>
+ this.callNextAction(cache),
+ );
+ } else if (channel?.permissionOverwrites) {
+ channel.permissionOverwrites
+ .edit(server.id, options, { reason, type: 0 })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_embed_description.js b/actions/set_embed_description.js
new file mode 100644
index 000000000..038c48975
--- /dev/null
+++ b/actions/set_embed_description.js
@@ -0,0 +1,112 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Embed Description',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Embed Message',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.message}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'message'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+ Description
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ let embed = this.getVariable(storage, varName, cache);
+
+ const { EmbedBuilder } = this.getDBM().DiscordJS;
+ embed = EmbedBuilder.from(embed).setDescription(this.evalMessage(data.message, cache));
+
+ this.storeValue(embed, storage, varName, cache);
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_embed_footer.js b/actions/set_embed_footer.js
new file mode 100644
index 000000000..2a2c1cae2
--- /dev/null
+++ b/actions/set_embed_footer.js
@@ -0,0 +1,121 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Embed Footer',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Embed Message',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${data.message}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'message', 'footerIcon'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Footer
+
+
+
+ Footer Icon URL
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ let embed = this.getVariable(storage, varName, cache);
+
+ const { EmbedBuilder } = this.getDBM().DiscordJS;
+ embed = EmbedBuilder.from(embed).setFooter({
+ text: this.evalMessage(data.message, cache),
+ iconURL: this.evalMessage(data.footerIcon, cache),
+ });
+
+ this.storeValue(embed, storage, varName, cache);
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_member_channel_multi_perms_MOD.js b/actions/set_member_channel_multi_perms_MOD.js
new file mode 100644
index 000000000..a5ac80bcd
--- /dev/null
+++ b/actions/set_member_channel_multi_perms_MOD.js
@@ -0,0 +1,488 @@
+module.exports = {
+ name: 'Set Member Channel Multi Perms',
+ section: 'Channel Control',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data, presets) {
+ return `${presets.getChannelText(data.channel, data.varName)}`;
+ },
+
+ fields: [
+ 'channel',
+ 'varName',
+ 'member',
+ 'varName2',
+ 'reparticao',
+ 'state1',
+ 'state2',
+ 'state3',
+ 'state4',
+ 'state5',
+ 'state6',
+ 'state7',
+ 'state8',
+ 'state9',
+ 'state10',
+ 'state11',
+ 'state12',
+ 'state13',
+ 'state14',
+ 'state15',
+ 'state16',
+ 'state17',
+ 'state18',
+ 'state19',
+ 'state20',
+ 'state21',
+ 'state22',
+ 'state23',
+ 'state24',
+ 'state25',
+ 'state26',
+ 'state27',
+ 'state1v',
+ 'state2v',
+ 'state3v',
+ 'state4v',
+ 'state5v',
+ 'state6v',
+ 'state7v',
+ 'state8v',
+ 'state9v',
+ 'state10v',
+ 'state11v',
+ 'state12v',
+ 'state13v',
+ 'state14v',
+ 'state15v',
+ 'state16v',
+ 'state17v',
+ 'state18v',
+ 'state19v',
+ 'state20v',
+ 'state21v',
+ 'state22v',
+ 'state23v',
+ 'state24v',
+ 'state25v',
+ 'state26v',
+ 'state27v',
+ 'reason',
+ ],
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+
+Resource
+
+
+
+
+
+
Permissions
Change to
+
+
View channels
+
+
Manage Channel
+
+
Manage webhooks
+
+
Create invitation
+
+
+
Send messages
+
+
Send messages in threads
+
+
Create Public Topics
+
+
Create private topics
+
+
Insert links
+
+
Attach files
+
+
Add Reactions
+
+
Use external emojis
+
+
Use external stickers
+
+
Mention @everyone
+
+
Manage Messages
+
+
Manage topics
+
+
View message history
+
+
Send Text-to-Voice Messages
+
+
Use Application Commands
+
+
[Voice Channel] Connect
+
+
[Voice Channel] Speak
+
+
[Voice Channel] Video
+
+
[Voice Channel] Use voice detection
+
+
[Voice Channel] Priority Voice
+
+
[Voice Channel] Mute Members
+
+
[Voice Channel] Deafen members
+
+
[Voice Channel] Move Members
+
+
+
+
+Use 0 for Allow, 1 for Inherit and 2 for Disallow
+
+
Permissions
Change to
+
+
View channels
+
+
Manage Channel
+
+
Manage webhooks
+
+
Create invitation
+
+
Send messages
+
+
Send messages in threads
+
+
Create public topics
+
+
Create private topics
+
+
Insert links
+
+
Attach files
+
+
Add Reactions
+
+
Use external emojis
+
+
Use external stickers
+
+
Mention @everyone
+
+
Manage messages
+
+
Manage topics
+
+
View message history
+
+
Send Text-to-Voice Messages
+
+
Use Application Commands
+
+
[Voice Channel] Connect
+
+
[Voice Channel] Talk
+
+
[Voice Channel] Video
+
+
[Voice Channel] Use voice detection
+
+
[Voice Channel] Priority Voice
+
+
[Voice Channel] Mute Members
+
+
[Voice Channel] Deafen members
+
+
[Voice Channel] Move Members
+
+
+
+
+
+
+
+ Reason
+
+
+
+
+
+`;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onComparisonChanged = function (event) {
+ if (event.value === '0') {
+ document.getElementById('containerdoxin1').style.display = null;
+ document.getElementById('containerdoxin2').style.display = 'none';
+ } else {
+ document.getElementById('containerdoxin2').style.display = null;
+ document.getElementById('containerdoxin1').style.display = 'none';
+ }
+ };
+
+ glob.onComparisonChanged(document.getElementById('reparticao'));
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const channel = await this.getChannelFromData(data.channel, data.varName, cache);
+ const member = await this.getMemberFromData(data.member, data.varName2, cache);
+ const reason = this.evalMessage(data.reason, cache);
+
+ const options = {
+ VIEW_CHANNEL: [true, null, false][parseInt(data.state1, 10)],
+ MANAGE_CHANNELS: [true, null, false][parseInt(data.state2, 10)],
+ MANAGE_WEBHOOKS: [true, null, false][parseInt(data.state3, 10)],
+ CREATE_INSTANT_INVITE: [true, null, false][parseInt(data.state4, 10)],
+ SEND_MESSAGES: [true, null, false][parseInt(data.state5, 10)],
+ SEND_MESSAGES_IN_THREADS: [true, null, false][parseInt(data.state6, 10)],
+ CREATE_PUBLIC_THREADS: [true, null, false][parseInt(data.state7, 10)],
+ CREATE_PRIVATE_THREADS: [true, null, false][parseInt(data.state8, 10)],
+ EMBED_LINKS: [true, null, false][parseInt(data.state9, 10)],
+ ATTACH_FILES: [true, null, false][parseInt(data.state10, 10)],
+ ADD_REACTIONS: [true, null, false][parseInt(data.state11, 10)],
+ USE_EXTERNAL_EMOJIS: [true, null, false][parseInt(data.state12, 10)],
+ USE_EXTERNAL_STICKERS: [true, null, false][parseInt(data.state13, 10)],
+ MENTION_EVERYONE: [true, null, false][parseInt(data.state14, 10)],
+ MANAGE_MESSAGES: [true, null, false][parseInt(data.state15, 10)],
+ MANAGE_THREADS: [true, null, false][parseInt(data.state16, 10)],
+ READ_MESSAGE_HISTORY: [true, null, false][parseInt(data.state17, 10)],
+ SEND_TTS_MESSAGES: [true, null, false][parseInt(data.state18, 10)],
+ USE_APPLICATION_COMMANDS: [true, null, false][parseInt(data.state19, 10)],
+ CONNECT: [true, null, false][parseInt(data.state20, 10)],
+ SPEAK: [true, null, false][parseInt(data.state21, 10)],
+ STREAM: [true, null, false][parseInt(data.state22, 10)],
+ USE_VAD: [true, null, false][parseInt(data.state23, 10)],
+ PRIORITY_SPEAKER: [true, null, false][parseInt(data.state24, 10)],
+ MUTE_MEMBERS: [true, null, false][parseInt(data.state25, 10)],
+ DEAFEN_MEMBERS: [true, null, false][parseInt(data.state26, 10)],
+ MOVE_MEMBERS: [true, null, false][parseInt(data.state27, 10)],
+ };
+ const state1v = this.evalMessage(data.state1v, cache);
+ const state2v = this.evalMessage(data.state2v, cache);
+ const state3v = this.evalMessage(data.state3v, cache);
+ const state4v = this.evalMessage(data.state4v, cache);
+ const state5v = this.evalMessage(data.state5v, cache);
+ const state6v = this.evalMessage(data.state6v, cache);
+ const state7v = this.evalMessage(data.state7v, cache);
+ const state8v = this.evalMessage(data.state8v, cache);
+ const state9v = this.evalMessage(data.state9v, cache);
+ const state10v = this.evalMessage(data.state10v, cache);
+ const state11v = this.evalMessage(data.state11v, cache);
+ const state12v = this.evalMessage(data.state12v, cache);
+ const state13v = this.evalMessage(data.state13v, cache);
+ const state14v = this.evalMessage(data.state14v, cache);
+ const state15v = this.evalMessage(data.state15v, cache);
+ const state16v = this.evalMessage(data.state16v, cache);
+ const state17v = this.evalMessage(data.state17v, cache);
+ const state18v = this.evalMessage(data.state18v, cache);
+ const state19v = this.evalMessage(data.state19v, cache);
+ const state20v = this.evalMessage(data.state20v, cache);
+ const state21v = this.evalMessage(data.state21v, cache);
+ const state22v = this.evalMessage(data.state22v, cache);
+ const state23v = this.evalMessage(data.state23v, cache);
+ const state24v = this.evalMessage(data.state24v, cache);
+ const state25v = this.evalMessage(data.state24v, cache);
+ const state26v = this.evalMessage(data.state24v, cache);
+ const state27v = this.evalMessage(data.state24v, cache);
+ const options2 = {
+ VIEW_CHANNEL: [true, null, false][parseInt(state1v, 10)],
+ MANAGE_CHANNELS: [true, null, false][parseInt(state2v, 10)],
+ MANAGE_WEBHOOKS: [true, null, false][parseInt(state3v, 10)],
+ CREATE_INSTANT_INVITE: [true, null, false][parseInt(state4v, 10)],
+ SEND_MESSAGES: [true, null, false][parseInt(state5v, 10)],
+ SEND_MESSAGES_IN_THREADS: [true, null, false][parseInt(state6v, 10)],
+ CREATE_PUBLIC_THREADS: [true, null, false][parseInt(state7v, 10)],
+ CREATE_PRIVATE_THREADS: [true, null, false][parseInt(state8v, 10)],
+ EMBED_LINKS: [true, null, false][parseInt(state9v, 10)],
+ ATTACH_FILES: [true, null, false][parseInt(state10v, 10)],
+ ADD_REACTIONS: [true, null, false][parseInt(state11v, 10)],
+ USE_EXTERNAL_EMOJIS: [true, null, false][parseInt(state12v, 10)],
+ USE_EXTERNAL_STICKERS: [true, null, false][parseInt(state13v, 10)],
+ MENTION_EVERYONE: [true, null, false][parseInt(state14v, 10)],
+ MANAGE_MESSAGES: [true, null, false][parseInt(state15v, 10)],
+ MANAGE_THREADS: [true, null, false][parseInt(state16v, 10)],
+ READ_MESSAGE_HISTORY: [true, null, false][parseInt(state17v, 10)],
+ SEND_TTS_MESSAGES: [true, null, false][parseInt(state18v, 10)],
+ USE_APPLICATION_COMMANDS: [true, null, false][parseInt(state19v, 10)],
+ CONNECT: [true, null, false][parseInt(state20v, 10)],
+ SPEAK: [true, null, false][parseInt(state21v, 10)],
+ STREAM: [true, null, false][parseInt(state22v, 10)],
+ USE_VAD: [true, null, false][parseInt(state23v, 10)],
+ PRIORITY_SPEAKER: [true, null, false][parseInt(state24v, 10)],
+ MUTE_MEMBERS: [true, null, false][parseInt(state25v, 10)],
+ DEAFEN_MEMBERS: [true, null, false][parseInt(state26v, 10)],
+ MOVE_MEMBERS: [true, null, false][parseInt(state27v, 10)],
+ };
+
+ const reparticao = parseInt(data.reparticao, 10);
+
+ switch (reparticao) {
+ case 0:
+ if (member?.id) {
+ if (Array.isArray(channel)) {
+ channel.permissionOverwrites.edit(member.id);
+ } else if (channel?.permissionOverwrites) {
+ channel.permissionOverwrites
+ .edit(member, options, { reason, type: 1 })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ break;
+ case 1:
+ if (member?.id) {
+ if (Array.isArray(channel)) {
+ channel.permissionOverwrites.edit(member.id);
+ } else if (channel?.permissionOverwrites) {
+ channel.permissionOverwrites
+ .edit(member, options2, { reason, type: 1 })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ break;
+ }
+ },
+
+ mod() {},
+};
diff --git a/actions/set_member_channel_perms.js b/actions/set_member_channel_perms.js
new file mode 100644
index 000000000..f0398db34
--- /dev/null
+++ b/actions/set_member_channel_perms.js
@@ -0,0 +1,150 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Member Channel Perms',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getChannelText(data.channel, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'varName', 'member', 'varName2', 'permission', 'state', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+
+
+ Permission
+
+
+
+ Change To
+
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const channel = await this.getChannelFromData(data.channel, data.varName, cache);
+ const member = await this.getMemberFromData(data.member, data.varName2, cache);
+ const reason = this.evalMessage(data.reason, cache);
+
+ const options = { [data.permission]: [true, null, false][parseInt(data.state, 10)] };
+
+ if (member?.id) {
+ if (Array.isArray(channel)) {
+ this.callListFunc(channel.permissionOverwrites, 'edit', [member, options, { reason, type: 1 }]).then(() =>
+ this.callNextAction(cache),
+ );
+ } else if (channel?.permissionOverwrites) {
+ channel.permissionOverwrites
+ .edit(member, options, { reason, type: 1 })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_member_channel_perms_MOD.js b/actions/set_member_channel_perms_MOD.js
new file mode 100644
index 000000000..cf4bb6d0d
--- /dev/null
+++ b/actions/set_member_channel_perms_MOD.js
@@ -0,0 +1,262 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Member Channel Perms',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getChannelText(data.channel, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'varName', 'member', 'varName2', 'permission', 'state', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const channel = await this.getChannelFromData(data.channel, data.varName, cache);
+ const member = await this.getMemberFromData(data.member, data.varName2, cache);
+ const reason = this.evalMessage(data.reason, cache);
+
+ const options = {
+ [data.permission]: [true, null, false][parseInt(data.state, 10)],
+ };
+
+ if (member?.id) {
+ if (Array.isArray(channel)) {
+ this.callListFunc(channel.permissionOverwrites, 'edit', [member, options, { reason, type: 1 }]).then(() =>
+ this.callNextAction(cache),
+ );
+ } else if (channel?.permissionOverwrites) {
+ channel.permissionOverwrites
+ .edit(member, options, { reason, type: 1 })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_member_deafen.js b/actions/set_member_deafen.js
new file mode 100644
index 000000000..c0369eaa9
--- /dev/null
+++ b/actions/set_member_deafen.js
@@ -0,0 +1,131 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Member Deafen',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)} - ${data.deafen === '0' ? 'Deafen' : 'Undeafen'}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'deafen', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Deafen Status
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+ if (Array.isArray(member)) {
+ this.callListFunc(
+ member.map((m) => m.voice),
+ 'setDeaf',
+ [data.deafen === '0', reason],
+ ).then(() => this.callNextAction(cache));
+ } else if (member?.voice) {
+ member.voice
+ .setDeaf(data.deafen === '0', reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_member_mute.js b/actions/set_member_mute.js
new file mode 100644
index 000000000..f355713d7
--- /dev/null
+++ b/actions/set_member_mute.js
@@ -0,0 +1,131 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Member Mute',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)} - ${data.mute === '0' ? 'Mute' : 'Unmute'}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'mute', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Mute Status
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+ if (Array.isArray(member)) {
+ this.callListFunc(
+ member.map((m) => m.voice),
+ 'setMute',
+ [data.mute === '0', reason],
+ ).then(() => this.callNextAction(cache));
+ } else if (member?.voice) {
+ member.voice
+ .setMute(data.mute === '0', reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_member_nickname.js b/actions/set_member_nickname.js
new file mode 100644
index 000000000..a65d35e78
--- /dev/null
+++ b/actions/set_member_nickname.js
@@ -0,0 +1,123 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Member Nickname',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)} - ${data.nickname}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'nickname', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ New Nickname
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ const nick = this.evalMessage(data.nickname, cache) || null;
+ const reason = this.evalMessage(data.reason, cache);
+ if (Array.isArray(member)) {
+ this.callListFunc(member, 'setNickname', [nick, reason]).then(() => this.callNextAction(cache));
+ } else if (member?.setNickname) {
+ member
+ .setNickname(nick, reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_member_permissions_MOD.js b/actions/set_member_permissions_MOD.js
new file mode 100644
index 000000000..e344545ec
--- /dev/null
+++ b/actions/set_member_permissions_MOD.js
@@ -0,0 +1,143 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Member Permissions',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data) {
+ const channels = ['Mentioned User', 'Command Author', 'Temp Variable', 'Server Variable', 'Global Variable'];
+ return `${channels[parseInt(data.member, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'permission', 'action'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editting actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source Member:
+
+
+
+ Variable Name:
+
+
+
+
+
+ Permission:
+
+
+
+ Action:
+
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.memberChange(document.getElementById('member'), 'varNameContainer');
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existance.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.member, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const member = this.getMember(storage, varName, cache);
+ const funcName = data.action === '0' ? 'add' : 'remove';
+ if (member && member.permissions) {
+ member.permissions[funcName](data.permission)
+ .then(
+ function () {
+ this.callNextAction(cache);
+ }.bind(this),
+ )
+ .catch(this.displayError.bind(this, data, cache));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflictions between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {},
+}; // End of module
diff --git a/actions/set_member_voice_channel.js b/actions/set_member_voice_channel.js
new file mode 100644
index 000000000..402279909
--- /dev/null
+++ b/actions/set_member_voice_channel.js
@@ -0,0 +1,131 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Member Voice Channel',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)} - ${presets.getVoiceChannelText(
+ data.channel,
+ data.varName2,
+ )}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'channel', 'varName2', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+ const channel = await this.getVoiceChannelFromData(data.channel, data.varName2, cache);
+ const reason = this.evalMessage(data.reason, cache);
+
+ if (Array.isArray(member)) {
+ this.callListFunc(
+ member.map((m) => m.voice),
+ 'setChannel',
+ [channel, reason],
+ ).then(() => this.callNextAction(cache));
+ } else if (member?.voice) {
+ member.voice
+ .setChannel(channel, reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ this.callNextAction(cache);
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_rich_presence_MOD.js b/actions/set_rich_presence_MOD.js
new file mode 100644
index 000000000..c45976d6b
--- /dev/null
+++ b/actions/set_rich_presence_MOD.js
@@ -0,0 +1,207 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Rich Presence',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data) {
+ return `Client ID: ${data.clientId}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Provides meta-information about the custom action.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action that the user can customize.
+ // ---------------------------------------------------------------------
+
+ fields: [
+ 'clientId',
+ 'state',
+ 'details',
+ 'startTimestamp',
+ 'endTimestamp',
+ 'largeImageKey',
+ 'largeImageText',
+ 'smallImageKey',
+ 'smallImageText',
+ 'partyId',
+ 'partySize',
+ 'partyMax',
+ 'joinSecret',
+ ],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns the HTML to display the fields.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+Use 0 for Allow, 1 for Inherit and 2 for Disallow
+
+
Permissions
Change to
+
+
View channels
+
+
Manage Channel
+
+
Manage webhooks
+
+
Create invitation
+
+
Send messages
+
+
Send messages in threads
+
+
Create public topics
+
+
Create private topics
+
+
Insert links
+
+
Attach files
+
+
Add Reactions
+
+
Use external emojis
+
+
Use external stickers
+
+
Mention @everyone
+
+
Manage messages
+
+
Manage topics
+
+
View message history
+
+
Send Text-to-Voice Messages
+
+
Use Application Commands
+
+
[Voice Channel] Connect
+
+
[Voice Channel] Talk
+
+
[Voice Channel] Video
+
+
[Voice Channel] Use voice detection
+
+
[Voice Channel] Priority Voice
+
+
[Voice Channel] Mute Members
+
+
[Voice Channel] Deafen members
+
+
[Voice Channel] Move Members
+
+
+
+
+
+
+
+ Reason
+
+
+
+
+
+`;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onComparisonChanged = function (event) {
+ if (event.value === '0') {
+ document.getElementById('containerdoxin1').style.display = null;
+ document.getElementById('containerdoxin2').style.display = 'none';
+ } else {
+ document.getElementById('containerdoxin2').style.display = null;
+ document.getElementById('containerdoxin1').style.display = 'none';
+ }
+ };
+
+ glob.onComparisonChanged(document.getElementById('apportionment'));
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const channel = await this.getChannelFromData(data.channel, data.varName, cache);
+ const role = await this.getRoleFromData(data.role, data.varName2, cache);
+ const reason = this.evalMessage(data.reason, cache);
+
+ const options = {
+ VIEW_CHANNEL: [true, null, false][parseInt(data.state1, 10)],
+ MANAGE_CHANNELS: [true, null, false][parseInt(data.state2, 10)],
+ MANAGE_WEBHOOKS: [true, null, false][parseInt(data.state3, 10)],
+ CREATE_INSTANT_INVITE: [true, null, false][parseInt(data.state4, 10)],
+ SEND_MESSAGES: [true, null, false][parseInt(data.state5, 10)],
+ SEND_MESSAGES_IN_THREADS: [true, null, false][parseInt(data.state6, 10)],
+ CREATE_PUBLIC_THREADS: [true, null, false][parseInt(data.state7, 10)],
+ CREATE_PRIVATE_THREADS: [true, null, false][parseInt(data.state8, 10)],
+ EMBED_LINKS: [true, null, false][parseInt(data.state9, 10)],
+ ATTACH_FILES: [true, null, false][parseInt(data.state10, 10)],
+ ADD_REACTIONS: [true, null, false][parseInt(data.state11, 10)],
+ USE_EXTERNAL_EMOJIS: [true, null, false][parseInt(data.state12, 10)],
+ USE_EXTERNAL_STICKERS: [true, null, false][parseInt(data.state13, 10)],
+ MENTION_EVERYONE: [true, null, false][parseInt(data.state14, 10)],
+ MANAGE_MESSAGES: [true, null, false][parseInt(data.state15, 10)],
+ MANAGE_THREADS: [true, null, false][parseInt(data.state16, 10)],
+ READ_MESSAGE_HISTORY: [true, null, false][parseInt(data.state17, 10)],
+ SEND_TTS_MESSAGES: [true, null, false][parseInt(data.state18, 10)],
+ USE_APPLICATION_COMMANDS: [true, null, false][parseInt(data.state19, 10)],
+ CONNECT: [true, null, false][parseInt(data.state20, 10)],
+ SPEAK: [true, null, false][parseInt(data.state21, 10)],
+ STREAM: [true, null, false][parseInt(data.state22, 10)],
+ USE_VAD: [true, null, false][parseInt(data.state23, 10)],
+ PRIORITY_SPEAKER: [true, null, false][parseInt(data.state24, 10)],
+ MUTE_MEMBERS: [true, null, false][parseInt(data.state25, 10)],
+ DEAFEN_MEMBERS: [true, null, false][parseInt(data.state26, 10)],
+ MOVE_MEMBERS: [true, null, false][parseInt(data.state27, 10)],
+ };
+ const state1v = this.evalMessage(data.state1v, cache);
+ const state2v = this.evalMessage(data.state2v, cache);
+ const state3v = this.evalMessage(data.state3v, cache);
+ const state4v = this.evalMessage(data.state4v, cache);
+ const state5v = this.evalMessage(data.state5v, cache);
+ const state6v = this.evalMessage(data.state6v, cache);
+ const state7v = this.evalMessage(data.state7v, cache);
+ const state8v = this.evalMessage(data.state8v, cache);
+ const state9v = this.evalMessage(data.state9v, cache);
+ const state10v = this.evalMessage(data.state10v, cache);
+ const state11v = this.evalMessage(data.state11v, cache);
+ const state12v = this.evalMessage(data.state12v, cache);
+ const state13v = this.evalMessage(data.state13v, cache);
+ const state14v = this.evalMessage(data.state14v, cache);
+ const state15v = this.evalMessage(data.state15v, cache);
+ const state16v = this.evalMessage(data.state16v, cache);
+ const state17v = this.evalMessage(data.state17v, cache);
+ const state18v = this.evalMessage(data.state18v, cache);
+ const state19v = this.evalMessage(data.state19v, cache);
+ const state20v = this.evalMessage(data.state20v, cache);
+ const state21v = this.evalMessage(data.state21v, cache);
+ const state22v = this.evalMessage(data.state22v, cache);
+ const state23v = this.evalMessage(data.state23v, cache);
+ const state24v = this.evalMessage(data.state24v, cache);
+ const state25v = this.evalMessage(data.state24v, cache);
+ const state26v = this.evalMessage(data.state24v, cache);
+ const state27v = this.evalMessage(data.state24v, cache);
+ const options2 = {
+ VIEW_CHANNEL: [true, null, false][parseInt(state1v, 10)],
+ MANAGE_CHANNELS: [true, null, false][parseInt(state2v, 10)],
+ MANAGE_WEBHOOKS: [true, null, false][parseInt(state3v, 10)],
+ CREATE_INSTANT_INVITE: [true, null, false][parseInt(state4v, 10)],
+ SEND_MESSAGES: [true, null, false][parseInt(state5v, 10)],
+ SEND_MESSAGES_IN_THREADS: [true, null, false][parseInt(state6v, 10)],
+ CREATE_PUBLIC_THREADS: [true, null, false][parseInt(state7v, 10)],
+ CREATE_PRIVATE_THREADS: [true, null, false][parseInt(state8v, 10)],
+ EMBED_LINKS: [true, null, false][parseInt(state9v, 10)],
+ ATTACH_FILES: [true, null, false][parseInt(state10v, 10)],
+ ADD_REACTIONS: [true, null, false][parseInt(state11v, 10)],
+ USE_EXTERNAL_EMOJIS: [true, null, false][parseInt(state12v, 10)],
+ USE_EXTERNAL_STICKERS: [true, null, false][parseInt(state13v, 10)],
+ MENTION_EVERYONE: [true, null, false][parseInt(state14v, 10)],
+ MANAGE_MESSAGES: [true, null, false][parseInt(state15v, 10)],
+ MANAGE_THREADS: [true, null, false][parseInt(state16v, 10)],
+ READ_MESSAGE_HISTORY: [true, null, false][parseInt(state17v, 10)],
+ SEND_TTS_MESSAGES: [true, null, false][parseInt(state18v, 10)],
+ USE_APPLICATION_COMMANDS: [true, null, false][parseInt(state19v, 10)],
+ CONNECT: [true, null, false][parseInt(state20v, 10)],
+ SPEAK: [true, null, false][parseInt(state21v, 10)],
+ STREAM: [true, null, false][parseInt(state22v, 10)],
+ USE_VAD: [true, null, false][parseInt(state23v, 10)],
+ PRIORITY_SPEAKER: [true, null, false][parseInt(state24v, 10)],
+ MUTE_MEMBERS: [true, null, false][parseInt(state25v, 10)],
+ DEAFEN_MEMBERS: [true, null, false][parseInt(state26v, 10)],
+ MOVE_MEMBERS: [true, null, false][parseInt(state27v, 10)],
+ };
+
+ const apportionment = parseInt(data.apportionment, 10);
+
+ switch (apportionment) {
+ case 0:
+ if (role?.id) {
+ if (Array.isArray(channel)) {
+ channel.permissionOverwrites.edit(role.id);
+ } else if (channel?.permissionOverwrites) {
+ channel.permissionOverwrites
+ .edit(role, options, { reason, type: 0 })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ break;
+ case 1:
+ if (role?.id) {
+ if (Array.isArray(channel)) {
+ channel.permissionOverwrites.edit(role.id);
+ } else if (channel?.permissionOverwrites) {
+ channel.permissionOverwrites
+ .edit(role, options2, { reason, type: 0 })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ break;
+ }
+ },
+
+ mod() {},
+};
diff --git a/actions/set_role_channel_perms.js b/actions/set_role_channel_perms.js
new file mode 100644
index 000000000..1dfd4122f
--- /dev/null
+++ b/actions/set_role_channel_perms.js
@@ -0,0 +1,150 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Role Channel Perms',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getRoleText(data.role, data.varName2)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'varName', 'role', 'varName2', 'permission', 'state', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+
+
+ Permission
+
+
+
+ Change To
+
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const channel = await this.getChannelFromData(data.channel, data.varName, cache);
+ const role = await this.getRoleFromData(data.role, data.varName2, cache);
+ const reason = this.evalMessage(data.reason, cache);
+
+ const options = { [data.permission]: [true, null, false][parseInt(data.state, 10)] };
+
+ if (role?.id) {
+ if (Array.isArray(channel)) {
+ this.callListFunc(channel.permissionOverwrites, 'edit', [role, options, { reason, type: 0 }]).then(() =>
+ this.callNextAction(cache),
+ );
+ } else if (channel?.permissionOverwrites) {
+ channel.permissionOverwrites
+ .edit(role, options, { reason, type: 0 })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_role_channel_perms_MOD.js b/actions/set_role_channel_perms_MOD.js
new file mode 100644
index 000000000..d923240e5
--- /dev/null
+++ b/actions/set_role_channel_perms_MOD.js
@@ -0,0 +1,186 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Role Channel Perms',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getRoleText(data.role, data.varName2)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'varName', 'role', 'varName2', 'permission', 'state', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const channel = await this.getChannelFromData(data.channel, data.varName, cache);
+ const role = await this.getRoleFromData(data.role, data.varName2, cache);
+ const reason = this.evalMessage(data.reason, cache);
+
+ const options = {
+ [data.permission]: [true, null, false][parseInt(data.state, 10)],
+ };
+
+ if (role?.id) {
+ if (Array.isArray(channel)) {
+ this.callListFunc(channel.permissionOverwrites, 'edit', [role, options, { reason, type: 0 }]).then(() =>
+ this.callNextAction(cache),
+ );
+ } else if (channel?.permissionOverwrites) {
+ channel.permissionOverwrites
+ .edit(role, options, { reason, type: 0 })
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_role_icon.js b/actions/set_role_icon.js
new file mode 100644
index 000000000..7107d1fe9
--- /dev/null
+++ b/actions/set_role_icon.js
@@ -0,0 +1,153 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Role Icon',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Role Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Set Icon of ${presets.getRoleText(data.role, data.roleVarName)} to ${presets.getVariableText(
+ data.image,
+ data.imageVarName,
+ )}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['role', 'roleVarName', 'image', 'imageVarName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Note:
+ Role icons only work in servers with a boost of level 2 or higher. If you are having issues, please ensure you are able to set role icons yourself before attempting with the bot.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Reason
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const reason = this.evalMessage(data.reason, cache);
+ const role = await this.getRoleFromData(data.role, data.roleVarName, cache);
+
+ const imageStorage = parseInt(data.image, 10);
+ const imageVarName = this.evalMessage(data.imageVarName, cache);
+ var imageOrEmoji = this.getVariable(imageStorage, imageVarName, cache);
+
+ const Images = this.getDBM().Images;
+ const DiscordJS = this.getDBM().DiscordJS;
+
+ if (Images.isImage(imageOrEmoji)) {
+ imageOrEmoji = await Images.createBuffer(imageOrEmoji);
+ } else if (imageOrEmoji instanceof DiscordJS.Emoji) {
+ // do nothing, setIcon accepts Emoji class
+ } else if (typeof imageOrEmoji === 'string') {
+ if (imageOrEmoji.startsWith('http')) {
+ imageOrEmoji = await Images.getImage(imageOrEmoji);
+ } else {
+ // otherwise, the string could be Emoji-resolvable, so do nothing
+ }
+ }
+
+ if (Array.isArray(role)) {
+ this.callListFunc(role, 'setIcon', [imageOrEmoji, reason]).then(() => this.callNextAction(cache));
+ } else if (role?.setIcon) {
+ role
+ .setIcon(imageOrEmoji, reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_server_icon.js b/actions/set_server_icon.js
new file mode 100644
index 000000000..8c5017a7b
--- /dev/null
+++ b/actions/set_server_icon.js
@@ -0,0 +1,139 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Server Icon',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Server Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storeTypes = presets.variables;
+ return `${presets.getServerText(data.server, data.varName)} - ${storeTypes[parseInt(data.storage, 10)]} (${
+ data.varName2
+ })`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName', 'storage', 'varName2', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const { Images } = this.getDBM();
+ const server = await this.getServerFromData(data.server, data.varName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+
+ if (!Array.isArray(server) && !server?.setIcon) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const image = this.getVariable(parseInt(data.storage, 10), varName2, cache);
+ Images.createBuffer(image)
+ .then((buffer) => {
+ if (Array.isArray(server)) {
+ this.callListFunc(server, 'setIcon', [buffer, reason]).then(() => this.callNextAction(cache));
+ } else {
+ server
+ .setIcon(buffer, reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ }
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_server_name.js b/actions/set_server_name.js
new file mode 100644
index 000000000..aa852a455
--- /dev/null
+++ b/actions/set_server_name.js
@@ -0,0 +1,125 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Server Name',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Server Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getServerText(data.server, data.varName)} - ${data.serverName}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName', 'serverName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Server Name
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = await this.getServerFromData(data.server, data.varName, cache);
+ const name = this.evalMessage(data.serverName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+ if (Array.isArray(server)) {
+ this.callListFunc(server, 'setName', [name, reason]).then(() => this.callNextAction(cache));
+ } else if (server?.setName) {
+ server
+ .setName(name, reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_server_region.js b/actions/set_server_region.js
new file mode 100644
index 000000000..b470c4983
--- /dev/null
+++ b/actions/set_server_region.js
@@ -0,0 +1,127 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Server Region',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Server Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getServerText(data.server, data.varName)} - ${data.region}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName', 'region', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Server Region
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_server_splash.js b/actions/set_server_splash.js
new file mode 100644
index 000000000..e57da73ad
--- /dev/null
+++ b/actions/set_server_splash.js
@@ -0,0 +1,144 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Server Splash Screen',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Server Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storeTypes = presets.variables;
+ return `${presets.getServerText(data.server, data.varName)} - ${storeTypes[parseInt(data.storage, 10)]} (${
+ data.varName2
+ })`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName', 'storage', 'varName2', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Note:
+ Discord Splash Screens are only available to Discord Partners or for servers with boost level 1 or higher.
+ For more information, check out this or this.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const { Images } = this.getDBM();
+ const server = await this.getServerFromData(data.server, data.varName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+ if (!Array.isArray(server) && !server?.setSplash) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const image = this.getVariable(parseInt(data.storage, 10), varName2, cache);
+ Images.createBuffer(image)
+ .then((buffer) => {
+ if (Array.isArray(server)) {
+ this.callListFunc(server, 'setSplash', [buffer, reason]).then(() => this.callNextAction(cache));
+ } else {
+ server
+ .setSplash(buffer, reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ }
+ })
+ .catch((err) => this.displayError(data, cache, err));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_server_time_restriction_MOD.js b/actions/set_server_time_restriction_MOD.js
new file mode 100644
index 000000000..4e24acf2e
--- /dev/null
+++ b/actions/set_server_time_restriction_MOD.js
@@ -0,0 +1,306 @@
+module.exports = {
+ name: 'Set Server Time Restriction',
+ section: 'Other Stuff',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+ subtitle(data) {
+ const results = [
+ 'Continue Actions',
+ 'Stop Action Sequence',
+ 'Jump To Action',
+ 'Jump Forward Actions',
+ 'Jump to Anchor',
+ ];
+ return `Cooldown | If True: ${results[parseInt(data.iftrue, 10)]} ~ If False: ${
+ results[parseInt(data.iffalse, 10)]
+ }`;
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, 'Seconds'];
+ },
+
+ fields: [
+ 'measurement',
+ 'value',
+ 'save',
+ 'restrict',
+ 'iftrue',
+ 'iftrueVal',
+ 'iffalse',
+ 'iffalseVal',
+ 'storage',
+ 'varName',
+ ],
+
+ html(_isEvent, data) {
+ data.conditions[0] = data.conditions[0]
+ .replace(/If True/g, 'If Cooldown is Active')
+ .replace(/If False/g, 'If Cooldown is Not Active');
+ return `
+
+
+
+ Time Measurement:
+
+
+
+ Cooldown Time:
+
+
+
+
+
+ Reset After Restart:
+
+
+
+ Restrict By:
+
+
+
+
+ ${data.conditions[0]}
+
+
+
+ Store Left Time In (s):
+
+
+
+ Variable Name:
+
+
+
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+ const value = document.getElementById('value');
+
+ glob.onChange = function onChange(Measurement) {
+ switch (parseInt(Measurement.value, 10)) {
+ case 0:
+ value.placeholder = '1000 = 1 second';
+ break;
+ case 1:
+ value.placeholder = '1 = 1 second';
+ break;
+ case 2:
+ value.placeholder = '1 = 60 seconds';
+ break;
+ case 3:
+ value.placeholder = '1 = 3600 seconds';
+ break;
+ default:
+ break;
+ }
+ };
+
+ const option = document.createElement('OPTION');
+ option.value = '4';
+ option.text = 'Jump to Anchor';
+ const iffalse = document.getElementById('iffalse');
+ if (iffalse.length === 4) iffalse.add(option);
+
+ const option2 = document.createElement('OPTION');
+ option2.value = '4';
+ option2.text = 'Jump to Anchor';
+ const iftrue = document.getElementById('iftrue');
+ if (iftrue.length === 4) iftrue.add(option2);
+
+ glob.onChangeTrue = function onChangeTrue(event) {
+ switch (parseInt(event.value, 10)) {
+ case 0:
+ case 1:
+ document.getElementById('iftrueContainer').style.display = 'none';
+ break;
+ case 2:
+ document.getElementById('iftrueName').innerHTML = 'Action Number';
+ document.getElementById('iftrueContainer').style.display = null;
+ break;
+ case 3:
+ document.getElementById('iftrueName').innerHTML = 'Number of Actions to Skip';
+ document.getElementById('iftrueContainer').style.display = null;
+ break;
+ case 4:
+ document.getElementById('iftrueName').innerHTML = 'Anchor ID';
+ document.getElementById('iftrueContainer').style.display = null;
+ break;
+ default:
+ break;
+ }
+ };
+ glob.onChangeFalse = function onChangeFalse(event) {
+ switch (parseInt(event.value, 10)) {
+ case 0:
+ case 1:
+ document.getElementById('iffalseContainer').style.display = 'none';
+ break;
+ case 2:
+ document.getElementById('iffalseName').innerHTML = 'Action Number';
+ document.getElementById('iffalseContainer').style.display = null;
+ break;
+ case 3:
+ document.getElementById('iffalseName').innerHTML = 'Number of Actions to Skip';
+ document.getElementById('iffalseContainer').style.display = null;
+ break;
+ case 4:
+ document.getElementById('iffalseName').innerHTML = 'Anchor ID';
+ document.getElementById('iffalseContainer').style.display = null;
+ break;
+ default:
+ break;
+ }
+ };
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer');
+ glob.onChangeTrue(document.getElementById('iftrue'));
+ glob.onChangeFalse(document.getElementById('iffalse'));
+ glob.onChange(document.getElementById('Measurement'));
+ },
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const value = parseInt(this.evalMessage(data.value, cache), 10);
+
+ if (isNaN(value)) return console.error(`${value} is not a valid number.`);
+
+ let cmd;
+ for (const command of this.getDBM().Files.data.commands) {
+ if (command && JSON.stringify(command.actions) === JSON.stringify(cache.actions)) {
+ cmd = command;
+ break;
+ }
+ }
+
+ const timeLeft = this.TimeRestriction(cache.msg, cmd, cache);
+ if (!timeLeft) {
+ this.executeResults(false, data, cache);
+ } else {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName, cache);
+ this.storeValue(timeLeft, storage, varName2, cache);
+ this.executeResults(true, data, cache);
+ }
+ },
+
+ mod(DBM) {
+ let Cooldown;
+ DBM.Actions.LoadTimeRestriction = function LoadTimeRestriction(cache) {
+ Cooldown = this.getVariable(3, 'DBMServerCooldown', cache);
+ if (typeof Cooldown === 'undefined') {
+ Cooldown = {};
+ } else if (typeof Cooldown === 'string') {
+ Cooldown = JSON.parse(Cooldown);
+ }
+ for (const command of Object.keys(Cooldown)) {
+ if (Cooldown[command].save === 1) {
+ delete Cooldown[command];
+ }
+ if (Cooldown[command]) {
+ if (!DBM.Bot.$cmds[command]) {
+ delete Cooldown[command];
+ } else {
+ const action = DBM.Bot.$cmds[command].actions.find((a) => a.name === 'Set Server Time Restriction');
+ if (action !== undefined) {
+ if (action.save === '1') {
+ delete Cooldown[command];
+ }
+ } else {
+ delete Cooldown[command];
+ }
+ }
+ }
+ }
+ };
+
+ DBM.Actions.TimeRestriction = function TimeRestriction(msg, cmd, cache) {
+ if (typeof Cooldown === 'undefined') this.LoadTimeRestriction(cache);
+ const { Files } = DBM;
+ let value = parseInt(this.evalMessage(cache.actions[cache.index].value, cache), 10);
+ const measurement = parseInt(cache.actions[cache.index].measurement, 10);
+ const restrict = parseInt(cache.actions[cache.index].restrict, 10);
+ switch (measurement) {
+ case 1:
+ value *= 1000;
+ break;
+ case 2:
+ value *= 60000;
+ break;
+ case 3:
+ value *= 3600000;
+ break;
+ default:
+ break;
+ }
+
+ if (!Cooldown[cmd.name]) Cooldown[cmd.name] = {};
+ Cooldown[cmd.name].save = parseInt(cache.actions[cache.index].save, 10);
+ Cooldown[cmd.name].cooldown = value;
+ const now = Date.now();
+ switch (restrict) {
+ case 0:
+ if (typeof Cooldown[cmd.name][cache.server.id] !== 'number') {
+ delete Cooldown[cmd.name][cache.server.id];
+ }
+ if (Cooldown[cmd.name][cache.server.id]) {
+ const expirationTime = Cooldown[cmd.name][cache.server.id] + Cooldown[cmd.name].cooldown;
+ if (now < expirationTime) {
+ return Math.ceil((expirationTime - now) / 1000);
+ }
+ Cooldown[cmd.name][cache.server.id] = now;
+ if (Cooldown[cmd.name].save === 0) Files.saveGlobalVariable('DBMServerCooldown', JSON.stringify(Cooldown));
+ return false;
+ }
+ Cooldown[cmd.name][cache.server.id] = now;
+ if (Cooldown[cmd.name].save === 0) Files.saveGlobalVariable('DBMServerCooldown', JSON.stringify(Cooldown));
+ return false;
+ case 1: {
+ let channelId;
+ if (typeof cache.server !== 'undefined') {
+ channelId = cache.server.id;
+ } else {
+ channelId = msg.channel.id;
+ }
+ if (typeof Cooldown[cmd.name][cache.server.id] !== 'object') {
+ Cooldown[cmd.name][cache.server.id] = {};
+ }
+ if (Cooldown[cmd.name][cache.server.id][channelId]) {
+ const expirationTime = Cooldown[cmd.name][cache.server.id][channelId] + Cooldown[cmd.name].cooldown;
+ if (now < expirationTime) {
+ return Math.ceil((expirationTime - now) / 1000);
+ }
+ Cooldown[cmd.name][cache.server.id][channelId] = now;
+ if (Cooldown[cmd.name].save === 0) Files.saveGlobalVariable('DBMServerCooldown', JSON.stringify(Cooldown));
+ return false;
+ }
+ Cooldown[cmd.name][cache.server.id][channelId] = now;
+ if (Cooldown[cmd.name].save === 0) Files.saveGlobalVariable('DBMServerCooldown', JSON.stringify(Cooldown));
+ return false;
+ }
+ default:
+ break;
+ }
+ };
+ },
+};
diff --git a/actions/set_server_verification.js b/actions/set_server_verification.js
new file mode 100644
index 000000000..ebac7bd35
--- /dev/null
+++ b/actions/set_server_verification.js
@@ -0,0 +1,147 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Set Server Verification',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Server Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const verifications = ['None', 'Low', 'Medium', 'High', 'Highest'];
+ return `${presets.getServerText(data.server, data.varName)} - ${verifications[parseInt(data.verification, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName', 'verification', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Verification Level
+
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = await this.getServerFromData(data.server, data.varName, cache);
+ const reason = this.evalMessage(data.reason, cache);
+
+ const { GuildVerificationLevel } = this.getDBM().DiscordJS;
+ let level = GuildVerificationLevel.None;
+ switch (data.verification) {
+ case '0':
+ level = GuildVerificationLevel.None;
+ case '1':
+ level = GuildVerificationLevel.Low;
+ case '2':
+ level = GuildVerificationLevel.Medium;
+ case '3':
+ level = GuildVerificationLevel.High;
+ case '4':
+ level = GuildVerificationLevel.VeryHigh;
+ }
+
+ if (Array.isArray(server)) {
+ this.callListFunc(server, 'setVerificationLevel', [level, reason]).then(() => this.callNextAction(cache));
+ } else if (server?.setVerificationLevel) {
+ server
+ .setVerificationLevel(level, reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/set_time_restriction2_MOD.js b/actions/set_time_restriction2_MOD.js
new file mode 100644
index 000000000..0a1cd30bf
--- /dev/null
+++ b/actions/set_time_restriction2_MOD.js
@@ -0,0 +1,327 @@
+module.exports = {
+ name: 'Set Time Restriction',
+ section: 'Other Stuff',
+ meta: {
+ version: '2.1.7',
+ preciseCheck: false,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods/blob/master/actions/set_time_restriction_MOD.js',
+ },
+
+ subtitle(data) {
+ const results = [
+ 'Continue Actions',
+ 'Stop Action Sequence',
+ 'Jump To Action',
+ 'Jump Forward Actions',
+ 'Jump to Anchor',
+ ];
+ const measurement = ['Milliseconds', 'Seconds', 'Minutes', 'Hours'];
+ return `${data.value} ${measurement[data.measurement]} | If True: ${
+ results[parseInt(data.iftrue, 10)]
+ } ~ If False: ${results[parseInt(data.iffalse, 10)]}`;
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, 'Seconds'];
+ },
+
+ fields: [
+ 'measurement',
+ 'value',
+ 'save',
+ 'restrict',
+ 'iftrue',
+ 'iftrueVal',
+ 'iffalse',
+ 'iffalseVal',
+ 'storage',
+ 'varName',
+ ],
+
+ html(_isEvent, data) {
+ data.conditions[0] = data.conditions[0]
+ .replace(/If True/g, 'If Cooldown is Active')
+ .replace(/If False/g, 'If Cooldown is Not Active');
+ return `
+
+
+
+ Time Measurement
+
+
+
+ Cooldown Time
+
+
+
+
+
+
+
+ Reset After Restart?
+
+
+
+ Restrict By
+
+
+
+
+
+
+ ${data.conditions[0]}
+
+
+
+
+
+
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+ const value = document.getElementById('value');
+
+ glob.onChange = function onChange(Measurement) {
+ switch (parseInt(Measurement.value, 10)) {
+ case 0:
+ value.placeholder = '1000 = 1 second';
+ break;
+ case 1:
+ value.placeholder = '1 = 1 second';
+ break;
+ case 2:
+ value.placeholder = '1 = 60 seconds';
+ break;
+ case 3:
+ value.placeholder = '1 = 3600 seconds';
+ break;
+ case 4:
+ value.placeholder = '1 = 86400 seconds';
+ default:
+ break;
+ }
+ };
+
+ const option = document.createElement('OPTION');
+ option.value = '4';
+ option.text = 'Jump to Anchor';
+ const iffalse = document.getElementById('iffalse');
+ if (iffalse.length === 4) iffalse.add(option);
+
+ const option2 = document.createElement('OPTION');
+ option2.value = '4';
+ option2.text = 'Jump to Anchor';
+ const iftrue = document.getElementById('iftrue');
+ if (iftrue.length === 4) iftrue.add(option2);
+
+ glob.onChangeTrue = function onChangeTrue(event) {
+ switch (parseInt(event.value, 10)) {
+ case 0:
+ case 1:
+ document.getElementById('iftrueContainer').style.display = 'none';
+ break;
+ case 2:
+ document.getElementById('iftrueName').innerHTML = 'Action Number';
+ document.getElementById('iftrueContainer').style.display = null;
+ break;
+ case 3:
+ document.getElementById('iftrueName').innerHTML = 'Number of Actions to Skip';
+ document.getElementById('iftrueContainer').style.display = null;
+ break;
+ case 4:
+ document.getElementById('iftrueName').innerHTML = 'Anchor ID';
+ document.getElementById('iftrueContainer').style.display = null;
+ break;
+ default:
+ break;
+ }
+ };
+ glob.onChangeFalse = function onChangeFalse(event) {
+ switch (parseInt(event.value, 10)) {
+ case 0:
+ case 1:
+ document.getElementById('iffalseContainer').style.display = 'none';
+ break;
+ case 2:
+ document.getElementById('iffalseName').innerHTML = 'Action Number';
+ document.getElementById('iffalseContainer').style.display = null;
+ break;
+ case 3:
+ document.getElementById('iffalseName').innerHTML = 'Number of Actions to Skip';
+ document.getElementById('iffalseContainer').style.display = null;
+ break;
+ case 4:
+ document.getElementById('iffalseName').innerHTML = 'Anchor ID';
+ document.getElementById('iffalseContainer').style.display = null;
+ break;
+ default:
+ break;
+ }
+ };
+ glob.onChangeTrue(document.getElementById('iftrue'));
+ glob.onChangeFalse(document.getElementById('iffalse'));
+ glob.onChange(document.getElementById('Measurement'));
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const value = parseInt(this.evalMessage(data.value, cache), 10);
+
+ if (isNaN(value)) return console.error(`${value} is not a valid number.`);
+
+ let cmd;
+ for (const command of this.getDBM().Files.data.commands) {
+ if (command && JSON.stringify(command.actions) === JSON.stringify(cache.actions)) {
+ cmd = command;
+ break;
+ }
+ }
+
+ const TRData = cache.interaction ?? cache.msg;
+ const timeLeft = await this.TimeRestriction(TRData, cmd, cache);
+
+ if (!timeLeft) {
+ this.executeResults(false, data, cache);
+ } else {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName, cache);
+ this.storeValue(timeLeft, storage, varName2, cache);
+ this.executeResults(true, data, cache);
+ }
+ },
+
+ async mod(DBM) {
+ let Cooldown;
+
+ DBM.Actions.LoadTimeRestriction = async function LoadTimeRestriction(cache) {
+ Cooldown = await this.getVariable(3, 'DBMCooldown', cache);
+
+ if (typeof Cooldown === 'undefined') {
+ Cooldown = {};
+ } else if (typeof Cooldown === 'string') {
+ Cooldown = JSON.parse(Cooldown);
+ }
+
+ const commandTypes = [
+ DBM.Bot.$slash,
+ DBM.Bot.$user,
+ DBM.Bot.$msge,
+ DBM.Bot.$cmds,
+ DBM.Bot.$icds,
+ DBM.Bot.$regx,
+ DBM.Bot.$anym,
+ ];
+
+ for (const commandType of commandTypes) {
+ for (const commandName of Object.keys(commandType)) {
+ const command = commandType[commandName];
+ if (Cooldown[commandName] && command.actions) {
+ const action = command.actions.find((a) => a.name === 'Set Time Restriction');
+ if (!action || action.save === '1') {
+ delete Cooldown[commandName];
+ }
+ }
+ }
+ }
+ };
+
+ DBM.Actions.TimeRestriction = async function TimeRestriction(TRData, cmd, cache) {
+ const author = TRData.author ?? TRData.user;
+ const { channel } = TRData;
+
+ if (typeof Cooldown === 'undefined' || Cooldown === {}) await this.LoadTimeRestriction(cache);
+
+ const { Files } = DBM;
+ let value = parseInt(await this.evalMessage(cache.actions[cache.index].value, cache), 10);
+ const measurement = parseInt(cache.actions[cache.index].measurement, 10);
+ const restrict = parseInt(cache.actions[cache.index].restrict, 10);
+
+ switch (measurement) {
+ case 1:
+ // Seconds to milliseconds
+ value *= 1000;
+ break;
+ case 2:
+ // Minutes to milliseconds
+ value *= 60000;
+ break;
+ case 3:
+ // Hours to milliseconds
+ value *= 3600000;
+ break;
+ case 4:
+ // Days to milliseconds
+ value *= 86400000;
+ default:
+ break;
+ }
+
+ if (!Cooldown[cmd.name]) Cooldown[cmd.name] = {};
+ Cooldown[cmd.name].save = parseInt(cache.actions[cache.index].save, 10);
+ Cooldown[cmd.name].cooldown = value;
+ const now = Date.now();
+
+ switch (restrict) {
+ case 0: {
+ if (typeof Cooldown[cmd.name][author.id] !== 'number') {
+ delete Cooldown[cmd.name][author.id];
+ }
+ if (Cooldown[cmd.name][author.id]) {
+ const expirationTime = Cooldown[cmd.name][author.id] + Cooldown[cmd.name].cooldown;
+ if (now < expirationTime) {
+ return Math.ceil((expirationTime - now) / 1000);
+ }
+ Cooldown[cmd.name][author.id] = now;
+ if (Cooldown[cmd.name].save === 0) Files.saveGlobalVariable('DBMCooldown', JSON.stringify(Cooldown));
+ return false;
+ }
+ Cooldown[cmd.name][author.id] = now;
+ if (Cooldown[cmd.name].save === 0) Files.saveGlobalVariable('DBMCooldown', JSON.stringify(Cooldown));
+ return false;
+ }
+ case 1: {
+ let channelId;
+ if (typeof cache.server !== 'undefined') {
+ channelId = cache.server.id;
+ } else {
+ channelId = channel.id;
+ }
+ if (typeof Cooldown[cmd.name][author.id] !== 'object') {
+ Cooldown[cmd.name][author.id] = {};
+ }
+ if (Cooldown[cmd.name][author.id][channelId]) {
+ const expirationTime = Cooldown[cmd.name][author.id][channelId] + Cooldown[cmd.name].cooldown;
+ if (now < expirationTime) {
+ return Math.ceil((expirationTime - now) / 1000);
+ }
+ Cooldown[cmd.name][author.id][channelId] = now;
+ if (Cooldown[cmd.name].save === 0) Files.saveGlobalVariable('DBMCooldown', JSON.stringify(Cooldown));
+ return false;
+ }
+ Cooldown[cmd.name][author.id][channelId] = now;
+ if (Cooldown[cmd.name].save === 0) Files.saveGlobalVariable('DBMCooldown', JSON.stringify(Cooldown));
+ return false;
+ }
+ default:
+ break;
+ }
+ };
+ },
+};
diff --git a/actions/show_modal.js b/actions/show_modal.js
new file mode 100644
index 000000000..37c692ddc
--- /dev/null
+++ b/actions/show_modal.js
@@ -0,0 +1,257 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Show Modal',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `"${data.title}" with ${data.textInputs.length} Text Inputs`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ if (varType !== 1) return;
+ if (!data.textInputs) return;
+ const result = [];
+ for (let i = 0; i < data.textInputs.length; i++) {
+ if (data.textInputs[i].id) {
+ result.push(data.textInputs[i].id);
+ result.push('Text from Input');
+ }
+ }
+ return result;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['title', 'textInputs'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+Modal Title
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+
+ const tempVariableNames = [];
+ let componentsArr = [];
+
+ if (Array.isArray(data.textInputs)) {
+ const existingTempVars = [];
+ for (let i = 0; i < data.textInputs.length; i++) {
+ const textInput = data.textInputs[i];
+
+ const unusedNameTemplate = 'unusedTempVarName';
+ let j = 0;
+ let unusedName = `${unusedNameTemplate}0`;
+ while (existingTempVars.includes(unusedName)) {
+ unusedName = unusedNameTemplate + ++j;
+ }
+
+ const textInputData = this.generateTextInput(textInput, unusedName, cache);
+ this.addTextInputToActionRowArray(componentsArr, this.evalMessage(textInput.row, cache), textInputData, cache);
+ existingTempVars.push(textInputData.customId);
+ if (textInput.id) {
+ tempVariableNames.push(textInputData.customId);
+ }
+ }
+ }
+
+ // if select components ever become valid components for modals
+ // in the future, copy the html from send_message.js,
+ // remove the action input, and uncomment the following code:
+ /*
+ if (Array.isArray(data.selectMenus)) {
+ for (let i = 0; i < data.selectMenus.length; i++) {
+ const select = data.selectMenus[i];
+ const selectData = this.generateSelectMenu(select, cache);
+ this.addSelectToActionRowArray(componentsArr, this.evalMessage(select.row, cache), selectData, cache);
+ }
+ }
+ */
+
+ if (componentsArr.length > 0) {
+ const { ComponentType } = this.getDBM().DiscordJS;
+ componentsArr = componentsArr
+ .filter((comps) => comps.length > 0)
+ .map(function (comps) {
+ return {
+ type: ComponentType.ActionRow,
+ components: comps,
+ };
+ });
+ }
+
+ if (cache.interaction) {
+ if (cache.interaction.showModal) {
+ const modalData = {
+ customId: cache.interaction.id,
+ title: this.evalMessage(data.title, cache),
+ components: componentsArr,
+ };
+
+ this.registerModalSubmitResponses(cache.interaction.id, (newInteraction) => {
+ newInteraction.__originalInteraction = cache.interaction;
+ cache.interaction = newInteraction;
+
+ for (let i = 0; i < tempVariableNames.length; i++) {
+ const name = tempVariableNames[i];
+ const val = newInteraction.fields.getTextInputValue(name);
+ if (typeof val === 'string') {
+ this.storeValue(val, 1, name, cache);
+ }
+ }
+
+ this.callNextAction(cache);
+ });
+
+ cache.interaction.showModal(modalData);
+ } else {
+ this.displayError(
+ data,
+ cache,
+ 'Cannot show modal from current interaction, perhaps attempting to show modal multiple times?',
+ );
+ this.callNextAction(cache);
+ }
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/show_modal_MOD.js b/actions/show_modal_MOD.js
new file mode 100644
index 000000000..a4eb35af1
--- /dev/null
+++ b/actions/show_modal_MOD.js
@@ -0,0 +1,334 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Show Modal Window',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ if (!data.uniq || data.inputs.length === 0 || !data.title) {
+ return 'You have not filled in the required fields!';
+ }
+ const title = data.title;
+ const inputs = data.inputs.length;
+ return `Open a modal window "${title}" with ${inputs} fields`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType, cache) {
+ if (varType !== 1) return;
+ return [data.uniq.replace('msg-', 'modal-'), 'Input Text'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/show_modal.js',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['inputs', 'title', 'uniq'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Window Title
+
+
+
+ Unique ID
+
+
+
+
+
+ Label
+
+
+
+ Unique ID
+
+
+
+ Type
+
+
+
+
+ Text Length
+
+
+
+
+ Start Value
+
+
+
+ Placeholder
+
+
+
+ Set Required
+
+
+
+
+ Text from this field will be saved in
+
+
+
+
+
+
+ Modal windows can only be opened with a slash command or a button or select menu
+
+
+ Attention!
+ Modal windows are an event they don't support "reply" and "ephemeral" messages
+ but it support buttons and select menus
+
+ `;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Editor On Save
+ //
+ // When the data for the action is saved, this function is called.
+ // It provides the ability to modify the final data associated with
+ // the action by retrieving it as an argument and returning a modified
+ // version through the return value. This can be used to verify the
+ // data and fill required entries the user did not.
+ //
+ // Its inclusion within action mods is optional.
+ // ---------------------------------------------------------------------
+
+ onSave(data, helpers, cache) {
+ for (let i = 0; i < data.inputs.length; i++) {
+ data.inputs[i].ssd = `\$\{tempVars("${data.uniq.replace('msg-', 'modal-')}")[${i}]}`;
+ if (data.inputs[i].uniqID === '') {
+ data.inputs[i].uniqID = `msg-modal-${helpers.generateUUID().substring(0, 7)}`;
+ }
+ }
+ return data;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor On Paste
+ //
+ // When the data for the action is pasted, this function is called.
+ // It provides the ability to modify the final data associated with
+ // the action by retrieving it as an argument and returning a modified
+ // version through the return value.
+ //
+ // Its inclusion within action mods is optional.
+ // ---------------------------------------------------------------------
+
+ onPaste(data, helpers) {
+ if (data.uniq === '') {
+ data.uniq = `msg-${helpers.generateUUID().substring(0, 7)}`;
+ }
+
+ for (let i = 0; i < data.inputs.length; i++) {
+ data.inputs[i].ssd = `\$\{tempVars("${data.uniq.replace('msg-', 'modal-')}")[${i}]}`;
+ if (data.inputs[i].uniqID === '') {
+ data.inputs[i].uniqID = `msg-modal-${helpers.generateUUID().substring(0, 7)}`;
+ }
+ }
+ return data;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const { Modal, TextInputComponent, showModal } = require('discord-modals'); // Now we extract the showModal method
+ const discordModals = require('discord-modals');
+ const title = this.evalMessage(data.title, cache);
+ const CustomId = this.evalMessage(data.uniq, cache);
+ const components = [];
+
+ const Bot = this.getDBM().Bot;
+ const client = Bot.bot;
+ discordModals(client);
+
+ for (let i = 0; i < data.inputs.length; i++) {
+ const uniqueId = this.evalMessage(data.inputs[i].uniqID, cache);
+ const label = this.evalMessage(data.inputs[i].label, cache);
+ const min = this.evalMessage(data.inputs[i].min, cache);
+ const max = this.evalMessage(data.inputs[i].max, cache);
+ const placeholder = this.evalMessage(data.inputs[i].plholder, cache);
+
+ components.push(
+ new TextInputComponent() // We create a Text Input Component
+ .setCustomId(uniqueId)
+ .setLabel(label)
+ .setStyle(data.inputs[i].type) // IMPORTANT: Text Input Component Style can be 'SHORT' or 'LONG'
+ .setMinLength(min)
+ .setMaxLength(max)
+ .setPlaceholder(placeholder)
+ .setRequired(data.inputs[i].req), // If it's required or not
+ );
+ }
+
+ const resultd = [];
+ const modal = new Modal().setTitle(title).setCustomId(CustomId).addComponents(components);
+ showModal(modal, {
+ client, // Client to show the Modal through the Discord API.
+ interaction: cache.interaction, // Show the modal with interaction data.
+ });
+
+ Bot.bot.on('modalSubmit', async (modal) => {
+ if (modal.customId === CustomId) {
+ for (let i = 0; i < data.inputs.length; i++) {
+ resultd.push(modal.getTextInputValue(data.inputs[i].uniqID));
+ }
+ await modal.reply({ ephemeral: true }).catch((e) => console.log(''));
+ await modal.deleteReply().catch((e) => console.log(''));
+ await this.storeValue(resultd, 1, CustomId.replace('msg-', 'modal-'), cache);
+ await this.callNextAction(cache);
+ }
+ });
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/show_modal_MOD2.js b/actions/show_modal_MOD2.js
new file mode 100644
index 000000000..26c6806b1
--- /dev/null
+++ b/actions/show_modal_MOD2.js
@@ -0,0 +1,383 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Show Modal MOD',
+ displayName: 'Show Modal MOD',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data) {
+ return `[${data.modalTitle || 'My Modal'}] - with ${data.modalComponents.length} components`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ if (!Array.isArray(data.modalComponents)) return;
+ const result = [];
+ for (const { storage, varName2: name, componentType } of data.modalComponents) {
+ const type = parseInt(storage, 10);
+ if (type !== varType || !name) continue;
+ const desc =
+ componentType === 'textInput'
+ ? 'Text From Input'
+ : componentType === 'selectMenu'
+ ? 'Option From Select'
+ : 'Modal Component';
+
+ result.push(name, desc);
+ }
+ return result.length ? result : undefined;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/shadoow051',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['modalTitle', 'modalComponents'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(data) {
+ return `
+
";
+ if (selectMenuType === 'textInput') {
+ result += '(Text Input)';
+ } else if (selectMenuType === 'selectMenu') {
+ result += '(Select Menu)';
+ }
+ result += '
';
+ return result;
+ };
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const {
+ ModalBuilder,
+ LabelBuilder,
+ TextInputBuilder,
+ StringSelectMenuBuilder,
+ UserSelectMenuBuilder,
+ RoleSelectMenuBuilder,
+ MentionableSelectMenuBuilder,
+ ChannelSelectMenuBuilder,
+ } = require('discord.js');
+ const modalTitle = this.evalMessage(data.modalTitle, cache) || 'My Modal';
+
+ const finalLabelComponents = [];
+ for (const component of data.modalComponents) {
+ const modalLabel = this.evalMessage(component.modalLabel, cache);
+ const modalDescription = this.evalMessage(component.modalDescription, cache);
+ const modalPlaceholder = this.evalMessage(component.modalPlaceholder, cache);
+ const customId = `${this.evalMessage(component.varName2, cache) || Math.random().toString(36).substring(2, 8)}`;
+
+ const labelComponent = new LabelBuilder().setLabel(modalLabel);
+ if (modalDescription) {
+ labelComponent.setDescription(modalDescription);
+ }
+
+ if (component.componentType === 'textInput') {
+ const textInputMinLength = parseInt(this.evalMessage(component.textInputMinLength, cache), 10) || 1;
+ const textInputMaxLength = parseInt(this.evalMessage(component.textInputMaxLength, cache), 10) || 4000;
+ const textInputStyle = Number(component.textInputStyle) || 1;
+ const textInputRequired = component.textInputRequired === 'true';
+ const textInputDefaultValue = this.evalMessage(component.textInputDefaultValue, cache) || '';
+ const textInputComponent = new TextInputBuilder()
+ .setCustomId(customId)
+ .setMaxLength(textInputMinLength)
+ .setMaxLength(textInputMaxLength)
+ .setStyle(textInputStyle)
+ .setRequired(textInputRequired)
+ .setValue(textInputDefaultValue);
+ if (modalPlaceholder) {
+ textInputComponent.setPlaceholder(modalPlaceholder);
+ }
+ labelComponent.setTextInputComponent(textInputComponent);
+ } else if (component.componentType === 'selectMenu') {
+ const selectsMinSelectNumber = parseInt(this.evalMessage(component.selectsMinSelectNumber, cache), 10) || 1;
+ const selectsMaxSelectNumber = parseInt(this.evalMessage(component.selectsMaxSelectNumber, cache), 10) || 1;
+ const selectsRequired = component.selectsRequired === 'true';
+ let selectMenuComponent;
+ switch (component.selectsSelectMenuType) {
+ case 'stringSelectMenu':
+ const options = [];
+ for (const option of component.options) {
+ const payload = {
+ label: option.label || '',
+ description: option.description || '',
+ value: option.value || '',
+ emoji: option.emoji || undefined,
+ default: option.default === 'true',
+ };
+ options.push(payload);
+ }
+ selectMenuComponent = new StringSelectMenuBuilder()
+ .setOptions(options)
+ .setCustomId(customId)
+ .setMinValues(selectsMinSelectNumber)
+ .setMaxValues(selectsMaxSelectNumber)
+ .setRequired(selectsRequired);
+ labelComponent.setStringSelectMenuComponent(selectMenuComponent);
+ break;
+ case 'userSelectMenu':
+ selectMenuComponent = new UserSelectMenuBuilder()
+ .setCustomId(customId)
+ .setMinValues(selectsMinSelectNumber)
+ .setMaxValues(selectsMaxSelectNumber)
+ .setRequired(selectsRequired);
+ labelComponent.setUserSelectMenuComponent(selectMenuComponent);
+ break;
+ case 'roleSelectMenu':
+ selectMenuComponent = new RoleSelectMenuBuilder()
+ .setCustomId(customId)
+ .setMinValues(selectsMinSelectNumber)
+ .setMaxValues(selectsMaxSelectNumber)
+ .setRequired(selectsRequired);
+ labelComponent.setRoleSelectMenuComponent(selectMenuComponent);
+ break;
+ case 'mentionableSelectMenu':
+ selectMenuComponent = new MentionableSelectMenuBuilder()
+ .setCustomId(customId)
+ .setMinValues(selectsMinSelectNumber)
+ .setMaxValues(selectsMaxSelectNumber)
+ .setRequired(selectsRequired);
+ labelComponent.setMentionableSelectMenuComponent(selectMenuComponent);
+ break;
+ case 'channelSelectMenu':
+ selectMenuComponent = new ChannelSelectMenuBuilder()
+ .setCustomId(customId)
+ .setMinValues(selectsMinSelectNumber)
+ .setMaxValues(selectsMaxSelectNumber)
+ .setRequired(selectsRequired);
+ labelComponent.setChannelSelectMenuComponent(selectMenuComponent);
+ break;
+ }
+ if (modalPlaceholder) {
+ selectMenuComponent.setPlaceholder(modalPlaceholder);
+ }
+ }
+
+ finalLabelComponents.push(labelComponent);
+ }
+
+ // ////////////////////////////////////////////////////////////
+
+ const modal = new ModalBuilder()
+ .setCustomId(cache.interaction.id)
+ .setTitle(modalTitle)
+ .setLabelComponents(finalLabelComponents);
+
+ // ////////////////////////////////////////////////////////////
+
+ this.registerModalSubmitResponses(cache.interaction.id, async (newInteraction) => {
+ newInteraction.__originalInteraction = cache.interaction;
+ cache.interaction = newInteraction;
+
+ const getFieldVal = (f) => {
+ if (!f) return '';
+ if ('value' in f) return f.value ?? '';
+ if (Array.isArray(f.values)) return f.values;
+ if (f.users) return [...f.users.keys()];
+ if (f.members) return [...f.members.keys()];
+ if (f.roles) return [...f.roles.keys()];
+ return '';
+ };
+ for (const comp of data.modalComponents) {
+ const cid = `${this.evalMessage(comp.varName2, cache)}`;
+ const storage = parseInt(comp.storage, 10);
+ const varName = cid;
+ let value = '';
+ if (comp.componentType === 'textInput' && newInteraction.fields?.getTextInputValue) {
+ try {
+ value = newInteraction.fields.getTextInputValue(cid);
+ } catch {}
+ }
+ if (!value) value = getFieldVal(newInteraction.fields?.fields?.get?.(cid)) || '';
+ if (Array.isArray(value) && value.length === 1) value = value[0];
+
+ if (!Number.isNaN(storage) && varName) this.storeValue(value, storage, varName, cache);
+ }
+
+ this.callNextAction(cache);
+ });
+
+ await cache.interaction.showModal(modal);
+ },
+};
diff --git a/actions/shuffle_list_MOD.js b/actions/shuffle_list_MOD.js
new file mode 100644
index 000000000..e0e3787f4
--- /dev/null
+++ b/actions/shuffle_list_MOD.js
@@ -0,0 +1,150 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Shuffle List',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Lists and Loops',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data) {
+ const storage2 = ['', 'Temp Variable', 'Server Variable', 'Global Variable'];
+ return `Suffled "${data.varName}" to ${storage2[parseInt(data.storage2, 10)]} (${data.varName2})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage2, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'List'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'storage2', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editting actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source List:
+
+
+
+ Variable Name:
+
+
+
+ Store Result In:
+
+
+
+ Variable Name:
+
+
+
`;
+ },
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existance.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const _this = this;
+ const data = cache.actions[cache.index];
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const list = this.getList(storage, varName, cache);
+ let number = list.length;
+
+ while (number > 0) {
+ const index = Math.floor(Math.random() * number);
+ number--;
+
+ const temp = list[number];
+ list[number] = list[index];
+ list[index] = temp;
+ }
+ if (list) {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage2 = parseInt(data.storage2, 10);
+ this.storeValue(list, storage2, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflictions between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {},
+}; // End of module
diff --git a/actions/shuffle_queue.js b/actions/shuffle_queue.js
new file mode 100644
index 000000000..d3a8edc8c
--- /dev/null
+++ b/actions/shuffle_queue.js
@@ -0,0 +1,116 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Shuffle Queue',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return 'The queue is shuffled.';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: [],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return '';
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const Audio = this.getDBM().Audio;
+ const server = cache.server;
+ const subscription = await Audio.getSubscription(server);
+ const queue = subscription?.queue.slice();
+
+ if (!queue?.length) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ subscription.queueLock = true;
+ for (let i = queue.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [queue[i], queue[j]] = [queue[j], queue[i]];
+ }
+ subscription.queue = queue;
+ subscription.queueLock = false;
+ subscription.processQueue();
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/shuffle_queue_MOD.js b/actions/shuffle_queue_MOD.js
new file mode 100644
index 000000000..b04a8bede
--- /dev/null
+++ b/actions/shuffle_queue_MOD.js
@@ -0,0 +1,134 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Shuffle Queue MOD',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Audio Control',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data) {
+ const servers = ['Current Server', 'Temp Variable', 'Server Variable', 'Global Variable'];
+ return `Shuffle Queue of ${servers[parseInt(data.server, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editting actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source Server:
+
+
+
+ Variable Name:
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.serverChange(document.getElementById('server'), 'varNameContainer');
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existance.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const Audio = this.getDBM().Audio;
+ const server = parseInt(data.server, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const targetServer = this.getServer(server, varName, cache);
+
+ let queue;
+ if (targetServer) {
+ queue = Audio.queue[targetServer.id];
+ }
+ if (queue && queue.length > 1) {
+ const temp = JSON.stringify(queue);
+ while (JSON.stringify(queue) === temp) {
+ queue.sort(() => Math.random() - 0.5);
+ }
+ Audio.queue[targetServer.id] = queue;
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflictions between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {},
+}; // End of module
diff --git a/actions/skip_queue.js b/actions/skip_queue.js
new file mode 100644
index 000000000..b432f769f
--- /dev/null
+++ b/actions/skip_queue.js
@@ -0,0 +1,108 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Skip Queue',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Skip ${data.amount} Items`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.1.7', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['amount'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+ Amount to Skip
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const Audio = this.getDBM().Audio;
+ const server = cache.server;
+ const subscription = Audio.subscriptions.get(server.id);
+ if (!subscription) return this.callNextAction(cache);
+ const amount = parseInt(this.evalMessage(data.amount, cache), 10);
+ for (let i = 0; i < amount; i++) subscription.audioPlayer.stop();
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/skip_queue.ts b/actions/skip_queue.ts
new file mode 100644
index 000000000..9f939b7ca
--- /dev/null
+++ b/actions/skip_queue.ts
@@ -0,0 +1,119 @@
+import * as djs from 'discord.js';
+import { Actions, ActionsCache } from '../bot.ts';
+import Audio, { Subscription } from '../bot_audio.ts';
+import { Action, ActionMod } from '../types.ts';
+
+type SkipQueueData = { amount: string };
+
+export default {
+ //---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ //---------------------------------------------------------------------
+
+ name: 'Skip Queue',
+
+ //---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ //---------------------------------------------------------------------
+
+ section: 'Audio Control',
+
+ //---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ //---------------------------------------------------------------------
+
+ subtitle(data: SkipQueueData, presets: any) {
+ return `Skip ${data.amount} Items`;
+ },
+
+ //---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ //---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ //---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ //---------------------------------------------------------------------
+
+ fields: ['amount'],
+
+ //---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //---------------------------------------------------------------------
+
+ html(isEvent: boolean, data: any) {
+ return `
+
+ Amount to Skip
+
+
`;
+ },
+
+ //---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ //---------------------------------------------------------------------
+
+ init() {},
+
+ //---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ //---------------------------------------------------------------------
+
+ async action(this: typeof Actions, cache: ActionsCache) {
+ const data = cache.actions[cache.index] as Action & SkipQueueData;
+ const server = cache.server;
+ const subscription: Subscription | null = await Audio.getSubscription(server);
+ if (!subscription) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const amount: number = parseInt(this.evalMessage(data.amount, cache), 10);
+ subscription.skip(amount);
+
+ this.callNextAction(cache);
+ },
+
+ //---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ //---------------------------------------------------------------------
+
+ mod() {},
+} satisfies ActionMod;
diff --git a/actions/start_thinking.js b/actions/start_thinking.js
new file mode 100644
index 000000000..3ecfb0037
--- /dev/null
+++ b/actions/start_thinking.js
@@ -0,0 +1,108 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Start Thinking',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `Inform User ${data.ephemeral ? 'Privately' : 'Publicly'}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.1.7', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['ephemeral'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ if (cache.interaction) {
+ cache.interaction
+ .deferReply(data.ephemeral ? { flags: this.getDBM().DiscordJS?.MessageFlags?.Ephemeral ?? 64 } : {})
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/start_thinking.ts b/actions/start_thinking.ts
new file mode 100644
index 000000000..757761d91
--- /dev/null
+++ b/actions/start_thinking.ts
@@ -0,0 +1,115 @@
+import { Actions, ActionsCache } from '../bot.ts';
+import { Action, ActionMod } from '../types.ts';
+
+type StartThinkingData = { ephemeral: boolean };
+
+export default {
+ //---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ //---------------------------------------------------------------------
+
+ name: 'Start Thinking',
+
+ //---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ //---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ //---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ //---------------------------------------------------------------------
+
+ subtitle(data: StartThinkingData, presets: any) {
+ return 'Inform User ' + (data.ephemeral ? 'Privately' : 'Publicly');
+ },
+
+ //---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ //---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ //---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ //---------------------------------------------------------------------
+
+ fields: ['ephemeral'],
+
+ //---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //---------------------------------------------------------------------
+
+ html(isEvent: boolean, data: any) {
+ return `
+
+
+
`;
+ },
+
+ //---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ //---------------------------------------------------------------------
+
+ init() {},
+
+ //---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ //---------------------------------------------------------------------
+
+ async action(this: typeof Actions, cache: ActionsCache) {
+ const data = cache.actions[cache.index] as Action & StartThinkingData;
+
+ if (cache.interaction && !cache.interaction.deferred && !cache.interaction.replied) {
+ try {
+ await cache.interaction!.deferReply({ ephemeral: data.ephemeral });
+ } catch (err: any) {
+ this.displayError(data, cache, err);
+ }
+ }
+
+ this.callNextAction(cache);
+ },
+
+ //---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ //---------------------------------------------------------------------
+
+ mod() {},
+} satisfies ActionMod;
diff --git a/actions/store_audio_info_MOD.js b/actions/store_audio_info_MOD.js
new file mode 100644
index 000000000..3dd69fac9
--- /dev/null
+++ b/actions/store_audio_info_MOD.js
@@ -0,0 +1,261 @@
+const itemList = [
+ { name: 'Volume (1-100)', type: 'Number' },
+ { name: 'Is Playing', type: 'Boolean' },
+ { name: 'Start Time (Seconds)', type: 'Seconds' },
+ { name: 'Queue URL List', type: 'List' },
+ { name: 'Next Song URL In Queue', type: 'Url' },
+ { name: 'Queue Length', type: 'Number' },
+ { name: 'Bitrate', type: 'Number' },
+ { name: 'This option was removed', type: 'null' },
+ { name: 'Current Seek Position (Seconds)', type: 'Seconds' },
+ { name: 'Current Song URL', type: 'Url' },
+ { name: 'Requester of Next Song URL', type: 'User' },
+ { name: 'Requester of Current Song URL', type: 'User' },
+ { name: 'Title of Next Song URL', type: 'Title String' },
+ { name: 'Title of Current Song URL', type: 'Title String' },
+ { name: 'Duration of Current Song URL', type: 'Duration' },
+ { name: 'Current Song Thumbnail URL', type: 'Url' },
+];
+
+module.exports = {
+ name: 'Store Audio Info',
+ section: 'Audio Control',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ fields: ['server', 'info', 'storage', 'varName', 'varName2'],
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+ Source Server:
+
+
+
+ Variable Name:
+
+
+
+
+ Source Info:
+
+
+
+ Store Result In:
+
+
+
+ Variable Name:
+
+
+`;
+ },
+
+ subtitle(data) {
+ const servers = ['Current Server', 'Temp Variable', 'Server Variable', 'Global Variable'];
+ return `${servers[parseInt(data.server, 10)]} - ${itemList[parseInt(data.info, 10)].name}`;
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, itemList[parseInt(data.info, 10)].type || 'Unknown Type'];
+ },
+
+ init() {
+ try {
+ const { glob, document } = this;
+
+ const wrexlinks = document.getElementsByClassName('wrexlink');
+ for (let x = 0; x < wrexlinks.length; x++) {
+ const wrexlink = wrexlinks[x];
+ const url = wrexlink.getAttribute('data-url');
+ if (url) {
+ wrexlink.setAttribute('title', url);
+ wrexlink.addEventListener('click', (e) => {
+ e.stopImmediatePropagation();
+ require('child_process').execSync(`start ${url}`);
+ });
+ }
+ }
+
+ const select = document.getElementById('info');
+ if (select.length === 0) {
+ for (let i = 0; i < itemList.length; i++) {
+ const item = itemList[i];
+
+ const option = document.createElement('option');
+ if (i === 0) option.className = 'selected';
+ option.value = i;
+ option.text = item.name;
+
+ select.add(option);
+ }
+ }
+
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer');
+ glob.serverChange(document.getElementById('server'), 'varNameContainer2');
+ } catch (error) {
+ alert(`Store Audio Info Init Error:\n\n${error}`);
+ }
+ },
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const server = parseInt(data.server, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const TimeFormat = this.getMods().require('hh-mm-ss');
+ const info = parseInt(data.info, 10);
+ const { Audio } = this.getDBM();
+ const targetServer = this.getServer(server, varName2, cache);
+
+ if (!targetServer || !Audio) return this.callNextAction(cache);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = (Audio.volumes[targetServer.id] && parseInt(Audio.volumes[targetServer.id], 10) * 100) || 50; // volume
+ break;
+ case 1:
+ result = Boolean(Audio.dispatchers[targetServer.id]); // is playing
+ break;
+ case 2:
+ result = this.dest(Audio.dispatchers[targetServer.id], 'startTime') || 0; // when the music first started playing
+ break;
+ case 3:
+ result = Audio.queue[targetServer.id] && Audio.queue[targetServer.id].map((q) => q[2]); // the queue list
+ break;
+ case 4:
+ result = Audio.queue[targetServer.id] && Audio.queue[targetServer.id].map((q) => q[2])[0]; // next item in queue
+ break;
+ case 5:
+ result = this.dest(Audio.queue[targetServer.id], 'length'); // queue length
+ break;
+ case 6:
+ result = this.dest(Audio.dispatchers[targetServer.id], 'streams', 'opus', '_options', 'rate') || 0; // bitrate
+ break;
+ case 8:
+ result = this.dest(Audio.dispatchers[targetServer.id], 'player', 'streamingData', 'timestamp') || 0; // seek position
+ break;
+ case 9:
+ result = this.dest(Audio.playingnow[targetServer.id], 1); // Current song url
+ break;
+ case 10:
+ result = Audio.queue[targetServer.id] && Audio.queue[targetServer.id].map((q) => q[1])[0].requester; // Requested person of next song in queue
+ break;
+ case 11:
+ result = this.dest(Audio.playingnow[targetServer.id], 1, 'requester'); // Requested person of current song
+ break;
+ case 12:
+ result = Audio.queue[targetServer.id] && Audio.queue[targetServer.id].map((q) => q[1])[0].title; // Title of next song in queue
+ break;
+ case 13:
+ result = this.dest(Audio.playingnow[targetServer.id], 1, 'title'); // Title of current song
+ break;
+ case 14:
+ result = TimeFormat.fromS(this.dest(Audio.playingnow[targetServer.id], 1, 'duration')); // Current song duration
+ break;
+ case 15:
+ result = this.dest(Audio.playingnow[targetServer.id], 1, 'thumbnail'); // Current Song Thumbnail URL
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/store_channel_data_MOD.js b/actions/store_channel_data_MOD.js
new file mode 100644
index 000000000..3a97b87f8
--- /dev/null
+++ b/actions/store_channel_data_MOD.js
@@ -0,0 +1,81 @@
+module.exports = {
+ name: 'Store Channel Data',
+ section: 'Data',
+
+ subtitle(data, presets) {
+ return `${presets.getChannelText(data.channel, data.varName)} -> ${presets.getVariableText(
+ data.storage,
+ data.varName2,
+ )}`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Unknown Type'];
+ },
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ fields: ['channel', 'varName', 'dataName', 'defaultVal', 'storage', 'varName2'],
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Data Name
+
+
+
+ Default Value (if data doesn't exist)
+
+
+
+
+
+
+ `;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const channel = await this.getChannelFromData(data.channel, data.varName, cache);
+ if (!channel) return this.callNextAction(cache);
+
+ const dataName = this.evalMessage(data.dataName, cache);
+ const defVal = this.eval(this.evalMessage(data.defaultVal, cache), cache);
+
+ const fs = require('fs');
+ const path = require('path');
+ const filePath = path.join(__dirname, '..', 'data', 'channels.json');
+
+ let fileData = {};
+ if (fs.existsSync(filePath)) {
+ fileData = JSON.parse(fs.readFileSync(filePath, 'utf8'));
+ }
+
+ const id = channel.id;
+ fileData[id] ??= {};
+ const result = fileData[id][dataName] !== undefined ? fileData[id][dataName] : defVal ?? 0;
+
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/store_channel_info.js b/actions/store_channel_info.js
new file mode 100644
index 000000000..3c4728698
--- /dev/null
+++ b/actions/store_channel_info.js
@@ -0,0 +1,239 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Store Channel Info',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = [
+ 'Channel Object',
+ 'Channel ID',
+ 'Channel Name',
+ 'Channel Topic',
+ 'Channel Last Message (Removed)',
+ 'Channel Position',
+ 'Channel Is NSFW?',
+ 'Channel Is DM?',
+ 'Channel Is Deleteable?',
+ 'Channel Creation Date',
+ 'Channel Category ID',
+ 'Channel Created At',
+ 'Channel Created At Timestamp',
+ ];
+ return `${presets.getChannelText(data.channel, data.varName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Channel';
+ break;
+ case 1:
+ dataType = 'Channel ID';
+ break;
+ case 2:
+ case 3:
+ dataType = 'Text';
+ break;
+ case 5:
+ dataType = 'Number';
+ break;
+ case 6:
+ case 7:
+ case 8:
+ dataType = 'Boolean';
+ break;
+ case 10:
+ dataType = 'Category ID';
+ break;
+ case 11:
+ dataType = 'Date';
+ break;
+ case 12:
+ dataType = 'Timestamp';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'varName', 'info', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Source Info
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const DiscordJS = this.getDBM().DiscordJS;
+
+ const targetChannel = await this.getChannelFromData(data.channel, data.varName, cache);
+
+ if (!targetChannel) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const info = parseInt(data.info, 10);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = targetChannel;
+ break;
+ case 1:
+ result = targetChannel.id;
+ break;
+ case 2:
+ result = targetChannel.name;
+ break;
+ case 3:
+ result = targetChannel.topic;
+ break;
+ case 4:
+ result = '';
+ break;
+ case 5:
+ result = targetChannel.position;
+ break;
+ case 6:
+ result = targetChannel.nsfw;
+ break;
+ case 7:
+ result = targetChannel.type === DiscordJS.ChannelType.DM;
+ break;
+ case 8:
+ result = targetChannel.deletable;
+ break;
+ case 9:
+ case 11:
+ result = targetChannel.createdAt;
+ break;
+ case 10:
+ result = targetChannel.parentId;
+ break;
+ case 12:
+ result = targetChannel.createdTimestamp;
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/store_command_params.js b/actions/store_command_params.js
new file mode 100644
index 000000000..85f624a05
--- /dev/null
+++ b/actions/store_command_params.js
@@ -0,0 +1,313 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Command Only
+ //
+ // If this is 'true', then this will only be available for commands.
+ // ---------------------------------------------------------------------
+
+ commandOnly: true,
+
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Store Command Params',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const infoSources = [
+ 'One Parameter',
+ 'Multiple Parameters',
+ 'Mentioned Member',
+ 'Mentioned Role',
+ 'Mentioned Channel',
+ ];
+ return `${infoSources[parseInt(data.info, 10)]} #${data.infoIndex}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'None';
+ switch (info) {
+ case 0:
+ case 1:
+ dataType = 'Text';
+ break;
+ case 2:
+ dataType = 'Server Member';
+ break;
+ case 3:
+ dataType = 'Role';
+ break;
+ case 4:
+ dataType = 'Channel';
+ break;
+ }
+ return [data.varName, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['info', 'infoIndex', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source Info
+
+
+
+ Parameter Number:
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onSourceInfoChanged = function (event) {
+ const value = parseInt(event.value, 10);
+ const infoCountLabel = document.getElementById('infoCountLabel');
+ switch (value) {
+ case 0:
+ infoCountLabel.innerHTML = 'Parameter Number';
+ break;
+ case 1:
+ infoCountLabel.innerHTML = 'Starting From Parameter Number';
+ break;
+ case 2:
+ infoCountLabel.innerHTML = 'Member Mention Number';
+ break;
+ case 3:
+ infoCountLabel.innerHTML = 'Role Mention Number';
+ break;
+ case 4:
+ infoCountLabel.innerHTML = 'Channel Mention Number';
+ break;
+ default:
+ infoCountLabel.innerHTML = '';
+ break;
+ }
+ };
+
+ glob.onSourceInfoChanged(document.getElementById('info'));
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const msg = cache.msg;
+ const interactionOptions = cache.interaction?.options ?? null;
+ if (!msg && !interactionOptions) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const { Bot, Files } = this.getDBM();
+ const { ApplicationCommandOptionType } = this.getDBM().DiscordJS;
+ const infoType = parseInt(data.info, 10);
+ const index = parseInt(this.evalMessage(data.infoIndex, cache), 10) - 1;
+
+ let separator;
+ let content = null;
+ const getContent = () => {
+ if (content === null) {
+ separator = Files.data.settings.separator || '\\s+';
+ Bot.populateTagRegex();
+ content = msg.content?.replace(Bot.tagRegex, '').replace(Bot.checkTag(msg.content), '').trimStart();
+ }
+ return content;
+ };
+
+ let source;
+ switch (infoType) {
+ case 0: {
+ if (interactionOptions) {
+ const result = this.getParameterFromParameterData(interactionOptions.data[index]);
+ if (result) {
+ source = result;
+ }
+ } else if (msg && getContent()) {
+ const params = content.split(new RegExp(separator));
+ source = params[index] || '';
+ }
+ break;
+ }
+
+ case 1: {
+ if (interactionOptions) {
+ const result = [];
+ for (let i = 0; i < index; i++) {
+ const r = this.getParameterFromParameterData(interactionOptions.data[i]);
+ if (r) {
+ result.push(r);
+ }
+ }
+ if (result.length > 0) {
+ source = result;
+ }
+ } else if (msg && getContent()) {
+ const params = content.split(new RegExp(separator));
+ source = '';
+ for (let i = 0; i < index; i++) {
+ source += `${params[i]} `;
+ }
+ const location = content.indexOf(source);
+ if (location === 0) {
+ source = content.substring(source.length);
+ }
+ }
+ break;
+ }
+
+ case 2: {
+ if (interactionOptions) {
+ const options = interactionOptions.data.filter((option) => option.type === ApplicationCommandOptionType.User);
+ if (options[index]) {
+ source = options[index].member ?? options[index].user;
+ }
+ } else if (msg.mentions.members.size) {
+ const members = [...msg.mentions.members.values()];
+ if (members[index]) {
+ source = members[index];
+ }
+ }
+ break;
+ }
+
+ case 3: {
+ if (interactionOptions) {
+ const options = interactionOptions.data.filter((option) => option.type === ApplicationCommandOptionType.Role);
+ if (options[index]) {
+ source = options[index].role;
+ }
+ } else if (msg.mentions.roles.size) {
+ const roles = [...msg.mentions.roles.values()];
+ if (roles[index]) {
+ source = roles[index];
+ }
+ }
+ break;
+ }
+
+ case 4: {
+ if (interactionOptions) {
+ const options = interactionOptions.data.filter(
+ (option) => option.type === ApplicationCommandOptionType.Channel,
+ );
+ if (options[index]) {
+ source = options[index].channel;
+ }
+ } else if (msg.mentions.channels.size) {
+ const channels = [...msg.mentions.channels.values()];
+ if (channels[index]) {
+ source = channels[index];
+ }
+ }
+ break;
+ }
+
+ default: {
+ break;
+ }
+ }
+
+ if (source) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(source, storage, varName, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/store_custom_data.js b/actions/store_custom_data.js
new file mode 100644
index 000000000..973a6a008
--- /dev/null
+++ b/actions/store_custom_data.js
@@ -0,0 +1,101 @@
+module.exports = {
+ name: 'Store Custom Data',
+ section: 'Data',
+ fields: ['filePath', 'valueName', 'jsonPath', 'varName', 'storage'],
+
+ meta: {
+ version: '2.1.2',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/store_custom_data.js',
+ },
+
+ subtitle(data) {
+ const filepath = data.filePath;
+ const filename = filepath !== '' ? filepath.split('/')[filepath.match(/[\/]/g).length] : '';
+ const match = data.jsonPath.split('/')[data.jsonPath.split('.').length - 1];
+ if (data.filePath !== '' && data.jsonPath !== '' && data.varName !== '') {
+ return `Store ${match} from ${filename} to ${data.varName}`;
+ }
+
+ if (data.filePath !== '' && data.dataField !== '' && data.varName === '') {
+ return `Store ${match} from ${filename} but not to a variable`;
+ }
+
+ if (data.filePath === '') {
+ return `File path is empty ( Error! )`;
+ }
+
+ if (data.dataField === '') {
+ return `Data field is empty ( Error! )`;
+ }
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, 'Custom Data'];
+ },
+
+ html() {
+ return `
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer');
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const date = this.evalMessage(data.date, cache);
+ const info = parseInt(data.info, 10);
+ if (isNaN(Date.parse(date))) {
+ console.log(
+ 'Invalid Date ! Check that your date is valid. A Date generally looks like the one stored in "Creation Date" of a server. (variables works)',
+ );
+ this.callNextAction(cache);
+ }
+
+ let result;
+ switch (info) {
+ case 0:
+ result = date.slice(0, 3);
+ break;
+ case 1:
+ result = date.slice(4, 7);
+ break;
+ case 2:
+ result = parseInt(Date.parse(date) / 1000, 10);
+ break;
+ case 4:
+ result = parseInt(date.slice(8, 10), 10);
+ break;
+ case 5:
+ result = parseInt(date.slice(11, 15), 10);
+ break;
+ case 6:
+ result = date.slice(16, 24);
+ break;
+ case 7:
+ result = date.slice(16, 18);
+ break;
+ case 8:
+ result = date.slice(4, 7);
+ if (result === 'Jan') result = 1;
+ if (result === 'Feb') result = 2;
+ if (result === 'Mar') result = 3;
+ if (result === 'Apr') result = 4;
+ if (result === 'May') result = 5;
+ if (result === 'Jun') result = 6;
+ if (result === 'Jul') result = 7;
+ if (result === 'Aug') result = 8;
+ if (result === 'Sep') result = 9;
+ if (result === 'Oct') result = 10;
+ if (result === 'Nov') result = 11;
+ if (result === 'Dec') result = 12;
+ if (result === date.slice(4, 7)) {
+ console.log('An error occurred on "Store Date Info (Month Number)"');
+ this.callNextAction(cache);
+ }
+ break;
+ case 9:
+ result = date.slice(19, 21);
+ break;
+ case 10:
+ result = date.slice(22, 24);
+ break;
+ case 11:
+ result = `GMT${date.slice(28, 29)}${parseInt(date.slice(29, 33), 10) / 100}`;
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/store_date_timezone_info_plus_MOD.js b/actions/store_date_timezone_info_plus_MOD.js
new file mode 100644
index 000000000..e234a6324
--- /dev/null
+++ b/actions/store_date_timezone_info_plus_MOD.js
@@ -0,0 +1,249 @@
+module.exports = {
+ name: 'Store Date Timezone Info Plus',
+ section: 'Other Stuff',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data) {
+ const info = [
+ 'Day of the week',
+ 'Day (number)',
+ 'Day of the year',
+ 'Week of the year',
+ 'Month of the year',
+ 'Month (number)',
+ 'Year',
+ 'Hour',
+ 'Minutes',
+ 'Seconds',
+ 'Milliseconds',
+ 'Time zone',
+ 'Unix Timestamp',
+ 'Data completa',
+ ];
+ const storage = ['', 'Temporary Variable', 'Server Variable', 'Global Variable'];
+ return `${
+ data.modeStorage === '0'
+ ? `"${info[data.info]}"`
+ : data.buildInput === ''
+ ? '"Not Configured"'
+ : `"${data.buildInput}"`
+ } of a date ~ ${storage[data.storage]}`;
+ },
+
+ short_description: 'Stores something from a date more completely!',
+ depends_on_mods: ['WrexMODS'],
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const dataType = 'Date';
+ return [data.varName, dataType];
+ },
+
+ fields: ['sourceDate', 'timezone', 'dateLanguage', 'modeStorage', 'info', 'buildInput', 'storage', 'varName'],
+
+ html(isEvent, data) {
+ return `
+
+
+ Date of origin
+
+
+
+ Date language (initials)
+
+
+
+ Timezone (Timezones)
+
+
+
+ Mode
+
+
+
+ Information
+
+
+
+ Build (Document):
+
+
+
+ Store in:
+
+
+
+ Variable name:
+
+
+
+ Nota: You can use square brackets to put the text in Build
+ Ex:DD/MM/YYYY [at] HH:mm:ss = 30/01/2022 at 13:38:20
+
+
+ `;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChangeMode = function (modeStorage) {
+ switch (parseInt(modeStorage.value, 10)) {
+ case 0:
+ document.getElementById('selectMode').style.display = null;
+ document.getElementById('buildMode').style.display = 'none';
+ document.getElementById('noteContainer').style.display = 'none';
+ break;
+ case 1:
+ document.getElementById('selectMode').style.display = 'none';
+ document.getElementById('buildMode').style.display = null;
+ document.getElementById('noteContainer').style.display = null;
+ break;
+ }
+ };
+
+ glob.onChangeMode(document.getElementById('modeStorage'));
+
+ const wrexlinks = document.getElementsByClassName('wrexlink');
+ for (let x = 0; x < wrexlinks.length; x++) {
+ const wrexlink = wrexlinks[x];
+ var url = wrexlink.getAttribute('data-url');
+ if (url) {
+ wrexlink.setAttribute('title', url);
+ wrexlink.addEventListener('click', function (e) {
+ e.stopImmediatePropagation();
+ console.log(`Posting URL: [${url}] in your default browser.`);
+ require('child_process').execSync(`start ${url}`);
+ });
+ }
+ }
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const moment = require('moment-timezone');
+ const dateLanguage = this.evalMessage(data.dateLanguage, cache);
+ const timezone = this.evalMessage(data.timezone, cache);
+ const date = moment(
+ Date.parse(this.evalMessage(data.sourceDate, cache)),
+ '',
+ dateLanguage === '' ? 'pt' : dateLanguage,
+ ).tz(timezone);
+ const buildInput = this.evalMessage(data.buildInput, cache);
+ const modeType = parseInt(this.evalMessage(data.modeStorage, cache), 10);
+ const info = parseInt(data.info, 10);
+
+ let result;
+
+ if (modeType === 0) {
+ switch (info) {
+ case 0:
+ result = date.format('dddd');
+ break;
+ case 1:
+ result = date.format('DD');
+ break;
+ case 2:
+ result = date.format('DDD');
+ break;
+ case 3:
+ result = date.format('ww');
+ break;
+ case 4:
+ result = date.format('MMMMM');
+ break;
+ case 5:
+ result = date.format('MM');
+ break;
+ case 6:
+ result = date.format('YYYY');
+ break;
+ case 7:
+ result = date.format('hh');
+ break;
+ case 8:
+ result = date.format('mm');
+ break;
+ case 9:
+ result = date.format('ss');
+ break;
+ case 10:
+ result = date.format('SS');
+ break;
+ case 11:
+ result = date.format('ZZ');
+ break;
+ case 12:
+ result = date.format('X');
+ break;
+ case 13:
+ result = date.format('DD/MM/YYYY HH:mm:ss');
+ break;
+ default:
+ }
+ } else {
+ result = date.format(buildInput);
+ }
+
+ if (result === 'Invalid date') {
+ return console.log(
+ 'Invalid Date! Check that your date is valid in "Store Date Info Plus". A Date usually looks like the one stored in a server\'s "Creation Date" (variables work)',
+ );
+ }
+
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ mod(DBM) {},
+};
diff --git a/actions/store_interaction_info_MOD.js b/actions/store_interaction_info_MOD.js
new file mode 100644
index 000000000..5979b3fd6
--- /dev/null
+++ b/actions/store_interaction_info_MOD.js
@@ -0,0 +1,117 @@
+module.exports = {
+ name: 'Store interaction Info',
+ section: 'Other Stuff',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data, presets) {
+ const info = [
+ 'Object of the interaction',
+ 'Interaction ID',
+ 'Author language',
+ 'Interaction type',
+ 'Interaction token',
+ 'Interaction token',
+ 'Interaction channel',
+ 'Interaction channel ID',
+ 'Object > Interaction Options',
+ ];
+ return `${info[parseInt(data.info, 10)]}`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ const prse2 = parseInt(data.info, 10);
+ const info2 = ['Object', 'ID', 'Language', 'Type', 'Token', 'Channel', 'Channel ID', 'Object > Options'];
+ if (type !== varType) return;
+ return [data.varName2, info2[prse2]];
+ },
+
+ fields: ['info', 'storage', 'varName2'],
+
+ html(isEvent, data) {
+ return `
+
+
+ Information
+
+
+
+
+
+
+Result in
+
+
+
+ Variable Name
+
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer');
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const interaction = cache.interaction;
+ const info = parseInt(data.info, 10);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = interaction;
+ break;
+ case 1:
+ result = interaction.id;
+ break;
+ case 2:
+ result = interaction.locale;
+ break;
+ case 3:
+ result = interaction.type;
+ break;
+ case 4:
+ result = interaction.token;
+ break;
+ case 5:
+ result = interaction.channel;
+ break;
+ case 6:
+ result = interaction.channel.id;
+ break;
+ case 7:
+ result = interaction.options._hoistedOptions;
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/store_json_from_webapi_MOD.js b/actions/store_json_from_webapi_MOD.js
index d802cb728..7f503e333 100644
--- a/actions/store_json_from_webapi_MOD.js
+++ b/actions/store_json_from_webapi_MOD.js
@@ -141,7 +141,47 @@ module.exports = {
const data = cache.actions[cache.index];
const { Actions } = this.getDBM();
const Mods = this.getMods();
- const fetch = Mods.require('node-fetch');
+ let fetch;
+ try {
+ // First try built-in fetch (Node.js 18+)
+ if (typeof globalThis.fetch === 'function') {
+ fetch = globalThis.fetch;
+ } else if (typeof global.fetch === 'function') {
+ fetch = global.fetch;
+ } else {
+ // Fallback to node-fetch if available
+ const nodeFetch = Mods.require('node-fetch');
+ // Handle both ESM and CJS exports
+ if (nodeFetch && typeof nodeFetch.default === 'function') {
+ fetch = nodeFetch.default;
+ } else if (typeof nodeFetch === 'function') {
+ fetch = nodeFetch;
+ } else {
+ throw new Error('node-fetch is not a function');
+ }
+ }
+ } catch (fetchError) {
+ // Last resort: try to use built-in fetch
+ if (typeof globalThis.fetch === 'function') {
+ fetch = globalThis.fetch;
+ } else if (typeof global.fetch === 'function') {
+ fetch = global.fetch;
+ } else {
+ console.error('[Store Json From WebAPI] fetch is not available. Please install node-fetch or use Node.js 18+');
+ const debugMode = parseInt(data.debugMode, 10);
+ if (debugMode) {
+ console.error('[Store Json From WebAPI] Fetch error:', fetchError);
+ }
+ return;
+ }
+ }
+
+ // Ensure fetch is a function
+ if (typeof fetch !== 'function') {
+ console.error('[Store Json From WebAPI] fetch is not a function. Available:', typeof fetch);
+ return;
+ }
+
const debugMode = parseInt(data.debugMode, 10);
const storage = parseInt(data.storage, 10);
const varName = this.evalMessage(data.varName, cache);
@@ -266,7 +306,13 @@ module.exports = {
const value = header[1] || 'Unknown';
setHeaders[key] = value;
- if (debugMode) console.log(`Applied Header: ${lines[i]}`);
+ if (debugMode) {
+ const line = String(lines[i]);
+ const idx = line.indexOf(':');
+ const key = idx === -1 ? '' : line.slice(0, idx).trim().toLowerCase();
+ const safeLine = key === 'authorization' ? `${line.slice(0, idx + 1)} [REDACTED]` : line;
+ console.log(`Applied Header: ${safeLine}`);
+ }
} else if (debugMode) {
console.error(
`WebAPI: Error: Custom Header line ${lines[i]} is wrongly formatted. You must split the key from the value with a colon (:)`,
@@ -281,10 +327,50 @@ module.exports = {
try {
const response = await fetch(url, { headers: setHeaders });
- const json = await response.json();
+
+ // Check if response is OK before parsing JSON
+ if (!response.ok) {
+ const text = await response.text();
+ storeData(`HTTP ${response.status}: ${text}`, response, null);
+ return;
+ }
+
+ // Check content type before parsing JSON
+ const contentType = response.headers.get('content-type') || '';
+ if (!contentType.includes('application/json') && !contentType.includes('text/json')) {
+ // Response is not JSON, read as text
+ const text = await response.text();
+ storeData(`Response is not JSON (content-type: ${contentType})`, response, null);
+ if (debugMode) {
+ console.warn(
+ `WebAPI: Response is not JSON. Content-Type: ${contentType}, First 100 chars: ${text.substring(
+ 0,
+ 100,
+ )}`,
+ );
+ }
+ return;
+ }
+
+ // Try to parse JSON with error handling
+ let json;
+ try {
+ const text = await response.text();
+ json = JSON.parse(text);
+ } catch (parseError) {
+ // JSON parsing failed - store error instead
+ storeData(`JSON parse error: ${parseError.message}`, response, null);
+ if (debugMode) {
+ console.error('WebAPI: JSON parsing failed:', parseError.message);
+ }
+ return;
+ }
+
storeData('', response, json);
} catch (err) {
if (debugMode) console.error(err.stack || err);
+ // Store error in variable
+ storeData(err.message || 'Unknown error', { statusCode: 0 }, null);
}
}
} catch (err) {
diff --git a/actions/store_member_data.js b/actions/store_member_data.js
new file mode 100644
index 000000000..aac26fd74
--- /dev/null
+++ b/actions/store_member_data.js
@@ -0,0 +1,146 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Store Member Data',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Data',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)} -> ${presets.getVariableText(
+ data.storage,
+ data.varName2,
+ )}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Unknown Type'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'dataName', 'defaultVal', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Data Name
+
+
+
+ Default Value (if data doesn't exist)
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+
+ if (member?.data) {
+ const dataName = this.evalMessage(data.dataName, cache);
+ const defVal = this.eval(this.evalMessage(data.defaultVal, cache), cache);
+ let result;
+ if (defVal === undefined) {
+ result = member.data(dataName);
+ } else {
+ result = member.data(dataName, defVal);
+ }
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/store_member_info.js b/actions/store_member_info.js
new file mode 100644
index 000000000..44bd3d42c
--- /dev/null
+++ b/actions/store_member_info.js
@@ -0,0 +1,417 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Store Member Info',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = [
+ 'Member Object',
+ 'Member ID',
+ 'Member Username',
+ 'Member Display Name',
+ 'Member Color',
+ 'Member Server',
+ 'Member Last Message (Removed)',
+ 'Member Highest Role',
+ 'Member Hoist Role',
+ 'Member Color Role',
+ 'Member Is Owner?',
+ 'Member Is Muted?',
+ 'Member Is Deafened?',
+ 'Member Is Bannable?',
+ 'Member Playing Status Name',
+ 'Member Status',
+ 'Member Avatar URL',
+ 'Member Roles List',
+ 'Member Roles Amount',
+ 'Member Voice Channel',
+ 'Member Discriminator',
+ 'Member Tag',
+ 'Member Created At',
+ 'Member Created Timestamp',
+ 'Member Joined At',
+ 'Member Joined Timestamp',
+ 'Last Message Id (Removed)',
+ 'Member Permission List',
+ 'Member Flags List',
+ 'Member Client Status',
+ 'Member Custom Status',
+ 'Member Server Avatar URL',
+ 'Member Timed Out At',
+ 'Member Timed Out Timestamp',
+ ];
+ return `${presets.getMemberText(data.member, data.varName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Server Member';
+ break;
+ case 1:
+ dataType = 'Member ID';
+ break;
+ case 2:
+ case 3:
+ dataType = 'Text';
+ break;
+ case 4:
+ dataType = 'Color';
+ break;
+ case 5:
+ dataType = 'Server';
+ break;
+ case 7:
+ case 8:
+ case 9:
+ dataType = 'Role';
+ break;
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ dataType = 'Boolean';
+ break;
+ case 14:
+ case 15:
+ dataType = 'Text';
+ break;
+ case 16:
+ case 31:
+ dataType = 'Image URL';
+ break;
+ case 17:
+ dataType = 'List of Roles';
+ break;
+ case 18:
+ dataType = 'Number';
+ break;
+ case 19:
+ dataType = 'Voice Channel';
+ break;
+ case 20:
+ dataType = 'Member Discriminator';
+ break;
+ case 21:
+ dataType = 'Member Tag';
+ break;
+ case 22:
+ dataType = 'Date';
+ break;
+ case 23:
+ dataType = 'Timestamp';
+ break;
+ case 24:
+ dataType = 'Date';
+ break;
+ case 25:
+ dataType = 'Timestamp';
+ break;
+ case 27:
+ case 28:
+ case 29:
+ dataType = 'List';
+ break;
+ case 30:
+ dataType = 'Text';
+ break;
+ case 32:
+ dataType = 'Timestamp';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'info', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Source Info
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+
+ if (!member) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const info = parseInt(data.info, 10);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = member;
+ break;
+ case 1:
+ result = member.id;
+ break;
+ case 2:
+ result = member.user?.username;
+ break;
+ case 3:
+ result = member.displayName;
+ break;
+ case 4:
+ result = member.displayHexColor;
+ break;
+ case 5:
+ result = member.guild;
+ break;
+ case 7:
+ result = member.roles.highest;
+ break;
+ case 8:
+ result = member.roles.hoist;
+ break;
+ case 9:
+ result = member.roles.color;
+ break;
+ case 10:
+ result = member.id === member.guild?.ownerId;
+ break;
+ case 11:
+ result = member.voice.mute;
+ break;
+ case 12:
+ result = member.voice.deaf;
+ break;
+ case 13:
+ result = member.bannable;
+ break;
+ case 14:
+ if (member.presence?.activities.length) {
+ const { ActivityType } = this.getDBM().DiscordJS;
+ const status = member.presence.activities.filter((s) => s.type !== ActivityType.Custom);
+ result = status[0]?.name;
+ }
+ break;
+ case 15:
+ if (member.presence?.status) {
+ const status = member.presence.status;
+ switch (status) {
+ case 'online': {
+ result = 'Online';
+ break;
+ }
+ case 'offline': {
+ result = 'Offline';
+ break;
+ }
+ case 'idle': {
+ result = 'Idle';
+ break;
+ }
+ case 'dnd': {
+ result = 'Do Not Disturb';
+ break;
+ }
+ }
+ }
+ break;
+ case 16:
+ if (member.user) {
+ result = member.user.displayAvatarURL({ extension: 'png', size: 4096 });
+ }
+ break;
+ case 17:
+ result = [...member.roles.cache.values()];
+ break;
+ case 18:
+ result = member.roles.cache.size;
+ break;
+ case 19:
+ result = member.voice.channel;
+ break;
+ case 20:
+ result = member.user?.discriminator;
+ break;
+ case 21:
+ result = member.user?.tag;
+ break;
+ case 22:
+ result = member.user?.createdAt;
+ break;
+ case 23:
+ result = member.user?.createdTimestamp;
+ break;
+ case 24:
+ result = member.joinedAt;
+ break;
+ case 25:
+ result = member.joinedTimestamp;
+ break;
+ case 27:
+ result = member.permissions.toArray();
+ break;
+ case 28:
+ result = member.user?.flags?.toArray() ?? (await member.user?.fetchFlags())?.toArray();
+ break;
+ case 29:
+ const status = member.presence?.clientStatus;
+ result = status && Object.keys(status);
+ break;
+ case 30: {
+ const { ActivityType } = this.getDBM().DiscordJS;
+ result = member.presence?.activities.find((s) => s.type === ActivityType.Custom)?.state;
+ break;
+ }
+ case 31:
+ result = member.displayAvatarURL({ extension: 'png', size: 4096 });
+ break;
+ case 32:
+ result = member.communicationDisabledUntil;
+ break;
+ case 33:
+ result = member.communicationDisabledUntilTimestamp;
+ break;
+ default:
+ break;
+ }
+
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/store_member_info_MOD.js b/actions/store_member_info_MOD.js
new file mode 100644
index 000000000..092cd8681
--- /dev/null
+++ b/actions/store_member_info_MOD.js
@@ -0,0 +1,370 @@
+module.exports = {
+ name: 'Store Member Info MOD',
+ section: 'Member Control',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ subtitle(data, presets) {
+ const info = [
+ 'Member Object',
+ 'Member ID',
+ 'Member Username',
+ 'Member Display Name',
+ 'Member Color',
+ 'Member Server',
+ 'Member Last Message (Removed)',
+ 'Member Highest Role',
+ 'Member Hoist Role',
+ 'Member Color Role',
+ 'Member Is Owner?',
+ 'Member Is Muted?',
+ 'Member Is Deafened?',
+ 'Member Is Bannable?',
+ 'Member Playing Status Name',
+ 'Member Status',
+ 'Member Avatar URL',
+ 'Member Roles List',
+ 'Member Roles Amount',
+ 'Member Voice Channel',
+ 'Member Discriminator',
+ 'Member Tag',
+ 'Member Created At',
+ 'Member Created Timestamp',
+ 'Member Joined At',
+ 'Member Joined Timestamp',
+ 'Last Message Id (Removed)',
+ 'Member Permission List',
+ 'Member Flags List',
+ 'Member Client Status',
+ 'Member Custom Status',
+ 'Member Server Avatar URL',
+ 'Member Timed Out At',
+ 'Member Timed Out Timestamp',
+ 'Member Banner URL',
+ 'Member Server ID',
+ 'Member Boost Timestamp',
+ ];
+ return `${presets.getMemberText(data.member, data.varName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Server Member';
+ break;
+ case 1:
+ dataType = 'Member ID';
+ break;
+ case 2:
+ case 3:
+ dataType = 'Text';
+ break;
+ case 4:
+ dataType = 'Color';
+ break;
+ case 5:
+ dataType = 'Server';
+ break;
+ case 7:
+ case 8:
+ case 9:
+ dataType = 'Role';
+ break;
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ dataType = 'Boolean';
+ break;
+ case 14:
+ case 15:
+ dataType = 'Text';
+ break;
+ case 16:
+ case 31:
+ dataType = 'Image URL';
+ break;
+ case 17:
+ dataType = 'List of Roles';
+ break;
+ case 18:
+ dataType = 'Number';
+ break;
+ case 19:
+ dataType = 'Voice Channel';
+ break;
+ case 20:
+ dataType = 'Member Discriminator';
+ break;
+ case 21:
+ dataType = 'Member Tag';
+ break;
+ case 22:
+ dataType = 'Date';
+ break;
+ case 23:
+ dataType = 'Timestamp';
+ break;
+ case 24:
+ dataType = 'Date';
+ break;
+ case 25:
+ dataType = 'Timestamp';
+ break;
+ case 27:
+ case 28:
+ case 29:
+ dataType = 'List';
+ break;
+ case 30:
+ dataType = 'Text';
+ break;
+ case 32:
+ dataType = 'Timestamp';
+ break;
+ case 33:
+ dataType = 'Timestamp';
+ break;
+ case 34:
+ dataType = 'Image URL';
+ break;
+ case 35:
+ dataType = 'Server ID';
+ break;
+ case 36:
+ dataType = 'Timestamp';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ fields: ['member', 'varName', 'info', 'storage', 'varName2'],
+
+ html(isEvent, data) {
+ return `
+
Version 1.0
+
DBM Extended
+
+
+
+
+
+
+ Source Info
+
+
+
+
+
+`;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+
+ if (!member) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const info = parseInt(data.info, 10);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = member;
+ break;
+ case 1:
+ result = member.id;
+ break;
+ case 2:
+ result = member.user?.username;
+ break;
+ case 3:
+ result = member.displayName;
+ break;
+ case 4:
+ result = member.displayHexColor;
+ break;
+ case 5:
+ result = member.guild;
+ break;
+ case 7:
+ result = member.roles.highest;
+ break;
+ case 8:
+ result = member.roles.hoist;
+ break;
+ case 9:
+ result = member.roles.color;
+ break;
+ case 10:
+ result = member.id === member.guild?.ownerId;
+ break;
+ case 11:
+ result = member.voice.mute;
+ break;
+ case 12:
+ result = member.voice.deaf;
+ break;
+ case 13:
+ result = member.bannable;
+ break;
+ case 14:
+ if (member.presence?.activities.length) {
+ const status = member.presence.activities.filter((s) => s.type !== 'CUSTOM');
+ result = status[0]?.name;
+ }
+ break;
+ case 15:
+ if (member.presence?.status) {
+ const status = member.presence.status;
+ switch (status) {
+ case 'online': {
+ result = 'Online';
+ break;
+ }
+ case 'offline': {
+ result = 'Offline';
+ break;
+ }
+ case 'idle': {
+ result = 'Ausente';
+ break;
+ }
+ case 'dnd': {
+ result = 'Ocupado';
+ break;
+ }
+ }
+ }
+ break;
+ case 16:
+ if (member.user) {
+ result = member.user.displayAvatarURL({ dynamic: true, format: 'png', size: 4096 });
+ }
+ break;
+ case 17:
+ result = [...member.roles.cache.values()];
+ break;
+ case 18:
+ result = member.roles.cache.size;
+ break;
+ case 19:
+ result = member.voice.channel;
+ break;
+ case 20:
+ result = member.user?.discriminator;
+ break;
+ case 21:
+ result = member.user?.tag;
+ break;
+ case 22:
+ result = member.user?.createdAt;
+ break;
+ case 23:
+ result = member.user?.createdTimestamp;
+ break;
+ case 24:
+ result = member.joinedAt;
+ break;
+ case 25:
+ result = member.joinedTimestamp;
+ break;
+ case 27:
+ result = member.permissions.toArray();
+ break;
+ case 28:
+ result = member.user?.flags?.toArray() ?? (await member.user?.fetchFlags())?.toArray();
+ break;
+ case 29:
+ const status = member.presence?.clientStatus;
+ result = status && Object.keys(status);
+ break;
+ case 30:
+ result = member.presence?.activities.find((s) => s.type === 'CUSTOM')?.state;
+ break;
+ case 31:
+ result = member.displayAvatarURL({ dynamic: true, format: 'png', size: 4096 });
+ break;
+ case 32:
+ result = member.communicationDisabledUntil;
+ break;
+ case 33:
+ result = member.communicationDisabledUntilTimestamp;
+ break;
+ case 34:
+ await member.user.fetch();
+ result = member.user.bannerURL({ fomart: 'png', size: 4096, dynamic: true });
+ break;
+ case 35:
+ result = member.guild.id;
+ break;
+ case 36:
+ result = member.premiumSinceTimestamp;
+ break;
+ default:
+ break;
+ }
+
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/store_member_level_MOD.js b/actions/store_member_level_MOD.js
new file mode 100644
index 000000000..1b2f7533b
--- /dev/null
+++ b/actions/store_member_level_MOD.js
@@ -0,0 +1,120 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Store Member Level',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Economy',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)} -> ${presets.getVariableText(
+ data.storage,
+ data.varName2,
+ )}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Unknown Type'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'dataName', 'defaultVal', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ `;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+
+ if (member?.data) {
+ const dataName = this.evalMessage(data.dataName, cache);
+ const defVal = this.eval(this.evalMessage(data.defaultVal, cache), cache);
+ let result;
+ if (defVal === undefined) {
+ result = member.data(dataName);
+ } else {
+ result = member.data(dataName, defVal);
+ }
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/store_message_data.js b/actions/store_message_data.js
new file mode 100644
index 000000000..b5c45e46b
--- /dev/null
+++ b/actions/store_message_data.js
@@ -0,0 +1,144 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Store Message Data',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Data',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMessageText(data.message, data.varName)} -> ${presets.getVariableText(
+ data.storage,
+ data.varName2,
+ )}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Unknown Type'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['message', 'varName', 'dataName', 'defaultVal', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Data Name
+
+
+
+ Default Value (if data doesn't exist)
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const message = await this.getMessageFromData(data.message, data.varName, cache);
+
+ if (message?.data) {
+ const dataName = this.evalMessage(data.dataName, cache);
+ const defVal = this.eval(this.evalMessage(data.defaultVal, cache), cache);
+ let result;
+ if (defVal === undefined) {
+ result = message.data(dataName);
+ } else {
+ result = message.data(dataName, defVal);
+ }
+ this.storeValue(result, parseInt(data.storage, 10), this.evalMessage(data.varName2, cache), cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/store_message_info.js b/actions/store_message_info.js
new file mode 100644
index 000000000..4617116ba
--- /dev/null
+++ b/actions/store_message_info.js
@@ -0,0 +1,303 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+ name: 'Store Message Info',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+ section: 'Messaging',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+ subtitle(data, presets) {
+ const info = [
+ 'Message Object',
+ 'Message ID',
+ 'Message Text',
+ 'Message Author',
+ 'Message Channel',
+ 'Message Timestamp',
+ 'Message is Pinned',
+ 'Message is TTS',
+ 'Message Attachments List',
+ 'Message Edits',
+ '',
+ '',
+ 'Messages Reactions Count',
+ 'Mentioned Users List',
+ 'Mentioned Users Count',
+ 'Message URL',
+ 'Message Creation Date',
+ 'Message Content Length',
+ 'Message Attachments Count',
+ 'Message Guild',
+ 'Message Type',
+ 'Message Webhook ID',
+ 'Message Embed Object',
+ ];
+ return `${presets.getMessageText(data.message, data.varName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Message';
+ break;
+ case 1:
+ dataType = 'Message ID';
+ break;
+ case 2:
+ dataType = 'Text';
+ break;
+ case 3:
+ dataType = 'Server Member';
+ break;
+ case 4:
+ dataType = 'Channel';
+ break;
+ case 5:
+ dataType = 'Text';
+ break;
+ case 6:
+ case 7:
+ dataType = 'Boolean';
+ break;
+ case 8:
+ dataType = 'Date';
+ case 9:
+ dataType = 'Messages List';
+ case 12:
+ dataType = 'Number';
+ break;
+ case 13:
+ dataType = 'Array';
+ break;
+ case 14:
+ dataType = 'Number';
+ break;
+ case 15:
+ dataType = 'URL';
+ break;
+ case 16:
+ dataType = 'Date';
+ break;
+ case 17:
+ case 18:
+ dataType = 'Number';
+ break;
+ case 19:
+ dataType = 'Guild';
+ break;
+ case 20:
+ dataType = 'Message Type';
+ break;
+ case 21:
+ dataType = 'Webhook ID';
+ break;
+ case 22:
+ dataType = 'Embed Message';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+ fields: ['message', 'varName', 'info', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Source Info
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const msg = await this.getMessageFromData(data.message, data.varName, cache);
+
+ if (!msg) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const info = parseInt(data.info, 10);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = msg;
+ break;
+ case 1:
+ result = msg.id;
+ break;
+ case 2:
+ result = msg.content;
+ break;
+ case 3:
+ result = msg.member ?? msg.author;
+ break;
+ case 4:
+ result = msg.channel;
+ break;
+ case 5:
+ result = msg.createdTimestamp;
+ break;
+ case 6:
+ result = msg.pinned;
+ break;
+ case 7:
+ result = msg.tts;
+ break;
+ case 8:
+ result = [...msg.attachments.values()];
+ break;
+ case 9:
+ result = msg.edits;
+ break;
+ case 12:
+ result = msg.reactions.cache.size;
+ break;
+ case 13:
+ result = [...msg.mentions.users.values()];
+ break;
+ case 14:
+ result = msg.mentions.users.size;
+ break;
+ case 15:
+ result = msg.url;
+ break;
+ case 16:
+ result = msg.createdAt;
+ break;
+ case 17:
+ result = msg.content.length;
+ break;
+ case 18:
+ result = msg.attachments.size;
+ break;
+ case 19:
+ result = msg.guild;
+ break;
+ case 20:
+ result = msg.type;
+ break;
+ case 21:
+ result = msg.webhookId;
+ break;
+ case 22:
+ result = msg.embeds[0];
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+ mod() {},
+};
diff --git a/actions/store_message_info_MOD.js b/actions/store_message_info_MOD.js
new file mode 100644
index 000000000..572d3d437
--- /dev/null
+++ b/actions/store_message_info_MOD.js
@@ -0,0 +1,282 @@
+module.exports = {
+ name: 'Store Message Info',
+ section: 'Messaging',
+ subtitle(data, presets) {
+ const info = [
+ 'Message Object',
+ 'Message ID',
+ 'Message Text',
+ 'Message Author',
+ 'Message Channel',
+ 'Message Timestamp',
+ 'Message is Pinned',
+ 'Message is TTS',
+ 'Message Attachments List',
+ 'Message Edits',
+ '',
+ '',
+ 'Messages Reactions Count',
+ 'Mentioned Users List',
+ 'Mentioned Users Count',
+ 'Message URL',
+ 'Message Creation Date',
+ 'Message Content Length',
+ 'Message Attachments Count',
+ 'Message Guild',
+ 'Message Type',
+ 'Message Webhook ID',
+ 'Message Embed Object',
+ 'Message Reference Object',
+ 'Replied-to Message ID',
+ 'Replied-to Message Channel ID',
+ 'Replied-to Message Guild ID',
+ 'Is Reply to Message?',
+ 'Message Stickers Count', // Added option for sticker count
+ ];
+ return `${presets.getMessageText(data.message, data.varName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Message';
+ break;
+ case 1:
+ dataType = 'Message ID';
+ break;
+ case 2:
+ dataType = 'Text';
+ break;
+ case 3:
+ dataType = 'Server Member';
+ break;
+ case 4:
+ dataType = 'Channel';
+ break;
+ case 5:
+ dataType = 'Text';
+ break;
+ case 6:
+ case 7:
+ dataType = 'Boolean';
+ break;
+ case 8:
+ dataType = 'Date';
+ break;
+ case 9:
+ dataType = 'Messages List';
+ break;
+ case 12:
+ dataType = 'Number';
+ break;
+ case 13:
+ dataType = 'Array';
+ break;
+ case 14:
+ dataType = 'Number';
+ break;
+ case 15:
+ dataType = 'URL';
+ break;
+ case 16:
+ dataType = 'Date';
+ break;
+ case 17:
+ case 18:
+ dataType = 'Number';
+ break;
+ case 19:
+ dataType = 'Guild';
+ break;
+ case 20:
+ dataType = 'Message Type';
+ break;
+ case 21:
+ dataType = 'Webhook ID';
+ break;
+ case 22:
+ dataType = 'Embed Message';
+ break;
+ case 23:
+ dataType = 'Message Reference Object';
+ break;
+ case 24:
+ dataType = 'Message ID';
+ break;
+ case 25:
+ dataType = 'Channel ID';
+ break;
+ case 26:
+ dataType = 'Guild ID';
+ break;
+ case 27:
+ case 28: // Added case for storing sticker count
+ dataType = 'Number';
+ break;
+ default:
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ meta: { version: '2.1.7', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ fields: ['message', 'varName', 'info', 'storage', 'varName2'],
+
+ html() {
+ return `
+
+
+
+
+
+ Source Info
+
+
+
+
+
+`;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const msg = await this.getMessageFromData(data.message, data.varName, cache);
+
+ if (!msg) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const info = parseInt(data.info, 10);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = msg;
+ break;
+ case 1:
+ result = msg.id;
+ break;
+ case 2:
+ result = msg.content;
+ break;
+ case 3:
+ result = msg.member ?? msg.author;
+ break;
+ case 4:
+ result = msg.channel;
+ break;
+ case 5:
+ result = msg.createdTimestamp;
+ break;
+ case 6:
+ result = msg.pinned;
+ break;
+ case 7:
+ result = msg.tts;
+ break;
+ case 8:
+ result = [...msg.attachments.values()];
+ break;
+ case 9:
+ result = msg.edits;
+ break;
+ case 12:
+ result = msg.reactions.cache.size;
+ break;
+ case 13:
+ result = [...msg.mentions.users.values()];
+ break;
+ case 14:
+ result = msg.mentions.users.size;
+ break;
+ case 15:
+ result = msg.url;
+ break;
+ case 16:
+ result = msg.createdAt;
+ break;
+ case 17:
+ result = msg.content.length;
+ break;
+ case 18:
+ result = msg.attachments.size;
+ break;
+ case 19:
+ result = msg.guild;
+ break;
+ case 20:
+ result = msg.type;
+ break;
+ case 21:
+ result = msg.webhookId;
+ break;
+ case 22:
+ result = msg.embeds[0];
+ break;
+ case 23:
+ result = msg.reference;
+ break;
+ case 24:
+ result = msg.reference?.messageId;
+ break;
+ case 25:
+ result = msg.reference?.channelId;
+ break;
+ case 26:
+ result = msg.reference?.guildId;
+ break;
+ case 27:
+ result = msg.type === 'REPLY' && msg.reference?.messageId !== undefined;
+ break;
+ case 28: // Added case for storing sticker count
+ result = msg.stickers ? msg.stickers.size : 0;
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/store_music_info_MOD.js b/actions/store_music_info_MOD.js
new file mode 100644
index 000000000..33113e501
--- /dev/null
+++ b/actions/store_music_info_MOD.js
@@ -0,0 +1,266 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Store Music Info',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Music',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = [
+ 'Music Title',
+ 'Music Url',
+ 'Music Author',
+ 'Music Views',
+ 'Music Thumbnail',
+ 'Music Duration',
+ 'Music Description',
+ 'Music Requested By',
+ 'Music Source',
+ ];
+ return `Retrieve the ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Music Title';
+ break;
+ case 1:
+ dataType = 'Music Url';
+ break;
+ case 2:
+ dataType = 'Music Author';
+ break;
+ case 3:
+ dataType = 'Music Views';
+ break;
+ case 4:
+ dataType = 'Music Thumbnail';
+ break;
+ case 5:
+ dataType = 'Music Duration';
+ break;
+ case 6:
+ dataType = 'Music Description';
+ break;
+ case 7:
+ dataType = 'Music Requested By (member)';
+ break;
+ case 8:
+ dataType = 'Music Source';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['type', 'song', 'info', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
`;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer');
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const interaction = cache.interaction;
+ const parametro = this.evalMessage(data.parametro, cache);
+ const info = parseInt(data.info, 10);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = interaction.options._hoistedOptions.find(
+ (f) => f.type === 'ATTACHMENT' && f.name === parametro,
+ ).attachment;
+ break;
+ case 1:
+ result = interaction.options._hoistedOptions.find((f) => f.type === 'ATTACHMENT' && f.name === parametro)
+ .attachment.id;
+ break;
+ case 2:
+ result = interaction.options._hoistedOptions.find((f) => f.type === 'ATTACHMENT' && f.name === parametro)
+ .attachment.attachment;
+ break;
+ case 3:
+ result = interaction.options._hoistedOptions.find((f) => f.type === 'ATTACHMENT' && f.name === parametro)
+ .attachment.name;
+ break;
+ case 4:
+ result = interaction.options._hoistedOptions.find((f) => f.type === 'ATTACHMENT' && f.name === parametro)
+ .attachment.size;
+ break;
+ case 5:
+ result = interaction.options._hoistedOptions.find((f) => f.type === 'ATTACHMENT' && f.name === parametro)
+ .attachment.contentType;
+ break;
+ case 6:
+ result = interaction.options._hoistedOptions.find((f) => f.type === 'ATTACHMENT' && f.name === parametro)
+ .attachment.width;
+ break;
+ case 7:
+ result = interaction.options._hoistedOptions.find((f) => f.type === 'ATTACHMENT' && f.name === parametro)
+ .attachment.height;
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/store_role_info.js b/actions/store_role_info.js
new file mode 100644
index 000000000..101e56968
--- /dev/null
+++ b/actions/store_role_info.js
@@ -0,0 +1,252 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Store Role Info',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Role Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = [
+ 'Role Object',
+ 'Role ID',
+ 'Role Name',
+ 'Role Color',
+ 'Role Position',
+ 'Role Timestamp',
+ 'Role Is Mentionable?',
+ 'Role Is Separate From Others?',
+ 'Role Is Managed?',
+ 'Role Members List',
+ 'Role Creation Date',
+ 'Role Permissions',
+ 'Role Members Amount',
+ 'Role Icon',
+ ];
+ return `${presets.getRoleText(data.role, data.varName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Role';
+ break;
+ case 1:
+ dataType = 'Role ID';
+ break;
+ case 2:
+ dataType = 'Text';
+ break;
+ case 3:
+ dataType = 'Color';
+ break;
+ case 4:
+ case 5:
+ dataType = 'Text';
+ break;
+ case 6:
+ case 7:
+ dataType = 'Boolean';
+ break;
+ case 8:
+ dataType = 'Boolean';
+ break;
+ case 9:
+ dataType = 'Member List';
+ break;
+ case 10:
+ dataType = 'Date';
+ break;
+ case 11:
+ case 12:
+ dataType = 'Number';
+ break;
+ case 13:
+ dataType = 'Image URL';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['role', 'varName', 'info', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Source Info
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const targetRole = await this.getRoleFromData(data.role, data.varName, cache);
+ const info = parseInt(data.info, 10);
+ if (!targetRole) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ let result;
+ switch (info) {
+ case 0:
+ result = targetRole;
+ break;
+ case 1:
+ result = targetRole.id;
+ break;
+ case 2:
+ result = targetRole.name;
+ break;
+ case 3:
+ result = targetRole.hexColor;
+ break;
+ case 4:
+ result = targetRole.position;
+ break;
+ case 5:
+ result = targetRole.createdTimestamp;
+ break;
+ case 6:
+ result = targetRole.mentionable;
+ break;
+ case 7:
+ result = targetRole.hoist;
+ break;
+ case 8:
+ result = targetRole.managed;
+ break;
+ case 9:
+ result = [...targetRole.members.values()];
+ break;
+ case 10:
+ result = targetRole.createdAt;
+ break;
+ case 11:
+ result = targetRole.permissions.toArray();
+ break;
+ case 12:
+ result = targetRole.members.size;
+ break;
+ case 13:
+ result = targetRole.iconURL({ dynamic: true, format: 'png', size: 4096 });
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/store_role_info_MOD.js b/actions/store_role_info_MOD.js
new file mode 100644
index 000000000..7d4f9b20f
--- /dev/null
+++ b/actions/store_role_info_MOD.js
@@ -0,0 +1,229 @@
+module.exports = {
+ name: 'Store Role Info',
+ section: 'Role Control',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ subtitle(data, presets) {
+ const info = [
+ 'Role Object',
+ 'Role ID',
+ 'Position Name',
+ 'Position Color',
+ 'Position of Position',
+ 'Timestamp of Job creation',
+ 'Is the Position mentionable?',
+ 'Is the job separate from the others?',
+ 'Is the Role manageable',
+ "The Role's member list",
+ 'Role creation date',
+ "Role's permission list",
+ 'Number of members of the Role',
+ 'Role Icon',
+ 'Position Tag',
+ 'Position Server',
+ "Position's Server ID",
+ 'Is the Position editable?',
+ 'List of member IDs of the Position',
+ ];
+ return `${presets.getRoleText(data.role, data.varName)} - ${info[parseInt(data.info, 10)]} to (${data.varName2})`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Role';
+ break;
+ case 1:
+ dataType = 'Role ID';
+ break;
+ case 2:
+ dataType = 'Text';
+ break;
+ case 3:
+ dataType = 'Color';
+ break;
+ case 4:
+ dataType = 'Number';
+ break;
+ case 5:
+ dataType = 'Timestamp';
+ break;
+ case 6:
+ case 7:
+ dataType = 'Boolean';
+ break;
+ case 8:
+ dataType = 'Boolean';
+ break;
+ case 9:
+ dataType = 'Member List';
+ break;
+ case 10:
+ dataType = 'Date';
+ break;
+ case 11:
+ case 12:
+ dataType = 'Number';
+ break;
+ case 13:
+ dataType = 'Image URL';
+ break;
+ case 14:
+ dataType = 'Object';
+ break;
+ case 15:
+ dataType = 'Server';
+ break;
+ case 16:
+ dataType = 'Server ID';
+ break;
+ case 17:
+ dataType = 'Boolean';
+ break;
+ case 18:
+ dataType = 'List';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ fields: ['role', 'varName', 'info', 'storage', 'varName2'],
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Source Information
+
+
+
+
+
+`;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const targetRole = await this.getRoleFromData(data.role, data.varName, cache);
+ const info = parseInt(data.info, 10);
+ if (!targetRole) {
+ this.callNextAction(cache);
+ return;
+ }
+ let result;
+ switch (info) {
+ case 0:
+ result = targetRole;
+ break;
+ case 1:
+ result = targetRole.id;
+ break;
+ case 2:
+ result = targetRole.name;
+ break;
+ case 3:
+ result = targetRole.hexColor;
+ break;
+ case 4:
+ result = targetRole.position;
+ break;
+ case 5:
+ result = targetRole.createdTimestamp;
+ break;
+ case 6:
+ result = targetRole.mentionable;
+ break;
+ case 7:
+ result = targetRole.hoist;
+ break;
+ case 8:
+ result = targetRole.managed;
+ break;
+ case 9:
+ result = [...targetRole.members.values()];
+ break;
+ case 10:
+ result = targetRole.createdAt;
+ break;
+ case 11:
+ result = targetRole.permissions.toArray().join(', ').replace(/_/g, ' ').toLowerCase();
+ break;
+ case 12:
+ result = targetRole.members.size;
+ break;
+ case 13:
+ result = targetRole.iconURL({ dynamic: true, format: 'png', size: 4096 });
+ break;
+ case 14:
+ result = targetRole.tags;
+ break;
+ case 15:
+ result = targetRole.guild;
+ break;
+ case 16:
+ result = targetRole.guild.id;
+ break;
+ case 17:
+ result = targetRole.editable;
+ break;
+ case 18:
+ result = [...targetRole.members.keys()];
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/store_server_data.js b/actions/store_server_data.js
new file mode 100644
index 000000000..665dcf9b7
--- /dev/null
+++ b/actions/store_server_data.js
@@ -0,0 +1,145 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Store Server Data',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Data',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getServerText(data.server, data.varName)} -> ${presets.getVariableText(
+ data.storage,
+ data.varName2,
+ )}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Unknown Type'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName', 'dataName', 'defaultVal', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Data Name
+
+
+
+ Default Value (if data doesn't exist)
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = await this.getServerFromData(data.server, data.varName, cache);
+ if (server?.data) {
+ const dataName = this.evalMessage(data.dataName, cache);
+ const defVal = this.eval(this.evalMessage(data.defaultVal, cache), cache);
+ let result;
+ if (defVal === undefined) {
+ result = server.data(dataName);
+ } else {
+ result = server.data(dataName, defVal);
+ }
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/store_server_info.js b/actions/store_server_info.js
new file mode 100644
index 000000000..ef54f79a7
--- /dev/null
+++ b/actions/store_server_info.js
@@ -0,0 +1,535 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Store Server Info',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Server Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = [
+ 'Server Object',
+ 'Server ID',
+ 'Server Name',
+ 'Server Name Acronym',
+ 'Server Region (Removed)',
+ 'Server Icon URL',
+ 'Server Verification Level',
+ 'Server Default Channel',
+ 'Server AFK Channel',
+ 'Server System Channel',
+ 'Server Default Role',
+ 'Server Owner Object',
+ 'Server Bot Member',
+ 'Server Channels List',
+ 'Server Roles List',
+ 'Server Members List',
+ 'Server Emojis List',
+ 'Server Member Count',
+ 'Server Created At',
+ 'Server AFK Timeout',
+ 'Server Available',
+ 'Server Large',
+ 'Server Joined At',
+ 'Server Channels Count',
+ 'Server Emojis Count',
+ 'Server Embed Enabled',
+ 'Server Do Not Disturb Members Count',
+ 'Server Online Members Count',
+ 'Server Offline Members Count',
+ 'Server Idle Members Count',
+ 'Server Bot Count',
+ 'Server Channels IDs List',
+ 'Server Roles IDs List',
+ 'Server Members IDs List',
+ '',
+ 'Server Human Count',
+ '',
+ 'Server Roles Count',
+ 'Server Text Channels Count',
+ 'Server Voice Channels Count',
+ 'Server Verified',
+ 'Server Bans List',
+ 'Server Invites List',
+ 'Server Explicit Content Filter',
+ 'Server Boosts Count',
+ 'Server Boost Tier',
+ 'Server Banner URL',
+ 'Server Features List',
+ 'Server Owner ID',
+ 'Server Vanity URL Code',
+ 'Server Widget Channel ID',
+ ];
+ return `${presets.getServerText(data.server, data.varName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Server';
+ break;
+ case 1:
+ dataType = 'Server ID';
+ break;
+ case 2:
+ case 3:
+ case 5:
+ dataType = 'Icon URL';
+ break;
+ case 6:
+ dataType = 'Text';
+ break;
+ case 7:
+ case 8:
+ case 9:
+ dataType = 'Channel';
+ break;
+ case 10:
+ dataType = 'Role';
+ break;
+ case 11:
+ dataType = 'Server Member';
+ break;
+ case 12:
+ dataType = 'Server Member';
+ break;
+ case 13:
+ dataType = 'Channels List';
+ break;
+ case 14:
+ dataType = 'Roles List';
+ break;
+ case 15:
+ dataType = 'Members List';
+ break;
+ case 16:
+ dataType = 'Emojis List';
+ break;
+ case 17:
+ dataType = 'Number';
+ break;
+ case 18:
+ dataType = 'Date';
+ break;
+ case 19:
+ dataType = 'Number';
+ break;
+ case 20:
+ case 21:
+ dataType = 'Boolean';
+ break;
+ case 22:
+ dataType = 'Date';
+ break;
+ case 23:
+ case 24:
+ dataType = 'Number';
+ break;
+ case 25:
+ dataType = 'Boolean';
+ break;
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ dataType = 'Number';
+ break;
+ case 31:
+ case 32:
+ case 33:
+ dataType = 'IDs List';
+ break;
+ case 35:
+ dataType = 'Number';
+ break;
+ case 37:
+ case 38:
+ case 39:
+ dataType = 'Number';
+ break;
+ case 40:
+ dataType = 'Boolean';
+ break;
+ case 41:
+ dataType = 'Bans List';
+ break;
+ case 42:
+ dataType = 'Invites List';
+ break;
+ case 43:
+ dataType = 'Text';
+ break;
+ case 44:
+ case 45:
+ dataType = 'Number';
+ break;
+ case 46:
+ dataType = 'Banner URL';
+ break;
+ case 47:
+ dataType = 'Server Features List';
+ break;
+ case 48:
+ case 49:
+ dataType = 'Text';
+ break;
+ case 50:
+ dataType = 'Channel ID';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['server', 'varName', 'info', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+
+ Source Info
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const targetServer = await this.getServerFromData(data.server, data.varName, cache);
+
+ if (!targetServer) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const fetchMembers = async (withPresences = false) => {
+ if (targetServer.memberCount !== targetServer.members.cache.size) {
+ await targetServer.members.fetch({ withPresences });
+ }
+ };
+
+ const info = parseInt(data.info, 10);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = targetServer;
+ break;
+ case 1:
+ result = targetServer.id;
+ break;
+ case 2:
+ result = targetServer.name;
+ break;
+ case 3:
+ result = targetServer.nameAcronym;
+ break;
+ case 4: // Server region
+ result = 'unknown';
+ break;
+ case 5:
+ result = targetServer.iconURL({ dynamic: true, format: 'png', size: 4096 });
+ break;
+ case 6:
+ result = targetServer.verificationLevel;
+ break;
+ case 7:
+ result = targetServer.getDefaultChannel();
+ break;
+ case 8:
+ result = targetServer.afkChannel;
+ break;
+ case 9:
+ result = targetServer.systemChannel;
+ break;
+ case 10:
+ result = targetServer.roles.resolve(targetServer.id);
+ break;
+ case 11:
+ try {
+ result = await targetServer.fetchOwner();
+ } catch (err) {
+ result = null;
+ }
+ break;
+ case 12:
+ result = targetServer.members.me;
+ break;
+ case 13:
+ result = [...targetServer.channels.cache.values()];
+ break;
+ case 14:
+ result = [...targetServer.roles.cache.values()];
+ break;
+ case 15:
+ result = [...targetServer.members.cache.values()];
+ break;
+ case 16:
+ result = [...targetServer.emojis.cache.values()];
+ break;
+ case 17:
+ result = targetServer.memberCount;
+ break;
+ case 18:
+ result = targetServer.createdAt;
+ break;
+ case 19:
+ result = targetServer.afkTimeout ?? 0;
+ break;
+ case 20:
+ result = targetServer.available;
+ break;
+ case 21:
+ result = targetServer.large;
+ break;
+ case 22:
+ result = targetServer.joinedAt;
+ break;
+ case 23:
+ result = targetServer.channels.cache.size;
+ break;
+ case 24:
+ result = targetServer.emojis.cache.size;
+ break;
+ case 25:
+ result = Boolean(targetServer.widgetEnabled);
+ break;
+ case 26:
+ await fetchMembers(true);
+ result = targetServer.members.cache.filter((m) => m.presence?.status === 'dnd').size;
+ break;
+ case 27:
+ await fetchMembers(true);
+ result = targetServer.members.cache.filter((m) => m.presence?.status === 'online').size;
+ break;
+ case 28:
+ await fetchMembers(true);
+ result = targetServer.members.cache.filter((m) => m.presence?.status === 'offline').size;
+ break;
+ case 29:
+ await fetchMembers(true);
+ result = targetServer.members.cache.filter((m) => m.presence?.status === 'idle').size;
+ break;
+ case 30:
+ result = targetServer.members.cache.filter((m) => m.user?.bot).size;
+ break;
+ case 31:
+ result = [...targetServer.channels.cache.keys()];
+ break;
+ case 32:
+ result = [...targetServer.roles.cache.keys()];
+ break;
+ case 33:
+ await fetchMembers();
+ result = [...targetServer.members.cache.keys()];
+ break;
+ case 35:
+ await fetchMembers();
+ result = targetServer.members.cache.filter((m) => !m.user?.bot).size;
+ break;
+ case 37:
+ result = targetServer.roles.cache.size;
+ break;
+ case 38: {
+ const { ChannelType } = this.getDBM().DiscordJS;
+ result = targetServer.channels.cache.filter(
+ (c) => c.type === ChannelType.GuildText || c.type === ChannelType.GuildAnnouncement,
+ ).size;
+ break;
+ }
+ case 39: {
+ const { ChannelType } = this.getDBM().DiscordJS;
+ result = targetServer.channels.cache.filter((c) => c.type === ChannelType.GuildVoice).size;
+ break;
+ }
+ case 40:
+ result = targetServer.verified;
+ break;
+ case 41:
+ const bans = await targetServer.bans.fetch();
+ result = [...bans.values()];
+ break;
+ case 42:
+ const invites = await targetServer.invites.fetch();
+ result = [...invites.values()];
+ break;
+ case 43:
+ result = targetServer.explicitContentFilter;
+ break;
+ case 44:
+ result = targetServer.premiumSubscriptionCount ?? 0;
+ break;
+ case 45:
+ result = targetServer.premiumTier;
+ break;
+ case 46:
+ result = targetServer.bannerURL({ format: 'png', size: 4096 });
+ break;
+ case 47:
+ result = targetServer.features;
+ break;
+ case 48:
+ result = targetServer.ownerId;
+ break;
+ case 49:
+ result = targetServer.vanityURLCode;
+ break;
+ case 50:
+ result = targetServer.widgetChannelId;
+ break;
+ default:
+ break;
+ }
+
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/store_server_info_MOD.js b/actions/store_server_info_MOD.js
new file mode 100644
index 000000000..19bc1bcbe
--- /dev/null
+++ b/actions/store_server_info_MOD.js
@@ -0,0 +1,700 @@
+module.exports = {
+ name: 'Store Server Info MOD',
+ section: 'Server Control',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadURL: 'https://github.com/dbm-network/mods',
+ },
+
+ subtitle(data, presets) {
+ const info = [
+ 'Server Object',
+ 'Server ID',
+ 'Server Name',
+ 'Server Name Acronym',
+ 'Server Preferred Language',
+ 'Server Icon URL',
+ 'Server Verification Level',
+ 'Server Default Channel',
+ 'Server AFK Channel',
+ 'Server System Channel',
+ 'Server Default Role',
+ 'Server Owner Object',
+ 'Server Bot Member',
+ 'Server Channels List',
+ 'Server Roles List',
+ 'Server Members List',
+ 'Server Emojis List',
+ 'Server Member Count',
+ 'Server Created At',
+ 'Server AFK Timeout',
+ 'Server Available',
+ 'Server Large',
+ 'Server Joined At',
+ 'Server Channels Count',
+ 'Server Emojis Count',
+ 'Server Embed Enabled',
+ 'Server Do Not Disturb Members Count',
+ 'Server Online Members Count',
+ 'Server Offline Members Count',
+ 'Server Idle Members Count',
+ 'Server Bot Count',
+ 'Server Channels IDs List',
+ 'Server Roles IDs List',
+ 'Server Members IDs List',
+ '',
+ 'Server Human Count',
+ '',
+ 'Server Roles Count',
+ 'Server Text Channels Count',
+ 'Server Voice Channels Count',
+ 'Server Verified',
+ 'Server Bans List',
+ 'Server Invites List',
+ 'Server Explicit Content Filter',
+ 'Server Boosts Count',
+ 'Server Boost Tier',
+ 'Server Banner URL',
+ 'Server Features List',
+ 'Server Owner ID',
+ 'Server Vanity URL Code',
+ 'Server Widget Channel ID',
+ 'Server AFK Channel ID',
+ 'Server Progress Bar Enable',
+ 'Server Description',
+ 'Server Partnered',
+ 'Server Rule Channel',
+ 'Server Rule Channel ID',
+ 'Server Widget Channel',
+ 'Server System Channel ID',
+ 'Server NSFW Level',
+ 'Server MFA/2FA Level',
+ 'Server Timestamp',
+ 'Template URL',
+ 'Template Code',
+ 'Template Name',
+ 'Template Description',
+ 'Times the Template has been used',
+ 'Template creator ID',
+ 'Timestamp of Template creation',
+ 'Timestamp of Template update',
+ 'Total members in the voice channel',
+ 'List of members by ID present in the voice channels',
+ 'List of members present in the voice channels',
+ ];
+ return `${presets.getServerText(data.server, data.varName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Server';
+ break;
+ case 1:
+ dataType = 'Server ID';
+ break;
+ case 2:
+ dataType = 'Text';
+ break;
+ case 3:
+ dataType = 'Text';
+ break;
+ case 4:
+ dataType = 'Text';
+ break;
+ case 5:
+ dataType = 'Icon URL';
+ break;
+ case 6:
+ dataType = 'Text';
+ break;
+ case 7:
+ dataType = 'Channel';
+ break;
+ case 8:
+ dataType = 'Channel';
+ break;
+ case 9:
+ dataType = 'Channel';
+ break;
+ case 10:
+ dataType = 'Role';
+ break;
+ case 11:
+ dataType = 'Server Member';
+ break;
+ case 12:
+ dataType = 'Server Member';
+ break;
+ case 13:
+ dataType = 'Channels List';
+ break;
+ case 14:
+ dataType = 'Roles List';
+ break;
+ case 15:
+ dataType = 'Members List';
+ break;
+ case 16:
+ dataType = 'Emojis List';
+ break;
+ case 17:
+ dataType = 'Number';
+ break;
+ case 18:
+ dataType = 'Date';
+ break;
+ case 19:
+ dataType = 'Number';
+ break;
+ case 20:
+ dataType = 'Boolean';
+ break;
+ case 21:
+ dataType = 'Boolean';
+ break;
+ case 22:
+ dataType = 'Date';
+ break;
+ case 23:
+ dataType = 'Number';
+ break;
+ case 24:
+ dataType = 'Number';
+ break;
+ case 25:
+ dataType = 'Boolean';
+ break;
+ case 26:
+ dataType = 'Number';
+ break;
+ case 27:
+ dataType = 'Number';
+ break;
+ case 28:
+ dataType = 'Number';
+ break;
+ case 29:
+ dataType = 'Number';
+ break;
+ case 30:
+ dataType = 'Number';
+ break;
+ case 31:
+ dataType = 'IDs List';
+ break;
+ case 32:
+ dataType = 'IDs List';
+ break;
+ case 33:
+ dataType = 'IDs List';
+ break;
+ case 35:
+ dataType = 'Number';
+ break;
+ case 37:
+ dataType = 'Number';
+ break;
+ case 38:
+ dataType = 'Number';
+ break;
+ case 39:
+ dataType = 'Number';
+ break;
+ case 40:
+ dataType = 'Boolean';
+ break;
+ case 41:
+ dataType = 'Bans List';
+ break;
+ case 42:
+ dataType = 'Invites List';
+ break;
+ case 43:
+ dataType = 'Text';
+ break;
+ case 44:
+ dataType = 'Number';
+ break;
+ case 45:
+ dataType = 'Number';
+ break;
+ case 46:
+ dataType = 'Banner URL';
+ break;
+ case 47:
+ dataType = 'Server Features List';
+ break;
+ case 48:
+ dataType = 'Server Member ID';
+ break;
+ case 49:
+ dataType = 'Text';
+ break;
+ case 50:
+ dataType = 'Channel ID';
+ break;
+ case 51:
+ dataType = 'Channel ID';
+ break;
+ case 52:
+ dataType = 'Boolean';
+ break;
+ case 53:
+ dataType = 'Text';
+ break;
+ case 54:
+ dataType = 'Boolean';
+ break;
+ case 55:
+ dataType = 'Channel';
+ break;
+ case 56:
+ dataType = 'Channel ID';
+ break;
+ case 57:
+ dataType = 'Channel';
+ break;
+ case 58:
+ dataType = 'Channel ID';
+ break;
+ case 59:
+ dataType = 'Text';
+ break;
+ case 60:
+ dataType = 'Text';
+ break;
+ case 61:
+ dataType = 'Timestamp';
+ break;
+ case 62:
+ dataType = 'URL';
+ break;
+ case 63:
+ dataType = 'Code';
+ break;
+ case 64:
+ dataType = 'Text';
+ break;
+ case 65:
+ dataType = 'Text';
+ break;
+ case 66:
+ dataType = 'Number';
+ break;
+ case 67:
+ dataType = 'ID User';
+ break;
+ case 68:
+ dataType = 'Timestamp';
+ break;
+ case 69:
+ dataType = 'Timestamp';
+ break;
+ case 70:
+ dataType = 'Number';
+ break;
+ case 71:
+ dataType = 'List';
+ break;
+ case 72:
+ dataType = 'List';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ fields: ['server', 'varName', 'info', 'storage', 'varName2'],
+
+ html(isEvent, data) {
+ return `
+
Version 1.1
+
DBM Extended
+
+
+
+
+
+
+
+ Source Info
+
+
+
+
+
+
+`;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const targetServer = await this.getServerFromData(data.server, data.varName, cache);
+
+ if (!targetServer) {
+ return this.callNextAction(cache);
+ }
+
+ const fetchMembers = async (withPresences = false) => {
+ if (targetServer.memberCount !== targetServer.members.cache.size) {
+ await targetServer.members.fetch({ withPresences });
+ }
+ };
+
+ const info = parseInt(data.info, 10);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = targetServer;
+ break;
+ case 1:
+ result = targetServer.id;
+ break;
+ case 2:
+ result = targetServer.name;
+ break;
+ case 3:
+ result = targetServer.nameAcronym;
+ break;
+ case 4:
+ result = targetServer.preferredLocale;
+ break;
+ case 5:
+ result = targetServer.iconURL({ dynamic: true, format: 'png', size: 4096 });
+ break;
+ case 6:
+ result = targetServer.verificationLevel;
+ break;
+ case 7:
+ result = targetServer.getDefaultChannel();
+ break;
+ case 8:
+ result = targetServer.afkChannel;
+ break;
+ case 9:
+ result = targetServer.systemChannel;
+ break;
+ case 10:
+ result = targetServer.roles.resolve(targetServer.id);
+ break;
+ case 11:
+ try {
+ result = await targetServer.fetchOwner();
+ } catch (error) {
+ // Handle case where owner cannot be fetched (e.g., owner left server, bot doesn't have permissions)
+ console.warn(`[Store Server Info] Could not fetch owner for server ${targetServer.id}:`, error.message);
+ result = null;
+ }
+ break;
+ case 12:
+ result = targetServer.me;
+ break;
+ case 13:
+ result = [...targetServer.channels.cache.values()];
+ break;
+ case 14:
+ result = [...targetServer.roles.cache.values()];
+ break;
+ case 15:
+ result = [...targetServer.members.cache.values()];
+ break;
+ case 16:
+ result = [...targetServer.emojis.cache.values()];
+ break;
+ case 17:
+ result = targetServer.memberCount;
+ break;
+ case 18:
+ result = targetServer.createdAt;
+ break;
+ case 19:
+ result = targetServer.afkTimeout ?? 0;
+ break;
+ case 20:
+ result = targetServer.available;
+ break;
+ case 21:
+ result = targetServer.large;
+ break;
+ case 22:
+ result = targetServer.joinedAt;
+ break;
+ case 23:
+ result = targetServer.channels.cache.size;
+ break;
+ case 24:
+ result = targetServer.emojis.cache.size;
+ break;
+ case 25:
+ result = Boolean(targetServer.widgetEnabled);
+ break;
+ case 26:
+ await fetchMembers(true);
+ result = targetServer.members.cache.filter((m) => m.presence?.status === 'dnd').size;
+ break;
+ case 27:
+ await fetchMembers(true);
+ result = targetServer.members.cache.filter((m) => m.presence?.status === 'online').size;
+ break;
+ case 28:
+ await fetchMembers(true);
+ result = targetServer.members.cache.filter((m) => m.presence?.status === 'offline').size;
+ break;
+ case 29:
+ await fetchMembers(true);
+ result = targetServer.members.cache.filter((m) => m.presence?.status === 'idle').size;
+ break;
+ case 30:
+ result = targetServer.members.cache.filter((m) => m.user?.bot).size;
+ break;
+ case 31:
+ result = [...targetServer.channels.cache.keys()];
+ break;
+ case 32:
+ result = [...targetServer.roles.cache.keys()];
+ break;
+ case 33:
+ await fetchMembers();
+ result = [...targetServer.members.cache.keys()];
+ break;
+ case 35:
+ await fetchMembers();
+ result = targetServer.members.cache.filter((m) => !m.user?.bot).size;
+ break;
+ case 37:
+ result = targetServer.roles.cache.size;
+ break;
+ case 38:
+ result = targetServer.channels.cache.filter((c) => c.type === 'GUILD_TEXT' || c.type === 'GUILD_NEWS').size;
+ break;
+ case 39:
+ result = targetServer.channels.cache.filter((c) => c.type === 'GUILD_VOICE').size;
+ break;
+ case 40:
+ result = targetServer.verified;
+ break;
+ case 41:
+ const bans = await targetServer.bans.fetch();
+ result = [...bans.values()];
+ break;
+ case 42:
+ const invites = await targetServer.invites.fetch();
+ result = [...invites.values()];
+ break;
+ case 43:
+ result = targetServer.explicitContentFilter;
+ break;
+ case 44:
+ result = targetServer.premiumSubscriptionCount ?? 0;
+ break;
+ case 45:
+ result = targetServer.premiumTier;
+ break;
+ case 46:
+ result = targetServer.bannerURL({ format: 'png', size: 4096 });
+ break;
+ case 47:
+ result = targetServer.features;
+ break;
+ case 48:
+ result = targetServer.ownerId;
+ break;
+ case 49:
+ result = targetServer.vanityURLCode;
+ break;
+ case 50:
+ result = targetServer.widgetChannelId;
+ break;
+ case 51:
+ result = targetServer.afkChannelId;
+ break;
+ case 52:
+ result = targetServer.premiumProgressBarEnabled;
+ break;
+ case 53:
+ result = targetServer.description;
+ break;
+ case 54:
+ result = targetServer.partnered;
+ break;
+ case 55:
+ result = targetServer.rulesChannel;
+ break;
+ case 56:
+ result = targetServer.rulesChannelId;
+ break;
+ case 57:
+ result = targetServer.widgetChannel;
+ break;
+ case 58:
+ result = targetServer.systemChannelId;
+ break;
+ case 59:
+ result = targetServer.nsfwLevel;
+ break;
+ case 60:
+ result = targetServer.mfaLevel;
+ break;
+ case 61:
+ result = targetServer.createdTimestamp;
+ break;
+ case 62:
+ result = `https://discord.new/${(await targetServer.fetchTemplates()).map((v) => v.code)}`;
+ break;
+ case 63:
+ result = `${(await targetServer.fetchTemplates()).map((v) => v.code)}`;
+ break;
+ case 64:
+ result = `${(await targetServer.fetchTemplates()).map((v) => v.name)}`;
+ break;
+ case 65:
+ result = `${(await targetServer.fetchTemplates()).map((v) => v.description)}`;
+ break;
+ case 66:
+ result = `${(await targetServer.fetchTemplates()).map((v) => v.usageCount)}`;
+ break;
+ case 67:
+ result = `${(await targetServer.fetchTemplates()).map((v) => v.creatorId)}`;
+ break;
+ case 68:
+ result = `${(await targetServer.fetchTemplates()).map((v) => v.createdAt)}`;
+ break;
+ case 69:
+ result = `${(await targetServer.fetchTemplates()).map((v) => v.updatedAt)}`;
+ break;
+ case 70:
+ result = targetServer.channels.cache
+ .filter((c) => c.type === 'GUILD_VOICE')
+ .map((c) => c.members.size)
+ .reduce((s, a) => s + a, 0);
+ break;
+ case 71:
+ const str = targetServer.channels.cache
+ .filter((c) => c.type === 'GUILD_VOICE')
+ .map((c) => c.members.map((member) => `${member.user.id},`).join(''))
+ .join('');
+ result = str.substring(0, str.length - 1).split(new RegExp(','));
+ break;
+ case 72:
+ result = targetServer.channels.cache
+ .filter((d) => d.type === 'GUILD_VOICE')
+ .map((d) => d.members.map((member) => member.user).join(''))
+ .join('');
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/store_thread_channel_info.js b/actions/store_thread_channel_info.js
new file mode 100644
index 000000000..e4a3ab8cd
--- /dev/null
+++ b/actions/store_thread_channel_info.js
@@ -0,0 +1,210 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Store Thread Channel Info',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = [
+ 'Thread Channel Object',
+ 'Thread Channel ID',
+ 'Thread Channel Name',
+ 'Thread Channel Is Archived?',
+ 'Thread Channel Is Locked?',
+ 'Thread Channel Is Invitable?',
+ 'Thread Channel Archived At',
+ 'Thread Channel Archived At Timestamp',
+ ];
+ return `${presets.getChannelText(data.thread, data.threadVarName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Thread Channel';
+ break;
+ case 1:
+ dataType = 'Thread Channel ID';
+ break;
+ case 2:
+ dataType = 'Text';
+ break;
+ case 3:
+ case 4:
+ case 5:
+ dataType = 'Boolean';
+ break;
+ case 6:
+ dataType = 'Date';
+ break;
+ case 7:
+ dataType = 'Timestamp';
+ break;
+ }
+ return [data.storageVarName, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['thread', 'threadVarName', 'info', 'storage', 'storageVarName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Source Info
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+
+ const targetChannel = await this.getChannelFromData(data.thread, data.threadVarName, cache);
+
+ if (!targetChannel) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ let result;
+ const info = parseInt(data.info, 10);
+ switch (info) {
+ case 0:
+ result = targetChannel;
+ break;
+ case 1:
+ result = targetChannel.id;
+ break;
+ case 2:
+ result = targetChannel.name;
+ break;
+ case 3:
+ result = targetChannel.archived;
+ break;
+ case 4:
+ result = targetChannel.locked;
+ break;
+ case 5:
+ result = targetChannel.invitable;
+ break;
+ case 6:
+ result = targetChannel.archivedAt;
+ break;
+ case 7:
+ result = targetChannel.archiveTimestamp;
+ break;
+ default:
+ break;
+ }
+
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const storageVarName = this.evalMessage(data.storageVarName, cache);
+ this.storeValue(result, storage, storageVarName, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/store_time_info.js b/actions/store_time_info.js
new file mode 100644
index 000000000..a3fb631d6
--- /dev/null
+++ b/actions/store_time_info.js
@@ -0,0 +1,183 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Store Time Info',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const time = ['Year', 'Month', 'Day of the Month', 'Hour', 'Minute', 'Second', 'Milisecond', 'Month Text'];
+ return `${time[parseInt(data.type, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ let result = 'Number';
+ if (data.type === '7') {
+ result = 'Text';
+ }
+ return [data.varName, result];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['type', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Time Info
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const type = parseInt(data.type, 10);
+ const date = new Date();
+ let result;
+ switch (type) {
+ case 0:
+ result = date.getFullYear();
+ break;
+ case 1:
+ result = date.getMonth() + 1;
+ break;
+ case 2:
+ result = date.getDate();
+ break;
+ case 3:
+ result = date.getHours();
+ break;
+ case 4:
+ result = date.getMinutes();
+ break;
+ case 5:
+ result = date.getSeconds();
+ break;
+ case 6:
+ result = date.getMilliseconds();
+ break;
+ case 7:
+ result = [
+ 'January',
+ 'February',
+ 'March',
+ 'April',
+ 'May',
+ 'June',
+ 'July',
+ 'August',
+ 'September',
+ 'October',
+ 'November',
+ 'December',
+ ][date.getMonth()];
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(result, storage, varName, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/store_unix_timestamp_MOD.js b/actions/store_unix_timestamp_MOD.js
new file mode 100644
index 000000000..6930f16f5
--- /dev/null
+++ b/actions/store_unix_timestamp_MOD.js
@@ -0,0 +1,50 @@
+module.exports = {
+ name: 'Store Unix Timestamp',
+ section: 'Other Stuff',
+ meta: {
+ version: '2.1.7',
+ preciseCheck: true,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods/blob/master/actions/store_unix_timestamp_MOD.js',
+ },
+
+ subtitle() {
+ return `Current Unix Timestamp`;
+ },
+
+ fields: ['storage', 'varName'],
+
+ html() {
+ return `
+
+ Time Info
+
+
+
+
+
+
+
+
+`;
+ },
+
+ init() {
+ const { glob, document } = this;
+ glob.variableChange(document.getElementById('storage'), 'varNameContainer');
+ },
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const result = Math.floor(new Date().getTime() / 1000);
+
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+
+ this.storeValue(result, storage, varName, cache);
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/store_voice_channel_info.js b/actions/store_voice_channel_info.js
new file mode 100644
index 000000000..afeb08861
--- /dev/null
+++ b/actions/store_voice_channel_info.js
@@ -0,0 +1,192 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Store Voice Channel Info',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = [
+ 'Voice Channel Object',
+ 'Voice Channel ID',
+ 'Voice Channel Name',
+ 'Voice Channel Position',
+ 'Voice Channel User Limit',
+ 'Voice Channel Bitrate',
+ ];
+ return `${presets.getVoiceChannelText(data.channel, data.varName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Voice Channel';
+ break;
+ case 1:
+ dataType = 'Voice Channel ID';
+ break;
+ case 2:
+ dataType = 'Text';
+ break;
+ case 3:
+ case 4:
+ case 5:
+ dataType = 'Number';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'varName', 'info', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Source Info
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const targetChannel = await this.getVoiceChannelFromData(data.channel, data.varName, cache);
+
+ if (!targetChannel) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const info = parseInt(data.info, 10);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = targetChannel;
+ break;
+ case 1:
+ result = targetChannel.id;
+ break;
+ case 2:
+ result = targetChannel.name;
+ break;
+ case 3:
+ result = targetChannel.position;
+ break;
+ case 4:
+ result = targetChannel.userLimit;
+ break;
+ case 5:
+ result = targetChannel.bitrate;
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/store_voice_channel_info_MOD.js b/actions/store_voice_channel_info_MOD.js
new file mode 100644
index 000000000..7062a1daa
--- /dev/null
+++ b/actions/store_voice_channel_info_MOD.js
@@ -0,0 +1,212 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Store Voice Channel Info',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Channel Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = [
+ 'Voice Channel Object',
+ 'Voice Channel ID',
+ 'Voice Channel Name',
+ 'Voice Channel Members',
+ 'Voice Channel Is Full?',
+ 'Voice Channel Position',
+ 'Voice Channel User Limit',
+ 'Voice Channel Bitrate',
+ 'Voice Channel Members Count',
+ 'Voice Channel Category ID',
+ ];
+ return `${presets.getVoiceChannelText(data.channel, data.varName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Voice Channel';
+ break;
+ case 1:
+ dataType = 'Voice Channel ID';
+ break;
+ case 2:
+ dataType = 'Text';
+ break;
+ case 3:
+ dataType = 'Members List';
+ break;
+ case 4:
+ dataType = 'Text';
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ dataType = 'Number';
+ break;
+ case 9:
+ dataType = 'Category ID';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.1.6', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'varName', 'info', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+ Source Info
+
+
+
+`;
+ },
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const targetChannel = await this.getVoiceChannelFromData(data.channel, data.varName, cache);
+
+ if (!targetChannel) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const info = parseInt(data.info, 10);
+
+ let result;
+ switch (info) {
+ case 0:
+ result = targetChannel;
+ break;
+ case 1:
+ result = targetChannel.id;
+ break;
+ case 2:
+ result = targetChannel.name;
+ break;
+ case 3:
+ result = [...targetChannel.members.values()];
+ break;
+ case 4:
+ result = targetChannel.full;
+ break;
+ case 5:
+ result = targetChannel.position;
+ break;
+ case 6:
+ result = targetChannel.userLimit;
+ break;
+ case 7:
+ result = targetChannel.bitrate;
+ break;
+ case 8:
+ result = targetChannel.members.size;
+ break;
+ case 9:
+ result = targetChannel.parentId;
+ break;
+
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/store_voice_channel_info_v2_MOD.js b/actions/store_voice_channel_info_v2_MOD.js
new file mode 100644
index 000000000..036c7707c
--- /dev/null
+++ b/actions/store_voice_channel_info_v2_MOD.js
@@ -0,0 +1,195 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Store Voice Channel Info V2',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Mods',
+ meta: {
+ version: '2.1.6',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = [
+ 'Voice Channel Object',
+ 'Voice Channel ID',
+ 'Voice Channel Name',
+ 'Voice Channel Position',
+ 'Voice Channel User Limit',
+ 'Voice Channel Bitrate',
+ 'Voice Channel Connected Users',
+ ];
+ return `${presets.getVoiceChannelText(data.channel, data.varName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Voice Channel';
+ break;
+ case 1:
+ dataType = 'Voice Channel ID';
+ break;
+ case 2:
+ dataType = 'Text';
+ break;
+ case 3:
+ case 4:
+ case 5:
+ dataType = 'Number';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['channel', 'varName', 'info', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ //
+ // The "data" parameter stores constants for select elements to use.
+ // Each is an array: index 0 for commands, index 1 for events.
+ // The names are: sendTargets, members, roles, channels,
+ // messages, servers, variables
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Source Info
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ const channel = parseInt(data.channel, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const info = parseInt(data.info, 10);
+ const targetChannel = this.getVoiceChannel(channel, varName, cache);
+ if (!targetChannel) {
+ this.callNextAction(cache);
+ return;
+ }
+ let result;
+ switch (info) {
+ case 0:
+ result = targetChannel;
+ break;
+ case 1:
+ result = targetChannel.id;
+ break;
+ case 2:
+ result = targetChannel.name;
+ break;
+ case 3:
+ result = targetChannel.position;
+ break;
+ case 4:
+ result = targetChannel.userLimit;
+ break;
+ case 5:
+ result = targetChannel.bitrate;
+ break;
+ case 6:
+ result = targetChannel.members.map((user) => user);
+ break;
+ default:
+ break;
+ }
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/temp_ban_member_MOD.js b/actions/temp_ban_member_MOD.js
new file mode 100644
index 000000000..583d990f6
--- /dev/null
+++ b/actions/temp_ban_member_MOD.js
@@ -0,0 +1,216 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Temp Ban Member',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'reason', 'days', 'time', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+
+ return [data.varName2, `Timestamp`];
+ },
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
This action can not deal with texts which are over than 200 characters.
+
Uses simple-tts-mp3 (chunks long text via Google TTS). In your bot project folder run: npm install simple-tts-mp3
+
Stores a local .mp3 file path (not an HTTP URL). Use Play File with this path, not Play URL.
+
Normal sentences work beyond 200 characters. A single very long "word" with no spaces may fail (Google TTS chunking).
+
Security (npm audit): In your botpackage.json, add root-level "overrides": { "axios": "^1.15.0" }, then npm install, so axios pulled in by Google TTS stays patched.
@@ -51,16 +54,33 @@ module.exports = {
const storage = parseInt(data.storage, 10);
const varName = this.evalMessage(data.varName, cache);
const text = this.evalMessage(data.text, cache);
- const language = this.evalMessage(data.lang, cache);
+ const languageRaw = this.evalMessage(data.lang, cache);
+ const language = (languageRaw && String(languageRaw).trim()) || 'en';
const Mods = this.getMods();
- const tts = Mods.require('google-tts-api');
+ const os = require('os');
+ const path = require('path');
+ const crypto = require('crypto');
- const play = await tts.getAudioUrl(text, {
- lang: language,
- slow: false,
- host: 'https://translate.google.com',
- });
- this.storeValue(play, storage, varName, cache);
+ if (!text || !String(text).trim()) {
+ console.error('[Text To Speech MOD] Missing or empty text.');
+ this.callNextAction(cache);
+ return;
+ }
+
+ try {
+ const { createAudioFile } = Mods.require('simple-tts-mp3');
+ const baseName = path.join(
+ os.tmpdir(),
+ `dbm-tts-${process.pid}-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`,
+ );
+ const filePath = await createAudioFile(text, baseName, language);
+ this.storeValue(filePath, storage, varName, cache);
+ } catch (err) {
+ const msg = err && err.message ? String(err.message) : 'Unknown error';
+ console.error('[Text To Speech MOD] Failed to generate audio:', msg);
+ this.callNextAction(cache);
+ return;
+ }
this.callNextAction(cache);
},
diff --git a/actions/timeout_member.js b/actions/timeout_member.js
new file mode 100644
index 000000000..bc186e3bb
--- /dev/null
+++ b/actions/timeout_member.js
@@ -0,0 +1,128 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Timeout Member',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'time', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Time
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+
+ let time = this.evalMessage(data.time, cache);
+ time = time ? Date.now() + time * 1000 : null;
+ const reason = this.evalMessage(data.reason, cache);
+
+ if (Array.isArray(member)) {
+ this.callListFunc(member, 'disableCommunicationUntil', [time, reason])
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else if (member?.disableCommunicationUntil) {
+ member
+ .disableCommunicationUntil(time, reason)
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/timeout_member_MOD.js b/actions/timeout_member_MOD.js
new file mode 100644
index 000000000..8d0e47ade
--- /dev/null
+++ b/actions/timeout_member_MOD.js
@@ -0,0 +1,88 @@
+module.exports = {
+ name: 'Timeout Member',
+
+ section: 'Member Management',
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)}`;
+ },
+
+ meta: {
+ version: '2.1.5',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods',
+ },
+
+ fields: ['member', 'varName', 'czas', 'ilosc', 'reason'],
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ `;
+ },
+
+ variableStorage(data, varType) {
+ const storageType = parseInt(data.storage, 10);
+ if (storageType !== varType) return;
+ return [data.varName, 'Top Members'];
+ },
+
+ async action(cache) {
+ const fs = require('fs');
+ const path = require('path');
+ const data = cache.actions[cache.index];
+ const filePath = path.join(__dirname, '../data/players.json');
+
+ const dataName = this.evalMessage(data.dataName, cache) || 'bank';
+ const topCount = parseInt(this.evalMessage(data.topCount, cache), 10) || 5;
+
+ const useNumbers = this.evalMessage(data.useNumbers, cache) === 'true';
+ const showValues = this.evalMessage(data.showValues, cache) === 'true';
+ const filterBots = this.evalMessage(data.filterBots, cache) === 'true';
+ const reversedOrder = this.evalMessage(data.reversedOrder, cache) === 'true';
+ const usePrefix = this.evalMessage(data.usePrefix, cache) === 'true';
+ const enableRankingTitle = this.evalMessage(data.enableRankingTitle, cache) === 'true';
+ const rankingTitle = enableRankingTitle ? this.evalMessage(data.rankingTitle, cache) || '🏆 Top Members 🏆' : '';
+
+ const suffix = this.evalMessage(data.suffix, cache) || '';
+ const suffix2 = this.evalMessage(data.suffix2, cache) || '';
+ const formattedSuffix2 = suffix2 ? `${suffix2} ` : '';
+ const suffix3 = this.evalMessage(data.suffix3, cache) || '';
+ const formattedSuffix3 = suffix3 ? ` ${suffix3}` : '';
+ const suffix4 = this.evalMessage(data.suffix4, cache) || '';
+ const formattedSuffix4 = suffix4 ? ` ${suffix4}` : '';
+
+ const boldNick = Boolean(data.boldNick);
+ const italicNick = Boolean(data.italicNick);
+ const strikethroughNick = Boolean(data.strikethroughNick);
+ const codeNick = Boolean(data.codeNick);
+ const boldNumbers = Boolean(data.boldNumbers);
+ const boldData = Boolean(data.boldData);
+ const boldSuffix = Boolean(data.boldSuffix);
+ const italicNumbers = Boolean(data.italicNumbers);
+ const italicData = Boolean(data.italicData);
+ const italicSuffix = Boolean(data.italicSuffix);
+ const strikethroughNumbers = Boolean(data.strikethroughNumbers);
+ const strikethroughData = Boolean(data.strikethroughData);
+ const strikethroughSuffix = Boolean(data.strikethroughSuffix);
+ const codeNumbers = Boolean(data.codeNumbers);
+ const codeData = Boolean(data.codeData);
+ const codeSuffix = Boolean(data.codeSuffix);
+
+ let playerData;
+ try {
+ playerData = JSON.parse(fs.readFileSync(filePath, 'utf8'));
+ } catch (err) {
+ console.error('Error reading the players.json file:', err);
+ return this.callNextAction(cache);
+ }
+
+ const guild = cache.interaction.guild;
+ if (!guild) {
+ console.error('Guild is undefined. Cannot access members.');
+ return this.callNextAction(cache);
+ }
+
+ const allMembers = await guild.members.fetch();
+
+ const validPlayers = Object.entries(playerData).filter(([userId, data]) => {
+ const member = allMembers.get(userId);
+ if (!member) return false;
+ if (filterBots && member.user.bot) return false;
+ return data[dataName] !== undefined && data[dataName] !== null;
+ });
+
+ if (validPlayers.length === 0) {
+ this.storeValue(
+ 'No members to display in the ranking.',
+ parseInt(data.storage, 10),
+ this.evalMessage(data.varName, cache),
+ cache,
+ );
+ return this.callNextAction(cache);
+ }
+
+ const sortedPlayers = validPlayers.sort(([, a], [, b]) =>
+ reversedOrder ? a[dataName] - b[dataName] : b[dataName] - a[dataName],
+ );
+ const topPlayers = sortedPlayers.slice(0, topCount);
+
+ let response = '';
+
+ if (enableRankingTitle) {
+ response += `**${rankingTitle}**\n\n`;
+ }
+
+ topPlayers.forEach(([userId, data], index) => {
+ const prefix = usePrefix ? '> ' : '';
+ let number = useNumbers ? `${index + 1}. ` : '';
+ let value = showValues ? `${data[dataName]}` : '';
+ let formattedSuffix = suffix ? ` ${suffix}` : '';
+ let formattedNick = `<@${userId}>`;
+
+ if (boldNumbers && useNumbers) number = `**${number}**`;
+ if (boldData && showValues) value = `**${value}**`;
+ if (boldSuffix && suffix) formattedSuffix = ` **${suffix}**`;
+
+ if (italicNumbers && useNumbers) number = `*${number}*`;
+ if (italicData && showValues) value = `*${value}*`;
+ if (italicSuffix && suffix) formattedSuffix = ` *${suffix}*`;
+
+ if (strikethroughNumbers && useNumbers) number = `~~${number}~~`;
+ if (strikethroughData && showValues) value = `~~${value}~~`;
+ if (strikethroughSuffix && suffix) formattedSuffix = ` ~~${suffix}~~`;
+
+ if (codeNumbers && useNumbers) number = `\`${number}\``;
+ if (codeData && showValues) value = `\`${value}\``;
+ if (codeSuffix && suffix) formattedSuffix = ` \`${suffix}\``;
+
+ if (boldNick) formattedNick = `**${formattedNick}**`;
+ if (italicNick) formattedNick = `*${formattedNick}*`;
+ if (strikethroughNick) formattedNick = `~~${formattedNick}~~`;
+ if (codeNick) formattedNick = `\`${formattedNick}\``;
+
+ response += `${formattedSuffix} ${prefix}${number}${formattedSuffix2}${formattedNick} ${formattedSuffix3} ${value}${formattedSuffix4}\n`;
+ });
+
+ if (response === '\n') {
+ response = 'No members to display in the ranking.';
+ }
+
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ this.storeValue(response, storage, varName, cache);
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/transfer_variable.js b/actions/transfer_variable.js
new file mode 100644
index 000000000..4bb8525b4
--- /dev/null
+++ b/actions/transfer_variable.js
@@ -0,0 +1,124 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Transfer Variable',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const storeTypes = presets.variables;
+ return `${storeTypes[parseInt(data.storage, 10)]} (${data.varName}) -> ${
+ storeTypes[parseInt(data.storage2, 10)]
+ } (${data.varName2})`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['storage', 'varName', 'storage2', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+ const var1 = this.getVariable(storage, varName, cache);
+ if (!var1) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const storage2 = parseInt(data.storage2, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const var2 = this.getVariable(storage2, varName2, cache);
+ if (!var2) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ this.storeValue(var1, storage2, varName2, cache);
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {},
+};
diff --git a/actions/transform_list.js b/actions/transform_list.js
new file mode 100644
index 000000000..ba3ab1bc6
--- /dev/null
+++ b/actions/transform_list.js
@@ -0,0 +1,180 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Transform List',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Lists and Loops',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const list = presets.lists;
+ return `Transform ${list[parseInt(data.list, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'List'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['list', 'varName', 'transform', 'null', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Source List
+
+
+
+ Variable Name
+
+
+
+
+
+
+
+
+ Transform Eval
+
+
+
+ Null Value
+
+
+
+
+
+
+`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {
+ const { glob, document } = this;
+
+ glob.listChange(document.getElementById('list'), 'varNameContainer');
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const list = (await this.getListFromData(data.list, data.varName, cache)) ?? [];
+
+ const result = [];
+ const code = this.evalMessage(data.transform, cache);
+ const nullVal = this.evalMessage(data.null, cache);
+ let defaultVal;
+
+ try {
+ defaultVal = eval(nullVal);
+ } catch (e) {
+ this.displayError(data, cache, e);
+ defaultVal = '';
+ }
+
+ for (let i = 0; i < list.length; i++) {
+ try {
+ const val = eval(code);
+ if (val) {
+ result.push(val);
+ } else if (defaultVal) {
+ result.push(defaultVal);
+ }
+ } catch (e) {
+ this.displayError(data, cache, e);
+ if (defaultVal) {
+ result.push(defaultVal);
+ }
+ }
+ }
+
+ if (result) {
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage2 = parseInt(data.storage, 10);
+ this.storeValue(result, storage2, varName2, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/unban_member.js b/actions/unban_member.js
new file mode 100644
index 000000000..83eb25fdf
--- /dev/null
+++ b/actions/unban_member.js
@@ -0,0 +1,120 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Unban Member',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Member Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ return `${presets.getMemberText(data.member, data.varName)}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'reason'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Reason
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const server = cache.server;
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+
+ if (Array.isArray(member)) {
+ this.callListFunc(member, 'unban', [server, this.evalMessage(data.reason, cache)])
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else if (member?.id && server?.bans) {
+ server.bans
+ .remove(member.id, this.evalMessage(data.reason, cache))
+ .then(() => this.callNextAction(cache))
+ .catch((err) => this.displayError(data, cache, err));
+ } else {
+ this.callNextAction(cache);
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/upload_image_to_imgur.js b/actions/upload_image_to_imgur.js
new file mode 100644
index 000000000..18f111bb8
--- /dev/null
+++ b/actions/upload_image_to_imgur.js
@@ -0,0 +1,96 @@
+module.exports = {
+ name: 'Upload Image To Imgur',
+ section: 'Other Stuff',
+
+ subtitle() {
+ return `Upload Image to Imgur`;
+ },
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName2, 'Image URL'];
+ },
+
+ fields: ['clientID', 'clientSecret', 'refreshToken', 'imageURL', 'storage', 'varName2'],
+
+ html() {
+ return `
+
+
+
+ Client ID:
+
+
+
+ Client Secret (optional):
+
+
+
+ Refresh Token (optional):
+
+
+
+
+
+ Image URL:
+
+
+
+ Store In:
+
+
+
+
+
+ Variable Name:
+
+
+
`;
+ },
+
+ init() {},
+
+ action(cache) {
+ const { ImgurClient } = this.getMods().require('imgur');
+ const data = cache.actions[cache.index];
+ const clientID = this.evalMessage(data.clientID, cache);
+ const clientSecret = this.evalMessage(data.clientSecret, cache);
+ const refreshToken = this.evalMessage(data.refreshToken, cache);
+ const imageURL = this.evalMessage(data.imageURL, cache);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ const storage = parseInt(data.storage, 10);
+
+ if (!clientID || !imageURL) {
+ console.error('Client ID or Image URL is missing!');
+ return this.callNextAction(cache);
+ }
+
+ const client = new ImgurClient({
+ clientId: clientID,
+ clientSecret: clientSecret || undefined,
+ refreshToken: refreshToken || undefined,
+ });
+
+ client
+ .upload({
+ image: imageURL,
+ type: 'url',
+ })
+ .then((response) => {
+ const uploadedImageUrl = response.data.link;
+ this.storeValue(uploadedImageUrl, storage, varName2, cache);
+ this.callNextAction(cache);
+ })
+ .catch((err) => {
+ console.error('Error uploading image to Imgur:', err.message);
+ this.callNextAction(cache);
+ });
+ },
+ mod() {},
+};
diff --git a/actions/user_banner_MOD.js b/actions/user_banner_MOD.js
new file mode 100644
index 000000000..e249d8b51
--- /dev/null
+++ b/actions/user_banner_MOD.js
@@ -0,0 +1,165 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'User Banner',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'DBM-Extended',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const info = ['Member Banner'];
+ return `${presets.getMemberText(data.member, data.varName)} - ${info[parseInt(data.info, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ //
+ // Stores the relevant variable info for the editor.
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ const info = parseInt(data.info, 10);
+ let dataType = 'Unknown Type';
+ switch (info) {
+ case 0:
+ dataType = 'Image URL';
+ break;
+ }
+ return [data.varName2, dataType];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.1.5',
+ preciseCheck: true,
+ author: 'DBM Extended',
+ authorUrl: 'https://github.com/DBM-Extended/mods',
+ downloadURL: 'https://github.com/DBM-Extended/mods/tree/main/actions/user_banner.js',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['member', 'varName', 'info', 'storage', 'varName2'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+
+
+
+ Source Info
+
+
+
+
+
+ `;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ const member = await this.getMemberFromData(data.member, data.varName, cache);
+
+ if (!member) {
+ this.callNextAction(cache);
+ return;
+ }
+
+ const info = parseInt(data.info, 10);
+
+ let result;
+ switch (info) {
+ case 0:
+ if (member) {
+ await member.user.fetch();
+ result = member.user.bannerURL({ fomart: 'png', size: 4096, dynamic: true });
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (result !== undefined) {
+ const storage = parseInt(data.storage, 10);
+ const varName2 = this.evalMessage(data.varName2, cache);
+ this.storeValue(result, storage, varName2, cache);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/wait.js b/actions/wait.js
new file mode 100644
index 000000000..0c0e08a25
--- /dev/null
+++ b/actions/wait.js
@@ -0,0 +1,129 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ //
+ // This is the name of the action displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Wait',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ //
+ // This is the section the action will fall into.
+ // ---------------------------------------------------------------------
+
+ section: 'Other Stuff',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ //
+ // This function generates the subtitle displayed next to the name.
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const measurements = ['Milliseconds', 'Seconds', 'Minutes', 'Hours'];
+ return `${data.time} ${measurements[parseInt(data.measurement, 10)]}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ //
+ // Helps check for updates and provides info if a custom mod.
+ // If this is a third-party mod, please set "author" and "authorUrl".
+ //
+ // It's highly recommended "preciseCheck" is set to false for third-party mods.
+ // This will make it so the patch version (0.0.X) is not checked.
+ // ---------------------------------------------------------------------
+
+ meta: { version: '2.2.0', preciseCheck: true, author: null, authorUrl: null, downloadUrl: null },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ //
+ // These are the fields for the action. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the action's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['time', 'measurement'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ //
+ // This function returns a string containing the HTML used for
+ // editing actions.
+ //
+ // The "isEvent" parameter will be true if this action is being used
+ // for an event. Due to their nature, events lack certain information,
+ // so edit the HTML to reflect this.
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
+
+ Measurement
+
+
+
+ Amount
+
+
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Editor Init Code
+ //
+ // When the HTML is first applied to the action editor, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init() {},
+
+ // ---------------------------------------------------------------------
+ // Action Bot Function
+ //
+ // This is the function for the action within the Bot's Action class.
+ // Keep in mind event calls won't have access to the "msg" parameter,
+ // so be sure to provide checks for variable existence.
+ // ---------------------------------------------------------------------
+
+ action(cache) {
+ const data = cache.actions[cache.index];
+ let time = parseInt(this.evalMessage(data.time, cache), 10);
+ const type = parseInt(data.measurement, 10);
+ switch (type) {
+ case 1:
+ time *= 1e3;
+ break;
+ case 2:
+ time *= 1e3 * 60;
+ break;
+ case 3:
+ time *= 1e3 * 60 * 60;
+ break;
+ default:
+ return this.callNextAction(cache);
+ }
+ setTimeout(() => this.callNextAction(cache), time).unref();
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ // ---------------------------------------------------------------------
+
+ mod() {},
+};
diff --git a/actions/write_in_json_file_MOD.js b/actions/write_in_json_file_MOD.js
new file mode 100644
index 000000000..215076db8
--- /dev/null
+++ b/actions/write_in_json_file_MOD.js
@@ -0,0 +1,445 @@
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Action Name
+ // ---------------------------------------------------------------------
+
+ name: 'Write In Json File',
+
+ // ---------------------------------------------------------------------
+ // Action Section
+ // ---------------------------------------------------------------------
+
+ section: 'Json Control',
+
+ // ---------------------------------------------------------------------
+ // Action Subtitle
+ // ---------------------------------------------------------------------
+
+ subtitle(data, presets) {
+ const filePath = data.filePath || 'file.json';
+ return `Edit JSON File: ${filePath}`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Meta Data
+ // ---------------------------------------------------------------------
+
+ meta: {
+ version: '2.2.0',
+ preciseCheck: true,
+ author: 'Shadow',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ downloadUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Storage Function
+ // ---------------------------------------------------------------------
+
+ variableStorage(data, varType) {
+ const type = parseInt(data.storage, 10);
+ if (type !== varType) return;
+ return [data.varName, 'File Path'];
+ },
+
+ // ---------------------------------------------------------------------
+ // Action Fields
+ // ---------------------------------------------------------------------
+
+ fields: ['filePath', 'action', 'key', 'value', 'index', 'newName', 'storage', 'varName'],
+
+ // ---------------------------------------------------------------------
+ // Command HTML
+ // ---------------------------------------------------------------------
+
+ html(isEvent, data) {
+ return `
+
`;
+ },
+
+ // ---------------------------------------------------------------------
+ // Extension Dialog Init Code
+ //
+ // When the HTML is first applied to the extension dialog, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init(document, globalObject) {
+ const PRIVILEGED = ['GUILD_PRESENCES', 'GUILD_MEMBERS', 'MESSAGE_CONTENT'];
+ function EnableAll(enable) {
+ for (let i = 0; i < INTENTS.length; i++) {
+ const val = document.getElementById(INTENTS[i]);
+ val.disabled = !enable;
+ }
+ }
+ document.getElementById('All').onclick = function () {
+ EnableAll(false);
+ for (let i = 0; i < INTENTS.length; i++) {
+ const val = document.getElementById(INTENTS[i]);
+ val.checked = true;
+ }
+ };
+ document.getElementById('NonPrivileged').onclick = function () {
+ EnableAll(false);
+ for (let i = 0; i < INTENTS.length; i++) {
+ const val = document.getElementById(INTENTS[i]);
+ val.checked = PRIVILEGED.indexOf(INTENTS[i]) === -1;
+ }
+ };
+ document.getElementById('Custom').onclick = function () {
+ EnableAll(true);
+ };
+ if (document.getElementById('All').checked) {
+ document.getElementById('All').onclick();
+ }
+ if (document.getElementById('NonPrivileged').checked) {
+ document.getElementById('NonPrivileged').onclick();
+ }
+ if (document.getElementById('Custom').checked) {
+ document.getElementById('Custom').onclick();
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Extension Dialog Close Code
+ //
+ // When the dialog is closed, this is called. Use it to save the data.
+ // ---------------------------------------------------------------------
+
+ close(document, data, globalObject) {
+ let result = 0;
+ if (document.getElementById('All').checked) {
+ result = -1;
+ } else if (document.getElementById('NonPrivileged').checked) {
+ result = -2;
+ } else {
+ for (let i = 0; i < INTENTS.length; i++) {
+ const val = document.getElementById(INTENTS[i]).checked;
+ if (val) result |= 1 << i;
+ }
+ }
+ data.intents = result;
+ },
+
+ // ---------------------------------------------------------------------
+ // Editor Extension Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ //
+ // This is absolutely necessary for editor extensions since it
+ // allows us to setup modifications for the necessary functions
+ // we want to change.
+ //
+ // The client object can be retrieved from: `const bot = DBM.Bot.bot;`
+ // Classes can be retrieved also using it: `const { Actions, Event } = DBM;`
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {
+ DBM.Bot.intents = function () {
+ const intentData = DBM.Files?.data.settings?.['Bot Intents'];
+ const intents = intentData?.customData?.['Bot Intents']?.intents;
+ let base;
+ if (!intentData || typeof intents === 'undefined') {
+ base = DBM.Bot.NON_PRIVILEGED_INTENTS;
+ } else if (intents === -1) {
+ base = DBM.Bot.ALL_INTENTS;
+ } else if (intents === -2) {
+ base = DBM.Bot.NON_PRIVILEGED_INTENTS;
+ } else {
+ base = intents;
+ }
+ const textCmdCount = typeof DBM.Bot._textCommandCount === 'number' ? DBM.Bot._textCommandCount : 0;
+ const mc = DBM.Bot._Intents && DBM.Bot._Intents.MessageContent;
+ if (textCmdCount > 0 && mc && (base & mc) !== mc) {
+ base |= mc;
+ }
+ return base;
+ };
+ },
+};
diff --git a/extensions/bot_partials.js b/extensions/bot_partials.js
new file mode 100644
index 000000000..1bf6f0fd9
--- /dev/null
+++ b/extensions/bot_partials.js
@@ -0,0 +1,201 @@
+// ---------------------------------------------------------------------
+// Defining global array of partials so they are not repeated later on.
+// ---------------------------------------------------------------------
+const PARTIALS = ['USER', 'GUILD_MEMBER', 'MESSAGE', 'REACTION', 'CHANNEL'];
+
+module.exports = {
+ // ---------------------------------------------------------------------
+ // Editor Extension Name
+ //
+ // This is the name of the editor extension displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Bot Partials',
+
+ // ---------------------------------------------------------------------
+ // Is Editor Extension
+ //
+ // Must be true to appear in the main editor context menu.
+ // This means there will only be one copy of this data per project.
+ // ---------------------------------------------------------------------
+
+ isEditorExtension: true,
+
+ // ---------------------------------------------------------------------
+ // Save Button Text
+ //
+ // Customizes the text of the "Save Extension" at the bottom
+ // of the extension window.
+ // ---------------------------------------------------------------------
+
+ saveButtonText: 'Save Partials',
+
+ // ---------------------------------------------------------------------
+ // Extension Fields
+ //
+ // These are the fields for the extension. These fields are customized
+ // by creating elements with corresponding Ids in the HTML. These
+ // are also the names of the fields stored in the command's/event's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: [],
+
+ // ---------------------------------------------------------------------
+ // Default Fields
+ //
+ // The default values of the fields.
+ // ---------------------------------------------------------------------
+
+ defaultFields: {
+ partials: [],
+ },
+
+ // ---------------------------------------------------------------------
+ // Extension Dialog Size
+ //
+ // Returns the size of the extension dialog.
+ // ---------------------------------------------------------------------
+
+ size() {
+ return { width: 320, height: 190 };
+ },
+
+ // ---------------------------------------------------------------------
+ // Extension HTML
+ //
+ // This function returns a string containing the HTML used for
+ // the context menu dialog.
+ // ---------------------------------------------------------------------
+
+ html(data) {
+ if (!data.partials) {
+ data.partials = [];
+ }
+
+ let result = `
+
+
+
+
+
+
+
+
+ 0 ? 'checked' : ''
+ }>
+
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ const partialNames = ['User', 'Guild Member', 'Message', 'Reaction', 'Channel (Enables DMs)'];
+ for (let i = 0; i < PARTIALS.length; i++) {
+ const partial = PARTIALS[i];
+ result += `
+
+
+
+
+ ${i % 2 === 1 ? `
` : ''}
+ `;
+ }
+
+ result += `
`;
+
+ return result;
+ },
+
+ // ---------------------------------------------------------------------
+ // Extension Dialog Init Code
+ //
+ // When the HTML is first applied to the extension dialog, this code
+ // is also run. This helps add modifications or setup reactionary
+ // functions for the DOM elements.
+ // ---------------------------------------------------------------------
+
+ init(document, globalObject) {
+ function EnableAll(enable) {
+ for (let i = 0; i < PARTIALS.length; i++) {
+ const val = document.getElementById(PARTIALS[i]);
+ val.disabled = !enable;
+ }
+ }
+ document.getElementById('None').onclick = function () {
+ EnableAll(false);
+ for (let i = 0; i < PARTIALS.length; i++) {
+ const val = document.getElementById(PARTIALS[i]);
+ val.checked = false;
+ }
+ };
+ document.getElementById('Custom').onclick = function () {
+ EnableAll(true);
+ };
+ if (document.getElementById('Custom').checked) {
+ document.getElementById('Custom').onclick();
+ } else {
+ document.getElementById('None').checked = true;
+ document.getElementById('None').onclick();
+ }
+ },
+
+ // ---------------------------------------------------------------------
+ // Extension Dialog Close Code
+ //
+ // When the dialog is closed, this is called. Use it to save the data.
+ // ---------------------------------------------------------------------
+
+ close(document, data, globalObject) {
+ const result = [];
+ if (document.getElementById('Custom').checked) {
+ for (let i = 0; i < PARTIALS.length; i++) {
+ const partial = PARTIALS[i];
+ const val = document.getElementById(partial).checked;
+ if (val) result.push(partial);
+ }
+ }
+ data.partials = result;
+ },
+
+ // ---------------------------------------------------------------------
+ // Editor Extension Bot Mod
+ //
+ // Upon initialization of the bot, this code is run. Using the bot's
+ // DBM namespace, one can add/modify existing functions if necessary.
+ // In order to reduce conflicts between mods, be sure to alias
+ // functions you wish to overwrite.
+ //
+ // This is absolutely necessary for editor extensions since it
+ // allows us to setup modifications for the necessary functions
+ // we want to change.
+ //
+ // The client object can be retrieved from: `const bot = DBM.Bot.bot;`
+ // Classes can be retrieved also using it: `const { Actions, Event } = DBM;`
+ // ---------------------------------------------------------------------
+
+ mod(DBM) {
+ DBM.Bot.usePartials = function () {
+ const partialData = DBM.Files?.data.settings?.['Bot Partials'];
+ const partials = partialData?.customData?.['Bot Partials']?.partials;
+ return partials?.length > 0;
+ };
+
+ DBM.Bot.partials = function () {
+ const partialData = DBM.Files?.data.settings?.['Bot Partials'];
+ const partials = partialData?.customData?.['Bot Partials']?.partials;
+ return partials;
+ };
+ },
+};
diff --git a/extensions/command_info/README.md b/extensions/command_info/README.md
deleted file mode 100644
index a7b5f5be6..000000000
--- a/extensions/command_info/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-adds a custom command_info field to each command with a provided raw data for an automatic help command.
-
-
-
diff --git a/extensions/command_info/command_info_EXT.js b/extensions/command_info_EXT.js
similarity index 100%
rename from extensions/command_info/command_info_EXT.js
rename to extensions/command_info_EXT.js
diff --git a/extensions/dashboard_EXT.js b/extensions/dashboard_EXT.js
new file mode 100644
index 000000000..3941dcde9
--- /dev/null
+++ b/extensions/dashboard_EXT.js
@@ -0,0 +1,3932 @@
+const fs = require('fs');
+const path = require('path');
+const util = require('util');
+
+const DASHBOARD_LOG_DIR = path.resolve(__dirname, '../../../logs');
+const DASHBOARD_ERROR_LOG = path.join(DASHBOARD_LOG_DIR, 'dashboard.newstargeted.com.error_log');
+const duplicateWarningCache = new Set();
+
+const originalConsoleError = console.error.bind(console);
+const originalConsoleWarn = console.warn.bind(console);
+
+function serializeLogArgs(args) {
+ return args
+ .map((arg) => {
+ if (typeof arg === 'string') {
+ return arg;
+ }
+ if (arg instanceof Error) {
+ return `${arg.stack || arg.message}`;
+ }
+ try {
+ return util.inspect(arg, { depth: 5, colors: false });
+ } catch (inspectError) {
+ return `[unserializable:${inspectError.message}]`;
+ }
+ })
+ .join(' ');
+}
+
+function appendDashboardLog(level, args) {
+ try {
+ if (!fs.existsSync(DASHBOARD_LOG_DIR)) {
+ fs.mkdirSync(DASHBOARD_LOG_DIR, { recursive: true, mode: 0o755 });
+ }
+
+ const timestamp = new Date().toISOString();
+ const message = serializeLogArgs(args);
+ const line = `[${timestamp}] [${level}] ${message}\n`;
+
+ fs.appendFile(DASHBOARD_ERROR_LOG, line, { encoding: 'utf8' }, (err) => {
+ if (err) {
+ originalConsoleError('Unable to append dashboard log:', err);
+ }
+ });
+ } catch (loggingError) {
+ originalConsoleError('Dashboard logging failure:', loggingError);
+ }
+}
+
+if (!global.__NT_CANARY_LOGGER__) {
+ global.__NT_CANARY_LOGGER__ = true;
+
+ console.error = (...args) => {
+ originalConsoleError(...args);
+ appendDashboardLog('ERROR', args);
+ };
+
+ console.warn = (...args) => {
+ const messageKey = serializeLogArgs(args);
+ if (messageKey.includes('already exists!')) {
+ if (duplicateWarningCache.has(messageKey)) {
+ return;
+ }
+ duplicateWarningCache.add(messageKey);
+ }
+ originalConsoleWarn(...args);
+ appendDashboardLog('WARN', args);
+ };
+
+ process.on('unhandledRejection', (reason, promise) => {
+ appendDashboardLog('UNHANDLED_REJECTION', [reason, { promise }]);
+ originalConsoleError('Unhandled promise rejection:', reason);
+ });
+
+ process.on('uncaughtException', (error) => {
+ appendDashboardLog('UNCAUGHT_EXCEPTION', [error]);
+ originalConsoleError('Uncaught exception:', error);
+ });
+}
+
+let resolvedFetch = typeof global.fetch === 'function' ? global.fetch.bind(global) : null;
+const fetchModulePromise = resolvedFetch
+ ? Promise.resolve(resolvedFetch)
+ : import('node-fetch')
+ .then((module) => {
+ const fetchFn = module.default || module;
+ if (typeof fetchFn !== 'function') {
+ throw new Error('node-fetch did not export a function');
+ }
+ return fetchFn;
+ })
+ .catch((error) => {
+ appendDashboardLog('ERROR', ['Failed to initialize fetch polyfill:', error]);
+ return null;
+ });
+
+const fetchProxy = (...args) => {
+ if (resolvedFetch) {
+ return resolvedFetch(...args);
+ }
+ return fetchModulePromise.then((fetchFn) => {
+ if (!fetchFn) {
+ throw new Error('Fetch polyfill failed to load.');
+ }
+ resolvedFetch = fetchFn;
+ return fetchFn(...args);
+ });
+};
+
+const enforceFetchProxy = () => {
+ if (global.fetch !== fetchProxy) {
+ global.fetch = fetchProxy;
+ }
+};
+
+enforceFetchProxy();
+setInterval(enforceFetchProxy, 60000);
+
+try {
+ const { EmbedBuilder } = require('discord.js');
+ if (EmbedBuilder && !EmbedBuilder.prototype.__ntRandomColorPatch) {
+ const originalSetColor = EmbedBuilder.prototype.setColor;
+ EmbedBuilder.prototype.setColor = function patchedSetColor(color) {
+ if (typeof color === 'string' && color.toUpperCase() === 'RANDOM') {
+ const randomColor = Math.floor(Math.random() * 0xffffff);
+ return originalSetColor.call(this, randomColor);
+ }
+ return originalSetColor.call(this, color);
+ };
+ EmbedBuilder.prototype.__ntRandomColorPatch = true;
+ }
+} catch (embedError) {
+ appendDashboardLog('WARN', ['Unable to apply EmbedBuilder color patch:', embedError.message]);
+}
+
+module.exports = {
+ /*
+ - Author: Great Plains Modding
+ - Version: 1.1.1
+ - GitHub: https://github.com/greatplainsmodding
+ - Description: Contains multiple stuff needed for my mods / extensions / events.
+ */
+
+ authors: ['Great Plains Modding'],
+ version: '1.1.1',
+ changeLog: '',
+ shortDescription: 'Discord Bot Maker Dashboard.',
+ longDescription: '',
+ requiredNodeModules: [],
+
+ // ---------------------------------------------------------------------
+ // Editor Extension Name
+ //
+ // This is the name of the editor extension displayed in the editor.
+ // ---------------------------------------------------------------------
+
+ name: 'Bot Dashboard',
+
+ // ---------------------------------------------------------------------
+ // Is Command Extension
+ //
+ // Must be true to appear in "command" context menu.
+ // This means each "command" will hold its own copy of this data.
+ // ---------------------------------------------------------------------
+
+ isCommandExtension: false,
+
+ // ---------------------------------------------------------------------
+ // Is Event Extension
+ //
+ // Must be true to appear in "event" context menu.
+ // This means each "event" will hold its own copy of this data.
+ // ---------------------------------------------------------------------
+
+ isEventExtension: false,
+
+ // ---------------------------------------------------------------------
+ // Is Editor Extension
+ //
+ // Must be true to appear in the main editor context menu.
+ // This means there will only be one copy of this data per project.
+ // ---------------------------------------------------------------------
+
+ isEditorExtension: true,
+
+ // ---------------------------------------------------------------------
+ // Extension Fields
+ //
+ // These are the fields for the extension. These fields are customized
+ // by creating elements with corresponding IDs in the HTML. These
+ // are also the names of the fields stored in the command's/event's JSON data.
+ // ---------------------------------------------------------------------
+
+ fields: ['port', 'clientSecret', 'callbackURLs', 'owner', 'supportServer'],
+
+ // ---------------------------------------------------------------------
+ // Default Fields
+ //
+ // The default values of the fields.
+ // ---------------------------------------------------------------------
+
+ defaultFields: {
+ port: (() => {
+ try {
+ const config = require(require('path').join(__dirname, 'dashboard_EXT', 'config.json'));
+ return config.port || 3000;
+ } catch {
+ return 3000;
+ }
+ })(),
+ clientSecret: (() => {
+ try {
+ const config = require(require('path').join(__dirname, 'dashboard_EXT', 'config.json'));
+ return config.clientSecret || '';
+ } catch {
+ return '';
+ }
+ })(),
+ callbackURLs: (() => {
+ try {
+ const config = require(require('path').join(__dirname, 'dashboard_EXT', 'config.json'));
+ return config.callbackURLs || [];
+ } catch {
+ return [];
+ }
+ })(),
+ owner: (() => {
+ try {
+ const config = require(require('path').join(__dirname, 'dashboard_EXT', 'config.json'));
+ // Convert ownerIds array to comma-separated string for the form
+ if (Array.isArray(config.ownerIds) && config.ownerIds.length > 0) {
+ return config.ownerIds.join(', ');
+ }
+ // Fallback to owner if ownerIds doesn't exist
+ if (Array.isArray(config.owner)) {
+ return config.owner.join(', ');
+ }
+ return config.owner || '';
+ } catch {
+ return '';
+ }
+ })(),
+ supportServer: (() => {
+ try {
+ const config = require(require('path').join(__dirname, 'dashboard_EXT', 'config.json'));
+ return config.supportServer || '';
+ } catch {
+ return '';
+ }
+ })(),
+ },
+
+ // ---------------------------------------------------------------------
+ // Extension Dialog Size
+ //
+ // Returns the size of the extension dialog.
+ // ---------------------------------------------------------------------
+
+ size() {
+ return {
+ width: 700,
+ height: 620,
+ };
+ },
+
+ // ---------------------------------------------------------------------
+ // Extension HTML
+ //
+ // This function returns a string containing the HTML used for
+ // the context menu dialog.
+ // ---------------------------------------------------------------------
+
+ html(data) {
+ try {
+ return `
+
+ <%- include('../../../views/shared/components/section-header', {
+ badge: 'Highlights',
+ title: 'Everything you need to keep your community thriving',
+ description: 'From enterprise security to playful engagement tools, the News Targeted Bot comes stacked with modules you can shape to your server’s identity.'
+ }) %>
+
+
+ <% const features = Array.isArray(data.features) && data.features.length ? data.features : [
+ { name: 'Enterprise Security', description: 'Rate limiting, granular permissions, and a full audit trail keep your community safe 24/7.' },
+ { name: 'Live Analytics', description: 'Instantly gauge server performance with real-time charts, member insights, and actionable metrics.' },
+ { name: 'Automations', description: 'Automated welcomes, moderation queues, and announcement scheduling reduce repetitive work.' },
+ { name: 'Music & Entertainment', description: 'High fidelity audio, playlists, and built-in fun commands to energise your members.' },
+ { name: 'Powerful Integrations', description: 'Connect with RSS, webhooks, and custom APIs to broadcast content everywhere.' },
+ { name: 'Owner-Grade Controls', description: 'Fine-tuned access controls, owner-only settings views, and configurable admin workflows.' }
+ ]; %>
+ <% const featureIcons = ['fa-shield-alt','fa-chart-line','fa-robot','fa-music','fa-plug','fa-crown']; %>
+
+ <% features.slice(0, 6).forEach((feature, index) => { %>
+
+
+
+
+
<%= feature.name %>
+
<%= feature.description %>
+
+ <% }); %>
+
+
+
+
+
+
+ <%- include('../../../views/shared/components/section-header', {
+ badge: 'Control Center',
+ title: 'Manage every server, command, and workflow from one place',
+ description: 'Jump straight into actionable panels, configure automations, and review activity without touching a line of code.'
+ }) %>
+
+
+
+
+
+
+
Visual Server Overview
+
Toggle between servers you manage, monitor key health metrics, and resolve incidents before members notice.
+ <%- include('../../../views/shared/components/hero', {
+ title: 'Ready to modernise your server?',
+ subtitle: 'Deploy the News Targeted Bot today and give your moderators, owners, and members a premium experience across every device.',
+ actions: ctaActions,
+ panel: true
+ }) %>
+