const { commas, quackGradeMultiplier, prestigeMultiplier, makeBackup, userHasCheckedQuackgrade, getUser } = require('./utils') const { quackStore } = require('./quackstore') const buyableItems = require('./buyableItems') const slack = require('../../slack') const possiblePrestige = coins => { let p = 0 while (totalCostForPrestige(p + 1) <= coins) { p += 1 } return p } const tpcRecMemo = [] const totalCostForPrestige = prestigeLevel => { if (prestigeLevel === 0) { return 0 } return (tpcRecMemo[prestigeLevel]) || (tpcRecMemo[prestigeLevel] = 1_000_000_000_000 * Math.pow(prestigeLevel, 3) + totalCostForPrestige(prestigeLevel - 1)) } const prestigeRoute = async ({ say, args, user }) => { const possible = possiblePrestige(user.coinsAllTime) const current = user.prestige ??= 0 if (args[0] === 'me') { await say( 'This will permanently remove all of your items, upgrades, and coins!\n\n' + 'Say \'!!prestige me\' to confirm.' ) } else { const currentCost = totalCostForPrestige(possible) const nextCost = totalCostForPrestige(possible + 1) const diff = nextCost - currentCost const progress = user.coinsAllTime - currentCost const bars = Math.round((progress / diff) * 10) const empty = 10 - bars const progressBar = '[' + '='.repeat(bars) + ' '.repeat(empty) + ']' await say( `Current Prestige: ${commas(current)}\n\n` + `Quacks gained if you prestige now: ${commas(possible - current)}\n\n` + `Next quack progress: \`${progressBar} ${commas(diff)} \`\n\n` + 'Say \'!prestige me\' to start the prestige process.' + `\n\nYour prestige is currently boosting your CPS by ${commas((prestigeMultiplier(user) - 1) * 100)}%` ) } }//, true, adminOnly) const prestigeConfirmRoute = async ({ event, say, user, YEET }) => { if (YEET) { return say(prestigeMenu(user)) } const possible = possiblePrestige(user.coinsAllTime) const current = user.prestige if (possible <= current) { await say('You don\'t have enough HVAC to prestige right now!') return } if (event?.text !== '!!prestige me') { await say('Say exactly \'!!prestige me\' to confirm') return } await makeBackup() user.isPrestiging = true user.quacks ??= 0 user.quacks += (possible - user.prestige) user.prestige = possible user.highestEver = 0 user.coins = 0 user.items = {} user.holdings = {} const starterUpgrades = (user.quackUpgrades?.starter || []) starterUpgrades.forEach(upgradeName => quackStore[upgradeName].effect(user)) user.upgrades = {} await say(prestigeMenu(user)) await say(`Say !quack _upgrade-name_ to purchase new quackgrades!`) //await say('You prestiged! Check out !quackstore to see what you can buy!') } const quackStoreListing = (showCost = true) => ([name, upgrade]) => `:${upgrade.emoji}: *${name}* - ${showCost ? 'Costs' : 'Worth'} *${upgrade.cost} Quack.*\n\n_${upgrade.description}_` const allUserQuackUpgrades = user => Object.entries(user.quackUpgrades || {}) .map(([type, upgrades]) => upgrades).flatMap(x => x) const hasPreReqs = user => ([name, upgrade]) => { if (!upgrade.preReqs) { return true } const allUserUpgrades = allUserQuackUpgrades(user) return upgrade.preReqs.every(preReq => allUserUpgrades.includes(preReq)) } const owns = (user, [name, upgrade]) => allUserQuackUpgrades(user).includes(name) const ownedQuackItems = user => Object.entries(quackStore).filter(upgrade => owns(user, upgrade)) const unownedQuackItems = user => Object.entries(quackStore).filter(upgrade => !owns(user, upgrade)) const quackStoreText = user => unownedQuackItems(user) .filter(hasPreReqs(user)) .map(quackStoreListing(true)) .join('\n\n') + `\n\nYou have ${user.quacks ??= 0} quacks to spend.` + `\nQuackStore upgrades are currently boosting your CPS by ${commas((quackGradeMultiplier(user) - 1) * 100)}%` const quackStoreRoute = async ({ user, say, args, YEET }) => { user.quackUpgrades ??= {} if (!args[0] || !YEET) { await say(quackStoreText(user)) return } const quackItem = quackStore[args[0]] if (!quackItem || !unownedQuackItems(user).find(([name]) => name === args[0])) { await say(`'${args[0]}' is not available in the quack store!`) return } const quacks = user.quacks ??= 0 if (quackItem.cost > quacks) { await say(`${args[0]} costs ${quackItem.cost} Quacks, but you only have ${quacks}!`) return } user.quacks -= quackItem.cost user.quackUpgrades[quackItem.type] ??= [] user.quackUpgrades[quackItem.type].push(args[0]) if (quackItem.type === 'starter') { quackItem.effect(user) } await say(`You bought ${args[0]}!`) } const buyQuackGradeButton = quackgrade => { //console.log('buyQuackGradeButton', quackgrade[1]) const [name, object] = quackgrade return { type: 'section', text: { type: 'mrkdwn', text: `:${object.emoji}: ${object.name} - ${object.cost} Quacks\n_${object.description}_` }, accessory: { type: 'button', text: { type: 'plain_text', text: 'Buy', emoji: true }, value: 'click_me_123', action_id: `buy-quackgrade-${name}` } } } const prestigeMenu = (user, extraMessage = '') => { user.quackUpgrades ??= {} const quacks = user.quacks ??= 0 return { text: 'Prestige menu', blocks: [ { type: 'section', text: { type: 'mrkdwn', text: `${extraMessage && extraMessage + '\n'}\n_You have ${quacks} quacks to spend._` // text: `${extraMessage && extraMessage + '\n'}_*PRESTIGE IN PROGRESS*_\n_You have ${quacks} quacks to spend. You may ONLY spend quacks on this menu._` } }, // { // type: 'section', // text: { // type: 'mrkdwn', // text: '~Challenge mode~ _TODO_' // }, // accessory: { // type: 'static_select', // placeholder: { // type: 'plain_text', // text: 'No challenge', // emoji: true // }, // options: [ // { // text: { // type: 'plain_text', // text: 'No challenge', // emoji: true // }, // value: 'no-challenge' // }, // /* // { // text: { // type: 'plain_text', // text: 'Clean Start (no prestige bonuses)', // emoji: true // }, // value: 'clean-start' // }*/ // ], // action_id: 'challenge_select-action' // } // }, { type: 'section', text: { type: 'mrkdwn', text: '*Available Quackgrades:*' } }, ...unownedQuackItems(user).filter(hasPreReqs(user)).map(buyQuackGradeButton), // { // type: 'actions', // elements: [ // { // type: 'button', // text: { // type: 'plain_text', // text: 'Complete Prestige', // emoji: true // }, // value: 'complete_prestige', // action_id: 'complete_prestige' // } // ] // } ] } } const buyQuackGrade = async ({ body, ack, say, trueSay, payload }) => { await ack() const buying = payload.action_id.substring('buy-quackgrade-'.length) console.log(`buyQuackGrade ${buying} clicked`) const user = getUser(body.user.id) // if (!user.isPrestiging) { // console.log('You must be prestiging!') // return say(`You must be prestiging to use this menu!`) // } const words = ['', buying, body.actions[0].text] const [, ...args] = words let extraMessage = '' //say = async text => extraMessage = text console.log('quackStoreRoute') await quackStoreRoute({ say, args, user, YEET: true }) await slack.app.client.chat.update({ channel: body.channel.id, ts: body.message.ts, ...prestigeMenu(user, extraMessage) }) } Object.keys(quackStore).forEach(itemName => slack.app.action('buy-quackgrade-' + itemName, buyQuackGrade)) slack.app.action('complete_prestige', async ({ body, ack, say }) => { await ack() const user = getUser(body.user.id) delete user.isPrestiging await slack.app.client.chat.delete({ channel: body.channel.id, ts: body.message.ts, }) await say(`Prestige complete!`) }) const prestigeMenuRoute = async ({ say, user }) => { user.quackUpgrades ??= {} user.quacks ??= 0 await say(prestigeMenu(user)) } const ownedQuacksText = user => ownedQuackItems(user) .filter(hasPreReqs(user)) .map(quackStoreListing(false)) .join('\n\n') + `\n\nQuackStore upgrades are currently boosting your CPS by ${commas((quackGradeMultiplier(user) - 1) * 100)}%` const ownedQuacksRoute = async ({ say, user }) => { user.quackUpgrades ??= {} user.quacks ??= 0 await say(ownedQuacksText(user)) } module.exports = { quackStoreRoute, prestigeRoute, prestigeConfirmRoute, prestigeMenuRoute, ownedQuacksRoute }