slackmaster/index.js

1781 lines
69 KiB
JavaScript
Raw Normal View History

2024-06-19 19:50:14 +00:00
const { App } = require('@slack/bolt');
2024-06-19 20:20:41 +00:00
const postgres = require('postgres');
2024-06-19 19:50:14 +00:00
require('dotenv').config()
2024-06-19 22:07:29 +00:00
const sql = postgres({
2024-06-20 01:03:30 +00:00
host: '/var/run/postgresql',
2024-06-19 20:20:41 +00:00
database: 'haroon_slackmaster',
2024-06-20 01:03:30 +00:00
username: 'haroon'
2024-06-19 20:20:41 +00:00
})
2024-06-19 19:50:14 +00:00
const SpecialOpponents = require('./opponents/special');
2024-06-20 01:03:30 +00:00
const BeginnerOpponents = require('./opponents/beginner');
const AllOpponents = [
...(SpecialOpponents.map(x => ({ ...x, rank: 'SPECIAL' }))),
...(BeginnerOpponents.map(x => ({ ...x, rank: 'BEGINNER' }))),
2024-06-20 01:03:30 +00:00
]
2024-06-19 19:50:14 +00:00
2024-06-27 22:02:36 +00:00
const shop = require('./shopItems');
2024-06-19 19:50:14 +00:00
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET
});
2024-06-19 22:07:29 +00:00
async function initializeUser(slackUserId) {
let a = await sql`SELECT * FROM users WHERE slack_id = ${slackUserId};`
2024-06-19 20:20:41 +00:00
if (a.length === 0) {
2024-06-19 22:07:29 +00:00
a = await sql`INSERT INTO users (slack_id) VALUES (${slackUserId}) RETURNING *;`
2024-06-22 18:45:37 +00:00
await sql`INSERT INTO cooldowns (slack_id) VALUES (${slackUserId});`
2024-06-26 18:41:06 +00:00
await sql`INSERT INTO customization (slack_id) VALUES (${slackUserId});`
2024-06-19 20:20:41 +00:00
}
2024-06-19 22:07:29 +00:00
return a[0];
}
2024-06-26 18:41:06 +00:00
async function getBattlerUrl(slackUserId, endpoint = "battler.png") {
2024-06-27 22:02:36 +00:00
const [user] = await sql`SELECT * FROM customization WHERE slack_id = ${slackUserId};`
2024-06-26 18:41:06 +00:00
const url = new URL(endpoint, "https://generator.battlemaster.obl.ong/");
const a = Object.entries(user);
for (let x of a) {
if (x[0] == "slack_id") continue;
url.searchParams.append(x[0], x[1] || "")
}
return url.href;
}
2024-06-19 22:07:29 +00:00
app.use(async (ctx) => {
2024-06-20 01:03:30 +00:00
await initializeUser(ctx.context.userId)
2024-06-19 22:07:29 +00:00
2024-06-19 20:20:41 +00:00
await ctx.next()
})
2024-06-19 19:50:14 +00:00
app.command('/chooseopponent', async (ctx) => {
await ctx.ack();
2024-06-20 01:03:30 +00:00
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}`
}
}
]
})
}
2024-06-19 19:50:14 +00:00
await ctx.client.views.open({
trigger_id: ctx.body.trigger_id,
view: {
2024-06-20 01:03:30 +00:00
"private_metadata": ctx.payload.channel_id,
2024-06-19 19:50:14 +00:00
"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\`!`
2024-06-19 19:50:14 +00:00
}
},
{
"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
}
}
]
}
})
});
2024-06-26 18:41:06 +00:00
async function generateProfile(dbUser, slackUser) {
2024-06-19 22:07:29 +00:00
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}%)`
2024-06-19 22:07:29 +00:00
},
{
"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",
2024-06-23 19:25:19 +00:00
"fields": [
{
"type": "mrkdwn",
"text": `*Base Health:* ${dbUser.health}\n*Base Min Damage:* ${dbUser.mindmg}\n*Base Max Damage:* ${dbUser.maxdmg}`
},
{
"type": "mrkdwn",
"text": `*Creation Shards:* ${dbUser.cshards}\n*Destruction Shards:* ${dbUser.dshards}\n*Skill Points:* ${dbUser.spoints}`
}
2024-06-26 18:41:06 +00:00
],
"accessory": {
type: "image",
image_url: (await getBattlerUrl(dbUser.slack_id, "profilebattler.png")) + "&username=" + slackUser.display_name_normalized,
alt_text: "user battler"
}
2024-06-19 22:07:29 +00:00
}
]
}
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}\``
}
},
2024-06-26 18:41:06 +00:00
...await generateProfile(dbUser, slackUser)
2024-06-19 22:07:29 +00:00
]
})
}
// 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\``
}
},
2024-06-26 18:41:06 +00:00
...await generateProfile(dbUser, slackUser)
2024-06-19 22:07:29 +00:00
]
})
}
})
2024-06-19 19:50:14 +00:00
app.view("chooseopponent", async (ctx) => {
2024-06-21 21:19:36 +00:00
const user = await initializeUser(ctx.context.userId);
2024-06-19 19:50:14 +00:00
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?`
}
2024-06-21 21:19:36 +00:00
const canRankUp = (() => {
if (user.rank == 'Beginner') {
return (user.health + user.mindmg + user.maxdmg) >= 50 && user.cshards >= 50
} else if (user.rank == 'Casual') {
return (user.health + user.mindmg + user.maxdmg) >= 200 && user.cshards >= 250
} else {
return false
}
})();
2024-06-19 19:50:14 +00:00
await ctx.ack({
response_action: 'update',
view: {
2024-06-20 01:03:30 +00:00
"private_metadata": ctx.payload.private_metadata,
2024-06-19 19:50:14 +00:00
"type": "modal",
"callback_id": "chooseopponent1",
2024-06-19 19:50:14 +00:00
"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.`
2024-06-19 19:50:14 +00:00
}
},
{
"type": "divider"
},
{
"type": "input",
"element": {
"type": "static_select",
"options": AllOpponents.filter(op => op.rank == rank).map(opponent => {
const battlePower = ((opponent) => {
if (opponent.stats.health instanceof Function) {
return opponent.stats.health(user) + opponent.stats.min(user) + opponent.stats.max(user)
} else {
return opponent.stats.health + opponent.stats.min + opponent.stats.max
}
})(opponent);
return {
"text": {
"type": "plain_text",
"text": `${opponent.name} // ${battlePower} Battle Power` + (opponent.secretCondition && !opponent.secretCondition(user) ? " :lock:" : ""),
"emoji": true
},
"value": opponent.rawId
}
}),
2024-06-19 19:50:14 +00:00
"action_id": "opponents"
},
"label": {
"type": "plain_text",
"text": "Choose an opponent:",
"emoji": true
}
2024-06-21 21:19:36 +00:00
},
...(canRankUp ? [
2024-06-21 21:19:36 +00:00
{
type: 'divider',
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": `You can also now participate in a rank up battle against *Battle ${user.rank}*. Click the button below to initiate the battle.`
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Click Me",
"emoji": true
},
"value": ctx.context.userId,
"action_id": "start-rankup-battle"
}
}
] : [])
2024-06-19 19:50:14 +00:00
]
}
})
})
app.view("chooseopponent1", async (ctx) => {
2024-06-19 20:20:41 +00:00
await ctx.ack();
2024-06-20 01:03:30 +00:00
const channelId = ctx.view.private_metadata;
const userId = ctx.context.userId;
const slackUser = (await ctx.client.users.info({ user: userId })).user.profile;
const opponent = AllOpponents.find(o => o.rawId == Object.values(ctx.payload.state.values)[0].opponents.selected_option.value);
2024-06-20 01:03:30 +00:00
const player = await initializeUser(userId);
if (opponent.secretCondition && !opponent.secretCondition(player)) {
return await ctx.client.chat.postEphemeral({
channel: channelId,
user: ctx.context.userId,
text: `${slackUser.display_name_normalized} started a battle against ${opponent.name}.`,
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: opponent.deniedIntro.replaceAll("{player}", slackUser.display_name_normalized)
},
"accessory": {
"type": "image",
"image_url": opponent.image,
"alt_text": opponent.name
2024-06-20 01:03:30 +00:00
}
}
]
2024-06-27 22:02:36 +00:00
})
}
const opponentStats = ((opponent) => {
if (opponent.stats.health instanceof Function) {
return [opponent.stats.health(player), opponent.stats.min(player), opponent.stats.max(player)]
} else {
return [opponent.stats.health, opponent.stats.min, opponent.stats.max]
}
})(opponent);
await sql`UPDATE users
SET playerhealth = ${player.health},
playermin = ${player.mindmg},
playermax = ${player.maxdmg},
currentOpponent = ${opponent.rawId},
opponenthealth = ${opponentStats[0]},
opponentmin = ${opponentStats[1]},
opponentmax = ${opponentStats[2]}
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"
}
]
2024-06-25 21:30:51 +00:00
},
2024-06-26 18:41:06 +00:00
{
type: 'image',
title: {
type: 'plain_text',
text: `${slackUser.display_name_normalized} vs ${opponent.name}`
},
2024-06-27 22:02:36 +00:00
image_url: await getBattlerUrl(userId, "battlesquadfight.png") + `&username=${encodeURIComponent(slackUser.display_name_normalized)}&opponent=${opponent.rawId}`
2024-06-26 18:41:06 +00:00
},
2024-06-25 21:30:51 +00:00
...(opponent.battleAwareness ? [{
type: 'section',
text: {
type: 'mrkdwn',
text: `Watch out, ${slackUser.display_name_normalized}! ${opponent.name} has ${opponent.battleAwareness.type} Battle Awareness! This means they will react to some or ALL of your actions. Be careful!`
},
"accessory": {
"type": "image",
"image_url": "",
"alt_text": `${opponent.battleAwareness.type} Battle Awareness`
}
}] : [])
]
});
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;
2024-06-20 19:49:30 +00:00
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);
2024-06-25 21:30:51 +00:00
const special = !!SpecialOpponents.find(x => x.rawId == user.currentopponent);
if (special) {
await sql`
UPDATE users
losses = ${user.losses + 1}
WHERE slack_id = ${ctx.context.userId};
`
} else {
await sql`
UPDATE users
SET spoints = ${user.spoints - 1},
cshards = ${user.cshards - 5},
losses = ${user.losses + 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",
2024-06-25 21:30:51 +00:00
"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\n*Losses:*\n> ${special ? 0 : -1} Skill Point(s)\n>${special ? 0 : -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
}
}
]
})
}
2024-06-20 19:49:30 +00:00
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;
2024-06-20 19:49:30 +00:00
if (user.playerhealth <= 0) {
return playerLoss(ctx)
}
ctx.respond({
replace_original: true,
text: "",
"blocks": [
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
2024-06-20 19:49:30 +00:00
"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,
2024-06-20 19:49:30 +00:00
"action_id": "forfeit"
}
]
}
]
})
})
2024-06-20 19:49:30 +00:00
app.action('forfeit', checkButton, async (ctx) => {
ctx.respond({
replace_original: false,
response_type: 'ephemeral',
text: 'Not yet...',
2024-06-20 19:49:30 +00:00
})
})
app.action(/attack|defend|item/, checkButton, async (ctx) => {
let response = "This error message isn't meant to show up. If it does, contact Haroon.";
2024-06-20 19:49:30 +00:00
const user = await initializeUser(ctx.context.userId);
const slackUser = (await ctx.client.users.info({ user: ctx.context.userId })).user.profile;
2024-06-25 21:30:51 +00:00
await sql`UPDATE users SET lastaction = ${ctx.payload.action_id} WHERE slack_id = ${ctx.context.userId};`;
2024-06-20 19:49:30 +00:00
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\`\`\``
2024-06-20 19:49:30 +00:00
} 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\`\`\``
2024-06-20 19:49:30 +00:00
} else {
const damage = Math.floor(Math.random() * (user.playermax - user.playermin + 1)) + user.playermin;
2024-06-20 19:49:30 +00:00
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\`\`\``
2024-06-20 19:49:30 +00:00
}
} 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\`\`\``
2024-06-20 19:49:30 +00:00
} else {
const damage = Math.floor(Math.random() * (user.playermax - user.playermin + 1)) + user.playermin;
2024-06-20 19:49:30 +00:00
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\`\`\``
2024-06-20 19:49:30 +00:00
}
await sql`UPDATE users SET playerdefendcount = ${user.opponentdefendcount + 1} WHERE slack_id = ${ctx.context.userId};`
2024-06-20 19:49:30 +00:00
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;
}
2024-06-20 19:49:30 +00:00
}
await sql`UPDATE users SET opponentdefense = 'None' WHERE slack_id = ${ctx.context.userId};`
2024-06-20 19:49:30 +00:00
await ctx.respond({
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": response
2024-06-20 19:49:30 +00:00
}
},
2024-06-26 18:41:06 +00:00
{
type: 'image',
image_url: `https://generator.battlemaster.obl.ong/playeraction.png?action=${ctx.payload.action_id.charAt(0).toUpperCase() + ctx.payload.action_id.slice(1)}+Left&player=${encodeURIComponent(await getBattlerUrl(ctx.context.userId))}`,
alt_text: ctx.payload.action_id.charAt(0).toUpperCase()
},
2024-06-20 19:49:30 +00:00
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Continue",
"emoji": true
},
"value": ctx.context.userId,
"action_id": "continue-opponent"
}
]
}
]
})
2024-06-20 19:49:30 +00:00
})
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;
2024-06-25 21:30:51 +00:00
const opponent = AllOpponents.find(x => x.rawId == user.currentopponent);
const action = (() => {
if (opponent.battleAwareness && opponent.battleAwareness.chances[user.lastaction]) {
return chooseAction(opponent.battleAwareness.chances[user.lastaction](user));
}
2024-06-25 21:30:51 +00:00
return chooseAction(opponent.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 playerhealth = ${user.playerhealth - 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.opponentmax - user.opponentmin + 1)) + user.opponentmin;
await sql`UPDATE users SET playerhealth = ${user.playerhealth - 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.opponentmax - user.opponentmin + 1)) + user.opponentmin;
await sql`UPDATE users SET playerhealth = ${user.playerhealth - 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;
2024-06-21 21:19:36 +00:00
switch (['health', 'health', 'min', 'min', 'max', 'nothing', 'nothing', 'nothing'][Math.floor(Math.random() * 8)]) {
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};`
2024-06-20 19:49:30 +00:00
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"
}
]
}
]
})
})
2024-06-20 19:49:30 +00:00
2024-06-19 20:49:07 +00:00
app.command('/bm-eval', async (ctx) => {
await ctx.ack();
if (ctx.context.userId != 'U06TBP41C3E') return;
2024-06-19 20:49:07 +00:00
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 + "```"
}
}
]
})
})
2024-06-19 19:50:14 +00:00
app.command('/viewopponents', async (ctx) => {
await ctx.ack();
2024-06-19 22:07:29 +00:00
const args = ctx.body.text.slice().split(/ +/g);
2024-06-19 19:50:14 +00:00
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',
2024-06-21 21:19:36 +00:00
fields: mappedBeginner.map(opponent => ({
2024-06-19 19:50:14 +00:00
type: 'mrkdwn',
2024-06-21 21:19:36 +00:00
text: `*${opponent.name}* // ${opponent.battlePower} Battle Power`
}))
2024-06-19 19:50:14 +00:00
}
]
})
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.")
}
});
2024-06-22 18:45:37 +00:00
function getTimeDifference(date1, date2) {
// Ensure both dates are Date objects
const start = new Date(date1);
const end = new Date(date2);
2024-06-22 18:45:37 +00:00
// Calculate the difference in milliseconds
const diff = Math.abs(end - start);
2024-06-22 18:45:37 +00:00
// Calculate the difference in weeks, days, hours, minutes, and seconds
const weeks = Math.floor(diff / (1000 * 60 * 60 * 24 * 7));
const days = Math.floor(diff / (1000 * 60 * 60 * 24)) % 7;
const hours = Math.floor(diff / (1000 * 60 * 60)) % 24;
const minutes = Math.floor(diff / (1000 * 60)) % 60;
const seconds = Math.floor(diff / 1000) % 60;
2024-06-22 18:45:37 +00:00
// Determine which unit to use for the output
if (weeks > 0) {
return `${weeks} Week${weeks > 1 ? 's' : ''}`;
} else if (days > 0) {
return `${days} Day${days > 1 ? 's' : ''}`;
} else if (hours > 0) {
return `${hours} Hour${hours > 1 ? 's' : ''}`;
} else if (minutes > 0) {
return `${minutes} Minute${minutes > 1 ? 's' : ''}`;
} else {
return `${seconds} Second${seconds > 1 ? 's' : ''}`;
}
}
2024-06-23 19:25:19 +00:00
app.command('/daily', async (ctx) => {
2024-06-22 18:45:37 +00:00
await ctx.ack();
const [cooldown] = await sql`SELECT * FROM cooldowns WHERE slack_id = ${ctx.context.userId};`
2024-06-22 18:45:37 +00:00
const user = await initializeUser(ctx.context.userId)
const slackUser = (await ctx.client.users.info({ user: ctx.context.userId })).user.profile;
const now = new Date();
if (!cooldown.daily || (cooldown.daily.getTime() <= now.getTime())) {
const cshards = Math.floor(Math.random() * 10) + 1;
const spoints = Math.floor(Math.random() * 5) + 1;
2024-06-22 18:45:37 +00:00
ctx.respond({
response_type: 'ephemeral',
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*Battle Master:* Oh ${slackUser.display_name_normalized}, apologies for the wait. Here is your reward for today.\n\n> ${cshards} Creation Shards\n> ${spoints} Skill Points`
}
}
]
})
2024-06-22 18:45:37 +00:00
await sql`UPDATE users SET cshards = ${user.cshards + cshards}, spoints = ${user.spoints + spoints} WHERE slack_id = ${ctx.context.userId};`
2024-06-22 18:51:55 +00:00
await sql`UPDATE cooldowns SET daily = ${new Date(now.getTime() + (24 * 60 * 60 * 1000))};`
2024-06-22 18:45:37 +00:00
} else {
ctx.respond({
response_type: 'ephemeral',
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*Battle Master:* Apologies battler. Unfortunately you must wait *${getTimeDifference(now, cooldown.daily)}* before you can collect your next daily reward.`
}
}
]
})
}
})
2024-06-23 19:25:19 +00:00
app.command('/weekly', async (ctx) => {
2024-06-22 18:45:37 +00:00
await ctx.ack();
const [cooldown] = await sql`SELECT * FROM cooldowns WHERE slack_id = ${ctx.context.userId};`
2024-06-22 18:45:37 +00:00
const user = await initializeUser(ctx.context.userId)
const slackUser = (await ctx.client.users.info({ user: ctx.context.userId })).user.profile;
2024-06-22 18:45:37 +00:00
const now = new Date();
if (!cooldown.weekly || (cooldown.weekly.getTime() <= now.getTime())) {
const cshards = Math.floor(Math.random() * 20) + 1;
const dshards = Math.floor(Math.random() * 15) + 1;
const spoints = Math.floor(Math.random() * 10) + 1;
ctx.respond({
response_type: 'ephemeral',
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*Battle Master:* It's that time again ${slackUser.display_name_normalized}. Enjoy your weekly reward.\n\n> ${cshards} Creation Shards\n> ${dshards} Destruction Shards\n> ${spoints} Skill Points`
}
}
]
})
2024-06-22 18:45:37 +00:00
await sql`UPDATE users SET cshards = ${user.cshards + cshards}, dshards = ${user.dshards + dshards}, spoints = ${user.spoints + spoints} WHERE slack_id = ${ctx.context.userId};`
await sql`UPDATE cooldowns SET weekly = ${new Date(now.getTime() + (7 * 24 * 60 * 60 * 1000))};`
2024-06-22 18:45:37 +00:00
} else {
ctx.respond({
response_type: 'ephemeral',
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*Battle Master:* Apologies battler. Unfortunately you must wait *${getTimeDifference(now, cooldown.weekly)}* before you can collect your next weekly reward.`
}
}
]
})
}
})
2024-06-23 19:25:19 +00:00
app.command('/monthly', async (ctx) => {
2024-06-22 18:45:37 +00:00
await ctx.ack();
const [cooldown] = await sql`SELECT * FROM cooldowns WHERE slack_id = ${ctx.context.userId};`
2024-06-22 18:45:37 +00:00
const user = await initializeUser(ctx.context.userId)
const slackUser = (await ctx.client.users.info({ user: ctx.context.userId })).user.profile;
const now = new Date();
if (!cooldown.monthly || (cooldown.monthly.getTime() <= now.getTime())) {
const cshards = Math.floor(Math.random() * 30) + 1;
const dshards = Math.floor(Math.random() * 25) + 1;
const spoints = Math.floor(Math.random() * 15) + 1;
ctx.respond({
response_type: 'ephemeral',
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*Battle Master:* Another month, another reward. You have my appreciation ${slackUser.display_name_normalized}.\n\n> ${cshards} Creation Shards\n> ${dshards} Destruction Shards\n> ${spoints} Skill Points`
}
}
]
})
2024-06-22 18:45:37 +00:00
await sql`UPDATE users SET cshards = ${user.cshards + cshards}, dshards = ${user.dshards + dshards}, spoints = ${user.spoints + spoints} WHERE slack_id = ${ctx.context.userId};`
await sql`UPDATE cooldowns SET monthly = ${new Date(now.getTime() + (30 * 24 * 60 * 60 * 1000))};`
2024-06-22 18:45:37 +00:00
} else {
ctx.respond({
response_type: 'ephemeral',
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*Battle Master:* Apologies battler. Unfortunately you must wait *${getTimeDifference(now, cooldown.monthly)}* before you can collect your next monthly reward.`
}
}
]
})
}
})
2024-06-23 19:25:19 +00:00
app.command('/upgrade', async (ctx) => {
await ctx.ack();
const user = await initializeUser(ctx.context.userId);
await ctx.client.views.open({
trigger_id: ctx.body.trigger_id,
view: {
"private_metadata": ctx.payload.channel_id,
"type": "modal",
"callback_id": "upgrade",
"title": {
"type": "plain_text",
"text": "Upgrade your stats",
"emoji": true
},
"submit": {
"type": "plain_text",
"text": "Upgrade",
"emoji": true
},
"close": {
"type": "plain_text",
"text": "Never mind",
"emoji": true
},
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": `*Battle Builder:* Helloooo <@${ctx.context.userId}>! You're here to upgrade yourself right? No problem! What would you like to... Erm... Upgrade?-`
}
},
{
"block_id": "select",
"type": "input",
"element": {
"type": "static_select",
"placeholder": {
"type": "plain_text",
"text": "Choose a statistic...",
"emoji": true
},
"options": [
{
"text": {
"type": "plain_text",
"text": "Health // 5 Skill Points" + (user.spoints < 5 ? " :lock:" : ""),
"emoji": true
},
"value": "health"
},
{
"text": {
"type": "plain_text",
"text": "Min Damage // 10 Skill Points" + (user.spoints < 10 || user.mindmg + 5 == user.maxdmg ? " :lock:" : ""),
"emoji": true
},
"value": "mindmg"
},
{
"text": {
"type": "plain_text",
"text": "Max Damage // 15 Skill Points" + (user.spoints < 15 ? " :lock:" : ""),
"emoji": true
},
"value": "maxdmg"
}
],
"action_id": "upgrade-modal"
},
"label": {
"type": "plain_text",
"text": "What would you like to upgrade?",
"emoji": true
}
}
]
}
})
});
app.view('upgrade', async (ctx) => {
const user = await initializeUser(ctx.context.userId);
const { selected_option } = ctx.view.state.values['select']['upgrade-modal'];
if (selected_option.value == "health" && user.spoints < 5) {
return await ctx.ack({
response_action: 'errors',
errors: {
'select': "You don't have enough skill points to upgrade your health!"
}
});
} else if (selected_option.value == "mindmg" && user.spoints < 10) {
return await ctx.ack({
response_action: 'errors',
errors: {
'select': "You don't have enough skill points to upgrade your minimum damage!"
}
});
} else if (selected_option == "mindmg" && user.mindmg + 5 == user.maxdmg) {
return await ctx.ack({
response_action: 'errors',
errors: {
'select': "You need to upgrade your maximum damage first!"
}
});
2024-06-23 19:25:19 +00:00
} else if (selected_option.value == "maxdmg" && user.spoints < 15) {
return await ctx.ack({
response_action: 'errors',
errors: {
'select': "You don't have enough skill points to upgrade your maximum damage!"
}
});
}
2024-06-23 19:25:19 +00:00
await ctx.ack();
if (selected_option.value == "health") {
await sql`UPDATE users SET spoints = ${user.spoints - 5}, health = ${user.health + 1} WHERE slack_id = ${ctx.context.userId};`
await ctx.client.chat.postEphemeral({
channel: ctx.view.private_metadata,
user: ctx.context.userId,
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*Battle Builder:* Yayyy <@${ctx.context.userId}>! Your health has been successfully increased!\n\n\`\`\`HEALTH INCREASED (${user.health} > ${user.health + 1})\`\`\``
}
}
]
})
} else if (selected_option.value == "mindmg") {
await sql`UPDATE users SET spoints = ${user.spoints - 10}, mindmg = ${user.mindmg + 1} WHERE slack_id = ${ctx.context.userId};`
await ctx.client.chat.postEphemeral({
channel: ctx.view.private_metadata,
user: ctx.context.userId,
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*Battle Builder:* Yayyy <@${ctx.context.userId}>! Your minimum damage has been successfully increased!\n\n\`\`\`MIN DAMAGE INCREASED (${user.mindmg} > ${user.mindmg + 1})\`\`\``
}
}
]
})
} else if (selected_option.value == "maxdmg") {
await sql`UPDATE users SET spoints = ${user.spoints - 15}, maxdmg = ${user.maxdmg + 1} WHERE slack_id = ${ctx.context.userId};`
await ctx.client.chat.postEphemeral({
channel: ctx.view.private_metadata,
user: ctx.context.userId,
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*Battle Builder:* Yayyy <@${ctx.context.userId}>! Your maximum damage has been successfully increased!\n\n\`\`\`MAX DAMAGE INCREASED (${user.maxdmg} > ${user.maxdmg + 1})\`\`\``
}
}
]
})
}
})
app.command('/downgrade', async (ctx) => {
await ctx.ack();
const user = await initializeUser(ctx.context.userId);
await ctx.client.views.open({
trigger_id: ctx.body.trigger_id,
view: {
"private_metadata": ctx.payload.channel_id,
"type": "modal",
"callback_id": "downgrade",
"title": {
"type": "plain_text",
"text": "Downgrade your stats",
"emoji": true
},
"submit": {
"type": "plain_text",
"text": "Downgrade",
"emoji": true
},
"close": {
"type": "plain_text",
"text": "Never mind",
"emoji": true
},
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": `*Battle Builder:* Helloooo <@${ctx.context.userId}>! You're downgrading today huh? No problem! What would you like to... Erm... Downgrade?-`
}
},
{
"block_id": "select",
"type": "input",
"element": {
"type": "static_select",
"placeholder": {
"type": "plain_text",
"text": "Choose a statistic...",
"emoji": true
},
"options": [
{
"text": {
"type": "plain_text",
"text": "Health // 30 Creation Shards" + (user.cshards < 30 ? " :lock:" : ""),
"emoji": true
},
"value": "health"
},
{
"text": {
"type": "plain_text",
"text": "Min Damage // 40 Creation Shards" + (user.cshards < 40 ? " :lock:" : ""),
"emoji": true
},
"value": "mindmg"
},
{
"text": {
"type": "plain_text",
"text": "Max Damage // 50 Creation Shards" + (user.cshards < 50 || user.mindmg + 5 == user.maxdmg ? " :lock:" : ""),
"emoji": true
},
"value": "maxdmg"
}
],
"action_id": "downgrade-modal"
},
"label": {
"type": "plain_text",
"text": "What would you like to downgrade?",
"emoji": true
}
}
]
}
})
});
app.view('downgrade', async (ctx) => {
const user = await initializeUser(ctx.context.userId);
const { selected_option } = ctx.view.state.values['select']['downgrade-modal'];
if (selected_option.value == "health" && user.cshards < 30) {
return await ctx.ack({
response_action: 'errors',
errors: {
'select': "You don't have enough creation shards to downgrade your health!"
}
});
} else if (selected_option.value == "mindmg" && user.cshards < 40) {
return await ctx.ack({
response_action: 'errors',
errors: {
'select': "You don't have enough creation shards to downgrade your minimum damage!"
}
});
} else if (selected_option == "maxdmg" && user.mindmg + 5 == user.maxdmg) {
return await ctx.ack({
response_action: 'errors',
errors: {
'select': "You need to downgrade your minimum damage first!"
}
});
} else if (selected_option.value == "maxdmg" && user.cshards < 50) {
return await ctx.ack({
response_action: 'errors',
errors: {
'select': "You don't have enough creation shards to downgrade your maximum damage!"
}
});
}
await ctx.ack();
if (selected_option.value == "health") {
await sql`UPDATE users SET spoints = ${user.spoints + 5}, health = ${user.health - 1}, cshards = ${user.cshards - 30} WHERE slack_id = ${ctx.context.userId};`
await ctx.client.chat.postEphemeral({
channel: ctx.view.private_metadata,
user: ctx.context.userId,
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*Battle Builder:* Yayyy <@${ctx.context.userId}>! Your health has been successfully decreased!\n\n\`\`\`HEALTH DECREASED (${user.health} > ${user.health - 1})\`\`\``
}
}
]
})
} else if (selected_option.value == "mindmg") {
await sql`UPDATE users SET spoints = ${user.spoints + 10}, mindmg = ${user.mindmg - 1}, cshards = ${user.cshards - 40} WHERE slack_id = ${ctx.context.userId};`
await ctx.client.chat.postEphemeral({
channel: ctx.view.private_metadata,
user: ctx.context.userId,
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*Battle Builder:* Yayyy <@${ctx.context.userId}>! Your minimum damage has been successfully decreased!\n\n\`\`\`MIN DAMAGE DECREASED (${user.mindmg} > ${user.mindmg - 1})\`\`\``
}
}
]
})
} else if (selected_option.value == "maxdmg") {
await sql`UPDATE users SET spoints = ${user.spoints + 15}, maxdmg = ${user.maxdmg - 1}, cshards = ${user.cshards - 50} WHERE slack_id = ${ctx.context.userId};`
await ctx.client.chat.postEphemeral({
channel: ctx.view.private_metadata,
user: ctx.context.userId,
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*Battle Builder:* Yayyy <@${ctx.context.userId}>! Your maximum damage has been successfully decreased!\n\n\`\`\`MAX DAMAGE DECREASED (${user.maxdmg} > ${user.maxdmg - 1})\`\`\``
}
}
]
})
}
2024-06-27 22:02:36 +00:00
});
2024-06-29 14:10:54 +00:00
const selectedOption = new Map();
const viewId = new Map();
2024-06-27 22:02:36 +00:00
2024-06-29 14:10:54 +00:00
function initialShop(ctx) {
return {
"type": "modal",
"callback_id": "battlershop",
"title": {
"type": "plain_text",
"text": "Battler Shop",
"emoji": true
},
"submit": {
"type": "plain_text",
"text": "Select",
"emoji": true
},
"close": {
"type": "plain_text",
"text": "Never mind",
"emoji": true
},
"blocks": [
{
"type": "section",
text: {
type: "mrkdwn",
text: `*Battle Special:* Heya <@${ctx.context.userId}>. Choose an accessory type you'd like take a look at.`
}
2024-06-27 22:02:36 +00:00
},
2024-06-29 14:10:54 +00:00
{
"type": "input",
block_id: "bap",
"element": {
"type": "static_select",
"placeholder": {
"type": "plain_text",
"text": "Select an accessory",
"emoji": true
},
"options": Object.keys(shop).map((x) => {
2024-06-27 22:02:36 +00:00
return {
"text": {
"type": "plain_text",
2024-06-29 14:10:54 +00:00
"text": x,
2024-06-27 22:02:36 +00:00
"emoji": true
},
2024-06-29 14:10:54 +00:00
"value": x
2024-06-27 22:02:36 +00:00
}
2024-06-29 14:10:54 +00:00
}),
"action_id": "static_select-action"
},
"label": {
"type": "plain_text",
"text": "Choose an accessory",
"emoji": true
2024-06-27 22:02:36 +00:00
}
2024-06-29 14:10:54 +00:00
}
]
}
}
2024-06-27 22:02:36 +00:00
2024-06-29 14:10:54 +00:00
app.command('/battlershop', async (ctx) => {
2024-06-27 22:02:36 +00:00
await ctx.ack();
2024-06-29 14:10:54 +00:00
const v = await ctx.client.views.open({
trigger_id: ctx.payload.trigger_id,
view: initialShop(ctx)
});
//viewId.set(ctx.context.userId, v.view.id)
});
2024-06-27 22:02:36 +00:00
app.view("battlershop", async (ctx) => {
2024-06-29 14:10:54 +00:00
const sel = ctx.view.state.values.bap['static_select-action'].selected_option.value
2024-06-27 22:02:36 +00:00
await ctx.ack({ response_action: 'push', view: {
"type": "modal",
"title": {
"type": "plain_text",
"text": `${sel} Accessories`,
"emoji": true
},
"submit": {
"type": "plain_text",
"text": "Select",
"emoji": true
},
"close": {
"type": "plain_text",
"text": "Back"
},
"blocks": [
2024-06-29 14:10:54 +00:00
{
type: 'section',
text: {
type: 'mrkdwn',
text: `Choose what you'd like to look at and the colour.`
}
},
2024-06-27 22:02:36 +00:00
{
"type": "actions",
"elements": [
{
"type": "static_select",
"placeholder": {
"type": "plain_text",
"text": "Select an accessory",
"emoji": true
},
"options": [
{
"text": {
"type": "plain_text",
"text": "*plain_text option 0*",
"emoji": true
},
"value": "value-0"
},
],
"action_id": "accessory-type"
},
2024-06-29 14:10:54 +00:00
...(sel != "Buddy" ? [
{
"type": "static_select",
"placeholder": {
"type": "plain_text",
"text": "Select a colour",
"emoji": true
2024-06-27 22:02:36 +00:00
},
2024-06-29 14:10:54 +00:00
"options": [
{
"text": {
"type": "plain_text",
"text": "*plain_text option 0*",
"emoji": true
},
"value": "value-0"
2024-06-27 22:02:36 +00:00
},
2024-06-29 14:10:54 +00:00
{
"text": {
"type": "plain_text",
"text": "*plain_text option 1*",
"emoji": true
},
"value": "value-1"
2024-06-27 22:02:36 +00:00
},
2024-06-29 14:10:54 +00:00
{
"text": {
"type": "plain_text",
"text": "*plain_text option 2*",
"emoji": true
},
"value": "value-2"
}
],
"action_id": "actionId-1"
}
] : [])
2024-06-27 22:02:36 +00:00
]
},
{
"type": "image",
2024-06-29 14:10:54 +00:00
"image_url": `https://generator.battlemaster.obl.ong/battler.png?${sel.toLowerCase() == "base" ? "colour" : sel.toLowerCase()}=${"None"}`,
2024-06-27 22:02:36 +00:00
"alt_text": "Battler preview"
}
]
} });
});
app.action
; (async () => {
await app.start(process.env.PORT);
2024-06-19 19:50:14 +00:00
2024-06-27 22:02:36 +00:00
console.log('⚡️ Bolt app is running!');
})();