fuk you rai <3
This commit is contained in:
@@ -0,0 +1,365 @@
|
|||||||
|
const {
|
||||||
|
SlashCommandBuilder,
|
||||||
|
MessageFlags
|
||||||
|
} = require("discord.js");
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CONFIG
|
||||||
|
*/
|
||||||
|
|
||||||
|
const POKE_MAX_TIMES = 5;
|
||||||
|
const POKE_DELAY_MS = 750;
|
||||||
|
const POKE_COOLDOWN_MS = 30_000;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In-memory cooldowns.
|
||||||
|
*
|
||||||
|
* Key:
|
||||||
|
* Discord user ID of the person sending the poke.
|
||||||
|
*
|
||||||
|
* Value:
|
||||||
|
* Timestamp when they may poke again.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const pokeCooldowns = new Map();
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName("fun")
|
||||||
|
.setDescription("Fun commands.")
|
||||||
|
|
||||||
|
.addSubcommand(subcommand =>
|
||||||
|
subcommand
|
||||||
|
.setName("poke")
|
||||||
|
.setDescription(
|
||||||
|
"Poke another server member in DMs."
|
||||||
|
)
|
||||||
|
|
||||||
|
.addUserOption(option =>
|
||||||
|
option
|
||||||
|
.setName("member")
|
||||||
|
.setDescription(
|
||||||
|
"The member you want to poke."
|
||||||
|
)
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
|
||||||
|
.addIntegerOption(option =>
|
||||||
|
option
|
||||||
|
.setName("times")
|
||||||
|
.setDescription(
|
||||||
|
`How many times to poke them. Max ${POKE_MAX_TIMES}.`
|
||||||
|
)
|
||||||
|
.setMinValue(1)
|
||||||
|
.setMaxValue(
|
||||||
|
POKE_MAX_TIMES
|
||||||
|
)
|
||||||
|
.setRequired(false)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
switch (
|
||||||
|
interaction.options.getSubcommand()
|
||||||
|
) {
|
||||||
|
case "poke":
|
||||||
|
return poke(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* POKE
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function poke(interaction) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Guild only.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!interaction.guild) {
|
||||||
|
return interaction.reply({
|
||||||
|
content:
|
||||||
|
"This command can only be used inside a server.",
|
||||||
|
|
||||||
|
flags:
|
||||||
|
MessageFlags.Ephemeral
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Options
|
||||||
|
*/
|
||||||
|
|
||||||
|
const user =
|
||||||
|
interaction.options.getUser(
|
||||||
|
"member",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const times =
|
||||||
|
interaction.options.getInteger(
|
||||||
|
"times"
|
||||||
|
)
|
||||||
|
?? 1;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't poke yourself.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
user.id ===
|
||||||
|
interaction.user.id
|
||||||
|
) {
|
||||||
|
return interaction.reply({
|
||||||
|
content:
|
||||||
|
"You can't poke yourself! 👉",
|
||||||
|
|
||||||
|
flags:
|
||||||
|
MessageFlags.Ephemeral
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't poke bots.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (user.bot) {
|
||||||
|
return interaction.reply({
|
||||||
|
content:
|
||||||
|
"You can't poke a bot!",
|
||||||
|
|
||||||
|
flags:
|
||||||
|
MessageFlags.Ephemeral
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure the target is actually
|
||||||
|
* a member of this guild.
|
||||||
|
*/
|
||||||
|
|
||||||
|
let member;
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
member =
|
||||||
|
await interaction.guild
|
||||||
|
.members
|
||||||
|
.fetch(
|
||||||
|
user.id
|
||||||
|
);
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
return interaction.reply({
|
||||||
|
content:
|
||||||
|
"I couldn't find that member in this server.",
|
||||||
|
|
||||||
|
flags:
|
||||||
|
MessageFlags.Ephemeral
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* COOLDOWN
|
||||||
|
*/
|
||||||
|
|
||||||
|
const now =
|
||||||
|
Date.now();
|
||||||
|
|
||||||
|
|
||||||
|
const cooldownUntil =
|
||||||
|
pokeCooldowns.get(
|
||||||
|
interaction.user.id
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
cooldownUntil &&
|
||||||
|
cooldownUntil > now
|
||||||
|
) {
|
||||||
|
const remaining =
|
||||||
|
Math.ceil(
|
||||||
|
(
|
||||||
|
cooldownUntil -
|
||||||
|
now
|
||||||
|
)
|
||||||
|
/
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return interaction.reply({
|
||||||
|
content:
|
||||||
|
`You need to wait **${remaining}s** before poking someone again.`,
|
||||||
|
|
||||||
|
flags:
|
||||||
|
MessageFlags.Ephemeral
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Defer before sending DMs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
await interaction.deferReply({
|
||||||
|
flags:
|
||||||
|
MessageFlags.Ephemeral
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set cooldown before sending.
|
||||||
|
*
|
||||||
|
* This prevents repeated invocations
|
||||||
|
* while the DM loop is running.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pokeCooldowns.set(
|
||||||
|
interaction.user.id,
|
||||||
|
now + POKE_COOLDOWN_MS
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sender name.
|
||||||
|
*
|
||||||
|
* Prefer their server display name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
let senderName =
|
||||||
|
interaction.user.displayName;
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const senderMember =
|
||||||
|
await interaction.guild
|
||||||
|
.members
|
||||||
|
.fetch(
|
||||||
|
interaction.user.id
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
senderName =
|
||||||
|
senderMember.displayName;
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
/*
|
||||||
|
* interaction.user.displayName
|
||||||
|
* remains the fallback.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SEND POKES
|
||||||
|
*/
|
||||||
|
|
||||||
|
let sent =
|
||||||
|
0;
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (
|
||||||
|
let i = 0;
|
||||||
|
i < times;
|
||||||
|
i++
|
||||||
|
) {
|
||||||
|
|
||||||
|
await member.send({
|
||||||
|
content:
|
||||||
|
`👉 **${senderName} poked you!**\n` +
|
||||||
|
`From **${interaction.guild.name}**`
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
sent++;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't sleep after the final DM.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
i <
|
||||||
|
times - 1
|
||||||
|
) {
|
||||||
|
await sleep(
|
||||||
|
POKE_DELAY_MS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
`Failed to poke ${user.tag}:`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If no messages made it through,
|
||||||
|
* this is most likely closed DMs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (sent === 0) {
|
||||||
|
return interaction.editReply({
|
||||||
|
content:
|
||||||
|
`I couldn't poke ${user}. They may have DMs disabled.`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some messages succeeded before
|
||||||
|
* Discord rejected a later one.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return interaction.editReply({
|
||||||
|
content:
|
||||||
|
`I poked ${user} **${sent}/${times}** times before I couldn't send any more.`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SUCCESS
|
||||||
|
*/
|
||||||
|
|
||||||
|
return interaction.editReply({
|
||||||
|
content:
|
||||||
|
times === 1
|
||||||
|
? `👉 Poked ${user}!`
|
||||||
|
: `👉 Poked ${user} **${times} times!**`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SLEEP
|
||||||
|
*/
|
||||||
|
|
||||||
|
function sleep(ms) {
|
||||||
|
return new Promise(
|
||||||
|
resolve =>
|
||||||
|
setTimeout(
|
||||||
|
resolve,
|
||||||
|
ms
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user