201 lines
4.7 KiB
JavaScript
201 lines
4.7 KiB
JavaScript
const { getCollections, getCookieBalance, getUnixTime } = require("./cookieEconomy");
|
|
const { trackProfileEvent } = require("./profileSystem");
|
|
|
|
const BANKRUPTCY_COLLECTION = "items_bankruptcy";
|
|
const BANKRUPTCY_GRANT = 1000;
|
|
const BANKRUPTCY_COOLDOWN = 1 * 60 * 60;
|
|
|
|
function getBankruptcyCollection() {
|
|
return getCollections().db.collection(BANKRUPTCY_COLLECTION);
|
|
}
|
|
|
|
async function ensureBankruptcyIndexes() {
|
|
const bankruptcy = getBankruptcyCollection();
|
|
|
|
await bankruptcy.createIndex(
|
|
{ userId: 1, guildId: 1 },
|
|
{ unique: true }
|
|
);
|
|
}
|
|
|
|
async function getBankruptcyStatus(userId, guildId) {
|
|
const balance = await getCookieBalance(userId);
|
|
const document = await getBankruptcyCollection().findOne({
|
|
userId,
|
|
guildId
|
|
});
|
|
|
|
const now = getUnixTime();
|
|
const nextAvailableAt = Number(document?.nextAvailableAt ?? 0);
|
|
|
|
return {
|
|
balance,
|
|
eligible: balance === 0 && nextAvailableAt <= now,
|
|
nextAvailableAt,
|
|
claims: Number(document?.claims ?? 0)
|
|
};
|
|
}
|
|
|
|
async function declareBankruptcy(interaction, userId = interaction.user.id) {
|
|
const guildId = interaction.guildId;
|
|
|
|
if (!guildId) {
|
|
return {
|
|
ok: false,
|
|
reason: "GUILD_ONLY"
|
|
};
|
|
}
|
|
|
|
const { cookies } = getCollections();
|
|
const bankruptcy = getBankruptcyCollection();
|
|
const now = getUnixTime();
|
|
|
|
const previous = await bankruptcy.findOne({
|
|
userId,
|
|
guildId
|
|
});
|
|
|
|
const nextAvailableAt = Number(previous?.nextAvailableAt ?? 0);
|
|
|
|
if (nextAvailableAt > now) {
|
|
return {
|
|
ok: false,
|
|
reason: "COOLDOWN",
|
|
nextAvailableAt
|
|
};
|
|
}
|
|
|
|
let claimLock;
|
|
|
|
try {
|
|
claimLock = await bankruptcy.findOneAndUpdate(
|
|
{
|
|
userId,
|
|
guildId,
|
|
$or: [
|
|
{ nextAvailableAt: { $exists: false } },
|
|
{ nextAvailableAt: { $lte: now } }
|
|
]
|
|
},
|
|
{
|
|
$set: {
|
|
nextAvailableAt: now + BANKRUPTCY_COOLDOWN,
|
|
lastClaimedAt: now
|
|
},
|
|
$inc: {
|
|
claims: 1
|
|
},
|
|
$setOnInsert: {
|
|
userId,
|
|
guildId
|
|
}
|
|
},
|
|
{
|
|
upsert: true,
|
|
returnDocument: "after"
|
|
}
|
|
);
|
|
} catch (error) {
|
|
if (error?.code !== 11000) {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
if (!claimLock) {
|
|
const status = await getBankruptcyStatus(userId, guildId);
|
|
|
|
return {
|
|
ok: false,
|
|
reason: "COOLDOWN",
|
|
nextAvailableAt: status.nextAvailableAt
|
|
};
|
|
}
|
|
|
|
let credit;
|
|
|
|
try {
|
|
credit = await cookies.updateOne(
|
|
{
|
|
userId,
|
|
$or: [
|
|
{ cookies: 0 },
|
|
{ cookies: { $exists: false } }
|
|
]
|
|
},
|
|
{
|
|
$inc: {
|
|
cookies: BANKRUPTCY_GRANT
|
|
},
|
|
$setOnInsert: {
|
|
userId
|
|
}
|
|
},
|
|
{
|
|
upsert: true
|
|
}
|
|
);
|
|
} catch (error) {
|
|
if (error?.code !== 11000) {
|
|
throw error;
|
|
}
|
|
|
|
credit = { modifiedCount: 0, upsertedCount: 0 };
|
|
}
|
|
|
|
if (credit.modifiedCount !== 1 && credit.upsertedCount !== 1) {
|
|
await bankruptcy.updateOne(
|
|
{ userId, guildId },
|
|
{
|
|
$set: {
|
|
nextAvailableAt,
|
|
lastClaimedAt: previous?.lastClaimedAt ?? null,
|
|
claims: Number(previous?.claims ?? 0)
|
|
}
|
|
}
|
|
);
|
|
|
|
return {
|
|
ok: false,
|
|
reason: "BALANCE_NOT_ZERO",
|
|
balance: await getCookieBalance(userId)
|
|
};
|
|
}
|
|
|
|
await trackProfileEvent(
|
|
interaction,
|
|
userId,
|
|
{
|
|
type: "cookie_gain",
|
|
source: "bankruptcy",
|
|
amount:
|
|
BANKRUPTCY_GRANT
|
|
}
|
|
);
|
|
|
|
await trackProfileEvent(
|
|
interaction,
|
|
userId,
|
|
{
|
|
type: "bankruptcy",
|
|
source: "bankruptcy",
|
|
amount: BANKRUPTCY_GRANT
|
|
}
|
|
);
|
|
|
|
return {
|
|
ok: true,
|
|
amount: BANKRUPTCY_GRANT,
|
|
balance: BANKRUPTCY_GRANT,
|
|
nextAvailableAt: now + BANKRUPTCY_COOLDOWN,
|
|
claims: Number(claimLock.claims ?? 1)
|
|
};
|
|
}
|
|
|
|
module.exports = {
|
|
BANKRUPTCY_GRANT,
|
|
BANKRUPTCY_COOLDOWN,
|
|
ensureBankruptcyIndexes,
|
|
getBankruptcyStatus,
|
|
declareBankruptcy
|
|
};
|