diff --git a/chat-plugins/info.js b/chat-plugins/info.js
index 3fd8163981..1b1429bb38 100644
--- a/chat-plugins/info.js
+++ b/chat-plugins/info.js
@@ -1185,6 +1185,171 @@ var commands = exports.commands = {
effectivenesshelp: ["/effectiveness [attack], [defender] - Provides the effectiveness of a move or type on another type or a Pokémon.",
"!effectiveness [attack], [defender] - Shows everyone the effectiveness of a move or type on another type or a Pokémon."],
+ cover: 'coverage',
+ coverage: function (target, room, user) {
+ if (!this.canBroadcast()) return;
+ if (!target) return this.parse("/help coverage");
+
+ var targets = target.split(/[,+]/);
+ var sources = [];
+
+ var dispTable = false;
+ var bestCoverage = {};
+ for (var type in Tools.data.TypeChart) {
+ // This command uses -5 to designate immunity
+ bestCoverage[type] = -5;
+ }
+
+ for (var i = 0; i < targets.length; i++) {
+ var move = targets[i].trim().capitalize();
+ if (move === 'Table' || move === 'All') {
+ if (this.broadcasting) return this.sendReplyBox("The full table cannot be broadcast.");
+ dispTable = true;
+ continue;
+ }
+
+ var eff;
+ if (move in Tools.data.TypeChart) {
+ sources.push(move);
+ for (var type in bestCoverage) {
+ if (!Tools.getImmunity(move, type) && !move.ignoreImmunity) continue;
+ eff = Tools.getEffectiveness(move, type);
+ if (eff > bestCoverage[type]) bestCoverage[type] = eff;
+ }
+ continue;
+ }
+ move = Tools.getMove(move);
+ if (move.exists) {
+ sources.push(move);
+ for (var type in bestCoverage) {
+ if (!Tools.getImmunity(move.type, type) && !move.ignoreImmunity) continue;
+ var baseMod = Tools.getEffectiveness(move, type);
+ var moveMod = move.onEffectiveness && move.onEffectiveness.call(Tools, baseMod, type, move);
+ eff = typeof moveMod === 'number' ? moveMod : baseMod;
+ if (eff > bestCoverage[type]) bestCoverage[type] = eff;
+ }
+ continue;
+ }
+
+ return this.sendReply("No type or move '" + targets[i] + "' found.");
+ }
+ if (sources.length > 4) return this.sendReply("Specify a maximum of 4 moves or types.");
+
+ // converts to fractional effectiveness, 0 for immune
+ for (var type in bestCoverage) {
+ if (bestCoverage[type] === -5) {
+ bestCoverage[type] = 0;
+ continue;
+ }
+ bestCoverage[type] = Math.pow(2, bestCoverage[type]);
+ }
+
+ if (!dispTable) {
+ var buffer = [];
+ var superEff = [];
+ var neutral = [];
+ var resists = [];
+ var immune = [];
+
+ for (var type in bestCoverage) {
+ switch (bestCoverage[type]) {
+ case 0:
+ immune.push(type);
+ break;
+ case 0.25:
+ case 0.5:
+ resists.push(type);
+ break;
+ case 1:
+ neutral.push(type);
+ break;
+ case 2:
+ case 4:
+ superEff.push(type);
+ break;
+ default:
+ throw new Error("/coverage effectiveness of " + bestCoverage[type] + " from parameters: " + target);
+ }
+ }
+ buffer.push('Coverage for ' + sources.join(' + ') + ':');
+ buffer.push('Super Effective: ' + (superEff.join(', ') || 'None'));
+ buffer.push(': ' + (neutral.join(', ') || 'None'));
+ buffer.push(': ' + (resists.join(', ') || 'None'));
+ buffer.push(': ' + (immune.join(', ') || 'None'));
+ return this.sendReplyBox(buffer.join('
'));
+ } else {
+ var buffer = '
| '; + var icon = {}; + for (var type in Tools.data.TypeChart) { + icon[type] = ' | ' + icon[type] + ' | '; + } + buffer += '
|---|---|
| ' + icon[type1] + ' | '; + for (var type2 in Tools.data.TypeChart) { + var typing; + var cell = 'bestEff) bestEff = curEff; + } + if (bestEff === -5) { + bestEff = 0; + } else { + bestEff = Math.pow(2, bestEff); + } + } + switch (bestEff) { + case 0: + cell += 'bgcolor=#666666 title="' + typing + '">' + bestEff + ''; + break; + case 0.25: + case 0.5: + cell += 'bgcolor=#AA5544 title="' + typing + '">' + bestEff + ''; + break; + case 1: + cell += 'bgcolor=#6688AA title="' + typing + '">' + bestEff + ''; + break; + case 2: + case 4: + cell += 'bgcolor=#559955 title="' + typing + '">' + bestEff + ''; + break; + default: + throw new Error("/coverage effectiveness of " + bestEff + " from parameters: " + target); + } + cell += ' | '; + buffer += cell; + } + } + buffer += '