diff --git a/index.js b/index.js index 2febce8..3b51e35 100644 --- a/index.js +++ b/index.js @@ -153,7 +153,7 @@ function generateProfile(dbUser, slackUser) { }, { "type": "mrkdwn", - "text": `*Victories/Losses:* ${dbUser.victories}/${dbUser.losses} (${dbUser.victories / (dbUser.victories + dbUser.losses) || 0}%)` + "text": `*Victories/Losses:* ${dbUser.victories}/${dbUser.losses} (${(dbUser.victories / (dbUser.victories + dbUser.losses)) * 100 || 0}%)` }, { "type": "mrkdwn", @@ -401,9 +401,125 @@ If you want to choose an opponent yourself, simply use \`/chooseopponent\` to ge await ctx.next(); } -async function playerLoss(ctx) { } +function chooseAction(chances) { + const random = Math.random(); + let cumulative = 0; -async function playerWin(ctx) { } + 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); @@ -411,8 +527,6 @@ app.action("continue", checkButton, async (ctx) => { if (user.playerhealth <= 0) { return playerLoss(ctx) - } else if (user.opponenthealth <= 0) { - return playerWin(ctx) } ctx.respond({ @@ -500,7 +614,7 @@ app.action('forfeit', checkButton, async (ctx) => { ctx.respond({ replace_original: false, response_type: 'ephemeral', - text: 'Not yet...' + text: 'Not yet...', }) }) @@ -544,6 +658,7 @@ app.action(/attack|defend|item/, checkButton, async (ctx) => { 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; @@ -566,7 +681,7 @@ app.action(/attack|defend|item/, checkButton, async (ctx) => { break; case 'nothing': response = `*_${slackUser.display_name_normalized} touches some grass_*\n\n\`\`\`NOTHING HAPPENED\`\`\`` - break; + break; } } @@ -600,7 +715,164 @@ app.action(/attack|defend|item/, checkButton, async (ctx) => { }) }) +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(); diff --git a/opponents/beginner.js b/opponents/beginner.js index 2532d85..d211fea 100644 --- a/opponents/beginner.js +++ b/opponents/beginner.js @@ -18,6 +18,11 @@ module.exports = [ *_Rap Star throws his microphone at {player}'s head. They get knocked down._* *{player}:* Is that how you're gonna be? Fine then, let's battle! -*Rap Star:* BEEP!` +*Rap Star:* BEEP!`, + "chances": { + "attack": 0.125, + "defend": 0.75, + "item": 0.125 + } } ] \ No newline at end of file