Merge pull request #63 from cassoule/milo-251229

some bug fixes and changes
This commit is contained in:
Milo Gourvest
2025-12-30 01:32:37 +01:00
committed by GitHub
8 changed files with 134 additions and 41 deletions

View File

@@ -36,7 +36,7 @@ export async function DiscordRequest(endpoint, options) {
} catch (err) {
data = res;
}
console.error(`[${Date.now()}] Discord API Error on endpoint ${endpoint}:`, res.status, data);
console.error(`Discord API Error on endpoint ${endpoint}:`, res.status, data);
throw new Error(JSON.stringify(data));
}

View File

@@ -96,7 +96,7 @@ async function handleAiMention(message, client, io) {
const timestamps = (requestTimestamps.get(authorId) || []).filter((ts) => now - ts < SPAM_INTERVAL);
if (timestamps.length >= MAX_REQUESTS_PER_INTERVAL) {
console.log(`[${Date.now()}] Rate limit exceeded for ${authorDB.username}`);
console.log(`Rate limit exceeded for ${authorDB.username}`);
if (!authorDB.warned) {
await message.reply(`T'abuses fréro, attends un peu ⏳`).catch(console.error);
}

View File

@@ -748,7 +748,7 @@ export const updateManyUsers = flopoDB.transaction((users) => {
try {
updateUser.run(user);
} catch (e) {
console.log(`[${Date.now()}] user update failed`);
console.log(`User update failed`);
}
});

View File

@@ -15,7 +15,7 @@ export async function eloHandler(p1Id, p2Id, p1Score, p2Score, type) {
const p1DB = getUser.get(p1Id);
const p2DB = getUser.get(p2Id);
if (!p1DB || !p2DB) {
console.error(`[${Date.now()}] Elo Handler: Could not find user data for ${p1Id} or ${p2Id}.`);
console.error(`Elo Handler: Could not find user data for ${p1Id} or ${p2Id}.`);
return;
}
@@ -51,8 +51,8 @@ export async function eloHandler(p1Id, p2Id, p1Score, p2Score, type) {
const finalP1Elo = Math.max(0, p1NewElo);
const finalP2Elo = Math.max(0, p2NewElo);
console.log(`[${Date.now()}] Elo Update (${type}) for ${p1DB.globalName}: ${p1CurrentElo} -> ${finalP1Elo}`);
console.log(`[${Date.now()}] Elo Update (${type}) for ${p2DB.globalName}: ${p2CurrentElo} -> ${finalP2Elo}`);
console.log(`Elo Update (${type}) for ${p1DB.globalName}: ${p1CurrentElo} -> ${finalP1Elo}`);
console.log(`Elo Update (${type}) for ${p2DB.globalName}: ${p2CurrentElo} -> ${finalP2Elo}`);
try {
const generalChannel = await client.channels.fetch(process.env.BOT_CHANNEL_ID);
const user1 = await client.users.fetch(p1Id);
@@ -70,7 +70,7 @@ export async function eloHandler(p1Id, p2Id, p1Score, p2Score, type) {
.setColor("#5865f2");
await generalChannel.send({ embeds: [embed] });
} catch (e) {
console.error(`[${Date.now()}] Failed to post elo update message`, e);
console.error(`Failed to post elo update message`, e);
}
// --- 4. Update Database ---
@@ -156,7 +156,7 @@ export async function pokerEloHandler(room) {
timestamp: Date.now(),
});
} else {
console.error(`[${Date.now()}] Error calculating new Elo for ${player.globalName}.`);
console.error(`Error calculating new Elo for ${player.globalName}.`);
}
});
}

View File

@@ -10,8 +10,9 @@ import {
pruneOldLogs,
updateUserCoins
} from "../database/index.js";
import { activeSlowmodes, messagesTimestamps, skins } from "./state.js";
import { activeSlowmodes, activeSolitaireGames, messagesTimestamps, skins } from "./state.js";
import { createDeck, createSeededRNG, deal, seededShuffle } from "./solitaire.js";
import { emitSolitaireUpdate } from "../server/socket.js";
/**
* Handles awarding points (coins) to users for their message activity.
@@ -88,7 +89,7 @@ export async function slowmodesHandler(message) {
// Check if the slowmode duration has passed
if (now > authorSlowmode.endAt) {
console.log(`[${Date.now()}] Slowmode for ${author.username} has expired.`);
console.log(`Slowmode for ${author.username} has expired.`);
delete activeSlowmodes[author.id];
return { deleted: false, expired: true };
}
@@ -97,10 +98,10 @@ export async function slowmodesHandler(message) {
if (authorSlowmode.lastMessage && now - authorSlowmode.lastMessage < 60 * 1000) {
try {
await message.delete();
console.log(`[${Date.now()}] Deleted a message from slowmoded user: ${author.username}`);
console.log(`Deleted a message from slowmoded user: ${author.username}`);
return { deleted: true, expired: false };
} catch (err) {
console.error(`[${Date.now()}] Failed to delete slowmode message:`, err);
console.error(`Failed to delete slowmode message:`, err);
return { deleted: false, expired: false };
}
} else {
@@ -144,16 +145,20 @@ export function randomSkinPrice() {
* This function clears previous stats, awards the winner, and generates a new daily seed.
*/
export function initTodaysSOTD() {
console.log(`[${Date.now()}] Initializing new Solitaire of the Day...`);
console.log(`Initializing new Solitaire of the Day...`);
// 1. Award previous day's winner
const rankings = getAllSOTDStats.all();
if (rankings.length > 0) {
const winnerId = rankings[0].user_id;
const secondPlaceId = rankings[1] ? rankings[1].user_id : null;
const thirdPlaceId = rankings[2] ? rankings[2].user_id : null;
const winnerUser = getUser.get(winnerId);
const secondPlaceUser = secondPlaceId ? getUser.get(secondPlaceId) : null;
const thirdPlaceUser = thirdPlaceId ? getUser.get(thirdPlaceId) : null;
if (winnerUser) {
const reward = 1000;
const reward = 2500;
const newCoinTotal = winnerUser.coins + reward;
updateUserCoins.run({ id: winnerId, coins: newCoinTotal });
insertLog.run({
@@ -165,21 +170,40 @@ export function initTodaysSOTD() {
user_new_amount: newCoinTotal,
});
console.log(
`[${Date.now()}] ${winnerUser.globalName || winnerUser.username} won the previous SOTD and received ${reward} coins.`,
`${winnerUser.globalName || winnerUser.username} won the previous SOTD and received ${reward} coins.`,
);
insertGame.run({
id: `${winnerId}-${Date.now()}`,
p1: winnerId,
p2: null,
p1_score: rankings[0].score,
p2_score: null,
p1_elo: winnerUser.elo,
p2_elo: null,
p1_new_elo: winnerUser.elo,
p2_new_elo: null,
type: "SOTD",
timestamp: Date.now(),
}
if (secondPlaceUser) {
const reward = 1500;
const newCoinTotal = secondPlaceUser.coins + reward;
updateUserCoins.run({ id: secondPlaceId, coins: newCoinTotal });
insertLog.run({
id: `${secondPlaceId}-sotd-second-${Date.now()}`,
target_user_id: null,
user_id: secondPlaceId,
action: "SOTD_SECOND_PLACE",
coins_amount: reward,
user_new_amount: newCoinTotal,
});
console.log(
`${secondPlaceUser.globalName || secondPlaceUser.username} got second place in the previous SOTD and received ${reward} coins.`,
);
}
if (thirdPlaceUser) {
const reward = 750;
const newCoinTotal = thirdPlaceUser.coins + reward;
updateUserCoins.run({ id: thirdPlaceId, coins: newCoinTotal });
insertLog.run({
id: `${thirdPlaceId}-sotd-third-${Date.now()}`,
target_user_id: null,
user_id: thirdPlaceId,
action: "SOTD_THIRD_PLACE",
coins_amount: reward,
user_new_amount: newCoinTotal,
});
console.log(
`${thirdPlaceUser.globalName || thirdPlaceUser.username} got third place in the previous SOTD and received ${reward} coins.`,
);
}
}
@@ -206,8 +230,15 @@ export function initTodaysSOTD() {
wastePile: JSON.stringify(todaysSOTD.wastePile),
seed: newRandomSeed,
});
console.log(`[${Date.now()}] Today's SOTD is ready with a new seed.`);
for (const [userId, gameData] of Object.entries(activeSolitaireGames)) {
if (gameData.isSOTD) {
delete activeSolitaireGames[userId];
emitSolitaireUpdate(userId);
}
}
console.log(`Today's SOTD is ready with a new seed.`);
} catch (e) {
console.error(`[${Date.now()}] Error saving new SOTD to database:`, e);
console.error(`Error saving new SOTD to database:`, e);
}
}

View File

@@ -27,7 +27,7 @@ import {
import { activePolls, activePredis, activeSlowmodes, skins } from "../../game/state.js";
// --- Utility and API Imports ---
import { formatTime } from "../../utils/index.js";
import { formatTime, isMeleeSkin, isVCTSkin, isChampionsSkin, getVCTRegion } from "../../utils/index.js";
import { DiscordRequest } from "../../api/discord.js";
// --- Discord.js Builder Imports ---
@@ -99,11 +99,11 @@ export function apiRoutes(client, io) {
user_new_amount: 5000,
});
console.log(`[${Date.now()}] New registered user: ${discordUser.username} (${discordUser.id})`);
console.log(`New registered user: ${discordUser.username} (${discordUser.id})`);
res.status(200).json({ message: `Bienvenue ${discordUser.username} !` });
} catch (e) {
console.log(`[${Date.now()}] Failed to register user ${discordUser.username} (${discordUser.id})`, e);
console.log(`Failed to register user ${discordUser.username} (${discordUser.id})`, e);
res.status(500).json({ error: "Erreur lors de la création du nouvel utilisateur." });
}
});
@@ -173,8 +173,18 @@ export function apiRoutes(client, io) {
);
const updatedSkin = getSkin.get(result.randomSkinData.uuid);
await handleCaseOpening(caseType, userId, result.randomSelectedSkinUuid, client);
const contentSkins = selectedSkins.map((item) => {
return {
...item,
isMelee: isMeleeSkin(item.displayName),
isVCT: isVCTSkin(item.displayName),
isChampions: isChampionsSkin(item.displayName),
vctRegion: getVCTRegion(item.displayName),
}
});
res.json({
selectedSkins,
selectedSkins: contentSkins,
randomSelectedSkinUuid: result.randomSelectedSkinUuid,
randomSelectedSkinIndex: result.randomSelectedSkinIndex,
updatedSkin,
@@ -475,6 +485,10 @@ export function apiRoutes(client, io) {
});
});
skin.offers = marketOffers || {};
skin.isMelee = isMeleeSkin(skin.displayName);
skin.isVCT = isVCTSkin(skin.displayName);
skin.isChampions = isChampionsSkin(skin.displayName);
skin.vctRegion = getVCTRegion(skin.displayName);
});
res.json({ inventory });
} catch (error) {
@@ -560,7 +574,7 @@ export function apiRoutes(client, io) {
user_new_amount: newCoins,
});
console.log(`[${Date.now()}] ${commandUserId} change nickname of ${userId}: ${old_nickname} -> ${nickname}`);
console.log(`${commandUserId} change nickname of ${userId}: ${old_nickname} -> ${nickname}`);
try {
const generalChannel = await guild.channels.fetch(process.env.GENERAL_CHANNEL_ID);
@@ -1065,7 +1079,7 @@ export function apiRoutes(client, io) {
user_new_amount: tempUser.coins + v.amount,
});
} catch (e) {
console.log(`[${Date.now()}] Impossible de rembourser ${v.id} (${v.amount} coins)`);
console.log(`Impossible de rembourser ${v.id} (${v.amount} coins)`);
}
});
activePredis[predi].options[1].votes.forEach((v) => {
@@ -1084,7 +1098,7 @@ export function apiRoutes(client, io) {
user_new_amount: tempUser.coins + v.amount,
});
} catch (e) {
console.log(`[${Date.now()}] Impossible de rembourser ${v.id} (${v.amount} coins)`);
console.log(`Impossible de rembourser ${v.id} (${v.amount} coins)`);
}
});
activePredis[predi].closed = true;
@@ -1110,7 +1124,7 @@ export function apiRoutes(client, io) {
user_new_amount: tempUser.coins + v.amount * (1 + ratio),
});
} catch (e) {
console.log(`[${Date.now()}] Impossible de créditer ${v.id} (${v.amount} coins pariés, *${1 + ratio})`);
console.log(`Impossible de créditer ${v.id} (${v.amount} coins pariés, *${1 + ratio})`);
}
});
activePredis[predi].paidTime = new Date();

View File

@@ -83,12 +83,12 @@ export function blackjackRoutes(io) {
h.surrendered = true;
h.stood = true;
h.hasActed = true;
room.leavingAfterRound[p.id] = true; // kick at end of round
//room.leavingAfterRound[p.id] = true; // kick at end of round
emitToast({ type: "player-timeout", userId: p.id });
changed = true;
} else if (h.hasActed && !h.stood) {
h.stood = true;
room.leavingAfterRound[p.id] = true; // kick at end of round
//room.leavingAfterRound[p.id] = true; // kick at end of round
emitToast({ type: "player-auto-stand", userId: p.id });
changed = true;
}
@@ -183,7 +183,7 @@ export function blackjackRoutes(io) {
router.post("/leave", async (req, res) => {
const { userId } = req.body;
if (!userId || !room.players[userId]) return res.status(404).json({ message: "not in room" });
if (!userId || !room.players[userId]) return res.status(403).json({ message: "not in room" });
try {
const guild = await client.guilds.fetch(process.env.GUILD_ID);
@@ -211,7 +211,7 @@ export function blackjackRoutes(io) {
}
const p = room.players[userId];
if (p.inRound) {
if (p?.inRound) {
// leave after round to avoid abandoning an active bet
room.leavingAfterRound[userId] = true;
return res.status(200).json({ message: "will-leave-after-round" });

View File

@@ -446,3 +446,51 @@ function formatTierText(rank, displayName) {
if (displayName.toLowerCase().includes("champions")) res += " | Champions";
return res;
}
export function isMeleeSkin(skinName) {
const name = skinName.toLowerCase();
return !(name.includes("classic") || name.includes("shorty") || name.includes("frenzy") || name.includes("ghost") || name.includes("sheriff") || name.includes("stinger") || name.includes("spectre") ||
name.includes("bucky") || name.includes("judge") || name.includes("bulldog") || name.includes("guardian") ||
name.includes("vandal") || name.includes("phantom") || name.includes("marshal") || name.includes("outlaw") ||
name.includes("operator") || name.includes("ares") || name.includes("odin"));
}
export function isVCTSkin(skinName) {
const name = skinName.toLowerCase();
return name.includes("vct");
}
const VCT_TEAMS = {
"vct-am": [
/x 100t\)$/g, /x c9\)$/g, /x eg\)$/g, /x fur\)$/g, /x krü\)$/g, /x lev\)$/g, /x loud\)$/g,
/x mibr\)$/g, /x sen\)$/g, /x nrg\)$/g, /x g2\)$/g, /x nv\)$/g, /x 2g\)$/g
],
"vct-emea": [
/x bbl\)$/g, /x fnc\)$/g, /x fut\)$/g, /x m8\)$/g, /x gx\)$/g, /x kc\)$/g, /x navi\)$/g,
/x th\)$/g, /x tl\)$/g, /x vit\)$/g, /x ulf\)$/g, /x pcf\)$/g, /x koi\)$/g, /x apk\)$/g
],
"vct-pcf": [
/x dfm\)$/g, /x drx\)$/g, /x fs\)$/g, /x gen\)$/g, /x ge\)$/g, /x prx\)$/g, /x rrq\)$/g,
/x t1\)$/g, /x ts\)$/g, /x zeta\)$/g, /x vl\)$/g, /x ns\)$/g, /x tln\)$/g, /x boom\)$/g, /x bld\)$/g
],
"vct-cn": [
/x ag\)$/g, /x blg\)$/g, /x edg\)$/g, /x fpx\)$/g, /x jdg\)$/g, /x nova\)$/g, /x tec\)$/g,
/x te\)$/g, /x tyl\)$/g, /x wol\)$/g, /x xlg\)$/g, /x xlg\)$/g, /x drg\)$/g, /x drg\)$/g
]
};
export function getVCTRegion(skinName) {
if (!isVCTSkin(skinName)) return null;
const name = skinName.toLowerCase().trim();
for (const [region, regexes] of Object.entries(VCT_TEAMS)) {
if (regexes.some(regex => regex.test(name))) {
return region;
}
}
return null;
}
export function isChampionsSkin(skinName) {
const name = skinName.toLowerCase();
return name.includes("champions");
}