diff options
| author | schneefux <schneefux+commit@schneefux.xyz> | 2017-12-30 13:11:06 +0100 |
|---|---|---|
| committer | schneefux <schneefux+commit@schneefux.xyz> | 2017-12-30 13:11:06 +0100 |
| commit | c6c5027865743328d0542246fef70e0fafe0f0f1 (patch) | |
| tree | 9348d4afa900c170aa534f602b6f7a823292a831 /views | |
| parent | abd33f47fbbcc92610b83341c61f5d1911eed590 (diff) | |
| parent | 1881a2ecd48be772fd83b20068fe9946f1365eeb (diff) | |
| download | discordbot-c6c5027865743328d0542246fef70e0fafe0f0f1.tar.gz discordbot-c6c5027865743328d0542246fef70e0fafe0f0f1.zip | |
Merge branch 'master' into developdevelop
Diffstat (limited to 'views')
| -rw-r--r-- | views/guild.js | 35 | ||||
| -rw-r--r-- | views/guild_create.js | 49 | ||||
| -rw-r--r-- | views/guild_member.js | 35 | ||||
| -rw-r--r-- | views/guild_progress.js | 30 | ||||
| -rw-r--r-- | views/guild_update.js | 34 | ||||
| -rw-r--r-- | views/match.js | 53 | ||||
| -rw-r--r-- | views/matches.js | 80 | ||||
| -rw-r--r-- | views/player.js | 105 | ||||
| -rw-r--r-- | views/register.js | 46 | ||||
| -rw-r--r-- | views/simple.js | 24 | ||||
| -rw-r--r-- | views/view.js | 47 |
11 files changed, 538 insertions, 0 deletions
diff --git a/views/guild.js b/views/guild.js new file mode 100644 index 0000000..15863b0 --- /dev/null +++ b/views/guild.js @@ -0,0 +1,35 @@ +#!/usr/bin/node +/* jshint esnext:true */ +"use strict"; + +const View = require("./view"), + GuildMemberView = require("./guild_member"), + util = require("../util"), + api = require("../api"), + strings = require("../strings"), + Promise = require("bluebird"), + oneLine = require("common-tags").oneLine; + +const GuildOverviewView = module.exports; + +// match detail view +module.exports = class extends View { + text(members) { + // TODO remove when API supports server side sort + return members.sort((m1, m2) => m1.fame < m2.fame).map((m) => + new GuildMemberView().text(m)).join("\n"); + } + + async embed(guild) { + const embed = util.vainsocialEmbed(`${guild.name} - ${guild.shard_id}`, + "", "vainsocial-guild-view") + .setDescription(await this.text(guild.members)); + return embed; + } + + async respond(guild, extra="") { + this.response = await util.respond(this.msg, + await this.embed(guild), this.response); + return this.response; + } +} diff --git a/views/guild_create.js b/views/guild_create.js new file mode 100644 index 0000000..38720e1 --- /dev/null +++ b/views/guild_create.js @@ -0,0 +1,49 @@ +#!/usr/bin/node +/* jshint esnext:true */ +"use strict"; + +const emoji = require("discord-emoji"), + View = require("./view"), + util = require("../util"), + api = require("../api"), + strings = require("../strings"), + oneLine = require("common-tags").oneLine; + +const GuildCreateView = module.exports; + +// match detail view +module.exports = class extends View { + constructor(msg, user_token) { + super(msg); + this.user_token = user_token; + } + + async text() { + return `Guild created. You can now use ${util.usg(this.msg, "vgadd ign1 ign2 ignN")} to add members to your Guild.`; + } + + async help() { + return `*${emoji.symbols.information_source} or ${util.usg(this.msg, "vgview")} to view your Guild*` + } + + async buttons() { + let reactions = {}; + reactions[emoji.symbols.information_source] = async () => { + util.trackAction(this.msg, "reaction-guildview"); + await new GuildOverviewView(this.msg).respond(this.user_token); + }; + return reactions; + } + + // TODO move to super class + async respond() { + this.response = await util.respond(this.msg, + await this.text() + "\n" + await this.help(), this.response); + if (!this.hasButtons) { + await util.reactionButtons(this.response, + await this.buttons()); + this.hasButtons = true; + } + return this.response; + }; +} diff --git a/views/guild_member.js b/views/guild_member.js new file mode 100644 index 0000000..d75ffe4 --- /dev/null +++ b/views/guild_member.js @@ -0,0 +1,35 @@ +#!/usr/bin/node +/* jshint esnext:true */ +"use strict"; + +const View = require("./view"), + PlayerView = require("./player"), + MatchesView = require("./matches"), + util = require("../util"), + api = require("../api"), + strings = require("../strings"), + oneLine = require("common-tags").oneLine; + +const GuildMemberView = module.exports; + +// combined fame + profile + last match +module.exports = class extends View { + text(member) { + return `${member.player.name} | ${member.status} | ${member.fame} VS Fame`; + } + + async embed(member, player, matches) { + const embed = util.vainsocialEmbed(`${member.player.name} - ${member.player.shard_id}`, + "", "vainsocial-guild-memberview") + .addField("Guild Profile", await this.text(member)) + .addField("Player Profile", await new PlayerView().text(player)) + .addField("Last Match", await new MatchesView().text(matches[0])); + return embed; + } + + async respond(member, player, matches) { + this.response = await util.respond(this.msg, + await this.embed(member, player, matches), this.response); + return this.response; + } +} diff --git a/views/guild_progress.js b/views/guild_progress.js new file mode 100644 index 0000000..b3fdeb3 --- /dev/null +++ b/views/guild_progress.js @@ -0,0 +1,30 @@ +#!/usr/bin/node +/* jshint esnext:true */ +"use strict"; + +const View = require("./view"), + util = require("../util"), + api = require("../api"), + strings = require("../strings"), + oneLine = require("common-tags").oneLine; + +const GuildMembersProgressView = module.exports; + +module.exports = class extends View { + constructor(msg, players) { + super(msg); + this.players = players; + } + + // players: obj, key=ign, value=progress + async text(players) { + return Object.entries(players).map((tuple) => + `${tuple[0]}: ${tuple[1]}`).join("\n"); + } + + async respond(extra="") { + this.response = await util.respond(this.msg, + await this.text(this.players) + "\n" + extra, this.response); + return this.response; + }; +} diff --git a/views/guild_update.js b/views/guild_update.js new file mode 100644 index 0000000..cb32dc3 --- /dev/null +++ b/views/guild_update.js @@ -0,0 +1,34 @@ +#!/usr/bin/node +/* jshint esnext:true */ +"use strict"; + +const View = require("./view"), + util = require("../util"), + api = require("../api"), + strings = require("../strings"), + oneLine = require("common-tags").oneLine; + +const GuildAddView = module.exports; + +// match detail view +module.exports = class extends View { + constructor(msg, players) { + super(msg); + this.players = players; + } + + // players: obj, key=ign, value=player + async text(players) { + return Object.entries(players).map((tuple) => + (tuple[1] == undefined)? + `Loading ${tuple[0]}…` + : `Loaded ${tuple[0]}.` + ).join("\n"); + } + + async respond() { + this.response = await util.respond(this.msg, + await this.text(this.players), this.response); + return this.response; + }; +} diff --git a/views/match.js b/views/match.js new file mode 100644 index 0000000..2dc55ec --- /dev/null +++ b/views/match.js @@ -0,0 +1,53 @@ +#!/usr/bin/node +/* jshint esnext:true */ +"use strict"; + +const View = require("./view"), + util = require("../util"), + api = require("../api"), + strings = require("../strings"), + oneLine = require("common-tags").oneLine; + +const PREVIEW = process.env.PREVIEW != "false", + ROOTURL = (PREVIEW? "https://preview.vainsocial.com/":"https://vainsocial.com/"); + +const MatchView = module.exports; + +// match detail view +module.exports = class extends View { + // return [[title, text], …] for rosters + async text(match) { + let resps = []; + for(let roster of match.rosters) { + let winstr = "Won"; + if (!roster.winner) winstr = "Lost"; + let rosterstr = `${roster.side} - \`${roster.hero_kills}\` Kills - ${winstr}`; + let teamstr = ""; + for(let participant of roster.participants) { + const hero = await api.mapActor(participant.actor), + emojiScore = strings.emojifyScore(participant.stats.impact_score); + teamstr += ` +\`${hero}\`, [${participant.player.name}](${ROOTURL}player/${participant.player.name}${util.track("match-detail")}) \`T${Math.floor(participant.skill_tier/3+1)}\` | \`${participant.stats.kills}/${participant.stats.deaths}/${participant.stats.assists}\`, \`${Math.floor(participant.stats.farm)}\`, Score ${emojiScore} \`${Math.floor(100 * participant.stats.impact_score)}%\``; + } + resps.push([rosterstr, teamstr]); + } + return resps; + } + + async embed(match) { + let embed = util.vainsocialEmbed(`${match.game_mode}, ${match.duration} minutes`, + "matches/" + match.api_id , "vainsocial-match") + .setTimestamp(new Date(match.created_at)); + (await this.text(match)).forEach(([title, text]) => { + embed.addField(title, text, true); + }); + return embed; + }; + + async respond(matchid) { + const match = await api.getMatch(matchid); + this.response = await util.respond(this.msg, + await this.embed(match), this.response); + return this.response; + }; +} diff --git a/views/matches.js b/views/matches.js new file mode 100644 index 0000000..a79654b --- /dev/null +++ b/views/matches.js @@ -0,0 +1,80 @@ +#!/usr/bin/node +/* jshint esnext:true */ +"use strict"; + +const emoji = require("discord-emoji"), + Promise = require("bluebird"), + View = require("./view"), + MatchView = require("./match"), + util = require("../util"), + api = require("../api"), + strings = require("../strings"); + +const MATCH_HISTORY_LEN = parseInt(process.env.MATCH_HISTORY_LEN) || 3; + +const MatchesView = module.exports; + +// match detail view +module.exports = class extends View { + constructor(msg, ign) { + super(msg); + this.ign = ign; + } + + async text(participant) { + let winstr = "Won", + hero = await api.mapActor(participant.actor), + game_mode = await api.mapGameMode(participant.game_mode_id), + emojiScore = strings.emojifyScore(participant.stats.impact_score); + if (!participant.winner) winstr = "Lost"; + return ` +${winstr} ${game_mode} with \`${hero}\` +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 | ${emojiScore} \`${Math.floor(100 * participant.stats.impact_score)}%\` +`; + } + + async embed(matches) { + const matchesPart = matches.slice(0, MATCH_HISTORY_LEN); + + // build embed + let embed = util.vainsocialEmbed(this.ign, + "player/" + this.ign, "vainsocial-matches") + .setDescription(`Last ${matchesPart.length} casual and ranked matches.\n` + + await this.help()) + .setTimestamp(new Date(matchesPart[0].created_at)); + await Promise.each(matchesPart, async (match, idx) => + embed.addField(`Match ${idx + 1}`, await this.text(match)) + ); + return embed; + } + + async help() { + return `*${emoji.symbols["1234"]} or ${util.usg(this.msg, "vm " + this.ign + " number")} for details*` + } + + async buttons(matches) { + const matchesPart = matches.slice(0, MATCH_HISTORY_LEN); + + let reactions = {}; + matchesPart.forEach((m, idx) => + reactions[strings.emojiCount[idx]] = async () => { + util.trackAction(this.msg, "reaction-match", m.match_api_id); + await new MatchView(this.msg).respond(m.match_api_id); + }); + return reactions; + } + + async respond() { + const matches = await api.getMatches(this.ign); + this.response = await util.respond(this.msg, + await this.embed(matches), this.response); + if (!this.hasButtons) { + await util.reactionButtons(this.response, + await this.buttons(matches), this.msg); + this.hasButtons = true; + } + return this.response; + } +} diff --git a/views/player.js b/views/player.js new file mode 100644 index 0000000..a481c69 --- /dev/null +++ b/views/player.js @@ -0,0 +1,105 @@ +#!/usr/bin/node +/* jshint esnext:true */ +"use strict"; + +const emoji = require("discord-emoji"), + View = require("./view"), + MatchView = require("./match"), + MatchesView = require("./matches"), + util = require("../util"), + api = require("../api"), + strings = require("../strings"), + oneLine = require("common-tags").oneLine; + +const PREVIEW = process.env.PREVIEW != "false", + ROOTURL = (PREVIEW? "https://preview.vainsocial.com/":"https://vainsocial.com/"); + +const PlayerView = module.exports; + +// player profile +module.exports = class extends View { + constructor(msg, ign) { + super(msg); + this.ign = ign; + } + + async text(player) { + const stats = oneLine` + Win Rate | \`${Math.round(100 * + player.currentSeries.reduce((t, s) => t + s.wins, 0) / + player.currentSeries.reduce((t, s) => t + s.played, 0) + )}%\` + `, + total_kda = oneLine` + Total KDA | \`${player.stats.kills}\` / \`${player.stats.deaths}\` / \`${player.stats.assists}\` + `; + let best_hero = "", + picks = ""; + if (player.best_hero.length > 0) + best_hero = oneLine` + Best | \`${player.best_hero[0].name}\` + `; + if (player.picks.length > 0) { + const hero = await api.mapActor(player.picks[0].actor); + picks = oneLine`Favorite | \`${hero}\`, \`${player.picks[0].hero_pick} picks\``; + } + return ` +${stats} +${total_kda} +${best_hero} +${picks} + `; + } + + async embed(player, matches) { + return util.vainsocialEmbed(`${player.name} - ${player.shard_id}`, "player/" + player.name, "vainsocial-user") + .setThumbnail(ROOTURL + "images/game/skill_tiers/" + + matches[0].skill_tier + ".png") + .setDescription("") + .addField(strings.profile, await this.text(player), true) + .addField(strings.lastMatch, await new MatchesView().text(matches[0]) + + "\n" + await this.help(), true) + .setTimestamp(new Date(matches[0].created_at)); + }; + + async help() { + return oneLine` +*${emoji.symbols.information_source} or ${util.usg(this.msg, "vm " + this.ign)} for detail, +${emoji.symbols["1234"]} or ${util.usg(this.msg, "vh " + this.ign)} for more*`; + } + + async buttons(player, matches) { + let reactions = {}; + reactions[emoji.symbols.information_source] = async () => { + util.trackAction(this.msg, "reaction-match", player.name); + await new MatchView(this.msg).respond(matches[0].match_api_id); + }; + reactions[emoji.symbols["1234"]] = async () => { + util.trackAction(this.msg, "reaction-matches", player.name); + await new MatchesView(this.msg, player.name).respond(); + }; + return reactions; + } + + async respond() { + let player, matches; + try { + [player, matches] = await Promise.all([ + api.getPlayer(this.ign), + api.getMatches(this.ign) + ]); + } catch (err) { + this.response = await util.respond(this.msg, + strings.loading(this.ign), this.response); + return this.response; + } + this.response = await util.respond(this.msg, + await this.embed(player, matches), this.response); + if (!this.hasButtons) { + await util.reactionButtons(this.response, + await this.buttons(player, matches)); + this.hasButtons = true; + } + return this.response; + } +} diff --git a/views/register.js b/views/register.js new file mode 100644 index 0000000..a636e84 --- /dev/null +++ b/views/register.js @@ -0,0 +1,46 @@ +#!/usr/bin/node +/* jshint esnext:true */ +"use strict"; + +const emoji = require("discord-emoji"), + View = require("./view"), + PlayerView = require("./player"), + util = require("../util"), + api = require("../api"), + strings = require("../strings"), + oneLine = require("common-tags").oneLine; + +const RegisterView = module.exports; + +// user register view +module.exports = class extends View { + constructor(msg, ign) { + super(msg); + this.ign = ign; + } + + async text() { + return `You are now registered at VainSocial, ${this.msg.author.toString()}.`; + } + async help() { + return `*${emoji.symbols.repeat} or ${util.usg(this.msg, "v")} to view your profile, ${util.usg(this.msg, "vgcreate")} to create a Guild*` + } + async buttons() { + let reactions = {}; + reactions[emoji.symbols.repeat] = async () => { + util.trackAction(this.msg, "reaction-player"); + await new PlayerView(this.msg, this.ign).respond(); + }; + return reactions; + } + async respond() { + this.response = await util.respond(this.msg, + await this.text() + "\n" + await this.help(), this.response); + if (!this.hasButtons) { + await util.reactionButtons(this.response, + await this.buttons()); + this.hasButtons = true; + } + return this.response; + }; +} diff --git a/views/simple.js b/views/simple.js new file mode 100644 index 0000000..5e8701a --- /dev/null +++ b/views/simple.js @@ -0,0 +1,24 @@ +#!/usr/bin/node +/* jshint esnext:true */ +"use strict"; + +const View = require("./view"), + util = require("../util"), + api = require("../api"), + strings = require("../strings"), + oneLine = require("common-tags").oneLine; + +const SimpleView = module.exports; + +// just respond with a text +module.exports = class extends View { + async text(txt) { + return txt; + } + + async respond(text) { + this.response = await util.respond(this.msg, + await this.text(text), this.response); + return this.response; + } +} diff --git a/views/view.js b/views/view.js new file mode 100644 index 0000000..771e3db --- /dev/null +++ b/views/view.js @@ -0,0 +1,47 @@ +#!/usr/bin/node +/* jshint esnext:true */ +"use strict"; + +const util = require("../util"); + +module.exports = class { + constructor(msg) { + // command message + this.msg = msg; + // response (d'oh) + this.response = undefined; + this.hasButtons = false; + } + static async text() { + // return the markdown or an array of [title, markdown] + return ""; + } + async embed() { + // return an embed using `text()` and `help()` + return util.vainsocialEmbed("title", "url"); + } + async help() { + // return explanation for buttons + return ""; + } + async buttons() { + // return buttons pointing to different views + // key: emoji, value: async func + return {}; + } + async respond() { + // reply with embed + buttons + this.response = await util.respond(this.msg, + await this.embed(), this.response); + if (!this.hasButtons) { + await util.reactionButtons(this.response, await this.buttons(), this.msg); + this.hasButtons = true; + } + return this.response; + } + async error(text) { + // reply with error + this.response = await util.respond(this.msg, text, this.response); + return this.response; + } +}; |
