TheOchulus/commands/100-games/wrapped.js

402 lines
13 KiB
JavaScript

const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const { getUserRegistration, getBeatenGames, checkGameStorageId, getChangelog, getLeaderboardEntriesBetweenDates, getLeaderboardEntries, getBeatenGamesForYear } = require('../../databaseHelperFunctions');
const { getGameJson, getGenres, getCompanyInfo } = require('../../igdbHelperFunctions');
let userBeatenGamesDatabaseEntries = {};
let beatGameIGDBEntries = [];
let companies = [];
module.exports = {
data: new SlashCommandBuilder()
.setName('wrapped')
.setDescription('Get your 2024 summary.')
.addUserOption(option => option.setName('user').setDescription('The user to check')),
async execute(interaction) {
await interaction.deferReply();
let user = interaction.user;
const userOption = interaction.options.getUser('user');
if (userOption) {
user = userOption;
}
const userDatabaseEntry = await getUserRegistration(user);
if (!userDatabaseEntry) return interaction.followUp({ content: `Issue checking registration with "${user.username}".`, ephemeral: true });
await GetBeatenGamesForYear(userDatabaseEntry, 2024);
if (!userBeatenGamesDatabaseEntries || userBeatenGamesDatabaseEntries.length === 0) {
return interaction.followUp({ content: `${user.username} hasn't beaten any games in this time frame.`, ephemeral: false });
}
await GetIGDBEntries(userBeatenGamesDatabaseEntries);
await GetDevelopers();
const numberOfGamesBeat = await GetNumberOfGamesBeat();
const averageBeatGameInterval = await GetAverageBeatInterval();
const mostActiveMonth = await GetMostActiveMonth(userDatabaseEntry);
const oldestGameBeat = await GetOldestGameBeat();
const newestGameBeat = await GetNewestGameBeat();
const averageGameAge = await GetAverageGameAge();
const favouriteGameGenres = await GetFavouriteGenres();
const favouriteGameDevs = await GetFavouriteDevelopers();
const favouriteGamePublishers = await GetFavouritePublishers();
const numberOfGamesDropped = await GetNumberOfDroppedGames(userDatabaseEntry);
const yearLeaderboardPlace = await GetYearLeaderboardPosition(userDatabaseEntry);
const currentLeaderboardPlace = await GetLeaderboardPosition(userDatabaseEntry);
const embed = new EmbedBuilder();
embed.setColor(0x3BA55C);
embed.setTitle('The 100 Games Challenge: 2024 Wrapped');
embed.setDescription(`Here are the stats for the games you played for the 100 Games Challenge in 2024 ${user.displayName}`);
embed.setThumbnail(user.avatarURL());
embed.setTimestamp();
embed.setFooter({ text: 'The Ochulus • 100 Games Challenge', iconURL: interaction.client.user.avatarURL() });
embed.addFields({ name: 'Number of Games Beat', value: numberOfGamesBeat.toString(), inline: true });
embed.addFields({ name: 'Average Beat Interval', value: `${Math.round(averageBeatGameInterval).toString()} days`, inline: true });
embed.addFields({ name: 'Most Active Month', value: mostActiveMonth, inline: true });
embed.addFields({ name: 'Number Of Games Dropped', value: numberOfGamesDropped, inline: true });
embed.addFields({ name: 'Yearly Leaderboard', value: yearLeaderboardPlace, inline: true });
embed.addFields({ name: 'Overall Leaderboard', value: currentLeaderboardPlace, inline: true });
embed.addFields({ name: 'Oldest Beat Game', value: oldestGameBeat });
embed.addFields({ name: 'Newest Beat Game', value: newestGameBeat });
embed.addFields({ name: 'Average Game Age', value: averageGameAge });
embed.addFields({ name: 'Favourite Game Genres', value: favouriteGameGenres });
embed.addFields({ name: 'Favourite Game Developers', value: favouriteGameDevs });
embed.addFields({ name: 'Favourite Game Publisher', value: favouriteGamePublishers });
return interaction.followUp({ embeds: [embed] });
},
};
function FilterByMonth(array, targetMonth) {
return array.filter(entry => {
const date = new Date(entry.updatedAt);
return date.getMonth() === targetMonth;
});
}
function FilterByYear(array, targetYear) {
return array.filter(entry => {
const date = new Date(entry.updatedAt);
return date.getFullYear() === targetYear;
});
}
async function GetBeatenGamesForYear(userDatabaseEntry, year) {
userBeatenGamesDatabaseEntries = await getBeatenGames(userDatabaseEntry.id);
if (userBeatenGamesDatabaseEntries && userBeatenGamesDatabaseEntries.length > 0) {
userBeatenGamesDatabaseEntries = FilterByYear(userBeatenGamesDatabaseEntries, year);
}
}
async function GetIGDBEntries(array) {
beatGameIGDBEntries = [];
for (let i = 0; i < array.length; i++) {
const game = await checkGameStorageId(array[i].gameId);
const json = await getGameJson(String.prototype.concat('where id = ', game.igdb_id, '; fields *;'));
beatGameIGDBEntries.push(json[0]);
}
}
async function GetDevelopers() {
companies = [];
const companyIds = new Set();
for (let i = 0; i < beatGameIGDBEntries.length; i++) {
for (let j = 0; j < beatGameIGDBEntries[i].involved_companies.length; j++) {
companyIds.add(beatGameIGDBEntries[i].involved_companies[j]);
}
}
const ids = [...companyIds];
const tempIds = [];
for (let i = 0; i < ids.length; i++) {
const company = await getCompanyInfo(ids[i]);
if (!tempIds.includes(company.id)) {
tempIds.push(company.id);
companies.push(company);
}
}
}
async function GetNumberOfGamesBeat() {
if (userBeatenGamesDatabaseEntries) {
return userBeatenGamesDatabaseEntries.length;
}
return 0;
}
async function GetAverageBeatInterval() {
if (userBeatenGamesDatabaseEntries && userBeatenGamesDatabaseEntries.length > 0) {
const today = new Date(2025, 0, 1);
const start = new Date(2024, 0, 1);
const days = (today - start) / (1000 * 60 * 60 * 24);
const timepergame = days / userBeatenGamesDatabaseEntries.length;
return Math.round(timepergame);
}
return 0;
}
async function GetMostActiveMonth(userDatabaseEntry) {
if (userBeatenGamesDatabaseEntries && userBeatenGamesDatabaseEntries.length > 0) {
const results = [];
results.push(['January', await getBeatenGamesForYear(userDatabaseEntry.id, '2024-01-01', '2024-02-01')]);
results.push(['February', await getBeatenGamesForYear(userDatabaseEntry.id, '2024-02-01', '2024-03-01')]);
results.push(['March', await getBeatenGamesForYear(userDatabaseEntry.id, '2024-03-01', '2024-04-01')]);
results.push(['April', await getBeatenGamesForYear(userDatabaseEntry.id, '2024-04-01', '2024-05-01')]);
results.push(['May', await getBeatenGamesForYear(userDatabaseEntry.id, '2024-05-01', '2024-06-01')]);
results.push(['June', await getBeatenGamesForYear(userDatabaseEntry.id, '2024-06-01', '2024-07-01')]);
results.push(['July', await getBeatenGamesForYear(userDatabaseEntry.id, '2024-07-01', '2024-08-01')]);
results.push(['August', await getBeatenGamesForYear(userDatabaseEntry.id, '2024-08-01', '2024-09-01')]);
results.push(['September', await getBeatenGamesForYear(userDatabaseEntry.id, '2024-09-01', '2024-10-01')]);
results.push(['October', await getBeatenGamesForYear(userDatabaseEntry.id, '2024-10-01', '2024-11-01')]);
results.push(['November', await getBeatenGamesForYear(userDatabaseEntry.id, '2024-11-01', '2024-12-01')]);
results.push(['December', await getBeatenGamesForYear(userDatabaseEntry.id, '2024-12-01', '2025-01-01')]);
const sorted = Object.entries(results).sort((a, b) => b[1][1] - a[1][1]);
return sorted[0][1][0] + ' (' + sorted[0][1][1].toString() + ' games)';
}
return '';
}
async function GetOldestGameBeat() {
if (beatGameIGDBEntries.length > 0) {
let oldestGame = beatGameIGDBEntries[0];
for (let i = 1; i < beatGameIGDBEntries.length; i++) {
if (beatGameIGDBEntries[i].first_release_date < oldestGame.first_release_date) {
oldestGame = beatGameIGDBEntries[i];
}
}
const gameName = oldestGame.name;
const gameReleaseDate = new Intl.DateTimeFormat('en-GB', { dateStyle: 'full' }).format(oldestGame.first_release_date * 1000);
return gameName + ' *(' + gameReleaseDate + ')*';
}
return '';
}
async function GetNewestGameBeat() {
if (beatGameIGDBEntries.length > 0) {
let newestGame = beatGameIGDBEntries[0];
for (let i = 1; i < beatGameIGDBEntries.length; i++) {
if (beatGameIGDBEntries[i].first_release_date > newestGame.first_release_date) {
newestGame = beatGameIGDBEntries[i];
}
}
const gameName = newestGame.name;
const gameReleaseDate = new Intl.DateTimeFormat('en-GB', { dateStyle: 'full' }).format(newestGame.first_release_date * 1000);
return gameName + ' *(' + gameReleaseDate + ')*';
}
return '';
}
async function GetAverageGameAge() {
if (beatGameIGDBEntries.length > 0) {
let averageGameAge = 0;
for (let i = 0; i < beatGameIGDBEntries.length; i++) {
averageGameAge += beatGameIGDBEntries[i].first_release_date;
}
averageGameAge /= beatGameIGDBEntries.length;
averageGameAge = new Date(averageGameAge * 1000);
const today = new Date();
let year = today.getFullYear() - averageGameAge.getFullYear();
let month = today.getMonth() - averageGameAge.getMonth();
let day = today.getDate() - averageGameAge.getDate();
while (month < 0 || day < 0) {
if (month < 0) {
year--;
month += 12;
}
if (day < 0) {
month--;
const previousMonth = new Date(today.getFullYear(), today.getMonth(), 0);
day += previousMonth.getDate();
}
}
return `${year} years, ${month} months, ${day} days old`;
}
return ' ';
}
async function GetFavouriteGenres() {
const genres = [];
const counts = [];
for (let i = 0; i < beatGameIGDBEntries.length; i++) {
for (let j = 0; j < beatGameIGDBEntries[i].genres.length; j++) {
const genre = await getGenres(beatGameIGDBEntries[i].genres[j]);
genres.push(genre);
}
}
genres.forEach(item => {
counts[item] = (counts[item] || 0) + 1;
});
const sortedCounts = Object.entries(counts).sort((a, b) => b[1] - a[1]);
const keys = Object.keys(sortedCounts);
let string = ' ';
for (let i = 0; i < keys.length && i < 5; i++) {
const genre = keys[i];
if (sortedCounts[genre][1] > 1) {
string = string.concat(` ${sortedCounts[genre][0]} (${sortedCounts[genre][1]} games),`);
}
}
if (string.length > 1) {
string = string.slice(1, -1);
}
return string;
}
async function GetFavouriteDevelopers() {
const developers = [];
const counts = [];
for (let i = 0; i < companies.length; i++) {
if (companies[i].developed) {
const developedGames = companies[i].developed;
for (let j = 0; j < beatGameIGDBEntries.length; j++) {
const found = developedGames.find(item => item === beatGameIGDBEntries[j].id);
if (found) {
developers.push(companies[i].name);
}
}
}
}
developers.forEach(item => {
counts[item] = (counts[item] || 0) + 1;
});
const sortedCounts = Object.entries(counts).sort((a, b) => b[1] - a[1]);
const keys = Object.keys(sortedCounts);
let string = ' ';
for (let i = 0; i < keys.length && i < 5; i++) {
const developer = keys[i];
if (sortedCounts[developer][1] > 1) {
string = string.concat(` ${sortedCounts[developer][0]} (${sortedCounts[developer][1] } games),`);
}
}
if (string.length > 1) {
string = string.slice(1, -1);
}
return string;
}
async function GetFavouritePublishers() {
const publishers = [];
const counts = [];
for (let i = 0; i < companies.length; i++) {
if (companies[i].published) {
const developedGames = companies[i].published;
for (let j = 0; j < beatGameIGDBEntries.length; j++) {
const found = developedGames.includes(beatGameIGDBEntries[j].id);
if (found) {
publishers.push(companies[i].name);
}
}
}
}
publishers.forEach(item => {
counts[item] = (counts[item] || 0) + 1;
});
const sortedCounts = Object.entries(counts).sort((a, b) => b[1] - a[1]);
const keys = Object.keys(sortedCounts);
let string = ' ';
for (let i = 0; i < keys.length && i < 5; i++) {
const publisher = keys[i];
if (sortedCounts[publisher][1] > 1) {
string = string.concat(` ${sortedCounts[publisher][0]} (${sortedCounts[publisher][1]} games),`);
}
}
if (string.length > 1) {
string = string.slice(1, -1);
}
return string;
}
async function GetNumberOfDroppedGames(userDatabaseEntry) {
const userChangelog = await getChangelog(userDatabaseEntry.id);
const droppedGames = userChangelog.filter(item => item.oldStatus === 'playing' && item.newStatus === null);
if (droppedGames) {
return droppedGames.length.toString();
}
return '0';
}
async function GetYearLeaderboardPosition(userDatabaseEntry) {
const leaderboard = await getLeaderboardEntriesBetweenDates('2024-01-01', '2024-12-31');
await leaderboard.sort((a, b) => parseInt(b.count) - parseInt(a.count));
const index = leaderboard.findIndex(item => item.username === userDatabaseEntry.username) + 1;
return await appendOrdinalSuffix(index);
}
async function GetLeaderboardPosition(userDatabaseEntry) {
const leaderboard = await getLeaderboardEntries();
await leaderboard.sort((a, b) => parseInt(b.count) - parseInt(a.count));
const index = leaderboard.findIndex(item => item.username === userDatabaseEntry.username) + 1;
return await appendOrdinalSuffix(index);
}
async function appendOrdinalSuffix(number) {
const lastDigit = number % 10;
const lastTwoDigits = number % 100;
// Handle special case for 11th, 12th, 13th, etc.
if (lastTwoDigits >= 11 && lastTwoDigits <= 13) {
return number + 'th';
}
// Handle the common cases for 1st, 2nd, 3rd
switch (lastDigit) {
case 1:
return number + 'st';
case 2:
return number + 'nd';
case 3:
return number + 'rd';
default:
return number + 'th';
}
}