summaryrefslogtreecommitdiff
path: root/responses.js
diff options
context:
space:
mode:
authorschneefux <schneefux+commit@schneefux.xyz>2017-04-17 19:02:23 +0200
committerschneefux <schneefux+commit@schneefux.xyz>2017-04-17 19:02:23 +0200
commit7aa7a45e3f46fd1bc3a965c0c4a40bded288d7a8 (patch)
treeead9bdbd19b2c93e8f0eeb7390fe5518665f9a46 /responses.js
parent3194e700332987e5cdd3e026bad930fc87dfd245 (diff)
downloaddiscordbot-7aa7a45e3f46fd1bc3a965c0c4a40bded288d7a8.tar.gz
discordbot-7aa7a45e3f46fd1bc3a965c0c4a40bded288d7a8.zip
it's done
Diffstat (limited to 'responses.js')
-rw-r--r--responses.js358
1 files changed, 224 insertions, 134 deletions
diff --git a/responses.js b/responses.js
index 5800650..15e7ec7 100644
--- a/responses.js
+++ b/responses.js
@@ -4,21 +4,38 @@
const Commando = require("discord.js-commando"),
Discord = require("discord.js"),
+ Promise = require("bluebird"),
emoji = require("discord-emoji"),
oneLine = require("common-tags").oneLine,
+ Channel = require("async-csp").Channel,
api = require("./api");
+const PREVIEW = process.env.PREVIEW || true,
+ MATCH_HISTORY_LEN = parseInt(process.env.MATCH_HISTORY_LEN) || 3;
+
+const reactionsPipe = new Channel();
+
+// embed template
function vainsocialEmbed(title, link) {
- return new Discord.RichEmbed()
+ let embed = new Discord.RichEmbed()
.setTitle(title)
- .setURL("https://vainsocial.com/" + link)
- .setColor("#55ADD3")
- .setAuthor("VainSocial", null, "https://vainsocial.com")
- .setFooter("VainSocial")
- ;
+ .setColor("#55ADD3");
+ if (PREVIEW) {
+ embed
+ .setURL("https://preview.vainsocial.com/" + link)
+ .setAuthor("VainSocial preview", null,
+ "https://preview.vainsocial.com")
+ .setFooter("VainSocial preview");
+ } else {
+ embed
+ .setURL("https://vainsocial.com/" + link)
+ .setAuthor("VainSocial", null, "https://vainsocial.com")
+ .setFooter("VainSocial");
+ }
+ return embed;
}
-// returns the shortest version of the usage help
+// return the shortest version of the usage help
// just '?vm'
function usg(msg, cmd) {
return msg.anyUsage(cmd, undefined, null);
@@ -34,11 +51,12 @@ function emojifyScore(score) {
}
// return a match overview string
-function formatMatch(participant) {
- let winstr = "Won";
+async function formatMatch(participant) {
+ let winstr = "Won",
+ game_mode = await api.mapGameMode(participant.game_mode_id);
if (!participant.winner) winstr = "Lost";
return `
-${winstr} ${participant.game_mode_id} with \`${participant.actor.replace(/\*/g, "")}\`
+${winstr} ${game_mode} with \`${participant.actor.replace(/\*/g, "")}\`
KDA, CS | \`${participant.stats.kills}/${participant.stats.deaths}/${participant.stats.assists}\`, \`${Math.round(participant.stats.farm)}\`
Kill Participation | \`${Math.floor(100 * participant.stats.kill_participation)}%\`
Score | ${emojifyScore(participant.stats.impact_score)} \`${Math.floor(100 * participant.stats.impact_score)}%\`
@@ -46,7 +64,7 @@ Score | ${emojifyScore(participant.stats.impact_score)} \`${Math.floor(100 * par
}
// return [[title, text], …] for rosters
-function formatMatchDetail(match) {
+async function formatMatchDetail(match) {
let strings = [];
for(let roster of match.rosters) {
let rosterstr = `${roster.side} - \`${roster.hero_kills}\` Kills`;
@@ -89,157 +107,229 @@ ${picks}
`;
}
+// reaction -> pipe ->>> consumers
+// handle new reaction event
+module.exports.onNewReaction = (reaction) => {
+ if (reaction.users.array().length <= 1) return; // was me TODO
+ reactionsPipe.put(reaction);
+}
+
+// create an iterator that returns promises to await new reactions
+// the Promise result is the reaction name
+function awaitReactions(message, emoji, timeout=60) {
+ const pipeOut = new Channel();
+ // stop listening after timeout
+ setTimeout(() => pipeOut.close(), timeout*1000);
+
+ Promise.each(emoji, async (em) =>
+ message.react(em)); // async in background
+
+ let reaction;
+ reactionsPipe.pipe(pipeOut);
+ return {
+ next: async function() {
+ do {
+ reaction = await pipeOut.take();
+ if (reaction == Channel.DONE)
+ return undefined;
+ } while (reaction.message.id != message.id ||
+ emoji.indexOf(reaction.emoji.name) == -1);
+ return reaction.emoji.name;
+ }
+ }
+}
+
+// respond or say text or embed
+async function respond(msg, data, response) {
+ if (response == undefined) {
+ if (typeof data === "string") {
+ response = await msg.say(data);
+ } else {
+ response = await msg.embed(data);
+ }
+ } else {
+ if (typeof data === "string") {
+ if (data != response.content)
+ await response.edit(data);
+ } else {
+ if (new Date(response.embeds[0].createdTimestamp).getTime()
+ != data.timestamp.getTime())
+ // TODO how2 edit embed properly?!
+ await msg.editResponse(response, {
+ type: "plain",
+ content: "",
+ options: { embed: data }
+ });
+ }
+ }
+ return response;
+}
+
+// about
+module.exports.showAbout = async (msg) => {
+ await msg.embed(vainsocialEmbed("About VainSocial", "")
+ .setDescription(
+`Built by the VainSocial development team using the MadGlory API.
+Currently running on ${msg.client.guilds.size} servers.`)
+ .addField("Website",
+ "https://vainsocial.com", true)
+ .addField("Bot invite link",
+ "https://discordapp.com/oauth2/authorize?&client_id=287297889024213003&scope=bot&permissions=52288", true)
+ .addField("Developer Discord invite",
+ "https://discord.gg/txTchJY", true)
+ .addField("Twitter",
+ "https://twitter.com/vainsocial", true)
+ );
+}
+
// show player profile and last match
module.exports.showUser = async (msg, args) => {
- let ign = args.name,
- iterator = await api.searchPlayer(ign),
- response, player;
- while (true) {
- try {
- player = await iterator.next();
- } catch (err) {
- if (err == "not found") {
- await msg.say("Could not find player `" + ign + "`.");
- break;
- }
- if (err == "exhausted")
- break;
- if (err.statusCode == 404)
- continue;
+ const ign = args.name,
+ waiter = api.subscribeUpdates(ign);
+ let responded = false,
+ response,
+ reactionsAdded = false;
+
+ while (await waiter.next() != undefined) {
+ const [player, matches] = await Promise.all([
+ api.getPlayer(ign),
+ api.getMatches(ign)
+ ]);
+ if (player == undefined) {
+ response = await respond(msg,
+ "Loading your data…", response);
+ continue;
}
- let matches = (await api.searchMatches(ign)).data;
- let matchstr = "not available",
- skill_tier = -1,
- last_match_date = new Date();
- if (matches.length > 0) {
- matchstr = formatMatch(matches[0]);
- skill_tier = matches[0].skill_tier;
- last_match_date = new Date(matches[0].created_at);
+ if (matches == undefined || matches.data.length == 0) {
+ response = await respond(msg,
+ "No match history for you yet", response);
+ continue;
}
- let embed = vainsocialEmbed(`${ign} - ${player.shard_id}`, "player/" + ign)
+ const moreHelp = oneLine`
+*${emoji.symbols.information_source} or ${usg(msg, "vm " + ign)} for detail,
+${emoji.symbols["1234"]} or ${usg(msg, "vh " + ign)} for more*`
+
+ const embed = vainsocialEmbed(`${ign} - ${player.shard_id}`, "player/" + ign)
.setThumbnail("https://vainsocial.com/images/game/skill_tiers/" +
- skill_tier + ".png")
+ matches.data[0].skill_tier + ".png")
.setDescription("")
.addField("Profile", formatPlayer(player), true)
- .addField("Last match", matchstr + `
-*${emoji.symbols.information_source} or ${usg(msg, "vm " + ign)} for detail, ${emoji.symbols["1234"]} or ${usg(msg, "vh " + ign)} for more*
- `, true)
- .setTimestamp(last_match_date)
- ;
+ .addField("Last match", await formatMatch(matches.data[0]) + moreHelp, true)
+ .setTimestamp(new Date(matches.data[0].created_at));
+ response = await respond(msg, embed, response);
- if (response == undefined) {
- response = await msg.embed(embed);
- msg.client.on("messageReactionAdd", async (react) => {
- if (react.message != response) return;
- if (react.users.array().length <= 1) return; // was me
- if (react.emoji.name == emoji.symbols.information_source)
- await showMatch(msg, {
- name: ign,
- id: matches[0].match_api_id
- });
- if (react.emoji.name == emoji.symbols["1234"])
- await showMatches(msg, { name: ign });
- });
- await response.react(emoji.symbols.information_source);
- await response.react(emoji.symbols["1234"]);
- } else {
- response = await msg.editResponse(response, {
- type: "plain",
- content: "",
- options: { embed: embed }
- });
+ if (!reactionsAdded) {
+ reactionsAdded = true;
+ let reactionWaiter = awaitReactions(response,
+ [emoji.symbols.information_source, emoji.symbols["1234"]]);
+ (async () => {
+ while (true) {
+ let rmoji = await reactionWaiter.next();
+ if (rmoji == undefined) break; // timeout
+ if (rmoji == emoji.symbols.information_source)
+ await respondMatch(msg, ign, matches.data[0].match_api_id);
+ if (rmoji == emoji.symbols["1234"])
+ await respondMatches(msg, ign);
+ }
+ })(); // async in background
}
}
+ if (!reactionsAdded)
+ await respond(msg, `Could not find \`${ign}\`.`, response);
}
// show match in detail
-let showMatch = module.exports.showMatch = async (msg, args) => {
- let response,
- ign = args.name,
- id = args.id,
- index = args.number;
+async function respondMatch(msg, ign, id, response=undefined) {
+ const match = await api.getMatch(id);
- let match;
- try {
- if (id == undefined)
- id = (await api.searchMatches(ign)).data[index - 1].match_api_id;
- match = await api.searchMatch(id);
- } catch (err) {
- await msg.say(oneLine`
- Ooops! I don't have any data for you yet.
- Please take a look at your profile first!
- ${usg(msg, "v " + ign)}
- `); // TODO!
- return;
- }
let embed = vainsocialEmbed(`${match.game_mode}, ${match.duration} minutes`, "match/" + id)
- .setTimestamp(new Date(match.created_at))
- formatMatchDetail(match).forEach(([title, text]) => {
+ .setTimestamp(new Date(match.created_at));
+ (await formatMatchDetail(match)).forEach(([title, text]) => {
embed.addField(title, text, true);
});
- ;
- response = await msg.editResponse(response, {
- type: "plain",
- content: "",
- options: { embed: embed }
- });
+ return await respond(msg, embed, response);
}
-// show match history
-let showMatches = module.exports.showMatches = async (msg, args) => {
- let ign = args.name,
+module.exports.showMatch = async (msg, args) => {
+ const ign = args.name,
+ index = args.number,
+ waiter = api.subscribeUpdates(ign);
+ let responded = false,
response;
- let count = [
- emoji.symbols.one,
- emoji.symbols.two,
- emoji.symbols.three,
- emoji.symbols.four,
- emoji.symbols.five,
- emoji.symbols.six,
- emoji.symbols.seven,
- emoji.symbols.eight,
- emoji.symbols.nine,
+
+ while (await waiter.next() != undefined) {
+ let matches = await api.getMatches(ign);
+ if (matches == undefined || matches.data.length == 0) {
+ response = await respond(msg, "No matches for you yet",
+ response);
+ continue;
+ }
+ if (index - 1 > matches.data.length) {
+ response = await respond(msg, "Not enough matches yet",
+ response);
+ continue;
+ }
+ let id = matches.data[index -1].match_api_id;
+ response = await respondMatch(msg, ign, id, response);
+ responded = true;
+ }
+ if (!responded)
+ await respond(msg, `Could not find \`${ign}\`.`, response);
+}
+
+// show match history
+async function respondMatches(msg, ign, response=undefined) {
+ const count = [ emoji.symbols.one, emoji.symbols.two, emoji.symbols.three,
+ emoji.symbols.four, emoji.symbols.five, emoji.symbols.six,
+ emoji.symbols.seven, emoji.symbols.eight, emoji.symbols.nine,
emoji.symbols.ten
];
- let data, matches, matches_num;
- try {
- data = await api.searchMatches(ign);
- } catch (err) {
- await msg.say(oneLine`
- Ooops! I don't have any data for you yet.
- Please take a look at your profile first!
- ${usg(msg, "v " + ign)}
- `); // TODO!
- return;
- }
- matches = data.data.slice(0, 3);
- matches_num = matches.length;
+ const data = await api.getMatches(ign),
+ matches = data.data.slice(0, MATCH_HISTORY_LEN),
+ matches_num = matches.length;
let embed = vainsocialEmbed(ign, "player/" + ign)
.setDescription(`
Last ${matches_num} casual and ranked matches.
*${emoji.symbols["1234"]} or ${usg(msg, "vm " + ign + " number")} for details*
- `);
- matches.forEach((match, idx) =>
- embed.addField(`Match ${idx + 1}`, formatMatch(match)));
- response = await msg.editResponse(response, {
- type: "plain",
- content: "",
- options: { embed: embed }
- });
+ `)
+ .setTimestamp(new Date(matches[0].created_at));
+ await Promise.each(matches, async (match, idx) =>
+ embed.addField(`Match ${idx + 1}`, await formatMatch(match))
+ );
+ response = await respond(msg, embed, response);
- msg.client.on("messageReactionAdd", async (react) => {
- if (react.message != response) return;
- if (react.users.array().length <= 1) return; // was me
- let idx = count.indexOf(react.emoji.name);
- if (idx == -1) return;
- await showMatch(msg, {
- name: ign,
- id: matches[idx].match_api_id
- });
- });
+ const reactionWaiter = awaitReactions(response,
+ count.slice(0, matches_num));
+ (async () => {
+ while (true) {
+ let rmoji = await reactionWaiter.next();
+ if (rmoji == undefined) break; // timeout
+ let idx = count.indexOf(rmoji);
+ await respondMatch(msg, ign, matches[idx].match_api_id);
+ }
+ })(); // async in background
+ return response;
+}
+
+module.exports.showMatches = async (msg, args) => {
+ const ign = args.name,
+ waiter = api.subscribeUpdates(ign);
+ let responded = false,
+ response;
- for (let num of count.slice(0, matches_num))
- await response.react(num)
+ while (await waiter.next() != undefined) {
+ let matches = await api.getMatches(ign);
+ if (matches == undefined || matches.data.length == 0) {
+ response = await respond(msg, "No matches for you yet",
+ response);
+ continue;
+ }
+ response = await respondMatches(msg, ign, response);
+ responded = true;
+ }
+ if (!responded)
+ await respond(msg, `Could not find \`${ign}\`.`,
+ response);
}