// 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;