const { App } = require('@slack/bolt'); const postgres = require('postgres'); require('dotenv').config() const sql = postgres({ host: '/var/run/postgresql', database: 'haroon_slackmaster', username: 'haroon' }) const BeginnerOpponents = require('./opponents/beginner'); const AllOpponents = [ ...BeginnerOpponents ] const app = new App({ token: process.env.SLACK_BOT_TOKEN, signingSecret: process.env.SLACK_SIGNING_SECRET }); async function initializeUser(slackUserId) { let a = await sql`SELECT * FROM users WHERE slack_id = ${slackUserId};` if (a.length === 0) { a = await sql`INSERT INTO users (slack_id) VALUES (${slackUserId}) RETURNING *;` } return a[0]; } app.use(async (ctx) => { await initializeUser(ctx.context.userId) await ctx.next() }) app.command('/chooseopponent', async (ctx) => { await ctx.ack(); const user = await initializeUser(ctx.body.user_id); if (user.currentopponent != "None") { const opponent = AllOpponents.find(x => x.rawId == user.currentopponent) return await ctx.respond({ response_type: 'ephemeral', text: `You are already in a battle with ${opponent.name}.`, blocks: [ { type: 'section', text: { type: 'mrkdwn', text: `*Battle Master:* You are already in a battle with *${opponent.name}*. Please finish your battle with them before proceeding. ${user.battlemessage}` } } ] }) } await ctx.client.views.open({ trigger_id: ctx.body.trigger_id, view: { "private_metadata": ctx.payload.channel_id, "type": "modal", "callback_id": "chooseopponent", "title": { "type": "plain_text", "text": "Choose an opponent", "emoji": true }, "submit": { "type": "plain_text", "text": "Choose", "emoji": true }, "close": { "type": "plain_text", "text": "Never mind", "emoji": true }, "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": `*Battle Support*: Hiya <@${ctx.body.user_id}>! What rank opponent would you like to battle against?\n\nNot sure yet? Don't worry! Just cancel out and view what opponents you can fight with \`/viewopponents\`!` } }, { "type": "divider" }, { "type": "input", "element": { "type": "radio_buttons", "options": [ { "text": { "type": "plain_text", "text": "Special", "emoji": true }, "value": "SPECIAL" }, { "text": { "type": "plain_text", "text": "Beginner", "emoji": true }, "value": "BEGINNER" }, { "text": { "type": "plain_text", "text": "Casual", "emoji": true }, "value": "CASUAL" } ], "action_id": "rank-selection" }, "label": { "type": "plain_text", "text": "Choose a rank:", "emoji": true } } ] } }) }); function generateProfile(dbUser, slackUser) { return [ { "type": "section", "fields": [ { "type": "mrkdwn", "text": "*User:* " + slackUser.display_name_normalized }, { "type": "mrkdwn", "text": "*Rank:* " + dbUser.rank }, { "type": "mrkdwn", "text": "*Battle Power*: " + (dbUser.health + dbUser.mindmg + dbUser.maxdmg) }, { "type": "mrkdwn", "text": `*Victories/Losses:* ${dbUser.victories}/${dbUser.losses} (${(dbUser.victories / (dbUser.victories + dbUser.losses)) * 100 || 0}%)` }, { "type": "mrkdwn", "text": "*Current Win Streak:* " + dbUser.curstreak }, { "type": "mrkdwn", "text": "*Highest Win Streak*: " + dbUser.highstreak } ], "accessory": { "type": "image", "image_url": slackUser.image_1024, "alt_text": "user profile" } }, { "type": "section", "text": { "type": "mrkdwn", "text": `*Base Health:* ${dbUser.health}\n*Base Min Damage:* ${dbUser.mindmg}\n*Base Max Damage:* ${dbUser.maxdmg}` } } ] } app.command('/profile', async (ctx) => { await ctx.ack(); const args = ctx.body.text.slice().split(/ +/g).filter(x => x); let match; // If there is an argument and the first one is a Slack ping if (args.length && (match = args[0].match(/\<\@(.+)\|(.+)>/))) { const mentionedUser = match[1]; const dbUser = await initializeUser(mentionedUser); const slackUser = (await ctx.client.users.info({ user: mentionedUser })).user.profile; ctx.say({ "text": `@${slackUser.display_name_normalized}'s profile`, "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": `<@${ctx.body.user_id}> ran \`/profile @${slackUser.display_name_normalized}\`` } }, ...generateProfile(dbUser, slackUser) ] }) } // If there is an argument but it isn't a Slack ping else if (args.length) { ctx.respond({ blocks: [ { type: 'section', text: { type: 'mrkdwn', text: `*Battle Master:* Greetings <@${ctx.body.user_id}>. You have tried to view the profile of an invalid user. Please ensure you either send a user ping as an argument or provide no argument at all.` } } ] }) } // There is no argument else { const dbUser = await initializeUser(ctx.body.user_id); const slackUser = (await ctx.client.users.info({ user: ctx.body.user_id })).user.profile; ctx.say({ "text": `@${slackUser.display_name_normalized}'s profile`, "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": `<@${ctx.body.user_id}> ran \`/profile\`` } }, ...generateProfile(dbUser, slackUser) ] }) } }) app.view("chooseopponent", async (ctx) => { const { selected_option } = Object.values(ctx.view.state.values)[0]['rank-selection']; const rank = selected_option.value; const messages = { "SPECIAL": `*Battle Special*: Wasn't expecting to see ya here <@${ctx.body.user.id}>... I guess you're up for a challenge huh? Alright then, who do ya wanna annoy today?`, "BEGINNER": `*Battle Beginner*: Hey there <@${ctx.body.user.id}>! Let's keep things simple, who do you want to battle against?`, "CASUAL": `*Battle Casual*: Alright <@${ctx.body.user.id}>, things are about to get a little bit tougher from here... Who do you feel like taking on today?` } await ctx.ack({ response_action: 'update', view: { "private_metadata": ctx.payload.private_metadata, "type": "modal", "callback_id": "chooseopponent-" + rank, "title": { "type": "plain_text", "text": "Choose an opponent", "emoji": true }, "submit": { "type": "plain_text", "text": "Battle", "emoji": true }, "close": { "type": "plain_text", "text": "Never mind", "emoji": true }, "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": messages[rank] || `*Battle Master*: Greetings <@${ctx.body.user.id}>. Please choose an opponent from below to battle.` } }, { "type": "divider" }, { "type": "input", "element": { "type": "static_select", "options": BeginnerOpponents.map(opponent => ({ "text": { "type": "plain_text", "text": `${opponent.name} // ${opponent.stats.health + opponent.stats.min + opponent.stats.max} Battle Power`, "emoji": true }, "value": opponent.rawId }) ), "action_id": "opponents" }, "label": { "type": "plain_text", "text": "Choose an opponent:", "emoji": true } } ] } }) }) app.view("chooseopponent-BEGINNER", async (ctx) => { await ctx.ack(); const channelId = ctx.view.private_metadata; const userId = ctx.context.userId; const slackUser = (await ctx.client.users.info({ user: userId })).user.profile; const opponent = BeginnerOpponents.find(o => o.rawId == Object.values(ctx.payload.state.values)[0].opponents.selected_option.value); const player = await initializeUser(userId); await sql`UPDATE users SET playerhealth = ${player.health}, playermin = ${player.mindmg}, playermax = ${player.maxdmg}, currentOpponent = ${opponent.rawId}, opponenthealth = ${opponent.stats.health}, opponentmin = ${opponent.stats.min}, opponentmax = ${opponent.stats.max} WHERE slack_id = ${userId};` const msg = await ctx.client.chat.postMessage({ channel: channelId, text: `${slackUser.display_name_normalized} started a battle against ${opponent.name}.`, blocks: [ { type: 'section', text: { type: 'mrkdwn', text: opponent.intro.replaceAll("{player}", slackUser.display_name_normalized) }, "accessory": { "type": "image", "image_url": opponent.image, "alt_text": opponent.name } }, { "type": "actions", "elements": [ { "type": "button", "text": { "type": "plain_text", "text": "Continue", "emoji": true }, "value": userId, "action_id": "continue" } ] } ] }); await sql`UPDATE users SET battlemessage = ${`https://hackclub.slack.com/archives/${channelId}/p${msg.ts.replace('.', '')}`} WHERE slack_id = ${userId};` }) async function checkButton(ctx) { await ctx.ack(); if (ctx.payload.value != ctx.context.userId) { return ctx.respond({ replace_original: false, response_type: 'ephemeral', text: "Battle Support: Please do not click other battlers buttons!", blocks: [ { type: 'section', text: { type: 'mrkdwn', text: `*Battle Support:* Erm, <@${ctx.context.userId}>?... Please don't press other battlers buttons! If you want to choose an opponent yourself, simply use \`/chooseopponent\` to get started!` } } ] }) } await ctx.next(); } function chooseAction(chances) { const random = Math.random(); let cumulative = 0; for (const action in chances) { cumulative += chances[action]; if (random < cumulative) { return action; } } } async function takeOutOfBattle(slack_id) { return await sql`UPDATE users SET currentopponent = 'None', playerhealth = NULL, playermin = NULL, playermax = NULL, playerdefense = NULL, playerdefendcount = 0, opponenthealth = NULL, opponentmin = NULL, opponentmax = NULL, opponentdefense = NULL, opponentdefendcount = 0, battlemessage = NULL WHERE slack_id = ${slack_id}; ` } async function playerLoss(ctx) { const user = await initializeUser(ctx.context.userId); const slackUser = (await ctx.client.users.info({ user: ctx.context.userId })).user.profile; await takeOutOfBattle(ctx.context.userId); await sql` UPDATE users SET spoints = ${user.spoints - 1}, cshards = ${user.cshards - 5}, defeats = ${user.defeats + 1} WHERE slack_id = ${ctx.context.userId}; ` ctx.respond({ replace_original: true, text: `${slackUser.display_name_normalized} lost against ${AllOpponents.find(x => x.rawId == user.currentopponent).name}`, "blocks": [ { "type": "context", "elements": [ { "type": "mrkdwn", "text": "*DEFEAT :trophy:*" } ] }, { "type": "section", "text": { "type": "mrkdwn", "text": `Oh no ${slackUser.display_name_normalized}... You've been defeated by ${AllOpponents.find(x => x.rawId == user.currentopponent).name}... Don't give up! There's always room for improvement!\n\n\nLosses:*\n> -1 Skill Point\n>-5 Creation Shards\n> 1 Defeat` }, "accessory": { "type": "image", "image_url": AllOpponents.find(x => x.rawId == user.currentopponent).image, "alt_text": AllOpponents.find(x => x.rawId == user.currentopponent).name } } ] }) } async function playerWin(ctx) { const user = await initializeUser(ctx.context.userId); const slackUser = (await ctx.client.users.info({ user: ctx.context.userId })).user.profile; await takeOutOfBattle(ctx.context.userId); await sql` UPDATE users SET spoints = ${user.spoints + 1}, cshards = ${user.cshards + 5}, victories = ${user.victories + 1} WHERE slack_id = ${ctx.context.userId}; ` ctx.respond({ replace_original: true, text: `${slackUser.display_name_normalized} won against ${AllOpponents.find(x => x.rawId == user.currentopponent).name}`, "blocks": [ { "type": "context", "elements": [ { "type": "mrkdwn", "text": "*YOU WON! :trophy:*" } ] }, { "type": "section", "text": { "type": "mrkdwn", "text": `Congratulations ${slackUser.display_name_normalized}! You have defeated ${AllOpponents.find(x => x.rawId == user.currentopponent).name} in battle! Good job!\n\n\n*Rewards:*\n> 1 Skill Point\n>5 Creation Shards\n> 1 Victory` }, "accessory": { "type": "image", "image_url": AllOpponents.find(x => x.rawId == user.currentopponent).image, "alt_text": AllOpponents.find(x => x.rawId == user.currentopponent).name } } ] }) } app.action("continue", checkButton, async (ctx) => { const user = await initializeUser(ctx.context.userId); const slackUser = (await ctx.client.users.info({ user: ctx.context.userId })).user.profile; if (user.playerhealth <= 0) { return playerLoss(ctx) } ctx.respond({ replace_original: true, text: "", "blocks": [ { "type": "section", "fields": [ { "type": "mrkdwn", "text": `${slackUser.display_name_normalized}:\n\n*Health:* ${user.playerhealth}\n*Min Damage:* ${user.playermin}\n*Max Damage:* ${user.playermax}` }, { "type": "mrkdwn", "text": `${AllOpponents.find(x => x.rawId == user.currentopponent).name}:\n\n*Health:* ${user.opponenthealth}\n*Min Damage:* ${user.opponentmin}\n*Max Damage:* ${user.opponentmax}` } ], "accessory": { "type": "image", "image_url": AllOpponents.find(x => x.rawId == user.currentopponent).image, "alt_text": AllOpponents.find(x => x.rawId == user.currentopponent).name } }, { "type": "context", "elements": [ { "type": "mrkdwn", "text": `*${slackUser.display_name_normalized}* vs *${AllOpponents.find(x => x.rawId == user.currentopponent).name}* | Your Turn` } ] }, { "type": "actions", "elements": [ { "type": "button", "text": { "type": "plain_text", "text": "⚔️ Attack", "emoji": true }, "value": ctx.context.userId, "action_id": "attack" }, { "type": "button", "text": { "type": "plain_text", "text": "🛡️ Defend", "emoji": true }, "value": ctx.context.userId, "action_id": "defend" }, { "type": "button", "text": { "type": "plain_text", "text": " 🎁 Item", "emoji": true }, "value": ctx.context.userId, "action_id": "item" }, { "type": "button", "text": { "type": "plain_text", "text": "☠️ Forfeit", "emoji": true }, "style": "danger", "value": ctx.context.userId, "action_id": "forfeit" } ] } ] }) }) app.action('forfeit', checkButton, async (ctx) => { ctx.respond({ replace_original: false, response_type: 'ephemeral', text: 'Not yet...', }) }) app.action(/attack|defend|item/, checkButton, async (ctx) => { let response = "This error message isn't meant to show up. If it does, contact Haroon."; const user = await initializeUser(ctx.context.userId); const slackUser = (await ctx.client.users.info({ user: ctx.context.userId })).user.profile; switch (ctx.payload.action_id) { case 'attack': if (user.opponentdefense == 'Strong') { response = `*_${slackUser.display_name_normalized} attacks ${AllOpponents.find(x => x.rawId == user.currentopponent).name}_*\n\n\`\`\`NO DAMAGE\`\`\`` } else if (user.opponentdefense == 'Moderate') { if (Math.random() < 0.5) { response = `*_${slackUser.display_name_normalized} attacks ${AllOpponents.find(x => x.rawId == user.currentopponent).name}_*\n\n\`\`\`NO DAMAGE\`\`\`` } else { const damage = Math.floor(Math.random() * (user.playermax - user.playermin + 1)) + user.playermin; await sql`UPDATE users SET opponenthealth = ${user.opponenthealth - damage} WHERE slack_id = ${ctx.context.userId};` response = `*_${slackUser.display_name_normalized} attacks ${AllOpponents.find(x => x.rawId == user.currentopponent).name}_*\n\n\`\`\`${damage.toLocaleString()} DAMAGE\`\`\`` } } else if (user.opponentdefense == 'Weak') { if (Math.random() < 0.25) { response = `*_${slackUser.display_name_normalized} attacks ${AllOpponents.find(x => x.rawId == user.currentopponent).name}_*\n\n\`\`\`NO DAMAGE\`\`\`` } else { const damage = Math.floor(Math.random() * (user.playermax - user.playermin + 1)) + user.playermin; await sql`UPDATE users SET opponenthealth = ${user.opponenthealth - damage} WHERE slack_id = ${ctx.context.userId};` response = `*_${slackUser.display_name_normalized} attacks ${AllOpponents.find(x => x.rawId == user.currentopponent).name}_*\n\n\`\`\`${damage.toLocaleString()} DAMAGE\`\`\`` } } else { const damage = Math.floor(Math.random() * (user.playermax - user.playermin + 1)) + user.playermin; await sql`UPDATE users SET opponenthealth = ${user.opponenthealth - damage} WHERE slack_id = ${ctx.context.userId};` response = `*_${slackUser.display_name_normalized} attacks ${AllOpponents.find(x => x.rawId == user.currentopponent).name}_*\n\n\`\`\`${damage.toLocaleString()} DAMAGE\`\`\`` } break; case 'defend': if (user.playerdefendcount < 3) { await sql`UPDATE users SET playerdefense = 'Strong' WHERE slack_id = ${ctx.context.userId};` response = `*_A blue forcefield magically appears around ${slackUser.display_name_normalized}_*\n\n\`\`\`STRONG DEFENCE\`\`\`` } else { const type = ["Strong", "Moderate", "Weak"][Math.floor(Math.random() * 3)]; await sql`UPDATE users SET playerdefense = ${type} WHERE slack_id = ${ctx.context.userId};` response = `*_A blue forcefield magically appears around ${slackUser.display_name_normalized}_*\n\n\`\`\`${type.toUpperCase()} DEFENCE\`\`\`` } await sql`UPDATE users SET playerdefendcount = ${user.opponentdefendcount + 1} WHERE slack_id = ${ctx.context.userId};` break; case 'item': const increase = Math.floor(Math.random() * 5) + 1; switch (['health', 'min', 'max', 'nothing'][Math.floor(Math.random() * 4)]) { case 'health': await sql`UPDATE users SET playerhealth = ${user.playerhealth + increase} WHERE slack_id = ${ctx.context.userId};` response = `*_${slackUser.display_name_normalized} drinks some squash. U N D I L U T E D._*\n\n\`\`\`+ ${increase} HEALTH\`\`\`` break; case 'min': if ((user.playermin + increase) < user.playermax) { response = `*_${slackUser.display_name_normalized} touches some grass_*\n\n\`\`\`NOTHING HAPPENED\`\`\`` break; } await sql`UPDATE users SET playermin = ${user.playermin + increase} WHERE slack_id = ${ctx.context.userId};` response = `*_${slackUser.display_name_normalized} drinks some squash. U N D I L U T E D._*\n\n\`\`\`+ ${increase} MIN DAMAGE\`\`\`` break; case 'max': await sql`UPDATE users SET playermax = ${user.playermax + increase} WHERE slack_id = ${ctx.context.userId};` response = `*_${slackUser.display_name_normalized} drinks some squash. U N D I L U T E D._*\n\n\`\`\`+ ${increase} MAX DAMAGE\`\`\`` break; case 'nothing': response = `*_${slackUser.display_name_normalized} touches some grass_*\n\n\`\`\`NOTHING HAPPENED\`\`\`` break; } } await sql`UPDATE users SET opponentdefense = 'None' WHERE slack_id = ${ctx.context.userId};` await ctx.respond({ "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": response } }, { "type": "actions", "elements": [ { "type": "button", "text": { "type": "plain_text", "text": "Continue", "emoji": true }, "value": ctx.context.userId, "action_id": "continue-opponent" } ] } ] }) }) app.action("continue-opponent", checkButton, async (ctx) => { const user = await initializeUser(ctx.context.userId); const slackUser = (await ctx.client.users.info({ user: ctx.context.userId })).user.profile; if (user.opponenthealth <= 0) { return playerWin(ctx) } ctx.respond({ replace_original: true, text: "", "blocks": [ { "type": "section", "fields": [ { "type": "mrkdwn", "text": `${slackUser.display_name_normalized}:\n\n*Health:* ${user.playerhealth}\n*Min Damage:* ${user.playermin}\n*Max Damage:* ${user.playermax}` }, { "type": "mrkdwn", "text": `${AllOpponents.find(x => x.rawId == user.currentopponent).name}:\n\n*Health:* ${user.opponenthealth}\n*Min Damage:* ${user.opponentmin}\n*Max Damage:* ${user.opponentmax}` } ], "accessory": { "type": "image", "image_url": AllOpponents.find(x => x.rawId == user.currentopponent).image, "alt_text": AllOpponents.find(x => x.rawId == user.currentopponent).name } }, { "type": "context", "elements": [ { "type": "mrkdwn", "text": `*${slackUser.display_name_normalized}* vs *${AllOpponents.find(x => x.rawId == user.currentopponent).name}* | ${AllOpponents.find(x => x.rawId == user.currentopponent).name}'s Turn` } ] }, { "type": "actions", "elements": [ { "type": "button", "text": { "type": "plain_text", "text": "Continue", "emoji": true }, "value": ctx.context.userId, "action_id": "viewaction-opponent" } ] } ] }) }) app.action('viewaction-opponent', checkButton, async (ctx) => { let response = "This error message isn't meant to show up. If it does, contact Haroon."; const user = await initializeUser(ctx.context.userId); const slackUser = (await ctx.client.users.info({ user: ctx.context.userId })).user.profile; const chances = AllOpponents.find(x => x.rawId == user.currentopponent).chances; const action = chooseAction(chances); switch (action) { case 'attack': if (user.playerdefense == 'Strong') { response = `*_${AllOpponents.find(x => x.rawId == user.currentopponent).name} attacks ${slackUser.display_name_normalized}_*\n\n\`\`\`NO DAMAGE\`\`\`` } else if (user.playerdefense == 'Moderate') { if (Math.random() < 0.5) { response = `*_${AllOpponents.find(x => x.rawId == user.currentopponent).name} attacks ${slackUser.display_name_normalized}_*\n\n\`\`\`NO DAMAGE\`\`\`` } else { const damage = Math.floor(Math.random() * (user.opponentmax - user.opponentmin + 1)) + user.opponentmin; await sql`UPDATE users SET opponenthealth = ${user.opponenthealth - damage} WHERE slack_id = ${ctx.context.userId};` response = `*_${AllOpponents.find(x => x.rawId == user.currentopponent).name} attacks ${slackUser.display_name_normalized}_*\n\n\`\`\`${damage.toLocaleString()} DAMAGE\`\`\`` } } else if (user.playerdefense == 'Weak') { if (Math.random() < 0.25) { response = `*_${AllOpponents.find(x => x.rawId == user.currentopponent).name} attacks ${lackUser.display_name_normalized}_*\n\n\`\`\`NO DAMAGE\`\`\`` } else { const damage = Math.floor(Math.random() * (user.playermax - user.playermin + 1)) + user.playermin; await sql`UPDATE users SET opponenthealth = ${user.opponenthealth - damage} WHERE slack_id = ${ctx.context.userId};` response = `*_${AllOpponents.find(x => x.rawId == user.currentopponent).name} attacks ${slackUser.display_name_normalized}_*\n\n\`\`\`${damage.toLocaleString()} DAMAGE\`\`\`` } } else { const damage = Math.floor(Math.random() * (user.playermax - user.playermin + 1)) + user.playermin; await sql`UPDATE users SET opponenthealth = ${user.opponenthealth - damage} WHERE slack_id = ${ctx.context.userId};` response = `*_${AllOpponents.find(x => x.rawId == user.currentopponent).name} attacks ${slackUser.display_name_normalized}_*\n\n\`\`\`${damage.toLocaleString()} DAMAGE\`\`\`` } break; case 'defend': if (user.opponentdefendcount < 3) { await sql`UPDATE users SET opponentdefense = 'Strong' WHERE slack_id = ${ctx.context.userId};` response = `*_A blue forcefield magically appears around ${AllOpponents.find(x => x.rawId == user.currentopponent).name}_*\n\n\`\`\`STRONG DEFENCE\`\`\`` } else { const type = ["Strong", "Moderate", "Weak"][Math.floor(Math.random() * 3)]; await sql`UPDATE users SET opponentdefense = ${type} WHERE slack_id = ${ctx.context.userId};` response = `*_A blue forcefield magically appears around ${AllOpponents.find(x => x.rawId == user.currentopponent).name}_*\n\n\`\`\`${type.toUpperCase()} DEFENCE\`\`\`` } await sql`UPDATE users SET opponentdefendcount = ${user.opponentdefendcount + 1} WHERE slack_id = ${ctx.context.userId};` break; case 'item': const increase = Math.floor(Math.random() * 5) + 1; switch (['health', 'min', 'max', 'nothing'][Math.floor(Math.random() * 4)]) { case 'health': await sql`UPDATE users SET opponenthealth = ${user.opponenthealth + increase} WHERE slack_id = ${ctx.context.userId};` response = `*_${AllOpponents.find(x => x.rawId == user.currentopponent).name} drinks some squash. U N D I L U T E D._*\n\n\`\`\`+ ${increase} HEALTH\`\`\`` break; case 'min': if ((user.opponentmin + increase) < user.opponentmax) { response = `*_${AllOpponents.find(x => x.rawId == user.currentopponent).name} touches some grass_*\n\n\`\`\`NOTHING HAPPENED\`\`\`` break; } await sql`UPDATE users SET opponentmin = ${user.opponentmin + increase} WHERE slack_id = ${ctx.context.userId};` response = `*_${AllOpponents.find(x => x.rawId == user.currentopponent).name} drinks some squash. U N D I L U T E D._*\n\n\`\`\`+ ${increase} MIN DAMAGE\`\`\`` break; case 'max': await sql`UPDATE users SET opponentmax = ${user.opponentmax + increase} WHERE slack_id = ${ctx.context.userId};` response = `*_${AllOpponents.find(x => x.rawId == user.currentopponent).name} drinks some squash. U N D I L U T E D._*\n\n\`\`\`+ ${increase} MAX DAMAGE\`\`\`` break; case 'nothing': response = `*_${AllOpponents.find(x => x.rawId == user.currentopponent).name} touches some grass_*\n\n\`\`\`NOTHING HAPPENED\`\`\`` break; } } await sql`UPDATE users SET playerdefense = 'None' WHERE slack_id = ${ctx.context.userId};` await ctx.respond({ "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": response } }, { "type": "actions", "elements": [ { "type": "button", "text": { "type": "plain_text", "text": "Continue", "emoji": true }, "value": ctx.context.userId, "action_id": "continue" } ] } ] }) }) app.command('/bm-eval', async (ctx) => { await ctx.ack(); if (ctx.context.userId != 'U06TBP41C3E') return; const resp = require('util').inspect(await eval(ctx.body.text), undefined, 1) ctx.respond({ text: resp, response_type: 'ephemeral', blocks: [ { type: 'section', text: { type: 'mrkdwn', text: "```" + resp + "```" } } ] }) }) app.command('/viewopponents', async (ctx) => { await ctx.ack(); const args = ctx.body.text.slice().split(/ +/g); switch (args[0].toUpperCase()) { case "SPECIAL": ctx.respond({ text: "You're trying to view Special opponents.", response_type: 'ephemeral' }) break; case "BEGINNER": const mappedBeginner = BeginnerOpponents.map(opponent => ({ name: opponent.name, battlePower: opponent.stats.health + opponent.stats.min + opponent.stats.max }) ) ctx.respond({ response_type: 'ephemeral', text: `*Battle Master:* Greetings battler. Here are the avaliable *Beginner* opponents for you to battle.`, blocks: [ { type: 'section', text: { type: 'mrkdwn', text: `*Battle Master:* Greetings <@${ctx.body.user_id}>. Here are the avaliable *Beginner* opponents for you to battle.` } }, { type: 'section', text: { type: 'mrkdwn', text: mappedBeginner.map(opponent => `*${opponent.name}:*\n\n${opponent.battlePower} Battle Power`).join('\n\n\n') } } ] }) break; case "CASUAL": ctx.say("You're trying to view Casual opponents.") break; default: ctx.say("You either wrote nothing or just chose a rank that doesn't exist.") } }); ; (async () => { // Start your app await app.start(process.env.PORT); console.log('⚡️ Bolt app is running!'); })();