Last active
June 20, 2022 21:47
-
-
Save alaninnovates/513a605eb2d69ae92193a55ea852261f to your computer and use it in GitHub Desktop.
Islands Totem Calculator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { MessageEmbed } = require('discord.js'); | |
const columnify = require('columnify'); | |
const { itemData, totemData, lmcPrice, priceData } = require('../data'); | |
const { getUserPrices } = require('../util'); | |
const INVALID_INPUT_MESSAGE = | |
'One or more of your inputs are not valid. Input must be in the format of `utility/efficiency/quality` and all values must be between 0 and 53.'; | |
const parseInteger = (str) => { | |
if (!/^(0|[1-9]\d*)$/.test(str)) return; | |
return parseInt(str); | |
}; | |
const validateInteger = (int) => { | |
const parsed = parseInteger(int); | |
// console.log(parsed, int, parsed > 53, parsed < 0); | |
if (parsed === undefined || parsed > 53 || parsed < 0) { | |
// console.log('returning false'); | |
return false; | |
} | |
return true; | |
}; | |
const getRange = (arr, start, end) => { | |
return arr.slice(start, end); | |
}; | |
/** | |
* @param {number} num | |
*/ | |
const roundLmc = (num) => { | |
// const roundedNumber = Math.floor(num); | |
// if (roundedNumber === 0) return 1; | |
// return roundedNumber; | |
return Math.floor(num); | |
}; | |
/** | |
* @typedef {Object} InputData | |
* @property {number} beginUtility | |
* @property {number} targetUtility | |
* @property {number} beginEfficiency | |
* @property {number} targetEfficiency | |
* @property {number} beginQuality | |
* @property {number} targetQuality | |
*/ | |
/** | |
* @param {InputData} inputData | |
* @param {import('discord.js').CommandInteraction} interaction | |
*/ | |
const calculatePrices = async ( | |
{ | |
beginUtility, | |
targetUtility, | |
beginEfficiency, | |
targetEfficiency, | |
beginQuality, | |
targetQuality, | |
}, | |
interaction, | |
) => { | |
/* | |
NEVERMIND | |
The table is formatted as follows: | |
if mode is ITEM: | |
| Item Name | Utility | Efficiency | Quality | Total Amount Required | Price | | |
| Wood | 10 | 30 | 39 | 79 | 47400 | | |
| Iron | 10 | 30 | 39 | 79 | 330 | | |
| ----------- | ------- | ---------- | ------- | --------------------- | ----- | | |
| Total | - | - | - | - | 47730 | | |
| Total (LMC) | - | - | - | - | ~2 | | |
if mode is COIN: | |
| Item Name | Utility | Efficiency | Quality | Total Amount Required | | |
| Wood | 6000 | 5000 | 10000 | 21000 | | |
| Iron | 310 | 3430 | 300 | 4040 | | |
| ----------- | ------- | ---------- | ------- | --------------------- | | |
| Total | - | - | - | 25040 | | |
| Total (LMC) | - | - | - | ~1 | | |
if mode is LMC: | |
todo | |
*/ | |
const userPrices = await getUserPrices( | |
interaction.client.db, | |
interaction.user.id, | |
); | |
const prices = Object.assign(priceData, userPrices); | |
const itemRequirements = {}; | |
for (const item of itemData) { | |
const utilityReq = getRange( | |
totemData.utility[item], | |
beginUtility, | |
targetUtility, | |
); | |
const efficiencyReq = getRange( | |
totemData.efficiency[item], | |
beginEfficiency, | |
targetEfficiency, | |
); | |
const qualityReq = getRange( | |
totemData.quality[item], | |
beginQuality, | |
targetQuality, | |
); | |
itemRequirements[item] = { | |
utility: utilityReq.reduce((acc, cur) => acc + cur, 0), | |
efficiency: efficiencyReq.reduce((acc, cur) => acc + cur, 0), | |
quality: qualityReq.reduce((acc, cur) => acc + cur, 0), | |
}; | |
} | |
const getPrice = (amount, item) => { | |
return amount * prices[item]; | |
}; | |
const coinRequirements = {}; | |
for (const requirement of Object.keys(itemRequirements)) { | |
const reqData = itemRequirements[requirement]; | |
coinRequirements[requirement] = { | |
utility: getPrice(reqData.utility, requirement), | |
efficiency: getPrice(reqData.efficiency, requirement), | |
quality: getPrice(reqData.quality, requirement), | |
}; | |
} | |
const lmcRequirements = {}; | |
for (const requirement of Object.keys(coinRequirements)) { | |
const reqData = coinRequirements[requirement]; | |
lmcRequirements[requirement] = { | |
utility: roundLmc(reqData.utility / lmcPrice), | |
efficiency: roundLmc(reqData.efficiency / lmcPrice), | |
quality: roundLmc(reqData.quality / lmcPrice), | |
}; | |
} | |
return { | |
itemRequirements, | |
coinRequirements, | |
lmcRequirements, | |
}; | |
}; | |
const generatePriceEmbed = (itemRequirements, requirementType) => { | |
// console.log(itemRequirements); | |
const itemRequirementTransformed = Object.keys(itemRequirements).map( | |
(itemName) => ({ | |
item: itemName, | |
utility: itemRequirements[itemName].utility, | |
efficiency: itemRequirements[itemName].efficiency, | |
quality: itemRequirements[itemName].quality, | |
total: | |
itemRequirements[itemName].utility + | |
itemRequirements[itemName].efficiency + | |
itemRequirements[itemName].quality, | |
}), | |
); | |
itemRequirementTransformed.push( | |
{ | |
item: '-', | |
utility: '-', | |
efficiency: '-', | |
quality: '-', | |
total: '-', | |
}, | |
{ | |
item: 'Total', | |
utility: itemRequirementTransformed.reduce( | |
(acc, cur) => acc + cur.utility, | |
0, | |
), | |
efficiency: itemRequirementTransformed.reduce( | |
(acc, cur) => acc + cur.efficiency, | |
0, | |
), | |
quality: itemRequirementTransformed.reduce( | |
(acc, cur) => acc + cur.quality, | |
0, | |
), | |
total: itemRequirementTransformed.reduce( | |
(acc, cur) => acc + cur.total, | |
0, | |
), | |
}, | |
); | |
for (const item of itemRequirementTransformed) { | |
item.utility = item.utility.toLocaleString(); | |
item.efficiency = item.efficiency.toLocaleString(); | |
item.quality = item.quality.toLocaleString(); | |
item.total = item.total.toLocaleString(); | |
} | |
return new MessageEmbed() | |
.setTitle(requirementType) | |
.setDescription( | |
'```\n' + columnify(itemRequirementTransformed) + '\n```', | |
) | |
.setColor('GREEN'); | |
}; | |
/** | |
* @param {import('discord.js').CommandInteraction} interaction | |
* @param {InputData} inputData | |
* @param {number} totemAmount | |
*/ | |
const showResultEmbed = async (interaction, inputData, totemAmount) => { | |
const priceData = await calculatePrices(inputData, interaction); | |
const priceMessage = await interaction.user.send({ | |
embeds: [ | |
new MessageEmbed() | |
.setTitle('Calculator Result') | |
.setDescription( | |
`These are the prices for ${totemAmount} totems upgraded by\n- ${ | |
inputData.targetUtility - inputData.beginUtility | |
} utility levels\n- ${ | |
inputData.targetEfficiency - inputData.beginEfficiency | |
} efficiency levels\n- ${ | |
inputData.targetQuality - inputData.beginQuality | |
} quality levels`, | |
) | |
.setColor('GREEN'), | |
generatePriceEmbed(priceData.itemRequirements, 'Item requirements'), | |
generatePriceEmbed(priceData.coinRequirements, 'Coin requirements'), | |
generatePriceEmbed(priceData.lmcRequirements, 'LMC requirements'), | |
new MessageEmbed() | |
.setTitle('Return') | |
.setDescription( | |
`Click [here](https://discord.com/channels/${interaction.guildId}/${interaction.channelId}) to return to the channel you were in.`, | |
) | |
.setFooter({ | |
text: 'Calculator made by alaninnovates#0123', | |
}), | |
], | |
}); | |
await interaction.followUp({ | |
embeds: [ | |
new MessageEmbed() | |
.setTitle("I have DM'd you the prices.") | |
.setDescription( | |
`Click [here](${priceMessage.url}) to view them.`, | |
) | |
.setColor('GREEN'), | |
], | |
}); | |
}; | |
module.exports = { | |
name: 'calculate', | |
/** | |
* @param {import('discord.js').CommandInteraction} interaction | |
*/ | |
execute: async (interaction) => { | |
const totemAmount = interaction.options.getNumber('amount'); | |
const inputData = { | |
beginUtility: 0, | |
targetUtility: 0, | |
beginEfficiency: 0, | |
targetEfficiency: 0, | |
beginQuality: 0, | |
targetQuality: 0, | |
}; | |
await interaction.reply({ | |
embeds: [ | |
new MessageEmbed() | |
.setTitle('Inputs') | |
.setDescription( | |
'Please input your desired upgrades in the format of `utility/efficiency/quality` when prompted to do so.\n**Example:** `0/0/0` means your totem is upgraded at 0 utility, 0 efficiency, and 0 quality.\n\n**Please input your begining upgrade values.** These values are what your totems are currently upgraded to.\n\nSay "cancel" at any time to cancel.', | |
), | |
], | |
}); | |
let currentInput = 0; | |
const inputsCollector = interaction.channel | |
.createMessageCollector({ | |
filter: (m) => m.author.id === interaction.user.id, | |
}) | |
.on('collect', async (message) => { | |
if (message.content.toLowerCase() === 'cancel') { | |
inputsCollector.stop(); | |
return await interaction.followUp('Alright, cancelled!'); | |
} | |
const inputs = message.content.split('/'); | |
// console.log( | |
// inputs.length, | |
// !inputs.every(validateInteger), | |
// inputs, | |
// ); | |
if (inputs.length !== 3 || !inputs.every(validateInteger)) { | |
await message.channel.send(INVALID_INPUT_MESSAGE); | |
return; | |
} | |
const [utility, efficiency, quality] = inputs.map(parseInteger); | |
if (currentInput === 0) { | |
inputData.beginUtility = utility; | |
inputData.beginEfficiency = efficiency; | |
inputData.beginQuality = quality; | |
await message.channel.send({ | |
embeds: [ | |
new MessageEmbed() | |
.setTitle('Target upgrades') | |
.setDescription( | |
'**Please input your target upgrade values.** These values are what you want your totems to be upgraded to.', | |
), | |
], | |
}); | |
currentInput = 1; | |
} else if (currentInput === 1) { | |
inputData.targetUtility = utility; | |
inputData.targetEfficiency = efficiency; | |
inputData.targetQuality = quality; | |
inputsCollector.stop(); | |
if ( | |
inputData.beginUtility > inputData.targetUtility || | |
inputData.beginEfficiency > | |
inputData.targetEfficiency || | |
inputData.beginQuality > inputData.targetQuality | |
) { | |
return await interaction.followUp( | |
'Your beginning upgrade values cannot be higher than your target upgrade values. **Please re-run the command** to try again.', | |
); | |
} | |
await showResultEmbed(interaction, inputData, totemAmount); | |
} | |
}); | |
}, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment