// Copyright 2019 Campbell Crowley. All rights reserved. // Author: Campbell Crowley (dev@campbellcrowley.com) const ChannelAction = require('./ChannelAction.js'); const Jimp = require('jimp'); /** * @description Sends message announcing the winner of the game. * * @memberof HungryGames~Action * @inner * @augments HungryGames~Action~ChannelAction */ class SendVictorAction extends ChannelAction { /** * @description Create an action that will send a message to the game channel * saying who won the game. */ constructor() { super((hg, game, channel) => { const current = game.currentGame; const numAlive = current.numAlive; const lastAlive = current.includedUsers.find((el) => el.living); let numTeams = 0; let lastTeam = null; if (game.options.teamSize > 0) { current.teams.forEach((team) => { if (team.numAlive > 0) { numTeams++; lastTeam = team; } }); } const collab = game.options.teammatesCollaborate == 'always'; if (collab && numTeams == 1) { this._sendTeamVictor(hg, game, channel, lastTeam); } else if (numAlive == 1) { this._sendSoloVictor(hg, game, channel, lastAlive, lastTeam); } else if (numAlive < 1) { this._sendNoVictor(hg, game, channel); } }); } /** * @description Send the message that a team has won the games. * @private * @param {HungryGames} hg HungryGames context. * @param {HungryGames~GuildGame} game Game context. * @param {Discord~TextChannel} channel Channel to send the message. * @param {HungryGames~Team} team The last team surviving. */ _sendTeamVictor(hg, game, channel, team) { const finalMessage = new hg._parent.Discord.EmbedBuilder(); finalMessage.setColor([255, 0, 255]); const teamName = team.name; const current = game.currentGame; finalMessage.setTitle(`${teamName} has won ${current.name}!`); let teamPlayerList = team.players.map((player) => { const p = current.includedUsers.find((user) => user.id == player); return (game.options.useNicknames && p.nickname) || p.name; }); teamPlayerList = teamPlayerList.join(', '); if (teamPlayerList.length > 1024) { teamPlayerList = `${teamPlayerList.substring(0, 1021)}...`; } finalMessage.setDescription(teamPlayerList); let winnerTag = '\u200B'; if (game.options.mentionVictor) { winnerTag = team.players.filter((p) => !p.startsWith('NPC')) .map((p) => `<@${p}>`) .join(' '); } const avatarSizes = game.options.victorAvatarSizes; const victorIconSize = avatarSizes.avatar; if (victorIconSize === 0) { channel.send({content: winnerTag, embeds: [finalMessage]}); } else { const iconGap = avatarSizes.gap; const underlineSize = avatarSizes.underline; const finalImage = new Jimp( team.players.length * (victorIconSize + iconGap) - iconGap, victorIconSize + underlineSize); let responses = 0; const newImage = function(image, userId) { try { if (victorIconSize > 0) { if (image) image.resize(victorIconSize, victorIconSize); if (underlineSize > 0) { const user = current.includedUsers.find((obj) => obj.id == userId); let color = 0x0; if (user && !user.living) { color = 0xFF0000FF; } else if (user && user.state == 'wounded') { color = 0xFFFF00FF; } else if (user) { color = 0x00FF00FF; } if (user && user.settings && typeof user.settings['hg:bar_color'] === 'number') { finalImage.blit( new Jimp( victorIconSize, underlineSize, user.settings['hg:bar_color']), responses * (victorIconSize + iconGap), 0); } finalImage.blit( new Jimp(victorIconSize, underlineSize, color), responses * (victorIconSize + iconGap), victorIconSize); } if (image) { finalImage.blit( image, responses * (victorIconSize + iconGap), underlineSize); } } } catch (err) { hg._parent.warn('Failed to blit victor image'); console.error(err); } responses++; if (responses == team.players.length) { finalImage.getBuffer(Jimp.MIME_PNG, (err, out) => { channel .send({ content: winnerTag, embeds: [finalMessage], files: [new hg._parent.Discord.AttachmentBuilder( out, {name: 'hgTeamVictor.png'})], }) .catch((err) => { hg._parent.error('Failed to send team victor image message.'); console.error(err); }); }); } }; team.players.forEach((player) => { const p = current.includedUsers.find((obj) => obj.id == player); const icon = p.avatarURL; const userId = p.id; hg._parent.readImage(icon) .then((image) => newImage(image, userId)) .catch((err) => { hg._parent.error('Failed to read image'); console.log(err); responses++; }); }); } } /** * @description Send the message that a player has won the games. * @private * @param {HungryGames} hg HungryGames context. * @param {HungryGames~GuildGame} game Game context. * @param {Discord~TextChannel} channel Channel to send the message. * @param {HungryGames~Player} p The last player surviving. * @param {?HungryGames~Team} team The last team surviving, if one. */ _sendSoloVictor(hg, game, channel, p, team) { const finalMessage = new hg._parent.Discord.EmbedBuilder(); finalMessage.setColor([255, 0, 255]); const current = game.currentGame; const name = game.options.useNicknames ? (p.nickname || p.name) : p.name; let teamName = ''; if (team) teamName = `(${team.name}) `; finalMessage.setTitle(`\`${name}${teamName}\` has won ${current.name}!`); finalMessage.setThumbnail(p.avatarURL); let winnerTag = ''; if (game.options.mentionVictor && !p.isNPC) winnerTag = `<@${p.id}>`; if (game.options.disableOutput) return; channel.send({content: winnerTag, embeds: [finalMessage]}).catch((err) => { hg._parent.error('Failed to send solo winner message: ' + channel.id); console.error(err); }); } /** * @description Send the message that no one has won the games. * @private * @param {HungryGames} hg HungryGames context. * @param {HungryGames~GuildGame} game Game context. * @param {Discord~TextChannel} channel Channel to send the message. */ _sendNoVictor(hg, game, channel) { const finalMessage = new hg._parent.Discord.EmbedBuilder(); finalMessage.setColor([255, 0, 255]); const current = game.currentGame; finalMessage.setTitle( `Everyone has died in ${current.name}!\nThere are no winners!`); if (game.options.disableOutput) return; channel.send({embeds: [finalMessage]}).catch((err) => { hg._parent.error('Failed to send no winner message: ' + channel.id); console.error(err); }); } /** * @description Create action from save data. * @public * @static * @override * @returns {HungryGames~SendVictorAction} The created action. */ static create() { return new SendVictorAction(); } } module.exports = SendVictorAction;