Readd
Some checks failed
Deploy bot / build-and-deploy (push) Failing after 2s

This commit is contained in:
2025-08-26 00:28:59 +02:00
commit 7a87b284af
40 changed files with 3681 additions and 0 deletions

39
bot/commands/bonus.js Normal file
View File

@ -0,0 +1,39 @@
exports.name = "bonus";
exports.description =
":star: Sums and calculates bonus for player stat numbers.";
exports.usage =
"CLIENT_PREFIX:bonus <number> <number> [inf optional extra numbers]";
exports.example = "CLIENT_PREFIX:bonus 100 100";
exports.hidden = false;
exports.run = (client, message, args) => {
let is1nan = false;
if (!args[0])
return message.channel.send(
"Not enough arguments, consult CLIENT_PREFIX:help.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
args.forEach((arg) => {
if (isNaN(parseInt(arg))) {
is1nan = true;
}
arg = parseInt(arg);
});
if (is1nan)
return message.channel.send(
"You have provided invalid arguments to this command, please consult CLIENT_PREFIX:help.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
let sum = 0;
args.forEach((arg) => {
if (arg > 2000) arg = 2000; // just dont bother for anything higher than 2000
sum += parseInt(arg);
});
sum--;
message.channel.send(
`Will reach ${sum}, ${Math.ceil(sum * 1.4)} with bonus.`
);
};

31
bot/commands/cat.js Normal file
View File

@ -0,0 +1,31 @@
exports.name = "cat";
exports.description = ":cat: Calculates boost for cat.";
exports.usage = "CLIENT_PREFIX:cat <boost> <levels>";
exports.example = "CLIENT_PREFIX:cat 80 120";
exports.hidden = false;
exports.run = (client, message, args) => {
if (!args[0] || !args[1])
return message.channel.send(
"Not enough arguments, consult CLIENT_PREFIX:help.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
let boost = parseInt(args[0]);
let levels = parseInt(args[1]);
if (isNaN(boost) || isNaN(levels))
return message.channel.send(
"Boost or levels is not a number. Consult CLIENT_PREFIX:help.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
let extraboost = Math.floor(levels / 3 - 3);
let players = Math.floor(levels / 29) + 1;
if (players > 4) players = 4;
message.channel.send(
`Your cat's boost should be atleast **${
boost + extraboost
}**. It will boost atleast **${players}** players.`
);
};

32
bot/commands/cb.js Normal file
View File

@ -0,0 +1,32 @@
const log = require("../log");
exports.name = "cb";
exports.description =
":crossed_swords: Calculate calamity blade damage taking in to account projectile speed.";
exports.usage = "CLIENT_PREFIX:cb <damage> <ups> [projectile speed]";
exports.example = "CLIENT_PREFIX:cb 10000 250 10000";
exports.hidden = false;
exports.run = (client, message, args) => {
if (!args[0] || !args[1])
return message.channel.send(
"Not enough arguments, consult CLIENT_PREFIX:help.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
let cb = parseInt(args[0]);
let ups = parseInt(args[1]);
if (isNaN(cb) || isNaN(ups))
return message.channel.send("Damage or ups should be a number.");
let initialspeed = null;
if (args[2]) {
initialspeed = parseInt(args[2]);
if (isNaN(initialspeed))
return message.channel.send("Projectile speed should be a number.");
initialspeed = 30000 - initialspeed;
let t = Math.ceil(initialspeed / 1200);
log.info(t);
ups = ups - t;
}
let resnum = cb + ups * 192;
message.channel.send(`Your Calamity Blade will hit **${resnum}** damage.`);
};

69
bot/commands/estimate.js Normal file
View File

@ -0,0 +1,69 @@
const log = require("../log");
exports.name = "estimate";
exports.description =
":money_with_wings: Give an estimated price of certain items in cv.";
exports.usage =
"CLIENT_PREFIX:estimate [summary of item you want the price of]";
exports.example =
"CLIENT_PREFIX:estimate 1600 ab2\nCLIENT_PREFIX:estimate 1100 thp\nCLIENT_PREFIX:estimate 2400 app builder staff\n(you can also include `showtable` anywhere to show raw price data)\n(always put number first, do not put conflicting data to avoid confusion)";
exports.hidden = false;
exports.run = async (client, message, args) => {
if (!args[0]) {
return fetch(client.sharedEndpoint + "estimate" + "?getPriceTable=true")
.then((d) => d.json())
.then((tbl) => {
return message.channel.send(
`Available items in pricing table:\n\`\`\`\n${tbl.join(
"\n"
)}\`\`\`\nFor usage, consult \`CLIENT_PREFIX:help estimate\`
`.replaceAll("CLIENT_PREFIX:", client.prefix)
);
});
}
const combined = args.join(" ");
let showtable = combined.includes("showtable");
fetch(
client.sharedEndpoint +
"estimate" +
`?q=${combined}&showTable=` +
showtable
)
.then((d) => d.json())
.then((data) => {
if (data.error) {
return message.channel.send(data.error);
} else {
if (showtable) {
const { returnKeyWord, subtable } = data;
let res = "";
subtable.forEach((entry) => {
res +=
String(entry.number).padEnd(14, " ") +
entry.val +
"\n";
});
message.channel.send(
`Displaying data price table for \`${returnKeyWord}\`.\n\`\`\`\nGame Value\tPrice\n${res}\`\`\``
);
} else {
const {
gameValue,
estimatedPrice,
returnKeyWord,
closestInTable,
} = data;
let stringprice;
if (estimatedPrice > 499) {
stringprice = `**__${estimatedPrice}__** (atleast 1 cheater, worth auctioning)`;
} else if (estimatedPrice == 0) {
stringprice = "**0** (<:TavKeep:1179145911180480563>)";
} else {
stringprice = `**${estimatedPrice}**`;
}
message.channel.send(
`Hmm... I estimate your **${gameValue} ${returnKeyWord}** to be worth approximately ${stringprice} cv.\n*Estimation is provided through looking at past trades/price checks/sheets in DDRNG.*\n*Closest price in table: **${closestInTable.val}** cv, diff: **${closestInTable.diff}***.`
);
}
}
});
};

113
bot/commands/ev.js Normal file
View File

@ -0,0 +1,113 @@
const BASEDMG = 1e9; // absurdly high to avoid base damage bottleneck
function getHeroDamageScaling(statVal) {
return (
1.0 +
0.33 *
(Math.pow(4.0, 0.1 * 1.1) -
1.0 +
0.68 * (Math.pow(statVal + 1, 0.375 * 1.1) - 1.0))
);
}
function getAb2Scaling(statVal) {
return (
1.0 +
0.66 * (Math.pow(4.0, 0.0825) - 1.0) +
0.75 * (Math.pow(statVal + 1, 0.3375) - 1.0)
);
}
function getTotalDamage(hdmgStat, baseDamage) {
return Math.max(
Math.max(32.0, Math.max(1.0, baseDamage)) *
getHeroDamageScaling(hdmgStat) *
(1.2 * 0.8 * 0.155),
1.0
);
}
function getBeamDamage(hdmg, ab2) {
return (
getTotalDamage(hdmg, BASEDMG) * 0.6 * Math.pow(getAb2Scaling(ab2), 0.93)
);
}
/**
* Find optimal split of totalStats between hdmg and ab2
* using a binary/golden section search.
*/
function findOptimalDistribution(totalStats) {
let left = 0;
let right = totalStats;
const phi = (Math.sqrt(5) - 1) / 2; // golden ratio for faster convergence
let x1 = right - phi * (right - left);
let x2 = left + phi * (right - left);
while (Math.abs(right - left) > 1e-3) {
const f1 = getBeamDamage(x1, totalStats - x1);
const f2 = getBeamDamage(x2, totalStats - x2);
if (f1 < f2) {
left = x1;
x1 = x2;
x2 = left + phi * (right - left);
} else {
right = x2;
x2 = x1;
x1 = right - phi * (right - left);
}
}
const hdmg = (left + right) / 2;
const ab2 = totalStats - hdmg;
return {
hdmg: hdmg,
ab2: ab2,
};
}
exports.name = "ev";
exports.description =
":robot: Calculate how much hero damage/ab2 you should aim for.";
exports.usage =
"CLIENT_PREFIX:ev <hdmg> <ab2> OR CLIENT_PREFIX:ev <total stats>";
exports.example = "CLIENT_PREFIX:ev 6000 5000\nCLIENT_PREFIX:ev 10000";
exports.hidden = false;
exports.run = (client, message, args) => {
if (!args[0])
return message.channel.send(
"Not enough arguments, consult CLIENT_PREFIX:help.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
let total = parseInt(args[0]);
if (isNaN(total))
return message.channel.send(
"One of the arguments is not a number. Consult CLIENT_PREFIX:help.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
if (args[1]) {
if (isNaN(parseInt(args[1]))) {
return message.channel.send(
"One of the arguments is not a number. Consult CLIENT_PREFIX:help.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
} else total += parseInt(args[1]);
}
const distribution = findOptimalDistribution(total);
message.channel.send(
`You should aim for **${
Math.round(distribution.hdmg) - 3
}** hero damage and **${
Math.round(distribution.ab2) + 3
}** ab2. *(approximately)*`
);
};

55
bot/commands/hb.js Normal file
View File

@ -0,0 +1,55 @@
const STAT_MULT_INITIAL_AB2 = 0.66;
const STAT_MULT_FULL_AB2 = 0.75;
const STAT_EXP_INITIAL_AB2 = 0.0825;
const STAT_EXP_FULL_AB2 = 0.3375;
const ADDITIONAL_DAMAGE_MULTIPLIER = 0.25;
const ADDITIONAL_DAMAGE_EXPONENT = 0.95;
// Functions
function get_ab2_scaling(stat_val) {
return (
1.0 +
STAT_MULT_INITIAL_AB2 *
(Math.min(stat_val + 1.0, 4.0) ** STAT_EXP_INITIAL_AB2 - 1.0) +
STAT_MULT_FULL_AB2 * ((stat_val + 1.0) ** STAT_EXP_FULL_AB2 - 1.0)
);
}
function get_damage_multiplier(stat_val) {
return (
1.0 +
ADDITIONAL_DAMAGE_MULTIPLIER *
get_ab2_scaling(Math.max(stat_val, 1)) ** ADDITIONAL_DAMAGE_EXPONENT
);
}
exports.name = "hb";
exports.description = ":muscle: Calculate hero boost's damage multiplier.";
exports.usage = "CLIENT_PREFIX:hb <points>";
exports.example = "CLIENT_PREFIX:hb 5000";
exports.hidden = false;
exports.run = (client, message, args) => {
if (!args[0])
return message.channel.send(
"Not enough arguments, consult CLIENT_PREFIX:help.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
let hbPoints = parseInt(args[0]);
if (isNaN(hbPoints))
return message.channel.send(
"Given argument is not a number. Consult CLIENT_PREFIX:help.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
message.channel.send(
`With **${hbPoints}** points in your hero boost, you will boost with a **${get_damage_multiplier(
hbPoints
).toFixed(4)}** damage multiplier.`
);
};

49
bot/commands/help.js Normal file
View File

@ -0,0 +1,49 @@
const { EmbedBuilder } = require("discord.js");
exports.name = "help";
exports.description =
":scroll: Shows this message and provides insight into other commands.";
exports.usage = "CLIENT_PREFIX:help [optional other command]";
exports.example = "CLIENT_PREFIX:help res";
exports.hidden = false;
exports.run = (client, message, args) => {
let embed = new EmbedBuilder();
embed.setTitle("Commands Helper");
if (args[0]) {
const cmd = client.commands.get(args[0]);
if (!cmd)
return message.channel.send(
"Command not found, try `CLIENT_PREFIX:help` first.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
if (cmd.hidden && message.author.id != client.ownerID) return;
embed.setTitle(`Help for \`${cmd.name}\` command`);
embed.setDescription(cmd.description);
embed.addFields(
{
name: "Usage",
value: cmd.usage.replaceAll("CLIENT_PREFIX:", client.prefix),
},
{
name: "Example",
value: cmd.example.replaceAll("CLIENT_PREFIX:", client.prefix),
}
);
} else {
[...client.commands.values()]
.sort((a, b) => (a.name > b.name ? 1 : -1))
.forEach((cmd) => {
if (cmd.hidden && message.author.id != client.ownerID) return;
embed.addFields({
name: cmd.name,
value: cmd.description.replaceAll(
"CLIENT_PREFIX:",
client.prefix
),
});
});
}
embed.setColor(0x00ff00);
message.channel.send({ embeds: [embed] });
};

33
bot/commands/ms.js Normal file
View File

@ -0,0 +1,33 @@
const log = require("../log");
exports.name = "ms";
exports.description =
":tada: Calculate moon staff damage taking in to account projectile speed.";
exports.usage = "CLIENT_PREFIX:ms <elemental damage> <ups> [projectile speed]";
exports.example = "CLIENT_PREFIX:ms 10000 250 10000";
exports.hidden = false;
exports.run = (client, message, args) => {
if (!args[0] || !args[1])
return message.channel.send(
"Not enough arguments, consult CLIENT_PREFIX:help.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
let moonstaff = parseInt(args[0]);
let ups = parseInt(args[1]);
if (isNaN(moonstaff) || isNaN(ups))
return message.channel.send("Damage or ups should be a number.");
let initialspeed = null;
if (args[2]) {
initialspeed = parseInt(args[2]);
if (isNaN(initialspeed))
return message.channel.send("Projectile speed should be a number.");
initialspeed = 30000 - initialspeed;
let t = Math.ceil(initialspeed / 1200);
log.info(t);
ups = ups - t;
}
message.channel.send(
`Your Moon Staff will hit ${moonstaff + ups * 99} damage.`
);
};

27
bot/commands/ping.js Normal file
View File

@ -0,0 +1,27 @@
function format(seconds) {
function pad(s) {
return (s < 10 ? "0" : "") + s;
}
var hours = Math.floor(seconds / (60 * 60));
var minutes = Math.floor((seconds % (60 * 60)) / 60);
var seconds = Math.floor(seconds % 60);
return pad(hours) + "h " + pad(minutes) + "m " + pad(seconds) + "s.";
}
exports.name = "ping";
exports.description = ":ping_pong: View service statistics.";
exports.usage = "CLIENT_PREFIX:ping";
exports.example = "CLIENT_PREFIX:ping";
exports.hidden = true;
exports.run = async (client, message, args) => {
message.channel.send("Fetching data...").then((m) => {
m.edit(
`🏓 Latency is **${
m.createdTimestamp - message.createdTimestamp
}ms**.\nAPI Latency is **${Math.round(
client.ws.ping
)}ms**.\nClient uptime is **${format(process.uptime())}**`
);
});
};

25
bot/commands/refetch.js Normal file
View File

@ -0,0 +1,25 @@
exports.name = "refetch";
exports.description = ":ninja: Refetch user react data.";
exports.usage = "CLIENT_PREFIX:refetch";
exports.example = "CLIENT_PREFIX:refetch";
exports.hidden = true;
exports.run = async (client, message, args) => {
if (message.author.id != client.ownerID) return;
try {
const url = "https://drive.overflow.fun/public/react.json";
client.usersToReactTo = [];
const res = await fetch(url);
const data = await res.json();
client.usersToReactTo = data.map((entry) => {
const [userId, emoji] = entry.split("|");
return { userId, emoji };
});
message.channel.send(
"Refetched react data. " + JSON.stringify(client.usersToReactTo)
);
} catch (e) {
message.channel.send("copyparty instance unreachable/offline...");
}
};

49
bot/commands/res.js Normal file
View File

@ -0,0 +1,49 @@
const logger = require("../log");
exports.name = "res";
exports.description =
":shield: Calculates how much upgrades you need to max your resistances. For Ult pieces and better. (slightly inaccurate but this is hard to calculate)";
exports.usage =
"CLIENT_PREFIX:res <res> <res> <res> [res] | <hero stat> <levels> [second hero stat]";
exports.example = "CLIENT_PREFIX:res -3 1 -16 14 | 406 440";
exports.hidden = false;
exports.run = async (client, message, args) => {
for (let i = 0; i < args.length; i++) {
if (args[i] == "|") continue;
args[i] = parseInt(args[i]);
if (isNaN(args[i]))
message.channel.send(
"Unable to parse argument `" +
i +
1 +
"` as number, try again or report this issue."
);
}
let type;
if (args[4] == "|") type = 4;
else if (args[3] == "|") type = 3;
else return message.channel.send("Please provide 3 or 4 resistances.");
let resistances = [args[0], args[1], args[2], type == 4 ? args[3] : null];
let mainStat1 = type == 4 ? args[5] : args[4];
let upgrades = type == 4 ? args[6] : args[5];
let substat = type == 4 ? args[7] : args[6];
if (!mainStat1 || !upgrades)
return message.channel.send("Please provide atleast 2 stats.");
if (!substat) substat = 0;
fetch(
client.sharedEndpoint +
"resistances" +
`?mainStat=${mainStat1}&upgrades=${upgrades}&subStat=${substat}&resistances=${JSON.stringify(
resistances
)}`
)
.then((d) => d.json())
.then((data) => {
const { resUpgrades, mainStat, subStat, bonus } = data;
logger.info(resUpgrades, mainStat, subStat, bonus);
message.channel.send(
`With ${resUpgrades} upgrades spent in resistances, your piece will reach ${
mainStat + subStat
}, or ${bonus} with set bonus!`
);
});
};

56
bot/commands/tb.js Normal file
View File

@ -0,0 +1,56 @@
const STAT_MULT_INITIAL_AB2 = 0.66;
const STAT_MULT_FULL_AB2 = 0.75;
const STAT_EXP_INITIAL_AB2 = 0.0825;
const STAT_EXP_FULL_AB2 = 0.3375;
// only this changed for tower boosting
const ADDITIONAL_DAMAGE_MULTIPLIER = 0.1;
const ADDITIONAL_DAMAGE_EXPONENT = 1.25;
// Functions
function get_ab2_scaling(stat_val) {
return (
1.0 +
STAT_MULT_INITIAL_AB2 *
(Math.min(stat_val + 1.0, 4.0) ** STAT_EXP_INITIAL_AB2 - 1.0) +
STAT_MULT_FULL_AB2 * ((stat_val + 1.0) ** STAT_EXP_FULL_AB2 - 1.0)
);
}
function get_damage_multiplier(stat_val) {
return (
1.0 +
ADDITIONAL_DAMAGE_MULTIPLIER *
get_ab2_scaling(Math.max(stat_val, 1)) ** ADDITIONAL_DAMAGE_EXPONENT
);
}
exports.name = "tb";
exports.description = ":fire: Calculate tower boost's damage multiplier.";
exports.usage = "CLIENT_PREFIX:tb <points>";
exports.example = "CLIENT_PREFIX:tb 5000";
exports.hidden = false;
exports.run = (client, message, args) => {
if (!args[0])
return message.channel.send(
"Not enough arguments, consult CLIENT_PREFIX:help.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
let tbPoints = parseInt(args[0]);
if (isNaN(tbPoints))
return message.channel.send(
"Given argument is not a number. Consult CLIENT_PREFIX:help.".replaceAll(
"CLIENT_PREFIX:",
client.prefix
)
);
message.channel.send(
`With **${tbPoints}** points in your tower boost, you will boost towers with a **${get_damage_multiplier(
tbPoints
).toFixed(4)}** multiplier.`
);
};