Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0407f4d7f1 | |||
| 0f48f09bd9 |
@@ -1,18 +0,0 @@
|
||||
const {
|
||||
performBossAction
|
||||
} = require(
|
||||
"../../utils/cookieBoss"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"cookieBossBurst",
|
||||
|
||||
async execute(interaction) {
|
||||
return performBossAction(
|
||||
interaction,
|
||||
"Burst"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
const {
|
||||
joinBoss
|
||||
} = require(
|
||||
"../../utils/cookieBoss"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"cookieBossJoinChampion",
|
||||
|
||||
async execute(interaction) {
|
||||
return joinBoss(
|
||||
interaction,
|
||||
"Champion"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
const {
|
||||
joinBoss
|
||||
} = require(
|
||||
"../../utils/cookieBoss"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"cookieBossJoinFighter",
|
||||
|
||||
async execute(interaction) {
|
||||
return joinBoss(
|
||||
interaction,
|
||||
"Fighter"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
const {
|
||||
joinBoss
|
||||
} = require(
|
||||
"../../utils/cookieBoss"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"cookieBossJoinScout",
|
||||
|
||||
async execute(interaction) {
|
||||
return joinBoss(
|
||||
interaction,
|
||||
"Scout"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
const {
|
||||
performBossAction
|
||||
} = require(
|
||||
"../../utils/cookieBoss"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"cookieBossLimit",
|
||||
|
||||
async execute(interaction) {
|
||||
return performBossAction(
|
||||
interaction,
|
||||
"Limit"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
const {
|
||||
startBossBattle
|
||||
} = require(
|
||||
"../../utils/cookieBoss"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"cookieBossStart",
|
||||
|
||||
async execute(interaction) {
|
||||
return startBossBattle(
|
||||
interaction
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -7,11 +7,19 @@ const {
|
||||
|
||||
const {
|
||||
getCookieBalance,
|
||||
getCooldown,
|
||||
getUnixTime,
|
||||
temporaryEphemeralReply
|
||||
} = require(
|
||||
"../../utils/cookieEconomy"
|
||||
);
|
||||
|
||||
const {
|
||||
HEIST_COOLDOWN
|
||||
} = require(
|
||||
"../../utils/cookieHeist"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
@@ -19,6 +27,10 @@ module.exports = {
|
||||
|
||||
|
||||
async execute(interaction) {
|
||||
/*
|
||||
* Verify ownership of the Crumb Saucer menu.
|
||||
*/
|
||||
|
||||
const footer =
|
||||
interaction.message
|
||||
.embeds[0]
|
||||
@@ -30,17 +42,13 @@ module.exports = {
|
||||
type,
|
||||
ownerId
|
||||
] =
|
||||
footer
|
||||
?.split(":")
|
||||
??
|
||||
[];
|
||||
footer?.split(":")
|
||||
?? [];
|
||||
|
||||
|
||||
if (
|
||||
type !==
|
||||
"crumbSaucer" ||
|
||||
ownerId !==
|
||||
interaction.user.id
|
||||
type !== "crumbSaucer" ||
|
||||
ownerId !== interaction.user.id
|
||||
) {
|
||||
return temporaryEphemeralReply(
|
||||
interaction,
|
||||
@@ -52,6 +60,43 @@ module.exports = {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ====================================================
|
||||
* SHARED HEIST COOLDOWN PRE-CHECK
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
const now =
|
||||
getUnixTime();
|
||||
|
||||
|
||||
const cooldown =
|
||||
await getCooldown(
|
||||
interaction.user.id,
|
||||
interaction.guildId,
|
||||
"heist"
|
||||
);
|
||||
|
||||
|
||||
if (
|
||||
cooldown >
|
||||
now
|
||||
) {
|
||||
return temporaryEphemeralReply(
|
||||
interaction,
|
||||
{
|
||||
content:
|
||||
`🏦 The ShaiBot Vault is still on alert.\nYou can attempt another heist <t:${cooldown}:R>.`
|
||||
},
|
||||
6000
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Balances
|
||||
*/
|
||||
|
||||
const vaultId =
|
||||
interaction.client.user.id;
|
||||
|
||||
@@ -72,7 +117,8 @@ module.exports = {
|
||||
|
||||
|
||||
if (
|
||||
player < 1
|
||||
player <
|
||||
1
|
||||
) {
|
||||
return temporaryEphemeralReply(
|
||||
interaction,
|
||||
@@ -85,7 +131,8 @@ module.exports = {
|
||||
|
||||
|
||||
if (
|
||||
vault < 1
|
||||
vault <
|
||||
1
|
||||
) {
|
||||
return temporaryEphemeralReply(
|
||||
interaction,
|
||||
@@ -97,11 +144,16 @@ module.exports = {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Heist menu
|
||||
*/
|
||||
|
||||
const embed =
|
||||
new EmbedBuilder()
|
||||
.setTitle(
|
||||
"🏦 ShaiBot Cookie Vault"
|
||||
)
|
||||
|
||||
.setDescription(
|
||||
[
|
||||
`**Vault Balance:** ${vault.toLocaleString()} 🍪`,
|
||||
@@ -119,6 +171,7 @@ module.exports = {
|
||||
"Low chance • Large haul • Large fine"
|
||||
].join("\n")
|
||||
)
|
||||
|
||||
.setFooter({
|
||||
text:
|
||||
`cookieHeist:${interaction.user.id}`
|
||||
@@ -172,19 +225,43 @@ module.exports = {
|
||||
);
|
||||
|
||||
|
||||
const backButton =
|
||||
new ActionRowBuilder()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbSaucerBack"
|
||||
)
|
||||
.setLabel(
|
||||
"Back to Crumb Saucer"
|
||||
)
|
||||
.setEmoji(
|
||||
"◀️"
|
||||
)
|
||||
.setStyle(
|
||||
ButtonStyle.Secondary
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
return interaction.update({
|
||||
embeds: [
|
||||
embed
|
||||
],
|
||||
|
||||
components: [
|
||||
heistButtons
|
||||
heistButtons,
|
||||
backButton
|
||||
]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* SECURITY LABEL
|
||||
*/
|
||||
|
||||
function getSecurityLabel(
|
||||
vault
|
||||
) {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
const {
|
||||
performCrumbleStrikeAction
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeDefend",
|
||||
|
||||
async execute(interaction) {
|
||||
return performCrumbleStrikeAction(
|
||||
interaction,
|
||||
"Defend"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
const {
|
||||
performCrumbleStrikeAction
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeHeal",
|
||||
|
||||
async execute(interaction) {
|
||||
return performCrumbleStrikeAction(
|
||||
interaction,
|
||||
"Heal"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
const {
|
||||
chooseCrumbleStrikeJob
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeJobAstrologian",
|
||||
|
||||
async execute(interaction) {
|
||||
return chooseCrumbleStrikeJob(
|
||||
interaction,
|
||||
"Healer",
|
||||
"Astrologian"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
const {
|
||||
chooseCrumbleStrikeJob
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeJobBard",
|
||||
|
||||
async execute(interaction) {
|
||||
return chooseCrumbleStrikeJob(
|
||||
interaction,
|
||||
"DPS",
|
||||
"Bard"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
const {
|
||||
chooseCrumbleStrikeJob
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeJobBlackMage",
|
||||
|
||||
async execute(interaction) {
|
||||
return chooseCrumbleStrikeJob(
|
||||
interaction,
|
||||
"DPS",
|
||||
"BlackMage"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
const {
|
||||
chooseCrumbleStrikeJob
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeJobDarkKnight",
|
||||
|
||||
async execute(interaction) {
|
||||
return chooseCrumbleStrikeJob(
|
||||
interaction,
|
||||
"Tank",
|
||||
"DarkKnight"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
const {
|
||||
chooseCrumbleStrikeJob
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeJobDragoon",
|
||||
|
||||
async execute(interaction) {
|
||||
return chooseCrumbleStrikeJob(
|
||||
interaction,
|
||||
"DPS",
|
||||
"Dragoon"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
const {
|
||||
chooseCrumbleStrikeJob
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeJobPaladin",
|
||||
|
||||
async execute(interaction) {
|
||||
return chooseCrumbleStrikeJob(
|
||||
interaction,
|
||||
"Tank",
|
||||
"Paladin"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
const {
|
||||
chooseCrumbleStrikeJob
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeJobScholar",
|
||||
|
||||
async execute(interaction) {
|
||||
return chooseCrumbleStrikeJob(
|
||||
interaction,
|
||||
"Healer",
|
||||
"Scholar"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
const {
|
||||
chooseCrumbleStrikeJob
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeJobWarrior",
|
||||
|
||||
async execute(interaction) {
|
||||
return chooseCrumbleStrikeJob(
|
||||
interaction,
|
||||
"Tank",
|
||||
"Warrior"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
const {
|
||||
chooseCrumbleStrikeJob
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeJobWhiteMage",
|
||||
|
||||
async execute(interaction) {
|
||||
return chooseCrumbleStrikeJob(
|
||||
interaction,
|
||||
"Healer",
|
||||
"WhiteMage"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
const {
|
||||
performCrumbleStrikeAction
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeLimitBreak",
|
||||
|
||||
async execute(interaction) {
|
||||
return performCrumbleStrikeAction(
|
||||
interaction,
|
||||
"LimitBreak"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
const {
|
||||
performCrumbleStrikeAction
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeRevive",
|
||||
|
||||
async execute(interaction) {
|
||||
return performCrumbleStrikeAction(
|
||||
interaction,
|
||||
"Revive"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
const {
|
||||
chooseCrumbleStrikeRole
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeRoleDPS",
|
||||
|
||||
async execute(interaction) {
|
||||
return chooseCrumbleStrikeRole(
|
||||
interaction,
|
||||
"DPS"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
const {
|
||||
chooseCrumbleStrikeRole
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeRoleHealer",
|
||||
|
||||
async execute(interaction) {
|
||||
return chooseCrumbleStrikeRole(
|
||||
interaction,
|
||||
"Healer"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
const {
|
||||
chooseCrumbleStrikeRole
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeRoleTank",
|
||||
|
||||
async execute(interaction) {
|
||||
return chooseCrumbleStrikeRole(
|
||||
interaction,
|
||||
"Tank"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
const {
|
||||
startCrumbleStrikeBattle
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeStart",
|
||||
|
||||
async execute(interaction) {
|
||||
return startCrumbleStrikeBattle(
|
||||
interaction
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,16 +1,16 @@
|
||||
const {
|
||||
performBossAction
|
||||
performCrumbleStrikeAction
|
||||
} = require(
|
||||
"../../utils/cookieBoss"
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"cookieBossStrike",
|
||||
"crumbleStrikeStrike",
|
||||
|
||||
async execute(interaction) {
|
||||
return performBossAction(
|
||||
return performCrumbleStrikeAction(
|
||||
interaction,
|
||||
"Strike"
|
||||
);
|
||||
@@ -0,0 +1,18 @@
|
||||
const {
|
||||
confirmCrumbleStrikeJoin
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeTierAdventurer",
|
||||
|
||||
async execute(interaction) {
|
||||
return confirmCrumbleStrikeJoin(
|
||||
interaction,
|
||||
"Adventurer"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
const {
|
||||
confirmCrumbleStrikeJoin
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeTierSprout",
|
||||
|
||||
async execute(interaction) {
|
||||
return confirmCrumbleStrikeJoin(
|
||||
interaction,
|
||||
"Sprout"
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
const {
|
||||
confirmCrumbleStrikeJoin
|
||||
} = require(
|
||||
"../../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
module.exports = {
|
||||
name:
|
||||
"crumbleStrikeTierWarriorOfLight",
|
||||
|
||||
async execute(interaction) {
|
||||
return confirmCrumbleStrikeJoin(
|
||||
interaction,
|
||||
"WarriorOfLight"
|
||||
);
|
||||
}
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,230 +0,0 @@
|
||||
const {
|
||||
getCollections,
|
||||
getUnixTime
|
||||
} = require("../utils/cookieEconomy");
|
||||
|
||||
const {
|
||||
activateBoss,
|
||||
failBoss,
|
||||
cancelBossAndRefund
|
||||
} = require("../utils/cookieBoss");
|
||||
|
||||
|
||||
/*
|
||||
* How often we check persistent boss timers.
|
||||
*
|
||||
* Discord timestamps handle the visible countdown,
|
||||
* so checking once per minute is plenty.
|
||||
*/
|
||||
const CHECK_INTERVAL = 60 * 1000;
|
||||
|
||||
|
||||
/*
|
||||
* Your index.js automatically loads every file
|
||||
* inside /handlers and passes the Discord client:
|
||||
*
|
||||
* require(`./handlers/${handler}`)(client)
|
||||
*/
|
||||
module.exports = (client) => {
|
||||
|
||||
/*
|
||||
* Run shortly after startup.
|
||||
*
|
||||
* This catches boss events whose timers expired
|
||||
* while ShaiBot was offline/restarting.
|
||||
*/
|
||||
setTimeout(() => {
|
||||
processBossEvents(client);
|
||||
}, 5000);
|
||||
|
||||
|
||||
/*
|
||||
* Persistent boss event watcher.
|
||||
*/
|
||||
setInterval(() => {
|
||||
processBossEvents(client);
|
||||
}, CHECK_INTERVAL);
|
||||
|
||||
|
||||
console.log(
|
||||
"[CookieBoss] Boss event watcher initialized"
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Check all currently pending Cookie Boss events.
|
||||
*/
|
||||
async function processBossEvents(client) {
|
||||
try {
|
||||
const {
|
||||
db
|
||||
} = getCollections();
|
||||
|
||||
|
||||
const events =
|
||||
db.collection(
|
||||
"items_events"
|
||||
);
|
||||
|
||||
|
||||
const now =
|
||||
getUnixTime();
|
||||
|
||||
|
||||
/*
|
||||
* ==========================================
|
||||
* JOINING PHASE
|
||||
* ==========================================
|
||||
*
|
||||
* Recruitment lasts for 30 minutes.
|
||||
*
|
||||
* If 5+ players joined:
|
||||
* start the battle automatically.
|
||||
*
|
||||
* If fewer than 5 joined:
|
||||
* cancel the boss and refund everyone.
|
||||
*/
|
||||
|
||||
const joiningEvents =
|
||||
await events
|
||||
.find({
|
||||
eventType:
|
||||
"CookieBoss",
|
||||
|
||||
state:
|
||||
"Joining",
|
||||
|
||||
joinUntil: {
|
||||
$lte: now
|
||||
}
|
||||
})
|
||||
.toArray();
|
||||
|
||||
|
||||
for (
|
||||
const event
|
||||
of joiningEvents
|
||||
) {
|
||||
const participantCount =
|
||||
Object.keys(
|
||||
event.participants ?? {}
|
||||
).length;
|
||||
|
||||
|
||||
console.log(
|
||||
`[CookieBoss] Recruitment expired for ${event.eventId} ` +
|
||||
`(${participantCount}/${event.minimumParticipants} players)`
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Enough players joined.
|
||||
*
|
||||
* Start the fight automatically.
|
||||
*/
|
||||
if (
|
||||
participantCount >=
|
||||
event.minimumParticipants
|
||||
) {
|
||||
const started =
|
||||
await activateBoss(
|
||||
client,
|
||||
event.eventId
|
||||
);
|
||||
|
||||
|
||||
if (started) {
|
||||
console.log(
|
||||
`[CookieBoss] Battle ${event.eventId} started automatically`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Not enough players.
|
||||
*
|
||||
* Nobody actually entered combat,
|
||||
* so refund all committed Cookies.
|
||||
*/
|
||||
await cancelBossAndRefund(
|
||||
client,
|
||||
event.eventId
|
||||
);
|
||||
|
||||
|
||||
console.log(
|
||||
`[CookieBoss] Battle ${event.eventId} cancelled and refunded`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ==========================================
|
||||
* ACTIVE BATTLES
|
||||
* ==========================================
|
||||
*
|
||||
* If the battle timer expires while the
|
||||
* boss still has HP remaining, the raid fails.
|
||||
*
|
||||
* All Cookies held in the encounter escrow
|
||||
* are transferred to the ShaiBot vault.
|
||||
*/
|
||||
|
||||
const activeEvents =
|
||||
await events
|
||||
.find({
|
||||
eventType:
|
||||
"CookieBoss",
|
||||
|
||||
state:
|
||||
"Active",
|
||||
|
||||
battleEndsAt: {
|
||||
$lte: now
|
||||
},
|
||||
|
||||
"boss.health": {
|
||||
$gt: 0
|
||||
}
|
||||
})
|
||||
.toArray();
|
||||
|
||||
|
||||
for (
|
||||
const event
|
||||
of activeEvents
|
||||
) {
|
||||
console.log(
|
||||
`[CookieBoss] Battle ${event.eventId} expired ` +
|
||||
`with ${event.boss.health}/${event.boss.maxHealth} HP remaining`
|
||||
);
|
||||
|
||||
|
||||
await failBoss(
|
||||
client,
|
||||
event.eventId
|
||||
);
|
||||
|
||||
|
||||
console.log(
|
||||
`[CookieBoss] Battle ${event.eventId} failed`
|
||||
);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
/*
|
||||
* Never let an exception kill the interval.
|
||||
*
|
||||
* The next watcher tick will simply try again.
|
||||
*/
|
||||
console.error(
|
||||
"[CookieBoss] Boss watcher error:",
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
const {
|
||||
getCollections,
|
||||
getUnixTime
|
||||
} = require(
|
||||
"../utils/cookieEconomy"
|
||||
);
|
||||
|
||||
const {
|
||||
activateCrumbleStrike,
|
||||
failCrumbleStrike,
|
||||
cancelCrumbleStrikeAndRefund
|
||||
} = require(
|
||||
"../utils/crumbleStrike"
|
||||
);
|
||||
|
||||
|
||||
const CHECK_INTERVAL =
|
||||
60 * 1000;
|
||||
|
||||
|
||||
module.exports = client => {
|
||||
|
||||
setTimeout(
|
||||
() => {
|
||||
processCrumbleStrikeEvents(
|
||||
client
|
||||
);
|
||||
},
|
||||
5000
|
||||
);
|
||||
|
||||
|
||||
setInterval(
|
||||
() => {
|
||||
processCrumbleStrikeEvents(
|
||||
client
|
||||
);
|
||||
},
|
||||
CHECK_INTERVAL
|
||||
);
|
||||
|
||||
|
||||
console.log(
|
||||
"[CrumbleStrike] Event watcher initialized"
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
async function processCrumbleStrikeEvents(
|
||||
client
|
||||
) {
|
||||
try {
|
||||
const {
|
||||
db
|
||||
} =
|
||||
getCollections();
|
||||
|
||||
|
||||
const events =
|
||||
db.collection(
|
||||
"items_events"
|
||||
);
|
||||
|
||||
|
||||
const now =
|
||||
getUnixTime();
|
||||
|
||||
|
||||
/*
|
||||
* Recruitment expired.
|
||||
*/
|
||||
|
||||
const joiningEvents =
|
||||
await events
|
||||
.find({
|
||||
eventType:
|
||||
"CrumbleStrike",
|
||||
|
||||
state:
|
||||
"Joining",
|
||||
|
||||
joinUntil: {
|
||||
$lte:
|
||||
now
|
||||
}
|
||||
})
|
||||
.toArray();
|
||||
|
||||
|
||||
for (
|
||||
const event
|
||||
of joiningEvents
|
||||
) {
|
||||
const participantCount =
|
||||
Object.keys(
|
||||
event.participants ??
|
||||
{}
|
||||
).length;
|
||||
|
||||
|
||||
console.log(
|
||||
`[CrumbleStrike] Recruitment expired for ${event.eventId} ` +
|
||||
`(${participantCount}/${event.minimumParticipants})`
|
||||
);
|
||||
|
||||
|
||||
if (
|
||||
participantCount >=
|
||||
event.minimumParticipants
|
||||
) {
|
||||
const started =
|
||||
await activateCrumbleStrike(
|
||||
client,
|
||||
event.eventId
|
||||
);
|
||||
|
||||
|
||||
if (started) {
|
||||
console.log(
|
||||
`[CrumbleStrike] ${event.eventId} started automatically`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
const cancelled =
|
||||
await cancelCrumbleStrikeAndRefund(
|
||||
client,
|
||||
event.eventId
|
||||
);
|
||||
|
||||
|
||||
if (cancelled) {
|
||||
console.log(
|
||||
`[CrumbleStrike] ${event.eventId} cancelled and refunded`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Battle expired.
|
||||
*/
|
||||
|
||||
const activeEvents =
|
||||
await events
|
||||
.find({
|
||||
eventType:
|
||||
"CrumbleStrike",
|
||||
|
||||
state:
|
||||
"Active",
|
||||
|
||||
battleEndsAt: {
|
||||
$lte:
|
||||
now
|
||||
},
|
||||
|
||||
"boss.health": {
|
||||
$gt:
|
||||
0
|
||||
}
|
||||
})
|
||||
.toArray();
|
||||
|
||||
|
||||
for (
|
||||
const event
|
||||
of activeEvents
|
||||
) {
|
||||
console.log(
|
||||
`[CrumbleStrike] ${event.eventId} expired with ` +
|
||||
`${event.boss.health}/${event.boss.maxHealth} HP remaining`
|
||||
);
|
||||
|
||||
|
||||
const failed =
|
||||
await failCrumbleStrike(
|
||||
client,
|
||||
event.eventId
|
||||
);
|
||||
|
||||
|
||||
if (failed) {
|
||||
console.log(
|
||||
`[CrumbleStrike] ${event.eventId} failed`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"[CrumbleStrike] Watcher error:",
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
-1693
File diff suppressed because it is too large
Load Diff
+967
-181
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