refactored and moved
This commit is contained in:
@@ -0,0 +1,417 @@
|
||||
const {
|
||||
SlashCommandBuilder,
|
||||
EmbedBuilder,
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
MessageFlags
|
||||
} = require("discord.js");
|
||||
|
||||
const {
|
||||
randomUUID
|
||||
} = require("node:crypto");
|
||||
|
||||
const {
|
||||
getCollections,
|
||||
getCookieBalance,
|
||||
transferCookies,
|
||||
getUnixTime
|
||||
} = require("../../utils/cookieEconomy");
|
||||
|
||||
|
||||
const SPAWN_COST =
|
||||
500;
|
||||
|
||||
const JOIN_DURATION =
|
||||
30 * 60;
|
||||
|
||||
const MINIMUM_PLAYERS =
|
||||
5;
|
||||
|
||||
|
||||
module.exports = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("crumblestrike")
|
||||
.setDescription(
|
||||
"Cooperative Cookie boss encounters."
|
||||
)
|
||||
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName("spawn")
|
||||
.setDescription(
|
||||
`Summon the Crumbbound Behemoth for ${SPAWN_COST} Cookies.`
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
async execute(interaction) {
|
||||
switch (
|
||||
interaction.options.getSubcommand()
|
||||
) {
|
||||
case "spawn":
|
||||
return spawnCrumbleStrike(
|
||||
interaction
|
||||
);
|
||||
|
||||
default:
|
||||
return interaction.reply({
|
||||
content:
|
||||
"Unknown Crumble Strike command.",
|
||||
flags:
|
||||
MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
async function spawnCrumbleStrike(
|
||||
interaction
|
||||
) {
|
||||
if (!interaction.guild) {
|
||||
return interaction.reply({
|
||||
content:
|
||||
"Crumble Strike can only be started inside a server.",
|
||||
flags:
|
||||
MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const {
|
||||
db
|
||||
} =
|
||||
getCollections();
|
||||
|
||||
|
||||
const events =
|
||||
db.collection(
|
||||
"items_events"
|
||||
);
|
||||
|
||||
|
||||
const existing =
|
||||
await events.findOne({
|
||||
eventType:
|
||||
"CrumbleStrike",
|
||||
|
||||
guildId:
|
||||
interaction.guildId,
|
||||
|
||||
state: {
|
||||
$in: [
|
||||
"Joining",
|
||||
"Starting",
|
||||
"Active",
|
||||
"Resolving"
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (existing) {
|
||||
return interaction.reply({
|
||||
content:
|
||||
"There is already an active Crumble Strike encounter in this server.",
|
||||
flags:
|
||||
MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const balance =
|
||||
await getCookieBalance(
|
||||
interaction.user.id
|
||||
);
|
||||
|
||||
|
||||
if (
|
||||
balance <
|
||||
SPAWN_COST
|
||||
) {
|
||||
return interaction.reply({
|
||||
content:
|
||||
`You need **${SPAWN_COST.toLocaleString()} Cookies** to summon the boss.`,
|
||||
flags:
|
||||
MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const eventId =
|
||||
randomUUID();
|
||||
|
||||
|
||||
const escrowId =
|
||||
`crumblestrike:${eventId}`;
|
||||
|
||||
|
||||
const now =
|
||||
getUnixTime();
|
||||
|
||||
|
||||
const joinUntil =
|
||||
now +
|
||||
JOIN_DURATION;
|
||||
|
||||
|
||||
try {
|
||||
await transferCookies(
|
||||
interaction.user.id,
|
||||
escrowId,
|
||||
SPAWN_COST
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
if (
|
||||
error.message ===
|
||||
"INSUFFICIENT_COOKIES"
|
||||
) {
|
||||
return interaction.reply({
|
||||
content:
|
||||
"Your Cookie balance changed before the boss could be summoned.",
|
||||
flags:
|
||||
MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
|
||||
const embed =
|
||||
new EmbedBuilder()
|
||||
.setTitle(
|
||||
"🍪 Crumble Strike"
|
||||
)
|
||||
|
||||
.setDescription(
|
||||
[
|
||||
"## The Crumbbound Behemoth",
|
||||
"",
|
||||
"*Drawn by the scent of an irresponsibly large Cookie Vault,*",
|
||||
"*the beast has lumbered into Shaiwase.*",
|
||||
"",
|
||||
`**Summoner:** ${interaction.user}`,
|
||||
`**Recruitment ends:** <t:${joinUntil}:R>`,
|
||||
`**Minimum adventurers:** ${MINIMUM_PLAYERS}`,
|
||||
`**Participants:** 0/${MINIMUM_PLAYERS}`,
|
||||
`**Reward Pool:** ${SPAWN_COST.toLocaleString()} 🍪`,
|
||||
"",
|
||||
"Choose your role below to begin preparing for battle.",
|
||||
"",
|
||||
"⚔️ **DPS** — Specializes in offensive actions.",
|
||||
"🛡️ **Tank** — Specializes in mitigating boss attacks.",
|
||||
"❤️ **Healer** — Specializes in restoring party HP.",
|
||||
"",
|
||||
"Once enough players have joined, the summoner may start the battle early."
|
||||
].join("\n")
|
||||
)
|
||||
|
||||
.setFooter({
|
||||
text:
|
||||
`crumbleStrike:${eventId}`
|
||||
});
|
||||
|
||||
|
||||
const roles =
|
||||
new ActionRowBuilder()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbleStrikeRoleDPS"
|
||||
)
|
||||
.setLabel(
|
||||
"DPS"
|
||||
)
|
||||
.setEmoji(
|
||||
"⚔️"
|
||||
)
|
||||
.setStyle(
|
||||
ButtonStyle.Danger
|
||||
),
|
||||
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbleStrikeRoleTank"
|
||||
)
|
||||
.setLabel(
|
||||
"Tank"
|
||||
)
|
||||
.setEmoji(
|
||||
"🛡️"
|
||||
)
|
||||
.setStyle(
|
||||
ButtonStyle.Primary
|
||||
),
|
||||
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbleStrikeRoleHealer"
|
||||
)
|
||||
.setLabel(
|
||||
"Healer"
|
||||
)
|
||||
.setEmoji(
|
||||
"❤️"
|
||||
)
|
||||
.setStyle(
|
||||
ButtonStyle.Success
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
const start =
|
||||
new ActionRowBuilder()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbleStrikeStart"
|
||||
)
|
||||
.setLabel(
|
||||
"Start Battle"
|
||||
)
|
||||
.setEmoji(
|
||||
"⚔️"
|
||||
)
|
||||
.setStyle(
|
||||
ButtonStyle.Secondary
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
let message;
|
||||
|
||||
|
||||
try {
|
||||
message =
|
||||
await interaction.reply({
|
||||
embeds: [
|
||||
embed
|
||||
],
|
||||
|
||||
components: [
|
||||
roles,
|
||||
start
|
||||
],
|
||||
|
||||
fetchReply:
|
||||
true
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
await safeRefund(
|
||||
escrowId,
|
||||
interaction.user.id,
|
||||
SPAWN_COST
|
||||
);
|
||||
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
await events.insertOne({
|
||||
eventType:
|
||||
"CrumbleStrike",
|
||||
|
||||
eventId,
|
||||
|
||||
escrowId,
|
||||
|
||||
guildId:
|
||||
interaction.guildId,
|
||||
|
||||
channelId:
|
||||
interaction.channelId,
|
||||
|
||||
messageId:
|
||||
message.id,
|
||||
|
||||
creatorId:
|
||||
interaction.user.id,
|
||||
|
||||
state:
|
||||
"Joining",
|
||||
|
||||
createdAt:
|
||||
now,
|
||||
|
||||
joinUntil,
|
||||
|
||||
battleStartedAt:
|
||||
null,
|
||||
|
||||
battleEndsAt:
|
||||
null,
|
||||
|
||||
minimumParticipants:
|
||||
MINIMUM_PLAYERS,
|
||||
|
||||
rewardPool:
|
||||
SPAWN_COST,
|
||||
|
||||
boss: {
|
||||
bossId:
|
||||
"crumbbound-behemoth",
|
||||
|
||||
name:
|
||||
"The Crumbbound Behemoth",
|
||||
|
||||
health:
|
||||
15000,
|
||||
|
||||
maxHealth:
|
||||
15000,
|
||||
|
||||
limitGauge:
|
||||
0,
|
||||
|
||||
actionGauge:
|
||||
0
|
||||
},
|
||||
|
||||
participants:
|
||||
{}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
try {
|
||||
await message.delete();
|
||||
} catch {}
|
||||
|
||||
|
||||
await safeRefund(
|
||||
escrowId,
|
||||
interaction.user.id,
|
||||
SPAWN_COST
|
||||
);
|
||||
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function safeRefund(
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
) {
|
||||
try {
|
||||
await transferCookies(
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"CRITICAL: Crumble Strike refund failed:",
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user