diff --git a/deploy-commands.js b/deploy-commands.js index 76cc67e..e700363 100644 --- a/deploy-commands.js +++ b/deploy-commands.js @@ -48,15 +48,29 @@ const commands = [ ) .addNumberOption(option => option - .setName('difficulty') - .setDescription('The difficulty of the roll.') + .setName('threshold') + .setDescription('The threshold of the roll.') .setRequired(true) ) .addNumberOption(option => option .setName('interval') .setDescription('The interval of the roll.') + .setRequired(true) + ) + .addStringOption(option => + option + .setName('interval-unit') + .setDescription('The unit of the interval. Defaults to Hours.') .setRequired(false) + .addChoices( + { name: 'Seconds', value: 'seconds' }, + { name: 'Minutes', value: 'minutes' }, + { name: 'Hours', value: 'hours' }, + { name: 'Days', value: 'days' }, + { name: 'Weeks', value: 'weeks' }, + { name: 'Months', value: 'months' }, + ) ) .addNumberOption(option => option diff --git a/index.js b/index.js index 550b82c..9477835 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ require('dotenv').config(); -const { crypto } = require('crypto'); +const { EOL } = require('os'); +const { randomInt } = require('node:crypto'); const { Client, GatewayIntentBits } = require('discord.js'); const token = process.env.TOKEN; @@ -13,7 +14,10 @@ client.once('ready', () => { }); client.on('interactionCreate', async interaction => { - if (!interaction.isCommand()) return; + if (!interaction.isCommand()) { + console.log('Not a command'); + return; + } console.log(interaction.commandName); switch (interaction.commandName) { @@ -33,39 +37,154 @@ client.on('interactionCreate', async interaction => { case "simulate": await interaction.deferReply(); - switch (interaction.options.getSubcommand()) { + switch (await interaction.options.getSubcommand()) { case "simple": await interaction.reply({ content: 'Simple dice roll!', ephemeral: true }); break; case "extended": - let dicepool = interaction.options.getNumber("dicepool"); - let difficulty = interaction.options.getNumber("difficulty"); - let interval = interaction.options.getNumber("interval") ?? 1; - let simAmount = interaction.options.getNumber("amount") ?? 10000; - let hidden = interaction.options.getBoolean("hidden") ?? false; - let edgeType = interaction.options.getString("edge") ?? "none"; - let edgeRefresh = interaction.options.getString("edgerefresh") ?? "none"; - let maxEdge = interaction.options.getNumber("edge-max") ?? 6; - let useTrueRandom = interaction.options.getBoolean("true-random") ?? false; + // Variables from Discord command + const dicepool = interaction.options.getNumber("dicepool"); + const threshold = interaction.options.getNumber("threshold"); + const interval = interaction.options.getNumber("interval") ?? 1; + const intervalUnit = interaction.options.getString("interval-unit") ?? "Hours"; + const simAmount = interaction.options.getNumber("amount") ?? 10000; + const hidden = interaction.options.getBoolean("hidden") ?? false; + const edgeType = interaction.options.getString("edgetype") ?? "none"; + const edgeRefresh = interaction.options.getString("edgerefresh") ?? "none"; + const maxEdge = interaction.options.getNumber("max-edge") ?? 6; + const useTrueRandom = interaction.options.getBoolean("true-random") ?? false; + + // Check if dicepool is valid + if (dicepool < 1 || dicepool > 100) { + await interaction.editReply({ content: 'Dicepool must be between 1 and 100!', ephemeral: true }); + return; + } + + // Arrays to build the final message + const warnings = []; + const parameters = []; + const calculatedResults = []; + const realResults = []; + let message = ""; + + // Variables for the simulation + let hits = 0; + let glitches = 0; + let criticalGlitches = 0; + let iterations = 0; let edge = maxEdge; + let failed = false; - let warnings = []; - let calculatedResults = []; - let realResults = []; + parameters.push(`Dicepool: ${dicepool}`); + parameters.push(`Threshold: ${threshold}`); + parameters.push(`Interval: ${interval} ${intervalUnit}`); + parameters.push(`Amount of simulations: ${simAmount}`); + parameters.push(`Edge: ${edgeType}`); + parameters.push(`Edge refresh: ${edgeRefresh}`); + parameters.push(`Max edge: ${maxEdge}`); + parameters.push(`Use true random: ${useTrueRandom}`); - await interaction.reply({ content: 'Extended dice roll!', ephemeral: hidden }); + message = `Parameters:${EOL}\t${parameters.join(EOL + '\t')}${EOL}${EOL}`; + calculatedResults.push("Calculated Results (Can't Use Edge): " + EOL); + + + calculatedResults.push(`Calc Rolls : `); + calculatedResults.push(`Hits Bought: `); + + realResults.push("Real Results: " + EOL); + + // Roll dice in dicepool using the fillArrayWithRandomDice Function till we have reached the threshold or above + while (hits < threshold) { + + if (dicepool - iterations === 0) { + failed = true; + break; + } + + let rolls = await fillArrayWithRandomDice(new Array(dicepool), useTrueRandom); + + // TODO: encapsulate into functions + // TODO: Add smart edgetype or warning + // Edge Section: + switch (edgeType) { + + case 'up': + console.log(`Pre Edge Up: ${rolls}`); + rolls.forEach((roll, index) => { + if (roll === 4 && edge >= 2) { + rolls[index] = 5; + edge -= 2; + } + }); + console.log(`Post Edge Up: ${rolls}`); + break; + + + case 'reroll': + console.log(`Pre Reroll: ${rolls.sort().reverse()}`); + if (edge >= 4) { + let rerolls = await fillArrayWithRandomDice(rolls.filter(roll => roll < 5), useTrueRandom); + rolls = rolls.filter(roll => roll >= 5).concat(rerolls); + } + console.log(`Post Reroll: ${rolls.sort().reverse()}`); + break; + } + + let tempHits = rolls.reduce((a, b) => b >= 5 ? a + 1 : a, 0); + let tempGlitches = rolls.reduce((a, b) => b === 1 ? a + 1 : a, 0) > rolls.length / 2 ? 1 : 0; + + if (tempHits === 0 && tempGlitches === 1) { + criticalGlitches++; + tempGlitches--; + } + + hits += tempHits; + glitches += tempGlitches; + + iterations += 1; + + + switch (edgeRefresh) { + case 'fill': + edge = maxEdge; + break; + + case 'once': + if (edge < maxEdge) { + edge++; + } + break; + + case 'twice': + if (edge < maxEdge - 1) { + edge += 2; + } + break; + + default: + break; + } + } + + if (failed) { + await interaction.editReply({ content: 'Failed to reach threshold!', ephemeral: hidden }); + } else { + await interaction.editReply({ content: message, ephemeral: hidden }); + } break; } break; } }); -async function fillArrayWithRandomDice(arr) { +async function fillArrayWithRandomDice(arr, trueRandom = false) { for (let i = 0; i < arr.length; i++) { - arr[i] = await crypto.randomInt(1, 7); + arr[i] = await randomInt(1, 7); } + return arr; } + client.login(token); \ No newline at end of file