refactored and moved
This commit is contained in:
-1693
File diff suppressed because it is too large
Load Diff
+267
-192
@@ -1,5 +1,8 @@
|
||||
const {
|
||||
EmbedBuilder
|
||||
EmbedBuilder,
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle
|
||||
} = require("discord.js");
|
||||
|
||||
const {
|
||||
@@ -23,86 +26,47 @@ const HEIST_COOLDOWN =
|
||||
|
||||
|
||||
/*
|
||||
* Each approach has a different risk/reward profile.
|
||||
* All three approaches use the SAME cooldown:
|
||||
*
|
||||
* Sneak:
|
||||
* High success chance
|
||||
* Small reward
|
||||
* Small failure penalty
|
||||
* cooldowns_cookies.heist
|
||||
*
|
||||
* Hack:
|
||||
* Medium success chance
|
||||
* Medium reward
|
||||
* Medium failure penalty
|
||||
*
|
||||
* Smash:
|
||||
* Low success chance
|
||||
* Large reward
|
||||
* Large failure penalty
|
||||
* Sneak does NOT have its own cooldown.
|
||||
* Hack does NOT have its own cooldown.
|
||||
* Smash does NOT have its own cooldown.
|
||||
*/
|
||||
|
||||
const HEIST_METHODS = {
|
||||
|
||||
Sneak: {
|
||||
baseChance:
|
||||
0.65,
|
||||
baseChance: 0.65,
|
||||
|
||||
minStealPercent:
|
||||
0.01,
|
||||
minStealPercent: 0.01,
|
||||
maxStealPercent: 0.03,
|
||||
maxStealAmount: 1500,
|
||||
|
||||
maxStealPercent:
|
||||
0.03,
|
||||
|
||||
maxStealAmount:
|
||||
1500,
|
||||
|
||||
minPenaltyPercent:
|
||||
0.01,
|
||||
|
||||
maxPenaltyPercent:
|
||||
0.04
|
||||
minPenaltyPercent: 0.01,
|
||||
maxPenaltyPercent: 0.04
|
||||
},
|
||||
|
||||
|
||||
Hack: {
|
||||
baseChance:
|
||||
0.45,
|
||||
baseChance: 0.45,
|
||||
|
||||
minStealPercent:
|
||||
0.03,
|
||||
minStealPercent: 0.03,
|
||||
maxStealPercent: 0.06,
|
||||
maxStealAmount: 3500,
|
||||
|
||||
maxStealPercent:
|
||||
0.06,
|
||||
|
||||
maxStealAmount:
|
||||
3500,
|
||||
|
||||
minPenaltyPercent:
|
||||
0.03,
|
||||
|
||||
maxPenaltyPercent:
|
||||
0.07
|
||||
minPenaltyPercent: 0.03,
|
||||
maxPenaltyPercent: 0.07
|
||||
},
|
||||
|
||||
|
||||
Smash: {
|
||||
baseChance:
|
||||
0.25,
|
||||
baseChance: 0.25,
|
||||
|
||||
minStealPercent:
|
||||
0.06,
|
||||
minStealPercent: 0.06,
|
||||
maxStealPercent: 0.12,
|
||||
maxStealAmount: 7500,
|
||||
|
||||
maxStealPercent:
|
||||
0.12,
|
||||
|
||||
maxStealAmount:
|
||||
7500,
|
||||
|
||||
minPenaltyPercent:
|
||||
0.06,
|
||||
|
||||
maxPenaltyPercent:
|
||||
0.12
|
||||
minPenaltyPercent: 0.06,
|
||||
maxPenaltyPercent: 0.12
|
||||
}
|
||||
};
|
||||
|
||||
@@ -117,15 +81,12 @@ async function resolveCookieHeist(
|
||||
interaction,
|
||||
methodName
|
||||
) {
|
||||
|
||||
/*
|
||||
* The original /cookies heist command stores
|
||||
* the player ID inside the embed footer:
|
||||
* Validate ownership of this Heist menu.
|
||||
*
|
||||
* cookieHeist:123456789
|
||||
* Footer:
|
||||
*
|
||||
* This prevents somebody else from pressing
|
||||
* another player's heist buttons.
|
||||
* cookieHeist:<userId>
|
||||
*/
|
||||
|
||||
const footer =
|
||||
@@ -139,10 +100,8 @@ async function resolveCookieHeist(
|
||||
type,
|
||||
ownerId
|
||||
] =
|
||||
footer
|
||||
?.split(":")
|
||||
??
|
||||
[];
|
||||
footer?.split(":")
|
||||
?? [];
|
||||
|
||||
|
||||
if (
|
||||
@@ -153,14 +112,14 @@ async function resolveCookieHeist(
|
||||
interaction,
|
||||
{
|
||||
content:
|
||||
"This isn't your heist. Start your own with `/cookies heist`."
|
||||
"This isn't your heist. Open your own from `/crumbsaucer`."
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Validate selected method.
|
||||
* Validate method.
|
||||
*/
|
||||
|
||||
const method =
|
||||
@@ -182,11 +141,18 @@ async function resolveCookieHeist(
|
||||
|
||||
/*
|
||||
* ========================================================
|
||||
* CLAIM COOLDOWN
|
||||
* SHARED HEIST COOLDOWN
|
||||
* ========================================================
|
||||
*
|
||||
* This is atomic so rapid double-clicks can't
|
||||
* resolve the same heist multiple times.
|
||||
* IMPORTANT:
|
||||
*
|
||||
* This is intentionally always "heist".
|
||||
*
|
||||
* It does NOT use:
|
||||
*
|
||||
* heistSneak
|
||||
* heistHack
|
||||
* heistSmash
|
||||
*/
|
||||
|
||||
const cooldown =
|
||||
@@ -203,18 +169,18 @@ async function resolveCookieHeist(
|
||||
interaction,
|
||||
{
|
||||
content:
|
||||
`You can attempt another vault heist <t:${cooldown.next}:R>.`
|
||||
}
|
||||
`🏦 The vault is still on high alert.\nYou can attempt another heist <t:${cooldown.next}:R>.`
|
||||
},
|
||||
6000
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ========================================================
|
||||
* LOCK THE HEIST MESSAGE
|
||||
* ========================================================
|
||||
* Lock this Heist interaction immediately.
|
||||
*
|
||||
* Remove all buttons immediately.
|
||||
* Prevents selecting another approach from
|
||||
* the same message.
|
||||
*/
|
||||
|
||||
await interaction.update({
|
||||
@@ -234,12 +200,6 @@ async function resolveCookieHeist(
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
* ========================================================
|
||||
* GET BALANCES
|
||||
* ========================================================
|
||||
*/
|
||||
|
||||
const playerId =
|
||||
interaction.user.id;
|
||||
|
||||
@@ -247,12 +207,16 @@ async function resolveCookieHeist(
|
||||
interaction.client.user.id;
|
||||
|
||||
|
||||
/*
|
||||
* Re-fetch balances because they may have
|
||||
* changed since the menu was opened.
|
||||
*/
|
||||
|
||||
const [
|
||||
playerCookies,
|
||||
vaultCookies
|
||||
] =
|
||||
await Promise.all([
|
||||
|
||||
getCookieBalance(
|
||||
playerId
|
||||
),
|
||||
@@ -260,15 +224,9 @@ async function resolveCookieHeist(
|
||||
getCookieBalance(
|
||||
vaultId
|
||||
)
|
||||
|
||||
]);
|
||||
|
||||
|
||||
/*
|
||||
* Something may have changed between opening
|
||||
* the heist menu and pressing the button.
|
||||
*/
|
||||
|
||||
if (
|
||||
playerCookies < 1 ||
|
||||
vaultCookies < 1
|
||||
@@ -282,18 +240,23 @@ async function resolveCookieHeist(
|
||||
.setDescription(
|
||||
"There weren't enough Cookies available to resolve the heist."
|
||||
)
|
||||
.addFields({
|
||||
name:
|
||||
"Next Heist",
|
||||
|
||||
value:
|
||||
`<t:${cooldown.next}:R>`
|
||||
})
|
||||
],
|
||||
|
||||
components: []
|
||||
components:
|
||||
buildReturnButton()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Small dramatic pause.
|
||||
*
|
||||
* Only one edit happens after this, so this is
|
||||
* comfortably within Discord rate limits.
|
||||
* Short theatrical delay.
|
||||
*/
|
||||
|
||||
await sleep(
|
||||
@@ -303,13 +266,8 @@ async function resolveCookieHeist(
|
||||
|
||||
/*
|
||||
* ========================================================
|
||||
* VAULT DIFFICULTY
|
||||
* DYNAMIC VAULT SECURITY
|
||||
* ========================================================
|
||||
*
|
||||
* The richer ShaiBot's vault becomes,
|
||||
* the harder it is to rob.
|
||||
*
|
||||
* Penalty is capped at 15 percentage points.
|
||||
*/
|
||||
|
||||
const securityPenalty =
|
||||
@@ -339,38 +297,21 @@ async function resolveCookieHeist(
|
||||
*/
|
||||
|
||||
if (success) {
|
||||
|
||||
/*
|
||||
* Roll percentage of the current vault.
|
||||
*/
|
||||
|
||||
const percent =
|
||||
const rolledPercent =
|
||||
randomFloat(
|
||||
method.minStealPercent,
|
||||
method.maxStealPercent
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Apply both:
|
||||
*
|
||||
* percentage roll
|
||||
* AND
|
||||
* hard maximum
|
||||
*
|
||||
* This prevents a massive vault from producing
|
||||
* absurd payouts.
|
||||
*/
|
||||
|
||||
const amount =
|
||||
Math.max(
|
||||
1,
|
||||
|
||||
Math.min(
|
||||
|
||||
Math.floor(
|
||||
vaultCookies *
|
||||
percent
|
||||
rolledPercent
|
||||
),
|
||||
|
||||
method.maxStealAmount,
|
||||
@@ -380,28 +321,67 @@ async function resolveCookieHeist(
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* ShaiBot pays the robber.
|
||||
*/
|
||||
|
||||
await transferCookies(
|
||||
vaultId,
|
||||
playerId,
|
||||
amount
|
||||
);
|
||||
|
||||
|
||||
const remaining =
|
||||
await getCookieBalance(
|
||||
vaultId
|
||||
try {
|
||||
await transferCookies(
|
||||
vaultId,
|
||||
playerId,
|
||||
amount
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
if (
|
||||
error.message ===
|
||||
"INSUFFICIENT_COOKIES"
|
||||
) {
|
||||
return interaction.editReply({
|
||||
embeds: [
|
||||
new EmbedBuilder()
|
||||
.setTitle(
|
||||
"🏦 Heist Interrupted"
|
||||
)
|
||||
.setDescription(
|
||||
"The ShaiBot Vault changed before you could complete the robbery."
|
||||
)
|
||||
.addFields({
|
||||
name:
|
||||
"Next Heist",
|
||||
|
||||
value:
|
||||
`<t:${cooldown.next}:R>`
|
||||
})
|
||||
],
|
||||
|
||||
components:
|
||||
buildReturnButton()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
|
||||
const [
|
||||
playerAfter,
|
||||
vaultAfter
|
||||
] =
|
||||
await Promise.all([
|
||||
getCookieBalance(
|
||||
playerId
|
||||
),
|
||||
|
||||
getCookieBalance(
|
||||
vaultId
|
||||
)
|
||||
]);
|
||||
|
||||
|
||||
const actualPercentage =
|
||||
(
|
||||
amount /
|
||||
vaultCookies
|
||||
) *
|
||||
)
|
||||
*
|
||||
100;
|
||||
|
||||
|
||||
@@ -410,6 +390,7 @@ async function resolveCookieHeist(
|
||||
.setTitle(
|
||||
"💥 Vault Breached!"
|
||||
)
|
||||
|
||||
.setDescription(
|
||||
getSuccessText(
|
||||
methodName,
|
||||
@@ -417,8 +398,8 @@ async function resolveCookieHeist(
|
||||
amount
|
||||
)
|
||||
)
|
||||
.addFields(
|
||||
|
||||
.addFields(
|
||||
{
|
||||
name:
|
||||
"Approach",
|
||||
@@ -465,10 +446,21 @@ async function resolveCookieHeist(
|
||||
|
||||
{
|
||||
name:
|
||||
"Vault Remaining",
|
||||
"Your Vault",
|
||||
|
||||
value:
|
||||
`**${remaining.toLocaleString()} 🍪**`,
|
||||
`**${playerAfter.toLocaleString()} 🍪**`,
|
||||
|
||||
inline:
|
||||
true
|
||||
},
|
||||
|
||||
{
|
||||
name:
|
||||
"House Vault",
|
||||
|
||||
value:
|
||||
`**${vaultAfter.toLocaleString()} 🍪**`,
|
||||
|
||||
inline:
|
||||
true
|
||||
@@ -482,9 +474,8 @@ async function resolveCookieHeist(
|
||||
`<t:${cooldown.next}:R>`,
|
||||
|
||||
inline:
|
||||
true
|
||||
false
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
|
||||
@@ -493,7 +484,8 @@ async function resolveCookieHeist(
|
||||
embed
|
||||
],
|
||||
|
||||
components: []
|
||||
components:
|
||||
buildReturnButton()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -502,11 +494,6 @@ async function resolveCookieHeist(
|
||||
* ========================================================
|
||||
* FAILURE
|
||||
* ========================================================
|
||||
*
|
||||
* Failure fines the player.
|
||||
*
|
||||
* Unlike normal player stealing, the fine goes
|
||||
* directly into ShaiBot's vault.
|
||||
*/
|
||||
|
||||
const penaltyPercent =
|
||||
@@ -521,7 +508,6 @@ async function resolveCookieHeist(
|
||||
1,
|
||||
|
||||
Math.min(
|
||||
|
||||
Math.floor(
|
||||
playerCookies *
|
||||
penaltyPercent
|
||||
@@ -532,11 +518,49 @@ async function resolveCookieHeist(
|
||||
);
|
||||
|
||||
|
||||
await transferCookies(
|
||||
playerId,
|
||||
vaultId,
|
||||
penalty
|
||||
);
|
||||
try {
|
||||
/*
|
||||
* Heist fines always go into
|
||||
* ShaiBot's central vault.
|
||||
*/
|
||||
|
||||
await transferCookies(
|
||||
playerId,
|
||||
vaultId,
|
||||
penalty
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
if (
|
||||
error.message ===
|
||||
"INSUFFICIENT_COOKIES"
|
||||
) {
|
||||
return interaction.editReply({
|
||||
embeds: [
|
||||
new EmbedBuilder()
|
||||
.setTitle(
|
||||
"🚨 Heist Failed"
|
||||
)
|
||||
.setDescription(
|
||||
"Your Cookie balance changed before the fine could be collected."
|
||||
)
|
||||
.addFields({
|
||||
name:
|
||||
"Next Heist",
|
||||
|
||||
value:
|
||||
`<t:${cooldown.next}:R>`
|
||||
})
|
||||
],
|
||||
|
||||
components:
|
||||
buildReturnButton()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
|
||||
const [
|
||||
@@ -544,7 +568,6 @@ async function resolveCookieHeist(
|
||||
vaultAfter
|
||||
] =
|
||||
await Promise.all([
|
||||
|
||||
getCookieBalance(
|
||||
playerId
|
||||
),
|
||||
@@ -552,15 +575,24 @@ async function resolveCookieHeist(
|
||||
getCookieBalance(
|
||||
vaultId
|
||||
)
|
||||
|
||||
]);
|
||||
|
||||
|
||||
const actualPenaltyPercentage =
|
||||
(
|
||||
penalty /
|
||||
playerCookies
|
||||
)
|
||||
*
|
||||
100;
|
||||
|
||||
|
||||
const embed =
|
||||
new EmbedBuilder()
|
||||
.setTitle(
|
||||
"🚨 HEIST FAILED"
|
||||
)
|
||||
|
||||
.setDescription(
|
||||
getFailureText(
|
||||
methodName,
|
||||
@@ -568,8 +600,8 @@ async function resolveCookieHeist(
|
||||
penalty
|
||||
)
|
||||
)
|
||||
.addFields(
|
||||
|
||||
.addFields(
|
||||
{
|
||||
name:
|
||||
"Approach",
|
||||
@@ -603,6 +635,17 @@ async function resolveCookieHeist(
|
||||
true
|
||||
},
|
||||
|
||||
{
|
||||
name:
|
||||
"Vault Lost",
|
||||
|
||||
value:
|
||||
`**${actualPenaltyPercentage.toFixed(1)}%**`,
|
||||
|
||||
inline:
|
||||
true
|
||||
},
|
||||
|
||||
{
|
||||
name:
|
||||
"Your Vault",
|
||||
@@ -633,9 +676,8 @@ async function resolveCookieHeist(
|
||||
`<t:${cooldown.next}:R>`,
|
||||
|
||||
inline:
|
||||
true
|
||||
false
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
|
||||
@@ -644,26 +686,51 @@ async function resolveCookieHeist(
|
||||
embed
|
||||
],
|
||||
|
||||
components: []
|
||||
components:
|
||||
buildReturnButton()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* VAULT SECURITY
|
||||
* RETURN TO CRUMB SAUCER
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
function buildReturnButton() {
|
||||
return [
|
||||
new ActionRowBuilder()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbSaucerBack"
|
||||
)
|
||||
.setLabel(
|
||||
"Back to Crumb Saucer"
|
||||
)
|
||||
.setEmoji(
|
||||
"◀️"
|
||||
)
|
||||
.setStyle(
|
||||
ButtonStyle.Secondary
|
||||
)
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* SECURITY
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
function getVaultSecurityPenalty(
|
||||
vaultCookies
|
||||
) {
|
||||
|
||||
/*
|
||||
* Logarithmic scaling means the vault gets harder
|
||||
* as it becomes richer without becoming impossible.
|
||||
*
|
||||
* Examples approximately:
|
||||
* Approximately:
|
||||
*
|
||||
* 100 -> 5%
|
||||
* 1,000 -> 7.5%
|
||||
@@ -673,10 +740,11 @@ function getVaultSecurityPenalty(
|
||||
*/
|
||||
|
||||
return Math.min(
|
||||
|
||||
Math.log10(
|
||||
vaultCookies + 1
|
||||
) *
|
||||
vaultCookies +
|
||||
1
|
||||
)
|
||||
*
|
||||
0.025,
|
||||
|
||||
0.15
|
||||
@@ -686,18 +754,16 @@ function getVaultSecurityPenalty(
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* FLAVOR TEXT
|
||||
* PROGRESS TEXT
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
function getHeistProgressText(
|
||||
methodName
|
||||
) {
|
||||
|
||||
switch (
|
||||
methodName
|
||||
) {
|
||||
|
||||
case "Sneak":
|
||||
return [
|
||||
"🥷 You slip through the service entrance...",
|
||||
@@ -728,65 +794,73 @@ function getHeistProgressText(
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* SUCCESS TEXT
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
function getSuccessText(
|
||||
methodName,
|
||||
user,
|
||||
amount
|
||||
) {
|
||||
|
||||
const amountText =
|
||||
const cookies =
|
||||
`**${amount.toLocaleString()} Cookies**`;
|
||||
|
||||
|
||||
switch (
|
||||
methodName
|
||||
) {
|
||||
|
||||
case "Sneak":
|
||||
return (
|
||||
`🥷 ${user} slipped through security and quietly escaped with ${amountText}.`
|
||||
`🥷 ${user} slipped through security and quietly escaped with ${cookies}.`
|
||||
);
|
||||
|
||||
|
||||
case "Hack":
|
||||
return (
|
||||
`💻 ${user} convinced the vault terminal that ${amountText} belonged to them.`
|
||||
`💻 ${user} convinced the vault terminal that ${cookies} belonged to them.`
|
||||
);
|
||||
|
||||
|
||||
case "Smash":
|
||||
return (
|
||||
`💥 ${user} smashed through the Cookie Vault and escaped with ${amountText}!`
|
||||
`💥 ${user} smashed through the Cookie Vault and escaped with ${cookies}!`
|
||||
);
|
||||
|
||||
|
||||
default:
|
||||
return (
|
||||
`${user} escaped with ${amountText}.`
|
||||
`${user} escaped with ${cookies}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* FAILURE TEXT
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
function getFailureText(
|
||||
methodName,
|
||||
user,
|
||||
penalty
|
||||
) {
|
||||
|
||||
const penaltyText =
|
||||
const cookies =
|
||||
`**${penalty.toLocaleString()} Cookies**`;
|
||||
|
||||
|
||||
switch (
|
||||
methodName
|
||||
) {
|
||||
|
||||
case "Sneak":
|
||||
return [
|
||||
`🚨 ${user} stepped directly on the world's loudest Cookie wrapper.`,
|
||||
"",
|
||||
`The ShaiBot Vault collected a ${penaltyText} fine.`
|
||||
`The ShaiBot Vault collected a ${cookies} fine.`
|
||||
].join("\n");
|
||||
|
||||
|
||||
@@ -794,7 +868,7 @@ function getFailureText(
|
||||
return [
|
||||
`🚨 ${user} entered the password incorrectly one too many times.`,
|
||||
"",
|
||||
`The ShaiBot Vault collected a ${penaltyText} security fee.`
|
||||
`The ShaiBot Vault collected a ${cookies} security fee.`
|
||||
].join("\n");
|
||||
|
||||
|
||||
@@ -802,13 +876,13 @@ function getFailureText(
|
||||
return [
|
||||
`🚨 ${user} discovered that the vault door is significantly stronger than expected.`,
|
||||
"",
|
||||
`Repairs cost ${penaltyText}. Naturally, you're paying.`
|
||||
`Repairs cost ${cookies}. Naturally, you're paying.`
|
||||
].join("\n");
|
||||
|
||||
|
||||
default:
|
||||
return (
|
||||
`The heist failed and cost ${user} ${penaltyText}.`
|
||||
`The heist failed and cost ${user} ${cookies}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -832,5 +906,6 @@ function sleep(ms) {
|
||||
|
||||
|
||||
module.exports = {
|
||||
resolveCookieHeist
|
||||
resolveCookieHeist,
|
||||
HEIST_COOLDOWN
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user