Merge pull request #2255 from Zarel/block-bindings

Use strict mode and let and const instead of var
This commit is contained in:
Guangcong Luo 2015-11-06 22:42:32 -06:00
commit 52dece0d09
178 changed files with 4494 additions and 4114 deletions

22
app.js
View File

@ -40,6 +40,8 @@
* @license MIT license
*/
'use strict';
/*********************************************************
* Make sure we have everything set up correctly
*********************************************************/
@ -56,10 +58,10 @@ function runNpm(command) {
process.exit(0);
}
var isLegacyEngine = !(''.includes);
const isLegacyEngine = !(''.includes);
var fs = require('fs');
var path = require('path');
const fs = require('fs');
const path = require('path');
try {
require('sugar');
if (isLegacyEngine) require('es6-shim');
@ -101,7 +103,7 @@ if (Config.watchconfig) {
// Autoconfigure the app when running in cloud hosting environments:
try {
var cloudenv = require('cloud-env');
let cloudenv = require('cloud-env');
Config.bindaddress = cloudenv.get('IP', Config.bindaddress || '');
Config.port = cloudenv.get('PORT', Config.port);
} catch (e) {}
@ -168,14 +170,14 @@ global.Cidr = require('./cidr.js');
if (Config.crashguard) {
// graceful crash - allow current battles to finish before restarting
var lastCrash = 0;
let lastCrash = 0;
process.on('uncaughtException', function (err) {
var dateNow = Date.now();
var quietCrash = require('./crashlogger.js')(err, 'The main process', true);
let dateNow = Date.now();
let quietCrash = require('./crashlogger.js')(err, 'The main process', true);
quietCrash = quietCrash || ((dateNow - lastCrash) <= 1000 * 60 * 5);
lastCrash = Date.now();
if (quietCrash) return;
var stack = ("" + err.stack).escapeHTML().split("\n").slice(0, 2).join("<br />");
let stack = ("" + err.stack).escapeHTML().split("\n").slice(0, 2).join("<br />");
if (Rooms.lobby) {
Rooms.lobby.addRaw('<div class="broadcast-red"><b>THE SERVER HAS CRASHED:</b> ' + stack + '<br />Please restart the server.</div>');
Rooms.lobby.addRaw('<div class="broadcast-red">You will not be able to talk in the lobby or start new battles until the server restarts.</div>');
@ -200,8 +202,8 @@ global.TeamValidator = require('./team-validator.js');
fs.readFile(path.resolve(__dirname, 'config/ipbans.txt'), function (err, data) {
if (err) return;
data = ('' + data).split("\n");
var rangebans = [];
for (var i = 0; i < data.length; i++) {
let rangebans = [];
for (let i = 0; i < data.length; i++) {
data[i] = data[i].split('#')[0].trim();
if (!data[i]) continue;
if (data[i].includes('/')) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,5 @@
'use strict';
const MAX_CATEGORY_COUNT = 5;
const MAX_QUESTION_COUNT = 5;
const BASE_POINTS = 200;
@ -6,9 +8,9 @@ function calculatePoints(category, question) {
return BASE_POINTS * (question + 1);
}
var jeopardies = {};
let jeopardies = {};
var JeopardyQuestions = (function () {
let JeopardyQuestions = (function () {
function JeopardyQuestions(room, categoryCount, questionCount) {
this.room = room;
this.categoryCount = categoryCount;
@ -20,10 +22,10 @@ var JeopardyQuestions = (function () {
this.grid = this.readPersistentData('grid');
this.revealedGrid = {};
if (!this.grid) this.grid = {};
for (var c = 0; c < categoryCount; ++c) {
for (let c = 0; c < categoryCount; ++c) {
if (!this.grid[c]) this.grid[c] = {};
this.revealedGrid[c] = {};
for (var q = 0; q < questionCount; ++q) {
for (let q = 0; q < questionCount; ++q) {
if (!this.grid[c][q]) this.grid[c][q] = {};
this.revealedGrid[c][q] = false;
}
@ -48,14 +50,14 @@ var JeopardyQuestions = (function () {
};
JeopardyQuestions.prototype.export = function (category, start, end) {
var data = [];
for (var q = start; q < end; ++q)
let data = [];
for (let q = start; q < end; ++q)
data.push(this.grid[category][q]);
return data;
};
JeopardyQuestions.prototype.import = function (category, start, end, data) {
var q1 = start;
var q2 = 0;
let q1 = start;
let q2 = 0;
for (; q1 < end && typeof data[q2] === 'object'; ++q1, ++q2) {
if (typeof data[q2].value === 'string') this.grid[category][q1].value = data[q2].value;
if (typeof data[q2].answer === 'string') this.grid[category][q1].answer = data[q2].answer;
@ -101,7 +103,7 @@ var JeopardyQuestions = (function () {
return JeopardyQuestions;
})();
var Jeopardy = (function () {
let Jeopardy = (function () {
function Jeopardy(host, room, categoryCount, questionCount) {
this.host = host;
this.room = room;
@ -127,9 +129,9 @@ var Jeopardy = (function () {
}
Jeopardy.prototype.checkPermission = function (user, output) {
var checks = Array.prototype.slice.call(arguments, 2);
let checks = Array.prototype.slice.call(arguments, 2);
var currentCheck = '';
let currentCheck = '';
while (!!(currentCheck = checks.pop())) {
switch (currentCheck) {
case 'started':
@ -185,14 +187,14 @@ var Jeopardy = (function () {
if (!this.checkPermission(user, output, 'notstarted', 'host')) return;
if (this.users.size < 2) return output.sendReply("There are not enough users participating.");
var isGridValid = true;
for (var c = 0; c < this.categoryCount; ++c) {
let isGridValid = true;
for (let c = 0; c < this.categoryCount; ++c) {
if (!this.questions.getCategory(c)) {
output.sendReply("Category " + (c + 1) + " is missing its name.");
isGridValid = false;
}
for (var q = 0; q < this.questionCount; ++q) {
var question = this.questions.getQuestion(c, q);
for (let q = 0; q < this.questionCount; ++q) {
let question = this.questions.getQuestion(c, q);
if (!question.value) {
output.sendReply("Category " + (c + 1) + " Question " + (q + 1) + " is empty.");
isGridValid = false;
@ -208,7 +210,7 @@ var Jeopardy = (function () {
output.sendReply("The final category is missing its name.");
isGridValid = false;
}
var finalQuestion = this.questions.getQuestion('final', 0);
let finalQuestion = this.questions.getQuestion('final', 0);
if (!finalQuestion.value) {
output.sendReply("The final question is empty.");
isGridValid = false;
@ -221,8 +223,8 @@ var Jeopardy = (function () {
if (!isGridValid) return;
this.isStarted = true;
var usersIterator = this.users.keys();
for (var n = 0, u = Math.floor(Math.random() * this.users.size); n <= u; ++n) {
let usersIterator = this.users.keys();
for (let n = 0, u = Math.floor(Math.random() * this.users.size); n <= u; ++n) {
this.currentUser = usersIterator.next().value;
}
this.room.add('|raw|<div class="infobox">' + renderGrid(this.questions) + '</div>');
@ -234,7 +236,7 @@ var Jeopardy = (function () {
if (user !== this.currentUser || this.currentCategory !== -1) return output.sendReply("You cannot select a question right now.");
if (!(0 <= category && category < this.categoryCount && 0 <= question && question < this.questionCount)) return output.sendReply("Invalid question.");
var data = this.questions.getQuestion(category, question);
let data = this.questions.getQuestion(category, question);
if (data.isRevealed) return output.sendReply("That question has already been revealed.");
this.questions.setRevealed(category, question, true);
@ -264,14 +266,14 @@ var Jeopardy = (function () {
if (!this.isDailyDouble || user !== this.currentUser) return output.sendReply("You cannot wager right now.");
if (this.currentAnswerer) return output.sendReply("You have already wagered.");
var userData = this.users.get(this.currentUser);
let userData = this.users.get(this.currentUser);
if (amount === 'all') amount = userData.points;
if (!(0 <= amount && amount <= (userData.points < 1000 ? 1000 : userData.points))) return output.sendReply("You cannot wager less than zero or more than your current amount of points.");
userData.wager = Math.round(amount);
this.room.add("" + this.currentUser.name + " has wagered " + userData.wager + " points.");
this.currentAnswerer = this.currentUser;
var data = this.questions.getQuestion(this.currentCategory, this.currentQuestion);
let data = this.questions.getQuestion(this.currentCategory, this.currentQuestion);
this.room.add("The question is: " + data.value);
};
Jeopardy.prototype.answer = function (user, answer, output) {
@ -296,8 +298,8 @@ var Jeopardy = (function () {
if (this.currentQuestion === 'final') return this.finalMark(user, isCorrect, output);
if (!this.currentAnswer) return output.sendReply("There is no answer to mark right now.");
var userData = this.users.get(this.currentAnswerer);
var points = this.isDailyDouble ? userData.wager : this.questions.getQuestion(this.currentCategory, this.currentQuestion).points;
let userData = this.users.get(this.currentAnswerer);
let points = this.isDailyDouble ? userData.wager : this.questions.getQuestion(this.currentCategory, this.currentQuestion).points;
if (isCorrect) {
userData.points += points;
this.room.add("The answer '" + this.currentAnswer + "' was correct! " + this.currentAnswerer.name + " gains " + points + " points to " + userData.points + "!");
@ -326,11 +328,11 @@ var Jeopardy = (function () {
if (isNaN(this.currentCategory) || this.currentCategory < 0) return output.sendReply("There is not question to skip.");
if (this.currentAnswer) return output.sendReply("Please mark the current answer.");
var answer = this.questions.getQuestion(this.currentCategory, this.currentQuestion).answer;
let answer = this.questions.getQuestion(this.currentCategory, this.currentQuestion).answer;
this.room.add("The correct answer was '" + answer + "'.");
if (this.isDailyDouble) {
var userData = this.users.get(this.currentUser);
let userData = this.users.get(this.currentUser);
userData.points -= userData.wager;
this.room.add("" + this.currentUser.name + " loses " + userData.wager + " points to " + userData.points + "!");
this.isDailyDouble = false;
@ -357,11 +359,11 @@ var Jeopardy = (function () {
if (this.currentCategory !== 'final') return output.sendReply("It is not the final round yet.");
if (this.remainingFinalWagers === 0) return output.sendReply("You cannot modify your wager after the question has been revealed.");
var userData = this.users.get(user);
let userData = this.users.get(user);
if (amount === 'all') amount = userData.points;
if (!(0 <= amount && amount <= (userData.points < 1000 ? 1000 : userData.points))) return output.sendReply("You cannot wager less than zero or more than your current amount of points.");
var isAlreadyWagered = userData.finalWager >= 0;
let isAlreadyWagered = userData.finalWager >= 0;
userData.finalWager = Math.round(amount);
output.sendReply("You have wagered " + userData.finalWager + " points.");
@ -385,8 +387,8 @@ var Jeopardy = (function () {
if (!answer) return output.sendReply("Please specify an answer.");
if (this.remainingFinalAnswers === 0) return output.sendReply("You cannot modify your answer after marking has started.");
var userData = this.users.get(user);
var isAlreadyAnswered = !!userData.finalAnswer;
let userData = this.users.get(user);
let isAlreadyAnswered = !!userData.finalAnswer;
userData.finalAnswer = answer;
output.sendReply("You have answered '" + userData.finalAnswer + "'.");
@ -400,7 +402,7 @@ var Jeopardy = (function () {
Jeopardy.prototype.automarkFinalAnswers = function () {
if (!this.finalMarkingIterator) this.finalMarkingIterator = this.users.entries();
var data = this.finalMarkingData = this.finalMarkingIterator.next().value;
let data = this.finalMarkingData = this.finalMarkingIterator.next().value;
if (!data) {
this.end();
return;
@ -416,7 +418,7 @@ var Jeopardy = (function () {
if (!this.checkPermission(user, output, 'started', 'host')) return;
if (!this.finalMarkingIterator) return output.sendReply("There is no final answer to mark right now.");
var data = this.finalMarkingData;
let data = this.finalMarkingData;
if (isCorrect) {
data[1].points += data[1].finalWager;
this.room.add("The answer '" + data[1].finalAnswer + "' was correct! " + data[0].name + " gains " + data[1].finalWager + " points to " + data[1].points + "!");
@ -429,15 +431,15 @@ var Jeopardy = (function () {
};
Jeopardy.prototype.end = function () {
var results = [];
for (var data, usersIterator = this.users.entries(); !!(data = usersIterator.next().value);) { // Replace with for-of loop when available
let results = [];
for (let data, usersIterator = this.users.entries(); !!(data = usersIterator.next().value);) { // Replace with for-of loop when available
results.push({user: data[0], points: data[1].points});
}
results.sort(function (a, b) {
return b.points - a.points;
});
var winner = results.shift();
let winner = results.shift();
this.room.add("Congratulations to " + winner.user.name + " for winning the Jeopardy match with " + winner.points + " points!");
this.room.add("Other participants:\n" + results.map(function (data) { return data.user.name + ": " + data.points; }).join("\n"));
@ -448,20 +450,20 @@ var Jeopardy = (function () {
})();
function renderGrid(questions, mode) {
var buffer = '<center><table>';
let buffer = '<center><table>';
buffer += '<tr>';
for (var c = 0; c < questions.categoryCount; ++c) {
for (let c = 0; c < questions.categoryCount; ++c) {
buffer += '<th>' + (Tools.escapeHTML(questions.getCategory(c)) || '&nbsp;') + '</th>';
}
buffer += '</tr>';
for (var q = 0; q < questions.questionCount; ++q) {
for (let q = 0; q < questions.questionCount; ++q) {
buffer += '<tr>';
for (var c = 0; c < questions.categoryCount; ++c) {
var data = questions.getQuestion(c, q);
for (let c = 0; c < questions.categoryCount; ++c) {
let data = questions.getQuestion(c, q);
var cellType = (mode === 'questions' || mode === 'answers') && data.isDailyDouble ? 'th' : 'td';
let cellType = (mode === 'questions' || mode === 'answers') && data.isDailyDouble ? 'th' : 'td';
buffer += '<' + cellType + '><center>';
if (mode === 'questions') {
@ -484,7 +486,7 @@ function renderGrid(questions, mode) {
return buffer;
}
var commands = {
let commands = {
help: function () {
if (!this.canBroadcast()) return;
@ -511,8 +513,8 @@ var commands = {
viewgrid: function (target, room, user) {
if (!this.canBroadcast()) return;
var jeopardy = jeopardies[room.id];
var questions = null;
let jeopardy = jeopardies[room.id];
let questions = null;
if (!jeopardy) {
if (!this.can('jeopardy', null, room)) return;
@ -534,16 +536,16 @@ var commands = {
},
edit: function (target, room, user) {
var params = target.split(',');
let params = target.split(',');
var usage =
let usage =
"Usage:\n" +
"edit category, [category number], [value]\n" +
"edit {question,answer}, [category number], [question number], [value]\n" +
"edit dailydouble, [category number], [question number], {true,false}\n" +
"(Category number can be 'final')";
var editType = toId(params[0]);
let editType = toId(params[0]);
if (!(editType in {category: 1, question: 1, answer: 1, dailydouble: 1})) return this.sendReply(usage);
if (editType === 'category') {
if (params.length < 3) return this.sendReply(usage);
@ -551,8 +553,8 @@ var commands = {
return this.sendReply(usage);
}
var jeopardy = jeopardies[room.id];
var questions = null;
let jeopardy = jeopardies[room.id];
let questions = null;
if (!jeopardy) {
if (!this.can('jeopardy', null, room)) return;
@ -562,7 +564,7 @@ var commands = {
questions = jeopardy.questions;
}
var categoryNumber = parseInt(params[1], 10) || toId(params[1]);
let categoryNumber = parseInt(params[1], 10) || toId(params[1]);
if (!(1 <= categoryNumber && categoryNumber <= questions.categoryCount || categoryNumber === 'final')) return this.sendReply("Please enter a valid category number.");
if (categoryNumber === 'final') {
categoryNumber = 'final';
@ -574,7 +576,7 @@ var commands = {
questions.setCategory(categoryNumber, params.slice(2).join(',').trim());
this.sendReply("The category name has been updated.");
} else {
var questionNumber = parseInt(params[2], 10);
let questionNumber = parseInt(params[2], 10);
if (!(1 <= questionNumber && questionNumber <= questions.questionCount || categoryNumber === 'final')) return this.sendReply("Please enter a valid question number.");
if (categoryNumber === 'final') {
questionNumber = 0;
@ -582,7 +584,8 @@ var commands = {
--questionNumber;
}
var value = params.slice(3).join(',').trim();
let value = params.slice(3).join(',').trim();
let isSet = false;
switch (editType) {
case 'question':
questions.setQuestion(categoryNumber, questionNumber, value);
@ -595,7 +598,7 @@ var commands = {
break;
case 'dailydouble':
var isSet = toId(value) === 'true';
isSet = toId(value) === 'true';
questions.setDailyDouble(categoryNumber, questionNumber, isSet);
this.sendReply("The daily double has been " + (isSet ? "set." : "unset."));
break;
@ -603,10 +606,10 @@ var commands = {
}
},
export: function (target, room, user) {
var params = target.split(',');
let params = target.split(',');
var jeopardy = jeopardies[room.id];
var questions = null;
let jeopardy = jeopardies[room.id];
let questions = null;
if (!jeopardy) {
if (!this.can('jeopardy', null, room)) return;
@ -616,22 +619,22 @@ var commands = {
questions = jeopardy.questions;
}
var categoryNumber = parseInt(params[0], 10);
let categoryNumber = parseInt(params[0], 10);
if (!(1 <= categoryNumber && categoryNumber <= questions.categoryCount)) return this.sendReply("Please enter a valid category number.");
var start = params[1] ? parseInt(params[1], 10) : 1;
var end = params[2] ? parseInt(params[2], 10) : questions.questionCount;
let start = params[1] ? parseInt(params[1], 10) : 1;
let end = params[2] ? parseInt(params[2], 10) : questions.questionCount;
if (!(1 <= start && start <= questions.questionCount)) return this.sendReply("Please enter a valid starting question number.");
if (!(1 <= end && end <= questions.questionCount)) return this.sendReply("Please enter a valid ending question number.");
this.sendReply('||' + JSON.stringify(questions.export(categoryNumber - 1, start - 1, end)));
},
import: function (target, room, user) {
var params = target.split(',');
let params = target.split(',');
if (params.length < 2) return this.sendReply("Usage: import [category number], [start], [end], [data]");
var jeopardy = jeopardies[room.id];
var questions = null;
let jeopardy = jeopardies[room.id];
let questions = null;
if (!jeopardy) {
if (!this.can('jeopardy', null, room)) return;
@ -641,12 +644,12 @@ var commands = {
questions = jeopardy.questions;
}
var categoryNumber = parseInt(params[0], 10);
let categoryNumber = parseInt(params[0], 10);
if (!(1 <= categoryNumber && categoryNumber <= questions.categoryCount)) return this.sendReply("Please enter a valid category number.");
var dataStart = 1;
var start = parseInt(params[1], 10);
var end = parseInt(params[2], 10);
let dataStart = 1;
let start = parseInt(params[1], 10);
let end = parseInt(params[2], 10);
if (!isNaN(start)) {
++dataStart;
if (!isNaN(end)) {
@ -658,7 +661,7 @@ var commands = {
if (!(1 <= start && start <= questions.questionCount)) return this.sendReply("Please enter a valid starting question number.");
if (!(1 <= end && end <= questions.questionCount)) return this.sendReply("Please enter a valid ending question number.");
var data;
let data;
try {
data = JSON.parse(params.slice(dataStart).join(','));
} catch (e) {
@ -669,20 +672,20 @@ var commands = {
},
create: function (target, room, user) {
var params = target.split(',');
let params = target.split(',');
if (jeopardies[room.id]) return this.sendReply("There is already a Jeopardy match in this room.");
if (!this.can('jeopardy', null, room)) return;
var categoryCount = parseInt(params[0], 10) || MAX_CATEGORY_COUNT;
var questionCount = parseInt(params[1], 10) || MAX_QUESTION_COUNT;
let categoryCount = parseInt(params[0], 10) || MAX_CATEGORY_COUNT;
let questionCount = parseInt(params[1], 10) || MAX_QUESTION_COUNT;
if (categoryCount > MAX_CATEGORY_COUNT) return this.sendReply("A match with more than " + MAX_CATEGORY_COUNT + " categories cannot be created.");
if (questionCount > MAX_QUESTION_COUNT) return this.sendReply("A match with more than " + MAX_CATEGORY_COUNT + " questions per category cannot be created.");
jeopardies[room.id] = new Jeopardy(user, room, categoryCount, questionCount);
},
start: function (target, room, user) {
var jeopardy = jeopardies[room.id];
let jeopardy = jeopardies[room.id];
if (!jeopardy) return this.sendReply("There is no Jeopardy match currently in this room.");
jeopardy.start(user, this);
@ -696,66 +699,66 @@ var commands = {
},
adduser: function (target, room, user) {
var targetUser = Users.get(target);
let targetUser = Users.get(target);
if (!targetUser) return this.sendReply("User '" + target + "' not found.");
var jeopardy = jeopardies[room.id];
let jeopardy = jeopardies[room.id];
if (!jeopardy) return this.sendReply("There is no Jeopardy match currently in this room.");
jeopardy.addUser(user, targetUser, this);
},
removeuser: function (target, room, user) {
var targetUser = Users.get(target);
let targetUser = Users.get(target);
if (!targetUser) return this.sendReply("User '" + target + "' not found.");
var jeopardy = jeopardies[room.id];
let jeopardy = jeopardies[room.id];
if (!jeopardy) return this.sendReply("There is no Jeopardy match currently in this room.");
jeopardy.removeUser(user, targetUser, this);
},
select: function (target, room, user) {
var params = target.split(',');
let params = target.split(',');
if (params.length < 2) return this.sendReply("Usage: select [category number], [question number]");
var jeopardy = jeopardies[room.id];
let jeopardy = jeopardies[room.id];
if (!jeopardy) return this.sendReply("There is no Jeopardy match currently in this room.");
var category = parseInt(params[0], 10) - 1;
var question = parseInt(params[1], 10) - 1;
let category = parseInt(params[0], 10) - 1;
let question = parseInt(params[1], 10) - 1;
jeopardy.select(user, category, question, this);
},
a: 'answer',
answer: function (target, room, user) {
var jeopardy = jeopardies[room.id];
let jeopardy = jeopardies[room.id];
if (!jeopardy) return this.sendReply("There is no Jeopardy match currently in this room.");
jeopardy.answer(user, target, this);
},
incorrect: 'correct',
correct: function (target, room, user, connection, cmd) {
var jeopardy = jeopardies[room.id];
let jeopardy = jeopardies[room.id];
if (!jeopardy) return this.sendReply("There is no Jeopardy match currently in this room.");
jeopardy.mark(user, cmd === 'correct', this);
},
skip: function (target, room, user) {
var jeopardy = jeopardies[room.id];
let jeopardy = jeopardies[room.id];
if (!jeopardy) return this.sendReply("There is no Jeopardy match currently in this room.");
jeopardy.skip(user, this);
},
wager: function (target, room, user) {
var jeopardy = jeopardies[room.id];
let jeopardy = jeopardies[room.id];
if (!jeopardy) return this.sendReply("There is no Jeopardy match currently in this room.");
jeopardy.wager(user, target, this);
}
};
var jeopardyRoom = Rooms.get('academics');
let jeopardyRoom = Rooms.get('academics');
if (jeopardyRoom) {
if (jeopardyRoom.plugin) {
jeopardies = jeopardyRoom.plugin.jeopardies;

View File

@ -3,9 +3,11 @@
* By bumbadadabum and Zarel.
*/
var permission = 'announce';
'use strict';
var Poll = (function () {
let permission = 'announce';
let Poll = (function () {
function Poll(room, question, options) {
if (room.pollNumber) {
room.pollNumber++;
@ -20,7 +22,7 @@ var Poll = (function () {
this.timeoutMins = 0;
this.options = new Map();
for (var i = 0; i < options.length; i++) {
for (let i = 0; i < options.length; i++) {
this.options.set(i + 1, {name: options[i], votes: 0});
}
}
@ -49,7 +51,7 @@ var Poll = (function () {
};
Poll.prototype.generateVotes = function () {
var output = '<div class="infobox"><p style="margin: 2px 0 5px 0"><span style="border:1px solid #6A6;color:#484;border-radius:4px;padding:0 3px"><i class="fa fa-bar-chart"></i> Poll</span> <strong style="font-size:11pt">' + Tools.escapeHTML(this.question) + '</strong></p>';
let output = '<div class="infobox"><p style="margin: 2px 0 5px 0"><span style="border:1px solid #6A6;color:#484;border-radius:4px;padding:0 3px"><i class="fa fa-bar-chart"></i> Poll</span> <strong style="font-size:11pt">' + Tools.escapeHTML(this.question) + '</strong></p>';
this.options.forEach(function (option, number) {
output += '<div style="margin-top: 3px"><button value="/poll vote ' + number + '" name="send" title="Vote for ' + number + '. ' + Tools.escapeHTML(option.name) + '">' + number + '. <strong>' + Tools.escapeHTML(option.name) + '</strong></button></div>';
});
@ -59,15 +61,15 @@ var Poll = (function () {
};
Poll.prototype.generateResults = function (ended) {
var icon = '<span style="border:1px solid #' + (ended ? '777;color:#555' : '6A6;color:#484') + ';border-radius:4px;padding:0 3px"><i class="fa fa-bar-chart"></i> ' + (ended ? "Poll ended" : "Poll") + '</span>';
var output = '<div class="infobox"><p style="margin: 2px 0 5px 0">' + icon + ' <strong style="font-size:11pt">' + Tools.escapeHTML(this.question) + '</strong></p>';
var iter = this.options.entries();
let icon = '<span style="border:1px solid #' + (ended ? '777;color:#555' : '6A6;color:#484') + ';border-radius:4px;padding:0 3px"><i class="fa fa-bar-chart"></i> ' + (ended ? "Poll ended" : "Poll") + '</span>';
let output = '<div class="infobox"><p style="margin: 2px 0 5px 0">' + icon + ' <strong style="font-size:11pt">' + Tools.escapeHTML(this.question) + '</strong></p>';
let iter = this.options.entries();
var i = iter.next();
var c = 0;
var colors = ['#79A', '#8A8', '#88B'];
let i = iter.next();
let c = 0;
let colors = ['#79A', '#8A8', '#88B'];
while (!i.done) {
var percentage = Math.round((i.value[1].votes * 100) / (this.totalVotes || 1));
let percentage = Math.round((i.value[1].votes * 100) / (this.totalVotes || 1));
output += '<div style="margin-top: 3px">' + i.value[0] + '. <strong>' + Tools.escapeHTML(i.value[1].name) + '</strong> <small>(' + i.value[1].votes + ' vote' + (i.value[1].votes === 1 ? '' : 's') + ')</small><br /><span style="font-size:7pt;background:' + colors[c % 3] + ';padding-right:' + (percentage * 3) + 'px"></span><small>&nbsp;' + percentage + '%</small></div>';
i = iter.next();
c++;
@ -78,11 +80,11 @@ var Poll = (function () {
};
Poll.prototype.update = function () {
var results = this.generateResults();
let results = this.generateResults();
// Update the poll results for everyone that has voted
for (var i in this.room.users) {
var user = this.room.users[i];
for (let i in this.room.users) {
let user = this.room.users[i];
if (this.voters.has(user.latestIp)) {
user.sendTo(this.room, '|uhtmlchange|poll' + this.room.pollNumber + '|' + results);
}
@ -90,10 +92,10 @@ var Poll = (function () {
};
Poll.prototype.display = function (user, broadcast) {
var votes = this.generateVotes();
var results = this.generateResults();
let votes = this.generateVotes();
let results = this.generateResults();
var target = {};
let target = {};
if (broadcast) {
target = this.room.users;
@ -101,8 +103,8 @@ var Poll = (function () {
target[0] = user;
}
for (var i in target) {
var thisUser = target[i];
for (let i in target) {
let thisUser = target[i];
if (this.voters.has(thisUser.latestIp)) {
thisUser.sendTo(this.room, '|uhtml|poll' + this.room.pollNumber + '|' + results);
} else {
@ -112,7 +114,7 @@ var Poll = (function () {
};
Poll.prototype.end = function () {
var results = this.generateResults(true);
let results = this.generateResults(true);
this.room.send('|uhtmlchange|poll' + this.room.pollNumber + '|<div class="infobox">(The poll has ended &ndash; scroll down to see the results)</div>');
this.room.send('|html|' + results);
@ -126,15 +128,15 @@ exports.commands = {
create: 'new',
new: function (target, room, user, connection, cmd, message) {
if (target.length > 1024) return this.errorReply("Poll too long.");
var params = target.split(target.includes('|') ? '|' : ',').map(function (param) { return param.trim(); });
let params = target.split(target.includes('|') ? '|' : ',').map(function (param) { return param.trim(); });
if (!this.can(permission, null, room)) return false;
if (room.poll) return this.errorReply("There is already a poll in progress in this room.");
if (params.length < 3) return this.errorReply("Not enough arguments for /poll new.");
var options = [];
let options = [];
for (var i = 1; i < params.length; i++) {
for (let i = 1; i < params.length; i++) {
options.push(params[i]);
}
@ -159,7 +161,7 @@ exports.commands = {
return;
}
var parsed = parseInt(target);
let parsed = parseInt(target);
if (isNaN(parsed)) return this.errorReply("To vote, specify the number of the option.");
if (!room.poll.options.has(parsed)) return this.sendReply("Option not in poll.");
@ -183,7 +185,7 @@ exports.commands = {
return this.errorReply("No timer to clear.");
}
}
var timeout = parseFloat(target);
let timeout = parseFloat(target);
if (isNaN(timeout) || timeout <= 0) return this.errorReply("Invalid time given.");
if (room.poll.timeout) clearTimeout(room.poll.timeout);
room.poll.timeoutMins = timeout;

View File

@ -5,7 +5,9 @@
* In an official hunt, the first three to finish within 60 seconds achieve blitz.
*/
var scavengers = {
'use strict';
let scavengers = {
status: 'off',
blitz: null,
hints: null,
@ -15,7 +17,7 @@ var scavengers = {
result: null
};
var scavengersRoom = Rooms.get('scavengers');
let scavengersRoom = Rooms.get('scavengers');
if (scavengersRoom) {
if (scavengersRoom.plugin) {
scavengers = scavengersRoom.plugin;
@ -34,7 +36,7 @@ exports.commands = {
if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
if (!this.can('mute', null, room)) return false;
if (scavengers.status === 'on') return this.errorReply('There is already an active scavenger hunt.');
var targets = target.split(target.includes('|') ? '|' : ',');
let targets = target.split(target.includes('|') ? '|' : ',');
if (!targets[0] || !targets[1] || !targets[2] || !targets[3] || !targets[4] || !targets[5] || targets[6]) {
return this.errorReply('You must specify three hints and three answers.');
}
@ -47,7 +49,7 @@ exports.commands = {
scavengers.status = 'on';
scavengers.hints = [targets[0].trim(), targets[2].trim(), targets[4].trim()];
scavengers.answers = [toId(targets[1]), toId(targets[3]), toId(targets[5])];
var result = (cmd === 'startofficialhunt' ? 'An official' : 'A new') + ' Scavenger Hunt has been started by <em> ' + Tools.escapeHTML(user.name) + '</em>! The first hint is: ' + Tools.escapeHTML(scavengers.hints[0]);
let result = (cmd === 'startofficialhunt' ? 'An official' : 'A new') + ' Scavenger Hunt has been started by <em> ' + Tools.escapeHTML(user.name) + '</em>! The first hint is: ' + Tools.escapeHTML(scavengers.hints[0]);
Rooms.rooms.scavengers.addRaw('<div class="broadcast-blue"><strong>' + result + '</strong></div>');
},
joinhunt: function (target, room, user) {
@ -63,7 +65,7 @@ exports.commands = {
if (!scavengers.participants[user.userid]) return this.errorReply('You are not participating in the current scavenger hunt. Use the command /joinhunt to participate.');
if (scavengers.participants[user.userid].room >= 3) return this.sendReply('You have already finished!');
target = toId(target);
var roomnum = scavengers.participants[user.userid].room;
let roomnum = scavengers.participants[user.userid].room;
if (scavengers.answers[roomnum] === target) {
scavengers.participants[user.userid].room++;
roomnum++;
@ -71,8 +73,8 @@ exports.commands = {
this.sendReply('Well done! Your ' + (roomnum === 1 ? 'second' : 'final') + ' hint is: ' + scavengers.hints[roomnum]);
} else {
scavengers.finished.push(user.name);
var position = scavengers.finished.length;
var result = '<em>' + Tools.escapeHTML(user.name) + '</em> has finished the hunt ';
let position = scavengers.finished.length;
let result = '<em>' + Tools.escapeHTML(user.name) + '</em> has finished the hunt ';
result += (position === 1) ? 'and is the winner!' : (position === 2) ? 'in 2nd place!' : (position === 3) ? 'in 3rd place!' : 'in ' + position + 'th place!';
result += (position < 4 && scavengers.blitz ? ' [BLITZ]' : '');
Rooms.rooms.scavengers.addRaw('<div class="broadcast-blue"><strong>' + result + '</strong></div>');
@ -87,18 +89,18 @@ exports.commands = {
if (scavengers.status !== 'on') return this.errorReply('There is no active scavenger hunt.');
if (!scavengers.participants[user.userid]) return this.errorReply('You are not participating in the current scavenger hunt. Use the command /joinhunt to participate.');
if (scavengers.participants[user.userid].room >= 3) return this.sendReply('You have finished the current scavenger hunt.');
var roomnum = scavengers.participants[user.userid].room;
let roomnum = scavengers.participants[user.userid].room;
this.sendReply('You are on hint number ' + (roomnum + 1) + ': ' + scavengers.hints[roomnum]);
},
endhunt: function (target, room, user) {
if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
if (!this.can('mute', null, room)) return false;
if (scavengers.status !== 'on') return this.errorReply('There is no active scavenger hunt.');
var winner = scavengers.finished[0];
var second = scavengers.finished[1];
var third = scavengers.finished[2];
var consolation = scavengers.finished.slice(3).join(', ');
var msg = 'The Scavenger Hunt was ended by <em>' + Tools.escapeHTML(user.name) + '</em>. ';
let winner = scavengers.finished[0];
let second = scavengers.finished[1];
let third = scavengers.finished[2];
let consolation = scavengers.finished.slice(3).join(', ');
let msg = 'The Scavenger Hunt was ended by <em>' + Tools.escapeHTML(user.name) + '</em>. ';
if (winner) {
msg += '<br />Winner: <em>' + Tools.escapeHTML(winner) + '</em>.';
if (second) msg += ' Second place: <em>' + Tools.escapeHTML(second) + '</em>.';

View File

@ -4,8 +4,10 @@
* Only works in a room with the id 'thestudio'
*/
'use strict';
function toArrayOfArrays(map) {
var ret = [];
let ret = [];
map.forEach(function (value, key) {
ret.push([value, key]);
});
@ -16,29 +18,29 @@ function toArtistId(artist) { // toId would return '' for foreign/sadistic artis
return artist.toLowerCase().replace(/\s/g, '').replace(/\b&\b/g, '');
}
var artistOfTheDay = {
let artistOfTheDay = {
pendingNominations: false,
nominations: new Map(),
removedNominators: []
};
var theStudio = Rooms.get('thestudio');
let theStudio = Rooms.get('thestudio');
if (theStudio && !theStudio.plugin) {
theStudio.plugin = artistOfTheDay;
}
var commands = {
let commands = {
start: function (target, room, user) {
if (room.id !== 'thestudio') return this.errorReply('This command can only be used in The Studio.');
if (!room.chatRoomData || !this.can('mute', null, room)) return false;
if ((user.locked || room.isMuted(user)) && !user.can('bypassall')) return this.errorReply("You cannot do this while unable to talk.");
if (artistOfTheDay.pendingNominations) return this.sendReply("Nominations for the Artist of the Day are already in progress.");
var nominations = artistOfTheDay.nominations;
var prenominations = room.chatRoomData.prenominations;
let nominations = artistOfTheDay.nominations;
let prenominations = room.chatRoomData.prenominations;
if (prenominations && prenominations.length) {
for (var i = 0; i < prenominations.length; i++) {
var prenomination = prenominations[i];
for (let i = 0; i < prenominations.length; i++) {
let prenomination = prenominations[i];
nominations.set(Users.get(prenomination[0].userid) || prenomination[0], prenomination[1]);
}
}
@ -61,8 +63,8 @@ var commands = {
if (!artistOfTheDay.pendingNominations) return this.sendReply("Nominations for the Artist of the Day are not in progress.");
if (!artistOfTheDay.nominations.size) return this.sendReply("No nominations have been submitted yet.");
var nominations = toArrayOfArrays(artistOfTheDay.nominations);
var artist = nominations[~~(Math.random() * nominations.length)][0];
let nominations = toArrayOfArrays(artistOfTheDay.nominations);
let artist = nominations[~~(Math.random() * nominations.length)][0];
artistOfTheDay.pendingNominations = false;
artistOfTheDay.nominations.clear();
artistOfTheDay.removedNominators = [];
@ -84,20 +86,20 @@ var commands = {
if (artistOfTheDay.pendingNominations) return this.sendReply("Nominations for the Artist of the Day are in progress.");
if (!room.chatRoomData.prenominations) room.chatRoomData.prenominations = [];
var userid = user.userid;
var ips = user.ips;
var prenominationId = toArtistId(target);
let userid = user.userid;
let ips = user.ips;
let prenominationId = toArtistId(target);
if (!prenominationId) return this.sendReply("" + target + " is not a valid artist name.");
if (room.chatRoomData.artistOfTheDay && toArtistId(room.chatRoomData.artistOfTheDay) === prenominationId) return this.sendReply("" + target + " is already the current Artist of the Day.");
var prenominations = room.chatRoomData.prenominations;
var prenominationIndex = -1;
var latestIp = user.latestIp;
for (var i = 0; i < prenominations.length; i++) {
let prenominations = room.chatRoomData.prenominations;
let prenominationIndex = -1;
let latestIp = user.latestIp;
for (let i = 0; i < prenominations.length; i++) {
if (toArtistId(prenominations[i][1]) === prenominationId) return this.sendReply("" + target + " has already been prenominated.");
if (prenominationIndex < 0) {
var prenominator = prenominations[i][0];
let prenominator = prenominations[i][0];
if (prenominator.userid === userid || prenominator.ips[latestIp]) {
prenominationIndex = i;
break;
@ -124,26 +126,26 @@ var commands = {
if ((user.locked || room.isMuted(user)) && !user.can('bypassall')) return this.errorReply("You cannot do this while unable to talk.");
if (!artistOfTheDay.pendingNominations) return this.sendReply("Nominations for the Artist of the Day are not in progress.");
var removedNominators = artistOfTheDay.removedNominators;
let removedNominators = artistOfTheDay.removedNominators;
if (removedNominators.indexOf(user) >= 0) return this.sendReply("Since your nomination has been removed, you cannot submit another artist until the next round.");
var alts = user.getAlts();
for (var i = 0; i < removedNominators.length; i++) {
let alts = user.getAlts();
for (let i = 0; i < removedNominators.length; i++) {
if (alts.indexOf(removedNominators[i].name) >= 0) return this.sendReply("Since your nomination has been removed, you cannot submit another artist until the next round.");
}
var nominationId = toArtistId(target);
let nominationId = toArtistId(target);
if (room.chatRoomData.artistOfTheDay && toArtistId(room.chatRoomData.artistOfTheDay) === nominationId) return this.sendReply("" + target + " was the last Artist of the Day.");
var userid = user.userid;
var latestIp = user.latestIp;
for (var data, nominationsIterator = artistOfTheDay.nominations.entries(); !!(data = nominationsIterator.next().value);) { // replace with for-of loop once available
var nominator = data[0];
let userid = user.userid;
let latestIp = user.latestIp;
for (let data, nominationsIterator = artistOfTheDay.nominations.entries(); !!(data = nominationsIterator.next().value);) { // replace with for-of loop once available
let nominator = data[0];
if (nominator.ips[latestIp] && nominator.userid !== userid || alts.indexOf(nominator.name) >= 0) return this.sendReply("You have already submitted a nomination for the Artist of the Day under the name " + nominator.name + ".");
if (toArtistId(data[1]) === nominationId) return this.sendReply("" + target + " has already been nominated.");
}
var response = "" + user.name + (artistOfTheDay.nominations.has(user) ? " changed their nomination from " + artistOfTheDay.nominations.get(user) + " to " + target + "." : " nominated " + target + " for the Artist of the Day.");
let response = "" + user.name + (artistOfTheDay.nominations.has(user) ? " changed their nomination from " + artistOfTheDay.nominations.get(user) + " to " + target + "." : " nominated " + target + " for the Artist of the Day.");
artistOfTheDay.nominations.set(user, target);
room.add(response);
},
@ -153,11 +155,11 @@ var commands = {
if (room.id !== 'thestudio') return this.errorReply('This command can only be used in The Studio.');
if (!room.chatRoomData) return false;
var buffer = "";
let buffer = "";
if (!artistOfTheDay.pendingNominations) {
if (!user.can('mute', null, room)) return false;
var prenominations = room.chatRoomData.prenominations;
let prenominations = room.chatRoomData.prenominations;
if (!prenominations || !prenominations.length) return this.sendReplyBox("No prenominations have been submitted yet.");
prenominations = prenominations.sort(function (a, b) {
@ -167,7 +169,7 @@ var commands = {
});
buffer += "Current prenominations:";
for (var i = 0; i < prenominations.length; i++) {
for (let i = 0; i < prenominations.length; i++) {
buffer += "<br />" +
"- " + Tools.escapeHTML(prenominations[i][1]) + " (submitted by " + Tools.escapeHTML(prenominations[i][0].name) + ")";
}
@ -177,14 +179,14 @@ var commands = {
if (!this.canBroadcast()) return false;
if (!artistOfTheDay.nominations.size) return this.sendReplyBox("No nominations have been submitted yet.");
var nominations = toArrayOfArrays(artistOfTheDay.nominations).sort(function (a, b) {
let nominations = toArrayOfArrays(artistOfTheDay.nominations).sort(function (a, b) {
if (a[1] > b[1]) return 1;
if (a[1] < b[1]) return -1;
return 0;
});
buffer += "Current nominations:";
for (var i = 0; i < nominations.length; i++) {
for (let i = 0; i < nominations.length; i++) {
buffer += "<br />" +
"- " + Tools.escapeHTML(nominations[i][0]) + " (submitted by " + Tools.escapeHTML(nominations[i][1].name) + ")";
}
@ -202,11 +204,11 @@ var commands = {
if (!artistOfTheDay.nominations.size) return this.sendReply("No nominations have been submitted yet.");
target = this.splitTarget(target);
var name = this.targetUsername;
var userid = toId(name);
let name = this.targetUsername;
let userid = toId(name);
if (!userid) return this.errorReply("'" + name + "' is not a valid username.");
for (var nominator, nominatorsIterator = artistOfTheDay.nominations.keys(); !!(nominator = nominatorsIterator.next().value);) { // replace with for-of loop once available
for (let nominator, nominatorsIterator = artistOfTheDay.nominations.keys(); !!(nominator = nominatorsIterator.next().value);) { // replace with for-of loop once available
if (nominator.userid === userid) {
artistOfTheDay.nominations.delete(nominator);
artistOfTheDay.removedNominators.push(nominator);

View File

@ -4,17 +4,19 @@
* By bumbadadabum with help from ascriptmaster, codelegend and the PS development team.
*/
var http = require('http');
'use strict';
const http = require('http');
function wikiaSearch(subdomain, query, callback) {
http.get('http://' + subdomain + '.wikia.com/api/v1/Search/List/?query=' + encodeURIComponent(query) + '&limit=1', function (res) {
var buffer = '';
let buffer = '';
res.setEncoding('utf8');
res.on('data', function (data) {
buffer += data;
});
res.on('end', function () {
var result;
let result;
try {
result = JSON.parse(buffer);
} catch (e) {
@ -36,9 +38,9 @@ exports.commands = {
yugioh: function (target, room, user, connection, cmd) {
if (room.id !== 'traditionalgames') return this.errorReply("This command can only be used in the Traditional Games room.");
if (!this.canBroadcast()) return;
var broadcasting = this.broadcasting;
var subdomain = (cmd === 'yugioh' || cmd === 'ygo') ? 'yugioh' : 'mtg';
var query = target.trim();
let broadcasting = this.broadcasting;
let subdomain = (cmd === 'yugioh' || cmd === 'ygo') ? 'yugioh' : 'mtg';
let query = target.trim();
wikiaSearch(subdomain, query, function (err, data) {
if (err) {
@ -49,9 +51,9 @@ exports.commands = {
if (!broadcasting) return connection.sendTo(room, "Error: " + err.message);
return room.add("Error: " + err.message).update();
}
var entryUrl = Tools.getString(data.url);
var entryTitle = Tools.getString(data.title);
var htmlReply = "<strong>Best result for " + Tools.escapeHTML(query) + ":</strong><br/><a href=\"" + Tools.escapeHTML(entryUrl) + "\">" + Tools.escapeHTML(entryTitle) + "</a>";
let entryUrl = Tools.getString(data.url);
let entryTitle = Tools.getString(data.title);
let htmlReply = "<strong>Best result for " + Tools.escapeHTML(query) + ":</strong><br/><a href=\"" + Tools.escapeHTML(entryUrl) + "\">" + Tools.escapeHTML(entryTitle) + "</a>";
if (!broadcasting) return connection.sendTo(room, "|raw|<div class=\"infobox\">" + htmlReply + "</div>");
room.addRaw("<div class=\"infobox\">" + htmlReply + "</div>").update();
});

View File

@ -4,7 +4,9 @@
* and end once a user's score has surpassed the score cap
*/
var fs = require('fs');
'use strict';
const fs = require('fs');
const MODES = {
first: 'First',
@ -30,7 +32,7 @@ const QUESTION_PERIOD = 15 * 1000;
const INTERMISSION_PERIOD = 30 * 1000;
var triviaData = {};
let triviaData = {};
try {
triviaData = require('../config/chat-plugins/triviadata.json');
} catch (e) {} // file doesn't exist or contains invalid JSON
@ -40,11 +42,11 @@ if (!Array.isArray(triviaData.ladder)) triviaData.ladder = [];
if (!Array.isArray(triviaData.questions)) triviaData.questions = [];
if (!Array.isArray(triviaData.submissions)) triviaData.submissions = [];
var writeTriviaData = (function () {
var writing = false;
var writePending = false; // whether or not a new write is pending
let writeTriviaData = (function () {
let writing = false;
let writePending = false; // whether or not a new write is pending
var finishWriting = function () {
let finishWriting = function () {
writing = false;
if (writePending) {
writePending = false;
@ -57,7 +59,7 @@ var writeTriviaData = (function () {
return;
}
writing = true;
var data = JSON.stringify(triviaData, null, 2);
let data = JSON.stringify(triviaData, null, 2);
fs.writeFile('config/chat-plugins/triviadata.json.0', data, function () {
// rename is atomic on POSIX, but will throw an error on Windows
fs.rename('config/chat-plugins/triviadata.json.0', 'config/chat-plugins/triviadata.json', function (err) {
@ -75,11 +77,11 @@ var writeTriviaData = (function () {
// Binary search for the index at which to splice in new questions in a category,
// or the index at which to slice up to for a category's questions
function findEndOfCategory(category, inSubmissions) {
var questions = inSubmissions ? triviaData.submissions : triviaData.questions;
var left = 0;
var right = questions.length - 1;
var i = 0;
var curCategory;
let questions = inSubmissions ? triviaData.submissions : triviaData.questions;
let left = 0;
let right = questions.length - 1;
let i = 0;
let curCategory;
while (left <= right) {
i = ~~((left + right) / 2);
curCategory = questions[i].category;
@ -99,27 +101,27 @@ function findEndOfCategory(category, inSubmissions) {
}
function sliceCategory(category) {
var questions = triviaData.questions;
let questions = triviaData.questions;
if (!questions.length) return [];
var sliceUpTo = findEndOfCategory(category, false);
let sliceUpTo = findEndOfCategory(category, false);
if (!sliceUpTo) return [];
var categories = Object.keys(CATEGORIES);
var categoryIdx = categories.indexOf(category);
let categories = Object.keys(CATEGORIES);
let categoryIdx = categories.indexOf(category);
if (!categoryIdx) return questions.slice(0, sliceUpTo);
// findEndOfCategory for the category prior to the specified one in
// alphabetical order returns the index of the first question in it
var sliceFrom = findEndOfCategory(categories[categoryIdx - 1], false);
let sliceFrom = findEndOfCategory(categories[categoryIdx - 1], false);
if (sliceFrom === sliceUpTo) return [];
return questions.slice(sliceFrom, sliceUpTo);
}
var trivia = {};
let trivia = {};
var triviaRoom = Rooms.get('trivia');
let triviaRoom = Rooms.get('trivia');
if (triviaRoom) {
if (triviaRoom.plugin) {
triviaData = triviaRoom.plugin.data;
@ -130,12 +132,12 @@ if (triviaRoom) {
write: writeTriviaData,
trivia: trivia
};
var questionWorkshop = Rooms.get('questionworkshop');
let questionWorkshop = Rooms.get('questionworkshop');
if (questionWorkshop) questionWorkshop.plugin = triviaRoom.plugin;
}
}
var Trivia = (function () {
let Trivia = (function () {
function Trivia(mode, category, scoreCap, room) {
this.room = room;
this.mode = mode;
@ -158,13 +160,13 @@ var Trivia = (function () {
Trivia.prototype.addParticipant = function (output, user) {
if (this.participants.has(user.userid)) return output.sendReply("You have already signed up for this trivia game.");
var latestIp = user.latestIp;
for (var participantid, participantsIterator = this.participants.keys(); !!(participantid = participantsIterator.next().value);) { // replace with for-of loop once available
var participant = Users.get(participantid);
let latestIp = user.latestIp;
for (let participantid, participantsIterator = this.participants.keys(); !!(participantid = participantsIterator.next().value);) { // replace with for-of loop once available
let participant = Users.get(participantid);
if (participant && participant.ips[latestIp]) return output.sendReply("You have already signed up for this trivia game.");
}
var scoreData = {
let scoreData = {
score: 0,
correctAnswers: 0,
answered: false
@ -180,7 +182,7 @@ var Trivia = (function () {
Trivia.prototype.kickParticipant = function (output, target, user) {
if (this.participants.size < 3) return output.sendReply("The trivia game requires at least three participants in order to run.");
var userid = toId(target);
let userid = toId(target);
if (!userid) return output.sendReply("User '" + target + "' does not exist.");
if (!this.participants.has(userid)) return output.sendReply("User '" + target + "' is not a participant in this trivia game.");
@ -212,7 +214,7 @@ var Trivia = (function () {
};
Trivia.prototype.askQuestion = function () {
var head = this.currentQuestions.pop();
let head = this.currentQuestions.pop();
this.currentAnswer = head.answers;
this.phase = 'question';
this.room.addRaw(
@ -238,13 +240,13 @@ var Trivia = (function () {
if (this.phase !== 'question') return output.sendReply("There is no question to answer.");
if (!this.participants.has(user.userid)) return output.sendReply("You are not a participant in this trivia game.");
var scoreData = this.participants.get(user.userid);
let scoreData = this.participants.get(user.userid);
if (scoreData.answered && this.mode === 'first') return output.sendReply("You have already submitted an answer for the current question.");
var correct = false;
let correct = false;
scoreData.answered = true;
for (var i = 0; i < this.currentAnswer.length; i++) {
var correctAnswer = this.currentAnswer[i];
for (let i = 0; i < this.currentAnswer.length; i++) {
let correctAnswer = this.currentAnswer[i];
if (target === correctAnswer || correctAnswer.length > 5 && Tools.levenshtein(target, correctAnswer) < 3) {
correct = true;
break;
@ -262,7 +264,7 @@ var Trivia = (function () {
scoreData.responderIndex = this.correctResponders++;
scoreData.correctAnswers++;
if (this.mode === 'timer') {
var points = 5 - ~~((Date.now() - this.askedAt) / (QUESTION_PERIOD / 5));
let points = 5 - ~~((Date.now() - this.askedAt) / (QUESTION_PERIOD / 5));
if ([1, 2, 3, 4, 5].indexOf(points) >= 0) {
scoreData.score += points;
scoreData.points = points;
@ -288,8 +290,8 @@ var Trivia = (function () {
this.phase = 'intermission';
var isActive = false;
for (var scoreData, participantsIterator = this.participants.values(); !!(scoreData = participantsIterator.next().value);) { // replace with for-of loop once available
let isActive = false;
for (let scoreData, participantsIterator = this.participants.values(); !!(scoreData = participantsIterator.next().value);) { // replace with for-of loop once available
if (scoreData.answered) {
scoreData.answered = false;
isActive = true;
@ -316,11 +318,11 @@ var Trivia = (function () {
clearTimeout(this.phaseTimeout);
this.phase = 'intermission';
var scoreData = this.participants.get(user.userid);
let scoreData = this.participants.get(user.userid);
scoreData.score += 5;
scoreData.correctAnswers++;
var buffer = "<div class=\"broadcast-blue\"><strong>The answering period has ended!</strong><br />" +
let buffer = "<div class=\"broadcast-blue\"><strong>The answering period has ended!</strong><br />" +
"Correct: " + Tools.escapeHTML(user.name) + "<br />" +
"Answer" + (this.currentAnswer.length > 1 ? "s: " : ": ") + this.currentAnswer.join(", ") + "<br />";
@ -332,7 +334,7 @@ var Trivia = (function () {
if (!this.currentQuestions.length) return this.stalemate();
for (var participantsIterator = this.participants.values(); !!(scoreData = participantsIterator.next().value);) { // replace with for-of loop once available
for (let participantsIterator = this.participants.values(); !!(scoreData = participantsIterator.next().value);) { // replace with for-of loop once available
scoreData.answered = false;
}
@ -348,22 +350,22 @@ var Trivia = (function () {
this.phase = 'intermission';
var winner = '';
var winnerIndex = this.correctResponders;
var score = this.scoreCap;
var buffer = "<div class=\"broadcast-blue\"><strong>The answering period has ended!</strong><br />" +
let winner = '';
let winnerIndex = this.correctResponders;
let score = this.scoreCap;
let buffer = "<div class=\"broadcast-blue\"><strong>The answering period has ended!</strong><br />" +
"Answer" + (this.currentAnswer.length > 1 ? "s: " : ": ") + this.currentAnswer.join(", ") + "<br />" +
"<br />" +
"<table width=\"100%\" bgcolor=\"#9CBEDF\">" +
"<tr bgcolor=\"#6688AA\"><th width=\"100px\">Points gained</th><th>Correct</th></tr>";
var innerBuffer = {5:[], 4:[], 3:[], 2:[], 1:[]};
let innerBuffer = {5:[], 4:[], 3:[], 2:[], 1:[]};
for (var data, participantsIterator = this.participants.entries(); !!(data = participantsIterator.next().value);) { // replace with for-of loop once available
var scoreData = data[1];
for (let data, participantsIterator = this.participants.entries(); !!(data = participantsIterator.next().value);) { // replace with for-of loop once available
let scoreData = data[1];
scoreData.answered = false;
if (scoreData.responderIndex < 0) continue;
var participant = Users.get(data[0]);
let participant = Users.get(data[0]);
participant = participant ? participant.name : data[0];
innerBuffer[scoreData.points].push(participant);
@ -376,7 +378,7 @@ var Trivia = (function () {
scoreData.responderIndex = -1;
}
for (var i = 6; --i;) {
for (let i = 6; --i;) {
if (innerBuffer[i].length) {
buffer += "<tr bgcolor=\"#6688AA\"><td align=\"center\">" + i + "</td><td>" + Tools.escapeHTML(innerBuffer[i].join(", ")) + "</td></tr>";
}
@ -403,18 +405,18 @@ var Trivia = (function () {
this.phase = 'intermission';
var winner = '';
var winnerIndex = this.correctResponders;
var score = this.scoreCap;
var points = ~~(5 - 4 * (this.correctResponders - 1) / (this.participants.size - 1 || 1));
var innerBuffer = [];
let winner = '';
let winnerIndex = this.correctResponders;
let score = this.scoreCap;
let points = ~~(5 - 4 * (this.correctResponders - 1) / (this.participants.size - 1 || 1));
let innerBuffer = [];
for (var data, participantsIterator = this.participants.entries(); !!(data = participantsIterator.next().value);) { // replace with for-of loop once available
var scoreData = data[1];
for (let data, participantsIterator = this.participants.entries(); !!(data = participantsIterator.next().value);) { // replace with for-of loop once available
let scoreData = data[1];
scoreData.answered = false;
if (scoreData.responderIndex < 0) continue;
var participant = Users.get(data[0]);
let participant = Users.get(data[0]);
participant = participant ? participant.name : data[0];
innerBuffer.push(participant);
@ -427,7 +429,7 @@ var Trivia = (function () {
scoreData.responderIndex = -1;
}
var buffer = "<div class=\"broadcast-blue\"><strong>The answering period has ended!</strong><br />" +
let buffer = "<div class=\"broadcast-blue\"><strong>The answering period has ended!</strong><br />" +
"Correct: " + Tools.escapeHTML(innerBuffer.join(", ")) + "<br />" +
"Answer" + (this.currentAnswer.length > 1 ? "s: " : ": ") + this.currentAnswer.join(", ") + "<br />";
@ -455,14 +457,14 @@ var Trivia = (function () {
};
Trivia.prototype.updateLeaderboard = function (winnerid) {
var leaderboard = triviaData.leaderboard;
let leaderboard = triviaData.leaderboard;
// update leaderboard scores
for (var data, participantsIterator = this.participants.entries(); !!(data = participantsIterator.next().value);) { // replace with for-of loop once available
var scoreData = data[1];
for (let data, participantsIterator = this.participants.entries(); !!(data = participantsIterator.next().value);) { // replace with for-of loop once available
let scoreData = data[1];
if (!scoreData.score) continue;
var rank = leaderboard[data[0]];
let rank = leaderboard[data[0]];
if (rank) {
rank[1] += scoreData.score;
rank[2] += scoreData.correctAnswers;
@ -473,19 +475,19 @@ var Trivia = (function () {
if (winnerid) leaderboard[winnerid][0] += this.prize;
// update leaderboard ranks and rebuild the ladder
var leaders = Object.keys(leaderboard);
var ladder = triviaData.ladder = [];
for (var i = 0; i < 3; i++) {
let leaders = Object.keys(leaderboard);
let ladder = triviaData.ladder = [];
for (let i = 0; i < 3; i++) {
leaders.sort(function (a, b) {
return leaderboard[b][i] - leaderboard[a][i];
});
var max = Infinity;
var rank = 0;
var rankIdx = i + 3;
for (var j = 0; j < leaders.length; j++) {
var leader = leaders[j];
var score = leaderboard[leader][i];
let max = Infinity;
let rank = 0;
let rankIdx = i + 3;
for (let j = 0; j < leaders.length; j++) {
let leader = leaders[j];
let score = leaderboard[leader][i];
if (max !== score) {
if (!i && rank < 15) {
if (ladder[rank]) {
@ -507,10 +509,10 @@ var Trivia = (function () {
};
Trivia.prototype.getStatus = function (output, user) {
var buffer = "There is a trivia game in progress, and it is in its " + this.phase + " phase.<br />" +
let buffer = "There is a trivia game in progress, and it is in its " + this.phase + " phase.<br />" +
"Mode: " + MODES[this.mode] + " | Category: " + CATEGORIES[this.category] + " | Score cap: " + this.scoreCap;
if (this.phase !== 'signup' && !output.broadcasting) {
var scoreData = this.participants.get(user.userid);
let scoreData = this.participants.get(user.userid);
if (scoreData) {
buffer += "<br />" +
"Current score: " + scoreData.score + " | Correct answers: " + scoreData.correctAnswers;
@ -521,13 +523,13 @@ var Trivia = (function () {
};
Trivia.prototype.getParticipants = function (output) {
var participantsLen = this.participants.size;
let participantsLen = this.participants.size;
if (!participantsLen) return output.sendReplyBox("There are no players in this trivia game.");
var participants = [];
var buffer = "There " + (participantsLen > 1 ? "are <strong>" + participantsLen + "</strong> players" : "is <strong>1</strong> player") + " participating in this trivia game:<br />";
let participants = [];
let buffer = "There " + (participantsLen > 1 ? "are <strong>" + participantsLen + "</strong> players" : "is <strong>1</strong> player") + " participating in this trivia game:<br />";
this.participants.forEach(function (scoreData, participantid) {
var participant = Users.get(participantid);
let participant = Users.get(participantid);
participants.push(participant ? participant.name : participantid);
});
buffer += Tools.escapeHTML(participants.join(", "));
@ -544,7 +546,7 @@ var Trivia = (function () {
return Trivia;
})();
var commands = {
let commands = {
// trivia game commands
new: function (target, room, user) {
if (room.id !== 'trivia') return this.errorReply('This command can only be used in Trivia.');
@ -555,13 +557,13 @@ var commands = {
target = target.split(',');
if (target.length !== 3) return this.errorReply("Invalid arguments specified. View /help trivia for more information.");
var mode = toId(target[0]);
let mode = toId(target[0]);
if (!MODES[mode]) return this.errorReply("'" + target[0].trim() + "' is not a valid mode. View /help trivia for more information.");
var category = toId(target[1]);
let category = toId(target[1]);
if (!CATEGORIES[category]) return this.errorReply("'" + target[1].trim() + "' is not a valid category. View /help trivia for more information.");
var scoreCap = SCORE_CAPS[toId(target[2])];
let scoreCap = SCORE_CAPS[toId(target[2])];
if (!scoreCap) return this.errorReply("'" + target[2].trim() + "' is not a valid score cap. View /help trivia for more information.");
trivia[room.id] = new Trivia(mode, category, scoreCap, room);
@ -574,7 +576,7 @@ var commands = {
join: function (target, room, user) {
if (room.id !== 'trivia') return this.errorReply('This command can only be used in Trivia.');
var trivium = trivia[room.id];
let trivium = trivia[room.id];
if (!trivium) return this.errorReply("There is no trivia game in progress.");
if (!this.canTalk()) return;
trivium.addParticipant(this, user);
@ -585,7 +587,7 @@ var commands = {
if (room.id !== 'trivia') return this.errorReply('This command can only be used in Trivia.');
if (!this.can('broadcast', null, room)) return false;
if ((user.locked || room.isMuted(user)) && !user.can('bypassall')) return this.errorReply("You cannot do this while unable to talk.");
var trivium = trivia[room.id];
let trivium = trivia[room.id];
if (!trivium) return this.errorReply("There is no trivia game to start.");
trivium.startGame(this);
},
@ -595,7 +597,7 @@ var commands = {
if (room.id !== 'trivia') return this.errorReply('This command can only be used in Trivia.');
if (!this.can('mute', null, room) || !target) return false;
if ((user.locked || room.isMuted(user)) && !user.can('bypassall')) return this.errorReply("You cannot do this while unable to talk.");
var trivium = trivia[room.id];
let trivium = trivia[room.id];
if (!trivium) return this.errorReply("There is no trivia game in progress.");
this.parse('/m ' + target);
trivium.kickParticipant(this, target, user);
@ -608,7 +610,7 @@ var commands = {
target = toId(target);
if (!target) return this.errorReply("No valid answer was specified.");
var trivium = trivia[room.id];
let trivium = trivia[room.id];
if (!trivium) return this.errorReply("There is no trivia game in progress.");
trivium.answerQuestion(this, target, user);
},
@ -618,7 +620,7 @@ var commands = {
if (room.id !== 'trivia') return this.errorReply('This command can only be used in Trivia.');
if (!this.can('broadcast', null, room)) return false;
if ((user.locked || room.isMuted(user)) && !user.can('bypassall')) return this.errorReply("You cannot do this while unable to talk.");
var trivium = trivia[room.id];
let trivium = trivia[room.id];
if (!trivium) return this.errorReply("There is no trivia game in progress.");
trivium.endGame(this, user);
},
@ -634,17 +636,17 @@ var commands = {
target = target.split('|');
if (target.length !== 3) return this.errorReply("Invalid arguments specified. View /help trivia for more information.");
var category = toId(target[0]);
let category = toId(target[0]);
if (category === 'random') return false;
if (!CATEGORIES[category]) return this.errorReply("'" + target[0].trim() + "' is not a valid category. View /help trivia for more information.");
target[1] = target[1].trim();
var question = Tools.escapeHTML(target[1]);
let question = Tools.escapeHTML(target[1]);
if (!question) return this.errorReply("'" + target[1] + "' is not a valid question.");
var answers = target[2].split(',');
var i;
let answers = target[2].split(',');
let i;
for (i = 0; i < answers.length; i++) {
answers[i] = toId(answers[i]);
}
@ -653,8 +655,8 @@ var commands = {
}
if (!answers.length) return this.errorReply("No valid answers were specified.");
var submissions = triviaData.submissions;
var submission = {
let submissions = triviaData.submissions;
let submission = {
category: category,
question: question,
answers: answers,
@ -679,17 +681,17 @@ var commands = {
if (room.id !== 'questionworkshop') return this.errorReply('This command can only be used in Question Workshop.');
if (!this.can('mute', null, room)) return false;
var submissions = triviaData.submissions;
var submissionsLen = submissions.length;
let submissions = triviaData.submissions;
let submissionsLen = submissions.length;
if (!submissionsLen) return this.sendReply("No questions await review.");
var buffer = "|raw|<div class=\"ladder\"><table>" +
let buffer = "|raw|<div class=\"ladder\"><table>" +
"<tr><td colspan=\"4\"><strong>" + submissionsLen + "</strong> questions await review:</td></tr>" +
"<tr><th>#</th><th>Category</th><th>Question</th><th>Answer(s)</th><th>Submitted By</th></tr>";
var i = 0;
let i = 0;
while (i < submissionsLen) {
var entry = submissions[i];
let entry = submissions[i];
buffer += "<tr><td><strong>" + (++i) + "</strong></td><td>" + entry.category + "</td><td>" + entry.question + "</td><td>" + entry.answers.join(", ") + "</td><td>" + entry.user + "</td></tr>";
}
buffer += "</table></div>";
@ -707,15 +709,15 @@ var commands = {
target = target.trim();
if (!target) return false;
var isAccepting = cmd === 'accept';
var questions = triviaData.questions;
var submissions = triviaData.submissions;
var submissionsLen = submissions.length;
let isAccepting = cmd === 'accept';
let questions = triviaData.questions;
let submissions = triviaData.submissions;
let submissionsLen = submissions.length;
if (toId(target) === 'all') {
if (isAccepting) {
for (var i = 0; i < submissionsLen; i++) {
var submission = submissions[i];
for (let i = 0; i < submissionsLen; i++) {
let submission = submissions[i];
questions.splice(findEndOfCategory(submission.category, false), 0, submission);
}
}
@ -726,13 +728,13 @@ var commands = {
}
if (/^\d+(?:-\d+)?(?:, ?\d+(?:-\d+)?)*$/.test(target)) {
var indices = target.split(',');
let indices = target.split(',');
// Parse number ranges and add them to the list of indices,
// then remove them in addition to entries that aren't valid index numbers
for (var i = indices.length; i--;) {
for (let i = indices.length; i--;) {
if (!indices[i].includes('-')) {
var index = Number(indices[i]);
let index = Number(indices[i]);
if (Number.isInteger(index) && index > 0 && index <= submissionsLen) {
indices[i] = index;
} else {
@ -741,9 +743,9 @@ var commands = {
continue;
}
var range = indices[i].split('-');
var left = Number(range[0]);
var right = Number(range[1]);
let range = indices[i].split('-');
let left = Number(range[0]);
let right = Number(range[1]);
if (!Number.isInteger(left) || !Number.isInteger(right) ||
left < 1 || right > submissionsLen || left === right) {
indices.splice(i, 1);
@ -763,16 +765,16 @@ var commands = {
return !index || indices[index - 1] !== entry;
});
var indicesLen = indices.length;
let indicesLen = indices.length;
if (!indicesLen) return this.errorReply("'" + target + "' is not a valid set of submission index numbers. View /trivia review and /help trivia for more information.");
if (isAccepting) {
for (var i = indicesLen; i--;) {
var submission = submissions.splice(indices[i] - 1, 1)[0];
for (let i = indicesLen; i--;) {
let submission = submissions.splice(indices[i] - 1, 1)[0];
questions.splice(findEndOfCategory(submission.category, false), 0, submission);
}
} else {
for (var i = indicesLen; i--;) {
for (let i = indicesLen; i--;) {
submissions.splice(indices[i] - 1, 1);
}
}
@ -794,11 +796,11 @@ var commands = {
target = target.trim();
if (!target) return false;
var question = Tools.escapeHTML(target);
let question = Tools.escapeHTML(target);
if (!question) return this.errorReply("'" + target + "' is not a valid argument. View /help trivia for more information.");
var questions = triviaData.questions;
for (var i = 0; i < questions.length; i++) {
let questions = triviaData.questions;
for (let i = 0; i < questions.length; i++) {
if (questions[i].question === question) {
questions.splice(i, 1);
writeTriviaData();
@ -813,21 +815,21 @@ var commands = {
qs: function (target, room, user) {
if (room.id !== 'questionworkshop') return this.errorReply('This command can only be used in Question Workshop.');
var buffer = "|raw|<div class=\"ladder\"><table>";
let buffer = "|raw|<div class=\"ladder\"><table>";
if (!target) {
if (!this.canBroadcast()) return false;
var questions = triviaData.questions;
var questionsLen = questions.length;
let questions = triviaData.questions;
let questionsLen = questions.length;
if (!questionsLen) return this.sendReplyBox("No questions have been submitted yet.");
var categories = Object.keys(CATEGORIES);
var categoryTally = {};
var lastCategoryIdx = 0;
let categories = Object.keys(CATEGORIES);
let categoryTally = {};
let lastCategoryIdx = 0;
buffer += "<tr><th>Category</th><th>Question Count</th></tr>";
for (var i = 0; i <= 11; i++) {
var tally = findEndOfCategory(categories[i], false) - lastCategoryIdx;
for (let i = 0; i <= 11; i++) {
let tally = findEndOfCategory(categories[i], false) - lastCategoryIdx;
lastCategoryIdx += tally;
buffer += "<tr><td>" + CATEGORIES[categories[i]] + "</td><td>" + tally + " (" + ((tally * 100) / questionsLen).toFixed(2) + "%)</td></tr>";
}
@ -838,12 +840,12 @@ var commands = {
if (!this.can('mute', null, room)) return false;
var category = toId(target);
let category = toId(target);
if (category === 'random') return false;
if (!CATEGORIES[category]) return this.errorReply("'" + target + "' is not a valid category. View /help trivia for more information.");
var list = sliceCategory(category);
var listLen = list.length;
let list = sliceCategory(category);
let listLen = list.length;
if (!listLen) {
buffer += "<tr><td>There are no questions in the " + target + " category.</td></table></div>";
return this.sendReply(buffer);
@ -852,14 +854,14 @@ var commands = {
if (user.can('declare', null, room)) {
buffer += "<tr><td colspan=\"3\">There are <strong>" + listLen + "</strong> questions in the " + target + " category.</td></tr>" +
"<tr><th>#</th><th>Question</th><th>Answer(s)</th></tr>";
for (var i = 0; i < listLen; i++) {
var entry = list[i];
for (let i = 0; i < listLen; i++) {
let entry = list[i];
buffer += "<tr><td><strong>" + (i + 1) + "</strong></td><td>" + entry.question + "</td><td>" + entry.answers.join(", ") + "</td><tr>";
}
} else {
buffer += "<td colspan=\"2\">There are <strong>" + listLen + "</strong> questions in the " + target + " category.</td></tr>" +
"<tr><th>#</th><th>Question</th></tr>";
for (var i = 0; i < listLen; i++) {
for (let i = 0; i < listLen; i++) {
buffer += "<tr><td><strong>" + (i + 1) + "</strong></td><td>" + list[i].question + "</td></tr>";
}
}
@ -877,7 +879,7 @@ var commands = {
status: function (target, room, user) {
if (room.id !== 'trivia') return this.errorReply('This command can only be used in Trivia.');
if (!this.canBroadcast()) return false;
var trivium = trivia[room.id];
let trivium = trivia[room.id];
if (!trivium) return this.errorReply("There is no trivia game in progress.");
trivium.getStatus(this, user);
},
@ -886,7 +888,7 @@ var commands = {
players: function (target, room) {
if (room.id !== 'trivia') return this.errorReply('This command can only be used in Trivia.');
if (!this.canBroadcast()) return false;
var trivium = trivia[room.id];
let trivium = trivia[room.id];
if (!trivium) return this.errorReply("There is no trivia game in progress.");
trivium.getParticipants(this);
},
@ -895,8 +897,8 @@ var commands = {
rank: function (target, room, user) {
if (room.id !== 'trivia') return this.errorReply('This command can only be used in Trivia.');
var name = '';
var userid = '';
let name = '';
let userid = '';
if (!target) {
name = Tools.escapeHTML(user.name);
userid = user.userid;
@ -906,7 +908,7 @@ var commands = {
userid = toId(name);
}
var score = triviaData.leaderboard[userid];
let score = triviaData.leaderboard[userid];
if (!score) return this.sendReplyBox("User '" + name + "' has not played any trivia games yet.");
this.sendReplyBox(
@ -922,18 +924,18 @@ var commands = {
if (room.id !== 'trivia') return this.errorReply('This command can only be used in Trivia.');
if (!this.canBroadcast()) return false;
var ladder = triviaData.ladder;
var leaderboard = triviaData.leaderboard;
let ladder = triviaData.ladder;
let leaderboard = triviaData.leaderboard;
if (!ladder.length) return this.errorReply("No trivia games have been played yet.");
var buffer = "|raw|<div class=\"ladder\"><table>" +
let buffer = "|raw|<div class=\"ladder\"><table>" +
"<tr><th>Rank</th><th>User</th><th>Leaderboard score</th><th>Total game points</th><th>Total correct answers</th></tr>";
for (var i = 0; i < ladder.length; i++) {
var leaders = ladder[i];
for (var j = 0; j < leaders.length; j++) {
var rank = leaderboard[leaders[j]];
var leader = Users.getExact(leaders[j]);
for (let i = 0; i < ladder.length; i++) {
let leaders = ladder[i];
for (let j = 0; j < leaders.length; j++) {
let rank = leaderboard[leaders[j]];
let leader = Users.getExact(leaders[j]);
leader = leader ? Tools.escapeHTML(leader.name) : leaders[j];
buffer += "<tr><td><strong>" + (i + 1) + "</strong></td><td>" + leader + "</td><td>" + rank[0] + "</td><td>" + rank[1] + "</td><td>" + rank[2] + "</td></tr>";
}

View File

@ -4,22 +4,24 @@
* Credits: Codelegend, SilverTactic, DanielCranham
**/
'use strict';
// checks whether any alt of the user is present in list.
function checkAllAlts(user, list) {
for (var prevName in user.prevNames) {
for (let prevName in user.prevNames) {
if (prevName === user.userid) continue;
if (prevName in list) return 'previous name ' + prevName;
}
var ip = user.latestIp;
for (var id in list) {
var matchUser = Users.get(id);
let ip = user.latestIp;
for (let id in list) {
let matchUser = Users.get(id);
if (matchUser.latestIp === ip && matchUser.userid !== user.userid) return 'alt ' + matchUser.name;
}
return false;
}
var giveaways = {};
var wifiRoom = Rooms.get('wifi');
let giveaways = {};
let wifiRoom = Rooms.get('wifi');
// import giveaways if stored in room
if (wifiRoom) {
@ -30,7 +32,7 @@ if (wifiRoom) {
}
}
var QuestionGiveAway = (function () {
let QuestionGiveAway = (function () {
function QuestionGiveAway(host, giver, room, options) {
this.host = host;
this.giver = giver;
@ -58,12 +60,12 @@ var QuestionGiveAway = (function () {
QuestionGiveAway.prototype.guessAnswer = function (user, guess, output) {
if (this.phase !== 'started') return output.sendReply("The giveaway has not started yet.");
var joinError = checkAllAlts(user, this.answered);
let joinError = checkAllAlts(user, this.answered);
if (joinError) return output.sendReply("You have already joined the giveaway under the " + joinError + ". Use that alt/account to continue.");
joinError = checkAllAlts(user, this.excluded) || (user.userid in this.excluded);
if (joinError) return output.sendReply("You are the host/giver of the giveaway, and cannot guess.");
var userid = user.userid;
let userid = user.userid;
if (!this.answered[userid]) this.answered[userid] = 0;
if (this.answered[userid] >= 3) return output.sendReply("You have already guessed three times. You cannot guess anymore in this giveaway.");
@ -87,8 +89,8 @@ var QuestionGiveAway = (function () {
this.question = value;
output.sendReply("The question has been changed to " + value + ".");
} else {
var ans = QuestionGiveAway.sanitizeAnswers(value);
var len = Object.keys(ans).length;
let ans = QuestionGiveAway.sanitizeAnswers(value);
let len = Object.keys(ans).length;
if (!len) return output.sendReply("You must specify at least one answer and it must not contain any special characters.");
this.answers = ans;
output.sendReply("The answer" + (len > 1 ? "s have" : " has") + " been changed to " + value + ".");
@ -114,8 +116,8 @@ var QuestionGiveAway = (function () {
if (!this.winner) {
this.room.addRaw("<b>The giveaway has been forcibly ended as no one has answered the question.</b>");
} else {
var ans = [];
for (var i in this.answers) {
let ans = [];
for (let i in this.answers) {
ans.push(this.answers[i]);
}
this.room.addRaw("<div class='broadcast-blue'><b>" + Tools.escapeHTML(this.winner.name) + "</b> guessed the correct answer.</b> Congratulations!<br/>" +
@ -128,7 +130,7 @@ var QuestionGiveAway = (function () {
};
QuestionGiveAway.sanitizeAnswers = function (target) {
var ret = {};
let ret = {};
target.split("/").forEach(function (ans) {
ans = ans.replace(/[^a-z0-9 ]+/ig, "").trim();
if (!toId(ans)) return;
@ -140,7 +142,7 @@ var QuestionGiveAway = (function () {
return QuestionGiveAway;
})();
var LotteryGiveAway = (function () {
let LotteryGiveAway = (function () {
function LotteryGiveAway(host, giver, room, options) {
this.host = host;
this.giver = giver;
@ -171,7 +173,7 @@ var LotteryGiveAway = (function () {
if (this.phase !== 'joining') return output.sendReply("The join phase of the lottery giveaway has ended.");
if (!user.named) return output.sendReply("You need to choose a name before joining a lottery giveaway.");
var joinError = checkAllAlts(user, this.joined);
let joinError = checkAllAlts(user, this.joined);
if (joinError) return output.sendReply("You have already joined the giveaway under the " + joinError + ". Use that alt/account to continue.");
joinError = checkAllAlts(user, this.excluded) || (user.userid in this.excluded);
if (joinError) return output.sendReply("You are the host/giver of the giveaway, and cannot join.");
@ -190,13 +192,13 @@ var LotteryGiveAway = (function () {
this.phase = 'drawing';
clearTimeout(this.drawTimer);
var userlist = Object.keys(this.joined);
let userlist = Object.keys(this.joined);
this.totalusers = userlist.length;
if (this.totalusers < this.maxwinners) return this.onEnd(true);
this.winners = {};
while (this.maxwinners) {
var index = Math.floor(Math.random() * this.totalusers);
let index = Math.floor(Math.random() * this.totalusers);
if (!(userlist[index] in this.winners)) {
this.winners[userlist[index]] = Users.get(userlist[index]);
this.maxwinners--;
@ -211,19 +213,19 @@ var LotteryGiveAway = (function () {
this.room.addRaw("<b>The giveaway was forcibly ended as not enough users participated.</b>").update();
} else {
this.phase = 'ended';
var finallist = [];
for (var id in this.winners) {
let finallist = [];
for (let id in this.winners) {
finallist.push(this.winners[id].name);
}
var multiWin = finallist.length > 1;
let multiWin = finallist.length > 1;
finallist = finallist.join(', ');
this.room.addRaw(
"<div class='broadcast-blue'><font size='2'><b>Lottery Draw: </b></font>" + this.totalusers + " users have joined the lottery.<br/>" +
"Our lucky winner" + (multiWin ? "s" : "") + ": <b>" + Tools.escapeHTML(finallist) + "!</b> Congratulations!"
).update();
for (var id in this.winners) {
var targetUser = this.winners[id];
for (let id in this.winners) {
let targetUser = this.winners[id];
if (targetUser.connected) targetUser.popup("You have won the lottery giveaway! PM **" + this.giver.name + "** to claim your prize!");
}
if (this.giver.connected) this.giver.popup("The following users have won your lottery giveaway:\n" + finallist);
@ -241,7 +243,7 @@ function spawnGiveaway(type, host, giver, room, options) {
}
}
var commands = {
let commands = {
// question giveaway.
quiz: 'question',
qg: 'question',
@ -250,12 +252,12 @@ var commands = {
if (giveaways[room.id]) return this.sendReply("There is already a giveaway going on!");
target = this.splitTarget(target);
var targetUser = this.targetUser;
let targetUser = this.targetUser;
if (!targetUser || !targetUser.connected) return this.sendReply("User '" + this.targetUsername + "' is not online.");
target = target.split(',').map(function (val) { return val.trim(); });
if (target.length !== 3) return this.sendReply("Invalid arguments specified - /question giver, prize, question, answer(s)");
var options = {
let options = {
prize: target[0],
question: target[1],
answers: QuestionGiveAway.sanitizeAnswers(target[2])
@ -278,16 +280,16 @@ var commands = {
showanswer: 'viewanswer',
viewanswer: function (target, room, user) {
if (room.id !== 'wifi') return false;
var giveaway = giveaways[room.id];
let giveaway = giveaways[room.id];
if (!giveaway) return this.sendReply("There is no giveaway going on at the moment.");
if (giveaway.type !== 'question') return this.sendReply("This is not a question giveaway.");
if (user.userid !== giveaway.host.userid && user.userid !== giveaway.giver.userid) return;
var answers = [];
for (var i in giveaway.answers) {
let answers = [];
for (let i in giveaway.answers) {
answers.push(giveaway.answers[i]);
}
var anstext = (answers.length === 1) ? 'answer is ' : 'answers are ';
let anstext = (answers.length === 1) ? 'answer is ' : 'answers are ';
this.sendReply("The giveaway question is " + giveaway.question + ".\n" +
"The " + anstext + answers.join('/') + ".");
},
@ -307,12 +309,12 @@ var commands = {
if (giveaways[room.id]) return this.sendReply("There is already a giveaway going on!");
target = this.splitTarget(target);
var targetUser = this.targetUser;
let targetUser = this.targetUser;
if (!targetUser || !targetUser.connected) return this.sendReply("User '" + this.targetUsername + "' is not online.");
target = target.split(',').map(function (val) { return val.trim(); });
if (target.length !== 2) return this.sendReply("Invalid arguments specified - /lottery giver, prize, max winners");
var options = {
let options = {
prize: target[0],
maxwinners: parseInt(target[1])
};
@ -328,7 +330,7 @@ var commands = {
joinlottery: 'join',
join: function (target, room, user, conn, cmd) {
if (room.id !== 'wifi') return this.sendReply("This command can only be used in the Wi-Fi room.");
var giveaway = giveaways[room.id];
let giveaway = giveaways[room.id];
if (!giveaway) return this.sendReply("There is no giveaway going on at the moment.");
if (giveaway.type !== 'lottery') return this.sendReply("This is not a lottery giveaway.");
@ -357,7 +359,7 @@ var commands = {
rm: 'remind',
remind: function (target, room, user) {
if (room.id !== 'wifi') return this.sendReply("This command can only be used in the Wi-Fi room.");
var giveaway = giveaways[room.id];
let giveaway = giveaways[room.id];
if (!giveaway) return this.sendReply("There is no giveaway going on at the moment.");
if (!this.canBroadcast()) return;
if (giveaway.type === 'question') {
@ -373,7 +375,7 @@ var commands = {
help: function (target, room, user) {
if (room.id !== 'wifi') return this.sendReply("This command can only be used in the Wi-Fi room.");
var reply = '';
let reply = '';
switch (target) {
case 'staff':
if (!this.can('warn', null, room)) return;

32
cidr.js
View File

@ -8,23 +8,25 @@
* @license MIT license
*/
var ipToLong = exports.ipToLong = function (ip) {
var numIp = 0;
var parts = ip.split('.');
for (var i = 0, len = parts.length; i < len; i++) {
'use strict';
let ipToLong = exports.ipToLong = function (ip) {
let numIp = 0;
let parts = ip.split('.');
for (let i = 0, len = parts.length; i < len; i++) {
numIp *= 256;
numIp += Number(parts[i]);
}
return numIp;
};
var getPattern = exports.getPattern = function (cidr) {
let getPattern = exports.getPattern = function (cidr) {
if (!cidr) return null;
var index = cidr.indexOf('/');
let index = cidr.indexOf('/');
if (index > 0) {
var subnet = ipToLong(cidr.substr(0, index));
var bits = parseInt(cidr.substr(index + 1), 10);
var mask = -1 << (32 - bits);
let subnet = ipToLong(cidr.substr(0, index));
let bits = parseInt(cidr.substr(index + 1), 10);
let mask = -1 << (32 - bits);
return [subnet & mask, mask];
}
return [ipToLong(cidr), -1];
@ -35,14 +37,14 @@ var getPattern = exports.getPattern = function (cidr) {
* ranges. The checker function returns boolean whether or not its
* passed IP is in the range.
*/
var checker = exports.checker = function (cidr) {
let checker = exports.checker = function (cidr) {
if (!cidr || !cidr.length) {
return function () {
return false;
};
}
var patterns;
let patterns;
if (Array.isArray(cidr)) {
patterns = cidr.map(getPattern).filter(function (x) {
return x;
@ -52,9 +54,9 @@ var checker = exports.checker = function (cidr) {
}
return function (ip) {
var longip = ipToLong(ip);
for (var i = 0; i < patterns.length; ++i) {
var pattern = patterns[i];
let longip = ipToLong(ip);
for (let i = 0; i < patterns.length; ++i) {
let pattern = patterns[i];
if ((longip & pattern[1]) === pattern[0]) {
return true;
}
@ -63,6 +65,6 @@ var checker = exports.checker = function (cidr) {
};
};
var check = exports.check = function (cidr, ip) {
let check = exports.check = function (cidr, ip) {
return checker(cidr)(ip);
};

View File

@ -22,6 +22,8 @@ To reload chat commands:
*/
'use strict';
const MAX_MESSAGE_LENGTH = 300;
const BROADCAST_COOLDOWN = 20 * 1000;
@ -34,15 +36,15 @@ const VALID_COMMAND_TOKENS = '/!';
const BROADCAST_TOKEN = '!';
var fs = require('fs');
var path = require('path');
const fs = require('fs');
const path = require('path');
/*********************************************************
* Load command files
*********************************************************/
var baseCommands = exports.baseCommands = require('./commands.js').commands;
var commands = exports.commands = Object.clone(baseCommands);
let baseCommands = exports.baseCommands = require('./commands.js').commands;
let commands = exports.commands = Object.clone(baseCommands);
// Install plug-in commands
@ -58,12 +60,12 @@ fs.readdirSync(path.resolve(__dirname, 'chat-plugins')).forEach(function (file)
* Modlog
*********************************************************/
var modlog = exports.modlog = {
let modlog = exports.modlog = {
lobby: fs.createWriteStream(path.resolve(__dirname, 'logs/modlog/modlog_lobby.txt'), {flags:'a+'}),
battle: fs.createWriteStream(path.resolve(__dirname, 'logs/modlog/modlog_battle.txt'), {flags:'a+'})
};
var writeModlog = exports.writeModlog = function (roomid, text) {
let writeModlog = exports.writeModlog = function (roomid, text) {
if (!modlog[roomid]) {
modlog[roomid] = fs.createWriteStream(path.resolve(__dirname, 'logs/modlog/modlog_' + roomid + '.txt'), {flags:'a+'});
}
@ -92,7 +94,7 @@ function canTalk(user, room, connection, message, targetUser) {
return false;
}
if (room && room.modchat) {
var userGroup = user.group;
let userGroup = user.group;
if (room.auth) {
if (room.auth[user.userid]) {
userGroup = room.auth[user.userid];
@ -106,7 +108,7 @@ function canTalk(user, room, connection, message, targetUser) {
return false;
}
} else if (Config.groupsranking.indexOf(userGroup) < Config.groupsranking.indexOf(room.modchat) && !user.can('bypassall')) {
var groupName = Config.groups[room.modchat].name || room.modchat;
let groupName = Config.groups[room.modchat].name || room.modchat;
connection.sendTo(room, "Because moderated chat is set, you must be of rank " + groupName + " or higher to speak in this room.");
return false;
}
@ -130,7 +132,7 @@ function canTalk(user, room, connection, message, targetUser) {
message = message.replace(/[\u0300-\u036f\u0483-\u0489\u064b-\u065f\u0670\u0E31\u0E34-\u0E3A\u0E47-\u0E4E]{3,}/g, '');
if (room && room.id === 'lobby') {
var normalized = message.trim();
let normalized = message.trim();
if ((normalized === user.lastMessage) &&
((Date.now() - user.lastMessageTime) < MESSAGE_COOLDOWN)) {
connection.popup("You can't send the same message again so soon.");
@ -141,6 +143,7 @@ function canTalk(user, room, connection, message, targetUser) {
}
if (Config.chatfilter) {
/*jshint validthis:true */
return Config.chatfilter.call(this, message, user, room, connection, targetUser);
}
return message;
@ -149,7 +152,7 @@ function canTalk(user, room, connection, message, targetUser) {
return true;
}
var Context = exports.Context = (function () {
let Context = exports.Context = (function () {
function Context(options) {
this.cmd = options.cmd || '';
this.cmdToken = options.cmdToken || '';
@ -200,11 +203,11 @@ var Context = exports.Context = (function () {
this.logModCommand(data);
};
Context.prototype.sendModCommand = function (data) {
var users = this.room.users;
var auth = this.room.auth;
let users = this.room.users;
let auth = this.room.auth;
for (var i in users) {
var user = users[i];
for (let i in users) {
let user = users[i];
// hardcoded for performance reasons (this is an inner loop)
if (user.isStaff || (auth && (auth[user.userid] || '+') !== '+')) {
user.sendTo(this.room, data);
@ -219,16 +222,16 @@ var Context = exports.Context = (function () {
this.logModCommand(text + (logOnlyText || ""));
};
Context.prototype.logModCommand = function (text) {
var roomid = (this.room.battle ? 'battle' : this.room.id);
let roomid = (this.room.battle ? 'battle' : this.room.id);
if (this.room.isPersonal) roomid = 'groupchat';
writeModlog(roomid, '(' + this.room.id + ') ' + text);
};
Context.prototype.globalModlog = function (action, user, text) {
var buf = "(" + this.room.id + ") " + action + ": ";
let buf = "(" + this.room.id + ") " + action + ": ";
if (typeof user === 'string') {
buf += "[" + toId(user) + "]";
} else {
var userid = this.getLastIdOf(user);
let userid = this.getLastIdOf(user);
buf += "[" + userid + "]";
if (user.autoconfirmed && user.autoconfirmed !== userid) buf += " ac:[" + user.autoconfirmed + "]";
}
@ -244,7 +247,7 @@ var Context = exports.Context = (function () {
};
Context.prototype.canBroadcast = function (suppressMessage) {
if (!this.broadcasting && this.cmdToken === BROADCAST_TOKEN) {
var message = this.canTalk(this.message);
let message = this.canTalk(this.message);
if (!message) return false;
if (!this.user.can('broadcast', null, this.room)) {
this.errorReply("You need to be voiced to broadcast this command's information.");
@ -253,7 +256,7 @@ var Context = exports.Context = (function () {
}
// broadcast cooldown
var normalized = message.toLowerCase().replace(/[^a-z0-9\s!,]/g, '');
let normalized = message.toLowerCase().replace(/[^a-z0-9\s!,]/g, '');
if (this.room.lastBroadcast === normalized &&
this.room.lastBroadcastTime >= Date.now() - BROADCAST_COOLDOWN) {
this.errorReply("You can't broadcast this because it was just broadcast.");
@ -274,12 +277,12 @@ var Context = exports.Context = (function () {
return CommandParser.parse(message, room || this.room, this.user, this.connection, this.levelsDeep + 1);
};
Context.prototype.run = function (targetCmd, inNamespace) {
var commandHandler;
let commandHandler;
if (typeof targetCmd === 'function') {
commandHandler = targetCmd;
} else if (inNamespace) {
commandHandler = commands;
for (var i = 0; i < this.namespaces.length; i++) {
for (let i = 0; i < this.namespaces.length; i++) {
commandHandler = commandHandler[this.namespaces[i]];
}
commandHandler = commandHandler[targetCmd];
@ -287,19 +290,19 @@ var Context = exports.Context = (function () {
commandHandler = commands[targetCmd];
}
var result;
let result;
try {
result = commandHandler.call(this, this.target, this.room, this.user, this.connection, this.cmd, this.message);
} catch (err) {
var stack = err.stack + '\n\n' +
let stack = err.stack + '\n\n' +
'Additional information:\n' +
'user = ' + this.user.name + '\n' +
'room = ' + this.room.id + '\n' +
'message = ' + this.message;
var fakeErr = {stack: stack};
let fakeErr = {stack: stack};
if (!require('./crashlogger.js')(fakeErr, 'A chat command')) {
var ministack = ("" + err.stack).escapeHTML().split("\n").slice(0, 2).join("<br />");
let ministack = ("" + err.stack).escapeHTML().split("\n").slice(0, 2).join("<br />");
if (Rooms.lobby) Rooms.lobby.send('|html|<div class="broadcast-red"><b>POKEMON SHOWDOWN HAS CRASHED:</b> ' + ministack + '</div>');
} else {
this.sendReply('|html|<div class="broadcast-red"><b>Pokemon Showdown crashed!</b><br />Don\'t worry, we\'re working on fixing it.</div>');
@ -310,18 +313,18 @@ var Context = exports.Context = (function () {
return result;
};
Context.prototype.canTalk = function (message, relevantRoom, targetUser) {
var innerRoom = (relevantRoom !== undefined) ? relevantRoom : this.room;
let innerRoom = (relevantRoom !== undefined) ? relevantRoom : this.room;
return canTalk.call(this, this.user, innerRoom, this.connection, message, targetUser);
};
Context.prototype.canHTML = function (html) {
html = '' + (html || '');
var images = html.match(/<img\b[^<>]*/ig);
let images = html.match(/<img\b[^<>]*/ig);
if (images) {
if (this.room.isPersonal && !this.user.can('announce')) {
this.errorReply("Images are not allowed in personal rooms.");
return false;
}
for (var i = 0; i < images.length; i++) {
for (let i = 0; i < images.length; i++) {
if (!/width=([0-9]+|"[0-9]+")/i.test(images[i]) || !/height=([0-9]+|"[0-9]+")/i.test(images[i])) {
// Width and height are required because most browsers insert the
// <img> element before width and height are known, and when the
@ -342,11 +345,11 @@ var Context = exports.Context = (function () {
}
// check for mismatched tags
var tags = html.toLowerCase().match(/<\/?(div|a|button|b|i|u|center|font)\b/g);
let tags = html.toLowerCase().match(/<\/?(div|a|button|b|i|u|center|font)\b/g);
if (tags) {
var stack = [];
for (var i = 0; i < tags.length; i++) {
var tag = tags[i];
let stack = [];
for (let i = 0; i < tags.length; i++) {
let tag = tags[i];
if (tag.charAt(1) === '/') {
if (!stack.length) {
this.errorReply("Extraneous </" + tag.substr(2) + "> without an opening tag.");
@ -381,16 +384,16 @@ var Context = exports.Context = (function () {
return (user.named ? user.userid : (Object.keys(user.prevNames).last() || user.userid));
};
Context.prototype.splitTarget = function (target, exactName) {
var commaIndex = target.indexOf(',');
let commaIndex = target.indexOf(',');
if (commaIndex < 0) {
var targetUser = Users.get(target, exactName);
let targetUser = Users.get(target, exactName);
this.targetUser = targetUser;
this.inputUsername = target.trim();
this.targetUsername = targetUser ? targetUser.name : target;
return '';
}
this.inputUsername = target.substr(0, commaIndex);
var targetUser = Users.get(this.inputUsername, exactName);
let targetUser = Users.get(this.inputUsername, exactName);
if (targetUser) {
this.targetUser = targetUser;
this.targetUsername = this.inputUsername = targetUser.name;
@ -427,8 +430,8 @@ var Context = exports.Context = (function () {
* if he's muted, will warn him that he's muted, and
* return false.
*/
var parse = exports.parse = function (message, room, user, connection, levelsDeep) {
var cmd = '', target = '', cmdToken = '';
let parse = exports.parse = function (message, room, user, connection, levelsDeep) {
let cmd = '', target = '', cmdToken = '';
if (!message || !message.trim().length) return;
if (!levelsDeep) {
levelsDeep = 0;
@ -448,7 +451,7 @@ var parse = exports.parse = function (message, room, user, connection, levelsDee
if (VALID_COMMAND_TOKENS.includes(message.charAt(0)) && message.charAt(1) !== message.charAt(0)) {
cmdToken = message.charAt(0);
var spaceIndex = message.indexOf(' ');
let spaceIndex = message.indexOf(' ');
if (spaceIndex > 0) {
cmd = message.substr(1, spaceIndex - 1).toLowerCase();
target = message.substr(spaceIndex + 1);
@ -458,9 +461,9 @@ var parse = exports.parse = function (message, room, user, connection, levelsDee
}
}
var namespaces = [];
var currentCommands = commands;
var commandHandler;
let namespaces = [];
let currentCommands = commands;
let commandHandler;
do {
commandHandler = currentCommands[cmd];
@ -471,7 +474,7 @@ var parse = exports.parse = function (message, room, user, connection, levelsDee
if (commandHandler && typeof commandHandler === 'object') {
namespaces.push(cmd);
var spaceIndex = target.indexOf(' ');
let spaceIndex = target.indexOf(' ');
if (spaceIndex > 0) {
cmd = target.substr(0, spaceIndex).toLowerCase();
target = target.substr(spaceIndex + 1);
@ -489,9 +492,9 @@ var parse = exports.parse = function (message, room, user, connection, levelsDee
commandHandler = currentCommands[commandHandler];
}
}
var fullCmd = namespaces.concat(cmd).join(' ');
let fullCmd = namespaces.concat(cmd).join(' ');
var context = new Context({
let context = new Context({
target: target, room: room, user: user, connection: connection, cmd: cmd, message: message,
namespaces: namespaces, cmdToken: cmdToken, levelsDeep: levelsDeep
});
@ -500,8 +503,8 @@ var parse = exports.parse = function (message, room, user, connection, levelsDee
return context.run(commandHandler);
} else {
// Check for mod/demod/admin/deadmin/etc depending on the group ids
for (var g in Config.groups) {
var groupid = Config.groups[g].id;
for (let g in Config.groups) {
let groupid = Config.groups[g].id;
if (cmd === groupid || cmd === 'global' + groupid) {
return parse('/promote ' + toId(target) + ', ' + g, room, user, connection, levelsDeep + 1);
} else if (cmd === 'de' + groupid || cmd === 'un' + groupid || cmd === 'globalde' + groupid || cmd === 'deglobal' + groupid) {
@ -542,10 +545,10 @@ fs.readFile(path.resolve(__dirname, 'package.json'), function (err, data) {
});
exports.uncacheTree = function (root) {
var uncache = [require.resolve(root)];
let uncache = [require.resolve(root)];
do {
var newuncache = [];
for (var i = 0; i < uncache.length; ++i) {
let newuncache = [];
for (let i = 0; i < uncache.length; ++i) {
if (require.cache[uncache[i]]) {
newuncache.push.apply(newuncache,
require.cache[uncache[i]].children.map('id')

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,5 @@
'use strict';
// The server port - the port to run Pokemon Showdown under
exports.port = 8000;
@ -180,7 +182,7 @@ exports.appealurl = '';
// replsocketprefix - the prefix for the repl sockets to be listening on
// replsocketmode - the file mode bits to use for the repl sockets
exports.replsocketprefix = './logs/repl/';
exports.replsocketmode = 0600;
exports.replsocketmode = '0600';
// permissions and groups:
// Each entry in `grouplist' is a seperate group. Some of the members are "special"

View File

@ -1,3 +1,5 @@
'use strict';
// Note: This is the list of formats
// The rules that formats use are stored in data/rulesets.js
@ -40,10 +42,10 @@ exports.Formats = [
ruleset: ['OU'],
onBegin: function () {
for (var i = 0; i < this.p1.pokemon.length; i++) {
for (let i = 0; i < this.p1.pokemon.length; i++) {
this.p1.pokemon[i].canMegaEvo = false;
}
for (var i = 0; i < this.p2.pokemon.length; i++) {
for (let i = 0; i < this.p2.pokemon.length; i++) {
this.p2.pokemon[i].canMegaEvo = false;
}
}
@ -425,15 +427,15 @@ exports.Formats = [
noChangeForme: true,
noChangeAbility: true,
abilityMap: (function () {
var Pokedex = require('./../tools.js').data.Pokedex;
let Pokedex = require('./../tools.js').data.Pokedex;
if (!Pokedex) return null; // Process is data-unaware
var abilityMap = Object.create(null);
for (var speciesid in Pokedex) {
var pokemon = Pokedex[speciesid];
let abilityMap = Object.create(null);
for (let speciesid in Pokedex) {
let pokemon = Pokedex[speciesid];
if (pokemon.num < 1 || pokemon.num > 720) continue;
for (var key in pokemon.abilities) {
var abilityId = toId(pokemon.abilities[key]);
for (let key in pokemon.abilities) {
let abilityId = toId(pokemon.abilities[key]);
if (abilityMap[abilityId]) {
abilityMap[abilityId].push(speciesid);
} else {
@ -444,7 +446,7 @@ exports.Formats = [
return abilityMap;
})(),
getEvoFamily: function (species) {
var template = Tools.getTemplate(species);
let template = Tools.getTemplate(species);
while (template.prevo) {
template = Tools.getTemplate(template.prevo);
}
@ -452,18 +454,18 @@ exports.Formats = [
},
onValidateTeam: function (team, format, teamHas) {
// Donor Clause
var evoFamilyLists = [];
for (var i = 0; i < team.length; i++) {
var set = team[i];
let evoFamilyLists = [];
for (let i = 0; i < team.length; i++) {
let set = team[i];
if (!set.abilitySources) continue;
evoFamilyLists.push(set.abilitySources.map(format.getEvoFamily).unique());
}
// Checking actual full incompatibility would require expensive algebra.
// Instead, we only check the trivial case of multiple Pokémon only legal for exactly one family. FIXME?
var requiredFamilies = Object.create(null);
for (var i = 0; i < evoFamilyLists.length; i++) {
var evoFamilies = evoFamilyLists[i];
let requiredFamilies = Object.create(null);
for (let i = 0; i < evoFamilyLists.length; i++) {
let evoFamilies = evoFamilyLists[i];
if (evoFamilies.length !== 1) continue;
if (requiredFamilies[evoFamilies[0]]) return ["You are limited to one inheritance from each family by the Donor Clause.", "(You inherit more than once from " + this.getTemplate(evoFamilies[0]).species + "'s.)"];
requiredFamilies[evoFamilies[0]] = 1;
@ -473,13 +475,13 @@ exports.Formats = [
if (!this.format.abilityMap) return this.validateSet(set, teamHas); // shouldn't happen
this.format.noChangeForme = false;
var problems = this.tools.getFormat('Pokemon').onChangeSet.call(this.tools, set, this.format) || [];
let problems = this.tools.getFormat('Pokemon').onChangeSet.call(this.tools, set, this.format) || [];
this.format.noChangeForme = true;
if (problems.length) return problems;
var species = toId(set.species);
var template = this.tools.getTemplate(species);
let species = toId(set.species);
let template = this.tools.getTemplate(species);
if (!template.exists) return ["" + set.species + " is not a real Pok\u00E9mon."];
if (template.isUnreleased) return ["" + set.species + " is unreleased."];
if (template.speciesid in this.format.customBans.receiver) {
@ -490,26 +492,26 @@ exports.Formats = [
}
}
var name = set.name;
let name = set.name;
var abilityId = toId(set.ability);
let abilityId = toId(set.ability);
if (!abilityId) return ["" + (set.name || set.species) + " must have an ability."];
var pokemonWithAbility = this.format.abilityMap[abilityId];
let pokemonWithAbility = this.format.abilityMap[abilityId];
if (!pokemonWithAbility) return ["" + set.ability + " is an invalid ability."];
var isBaseAbility = Object.values(template.abilities).map(toId).indexOf(abilityId) >= 0;
let isBaseAbility = Object.values(template.abilities).map(toId).indexOf(abilityId) >= 0;
// Items must be fully validated here since we may pass a different item to the base set validator.
var item = this.tools.getItem(set.item);
let item = this.tools.getItem(set.item);
if (item.id) {
if (!item.exists) return ["" + set.item + " is an invalid item."];
if (item.isUnreleased) return ["" + (set.name || set.species) + "'s item " + item.name + " is unreleased."];
if (item.id in this.format.customBans.items) return ["" + item.name + " is banned."];
}
var validSources = set.abilitySources = []; // evolutionary families
for (var i = 0; i < pokemonWithAbility.length; i++) {
var donorTemplate = this.tools.getTemplate(pokemonWithAbility[i]);
var evoFamily = this.format.getEvoFamily(donorTemplate);
let validSources = set.abilitySources = []; // evolutionary families
for (let i = 0; i < pokemonWithAbility.length; i++) {
let donorTemplate = this.tools.getTemplate(pokemonWithAbility[i]);
let evoFamily = this.format.getEvoFamily(donorTemplate);
if (validSources.indexOf(evoFamily) >= 0) {
// The existence of a legal set has already been established.
@ -720,11 +722,11 @@ exports.Formats = [
'Blazikenite', 'Gengarite', 'Kangaskhanite', 'Lucarionite', 'Mawilite', 'Salamencite', 'Soul Dew', 'Chatter'
],
onValidateSet: function (set) {
var bannedAbilities = {'Aerilate': 1, 'Arena Trap': 1, 'Contrary': 1, 'Fur Coat': 1, 'Huge Power': 1, 'Imposter': 1, 'Parental Bond': 1, 'Protean': 1, 'Pure Power': 1, 'Shadow Tag': 1, 'Simple':1, 'Speed Boost': 1, 'Wonder Guard': 1};
let bannedAbilities = {'Aerilate': 1, 'Arena Trap': 1, 'Contrary': 1, 'Fur Coat': 1, 'Huge Power': 1, 'Imposter': 1, 'Parental Bond': 1, 'Protean': 1, 'Pure Power': 1, 'Shadow Tag': 1, 'Simple':1, 'Speed Boost': 1, 'Wonder Guard': 1};
if (set.ability in bannedAbilities) {
var template = this.getTemplate(set.species || set.name);
var legalAbility = false;
for (var i in template.abilities) {
let template = this.getTemplate(set.species || set.name);
let legalAbility = false;
for (let i in template.abilities) {
if (set.ability === template.abilities[i]) legalAbility = true;
}
if (!legalAbility) return ['The ability ' + set.ability + ' is banned on Pok\u00e9mon that do not naturally have it.'];
@ -743,16 +745,16 @@ exports.Formats = [
ruleset: ['OU'],
banlist: ['Diggersby', 'Keldeo', 'Porygon-Z', 'Sylveon', 'Aerodactylite', 'Altarianite', "King's Rock", 'Lopunnite', 'Metagrossite', 'Razor Fang'],
validateSet: function (set, teamHas) {
var statusProblems = this.validateSet(set, teamHas, {ignorestabmoves: {'Status':1}});
let statusProblems = this.validateSet(set, teamHas, {ignorestabmoves: {'Status':1}});
if (!statusProblems.length) return;
var attackProblems = this.validateSet(set, teamHas, {ignorestabmoves: {'Physical':1, 'Special':1}});
let attackProblems = this.validateSet(set, teamHas, {ignorestabmoves: {'Physical':1, 'Special':1}});
if (!attackProblems.length) return;
var problems = [];
for (var i = 0; i < statusProblems.length; i++) {
let problems = [];
for (let i = 0; i < statusProblems.length; i++) {
problems.push('(Status) ' + statusProblems[i]);
}
for (var i = 0; i < attackProblems.length; i++) {
for (let i = 0; i < attackProblems.length; i++) {
problems.push('(Attack) ' + attackProblems[i]);
}
return problems;

View File

@ -1573,27 +1573,25 @@ exports.BattleAbilities = {
onResidualOrder: 26,
onResidualSubOrder: 1,
onResidual: function (pokemon) {
var stats = [], i = '';
var stats = [];
var boost = {};
for (var i in pokemon.boosts) {
if (pokemon.boosts[i] < 6) {
stats.push(i);
for (var statPlus in pokemon.boosts) {
if (pokemon.boosts[statPlus] < 6) {
stats.push(statPlus);
}
}
if (stats.length) {
i = stats[this.random(stats.length)];
boost[i] = 2;
}
var randomStat = stats.length ? stats[this.random(stats.length)] : "";
if (randomStat) boost[randomStat] = 2;
stats = [];
for (var j in pokemon.boosts) {
if (pokemon.boosts[j] > -6 && j !== i) {
stats.push(j);
for (var statMinus in pokemon.boosts) {
if (pokemon.boosts[statMinus] > -6 && statMinus !== randomStat) {
stats.push(statMinus);
}
}
if (stats.length) {
i = stats[this.random(stats.length)];
boost[i] = -1;
}
randomStat = stats.length ? stats[this.random(stats.length)] : "";
if (randomStat) boost[randomStat] = -1;
this.boost(boost);
},
id: "moody",
@ -1819,23 +1817,17 @@ exports.BattleAbilities = {
onResidual: function (pokemon) {
if (pokemon.item) return;
var pickupTargets = [];
var target;
for (var i = 0; i < pokemon.side.active.length; i++) {
target = pokemon.side.active[i];
if (target.lastItem && target.usedItemThisTurn && this.isAdjacent(pokemon, target)) {
pickupTargets.push(target);
}
}
for (var i = 0; i < pokemon.side.foe.active.length; i++) {
target = pokemon.side.foe.active[i];
var allActives = pokemon.side.active.concat(pokemon.side.foe.active);
for (var i = 0; i < allActives.length; i++) {
var target = allActives[i];
if (target.lastItem && target.usedItemThisTurn && this.isAdjacent(pokemon, target)) {
pickupTargets.push(target);
}
}
if (!pickupTargets.length) return;
target = pickupTargets[this.random(pickupTargets.length)];
pokemon.setItem(target.lastItem);
target.lastItem = '';
var randomTarget = pickupTargets[this.random(pickupTargets.length)];
pokemon.setItem(randomTarget.lastItem);
randomTarget.lastItem = '';
var item = pokemon.getItem();
this.add('-item', pokemon, item, '[from] Pickup');
if (item.isBerry) pokemon.update();

View File

@ -2322,9 +2322,9 @@ exports.BattleItems = {
pokemon.removeVolatile('leppaberry');
} else {
var pp = 99;
for (var i in pokemon.moveset) {
if (pokemon.moveset[i].pp < pp) {
move = pokemon.moveset[i];
for (var moveid in pokemon.moveset) {
if (pokemon.moveset[moveid].pp < pp) {
move = pokemon.moveset[moveid];
pp = move.pp;
}
}
@ -4329,15 +4329,15 @@ exports.BattleItems = {
},
onEat: function (pokemon) {
var stats = [];
for (var i in pokemon.boosts) {
if (i !== 'accuracy' && i !== 'evasion' && pokemon.boosts[i] < 6) {
stats.push(i);
for (var stat in pokemon.boosts) {
if (stat !== 'accuracy' && stat !== 'evasion' && pokemon.boosts[stat] < 6) {
stats.push(stat);
}
}
if (stats.length) {
var i = stats[this.random(stats.length)];
var randomStat = stats[this.random(stats.length)];
var boost = {};
boost[i] = 2;
boost[randomStat] = 2;
this.boost(boost);
}
},

View File

@ -142,15 +142,15 @@ exports.BattleMovedex = {
flags: {},
onHit: function (target) {
var stats = [];
for (var i in target.boosts) {
if (target.boosts[i] < 6) {
stats.push(i);
for (var stat in target.boosts) {
if (target.boosts[stat] < 6) {
stats.push(stat);
}
}
if (stats.length) {
var i = stats[this.random(stats.length)];
var randomStat = stats[this.random(stats.length)];
var boost = {};
boost[i] = 2;
boost[randomStat] = 2;
this.boost(boost);
} else {
return false;
@ -502,12 +502,12 @@ exports.BattleMovedex = {
}
}
}
var move = '';
if (moves.length) move = moves[this.random(moves.length)];
if (!move) {
var randomMove = '';
if (moves.length) randomMove = moves[this.random(moves.length)];
if (!randomMove) {
return false;
}
this.useMove(move, target);
this.useMove(randomMove, target);
},
secondary: false,
target: "self",
@ -1991,10 +1991,10 @@ exports.BattleMovedex = {
if (!possibleTypes.length) {
return false;
}
var type = possibleTypes[this.random(possibleTypes.length)];
var randomType = possibleTypes[this.random(possibleTypes.length)];
if (!source.setType(type)) return false;
this.add('-start', source, 'typechange', type);
if (!source.setType(randomType)) return false;
this.add('-start', source, 'typechange', randomType);
},
secondary: false,
target: "normal",
@ -2485,16 +2485,17 @@ exports.BattleMovedex = {
flags: {protect: 1, reflectable: 1, mirror: 1, authentic: 1},
onHit: function (target, source, move) {
if (!target.volatiles['substitute'] || move.infiltrates) this.boost({evasion:-1});
var sideConditions = {reflect:1, lightscreen:1, safeguard:1, mist:1, spikes:1, toxicspikes:1, stealthrock:1, stickyweb:1};
var sideEnd = {spikes:1, toxicspikes:1, stealthrock:1, stickyweb:1};
for (var i in sideConditions) {
if (target.side.removeSideCondition(i)) {
if (sideEnd[i]) this.add('-sideend', target.side, this.getEffect(i).name, '[from] move: Defog', '[of] ' + target);
var removeTarget = {reflect:1, lightscreen:1, safeguard:1, mist:1, spikes:1, toxicspikes:1, stealthrock:1, stickyweb:1};
var removeAll = {spikes:1, toxicspikes:1, stealthrock:1, stickyweb:1};
for (var targetCondition in removeTarget) {
if (target.side.removeSideCondition(targetCondition)) {
if (!removeAll[targetCondition]) continue;
this.add('-sideend', target.side, this.getEffect(targetCondition).name, '[from] move: Defog', '[of] ' + target);
}
}
for (var i in sideEnd) {
if (source.side.removeSideCondition(i)) {
this.add('-sideend', source.side, this.getEffect(i).name, '[from] move: Defog', '[of] ' + source);
for (var sideCondition in removeAll) {
if (source.side.removeSideCondition(sideCondition)) {
this.add('-sideend', source.side, this.getEffect(sideCondition).name, '[from] move: Defog', '[of] ' + source);
}
}
},
@ -4464,16 +4465,19 @@ exports.BattleMovedex = {
flags: {distance: 1},
onHitField: function (target, source) {
var targets = [];
for (var i = 0; i < this.sides.length; i++) {
for (var j = 0; j < this.sides[i].active.length; j++) {
if (this.sides[i].active[j] && this.sides[i].active[j].hasType('Grass')) {
for (var sideSlot = 0; sideSlot < this.sides.length; sideSlot++) {
var sideActive = this.sides[sideSlot].active;
for (var activeSlot = 0; activeSlot < sideActive.length; activeSlot++) {
if (sideActive[activeSlot] && sideActive[activeSlot].hasType('Grass')) {
// This move affects every Grass-type Pokemon in play.
targets.push(this.sides[i].active[j]);
targets.push(sideActive[activeSlot]);
}
}
}
if (!targets.length) return false; // No targets; move fails
for (var i = 0; i < targets.length; i++) this.boost({def: 1}, targets[i], source, this.getMove('Flower Shield'));
for (var i = 0; i < targets.length; i++) {
this.boost({def: 1}, targets[i], source, this.getMove('Flower Shield'));
}
},
secondary: false,
target: "all",
@ -8451,15 +8455,15 @@ exports.BattleMovedex = {
moves.push(move);
}
}
var move = '';
var randomMove = '';
if (moves.length) {
moves.sort(function (a, b) {return a.num - b.num;});
move = moves[this.random(moves.length)].id;
randomMove = moves[this.random(moves.length)].id;
}
if (!move) {
if (!randomMove) {
return false;
}
this.useMove(move, target);
this.useMove(randomMove, target);
},
secondary: false,
target: "self",
@ -11390,18 +11394,18 @@ exports.BattleMovedex = {
onHitField: function (target, source) {
var targets = [];
var anyAirborne = false;
for (var i = 0; i < this.sides.length; i++) {
for (var j = 0; j < this.sides[i].active.length; j++) {
if (this.sides[i].active[j]) {
if (!this.sides[i].active[j].runImmunity('Ground')) {
this.add('-immune', this.sides[i].active[j], '[msg]');
anyAirborne = true;
continue;
}
if (this.sides[i].active[j].hasType('Grass')) {
// This move affects every grounded Grass-type Pokemon in play.
targets.push(this.sides[i].active[j]);
}
for (var sideSlot = 0; sideSlot < this.sides.length; sideSlot++) {
var sideActive = this.sides[sideSlot].active;
for (var activeSlot = 0; activeSlot < sideActive.length; activeSlot++) {
if (!sideActive[activeSlot]) continue;
if (!sideActive[activeSlot].runImmunity('Ground')) {
this.add('-immune', sideActive[activeSlot], '[msg]');
anyAirborne = true;
continue;
}
if (sideActive[activeSlot].hasType('Grass')) {
// This move affects every grounded Grass-type Pokemon in play.
targets.push(sideActive[activeSlot]);
}
}
}
@ -12483,12 +12487,12 @@ exports.BattleMovedex = {
moves.push(move);
}
}
var move = '';
if (moves.length) move = moves[this.random(moves.length)];
if (!move) {
var randomMove = '';
if (moves.length) randomMove = moves[this.random(moves.length)];
if (!randomMove) {
return false;
}
this.useMove(move, pokemon);
this.useMove(randomMove, pokemon);
},
secondary: false,
target: "self",

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleStatuses = {
brn: {
effectType: 'Status',
@ -62,7 +64,7 @@ exports.BattleStatuses = {
onStart: function (target) {
this.add('-status', target, 'frz');
if (target.template.species === 'Shaymin-Sky' && target.baseTemplate.baseSpecies === 'Shaymin') {
var template = this.getTemplate('Shaymin');
let template = this.getTemplate('Shaymin');
target.formeChange(template);
target.baseTemplate = template;
target.setAbility(template.abilities['0']);
@ -128,7 +130,7 @@ exports.BattleStatuses = {
confusion: {
// this is a volatile status
onStart: function (target, source, sourceEffect) {
var result = this.runEvent('TryConfusion', target, source, sourceEffect);
let result = this.runEvent('TryConfusion', target, source, sourceEffect);
if (!result) return result;
if (sourceEffect && sourceEffect.id === 'lockedmove') {
this.add('-start', target, 'confusion', '[fatigue]');
@ -270,8 +272,8 @@ exports.BattleStatuses = {
if (pokemon.ignoringItem()) {
return;
}
var moves = pokemon.moveset;
for (var i = 0; i < moves.length; i++) {
let moves = pokemon.moveset;
for (let i = 0; i < moves.length; i++) {
if (moves[i].id !== this.effectData.move) {
pokemon.disableMove(moves[i].id, false, this.effectData.sourceEffect);
}
@ -295,15 +297,15 @@ exports.BattleStatuses = {
// this is a side condition
onStart: function (side) {
this.effectData.positions = [];
for (var i = 0; i < side.active.length; i++) {
for (let i = 0; i < side.active.length; i++) {
this.effectData.positions[i] = null;
}
},
onResidualOrder: 3,
onResidual: function (side) {
var finished = true;
for (var i = 0; i < side.active.length; i++) {
var posData = this.effectData.positions[i];
let finished = true;
for (let i = 0; i < side.active.length; i++) {
let posData = this.effectData.positions[i];
if (!posData) continue;
posData.duration--;
@ -314,8 +316,8 @@ exports.BattleStatuses = {
}
// time's up; time to hit! :D
var target = side.foe.active[posData.targetPosition];
var move = this.getMove(posData.move);
let target = side.foe.active[posData.targetPosition];
let move = this.getMove(posData.move);
if (target.fainted) {
this.add('-hint', '' + move.name + ' did not hit because the target is fainted.');
this.effectData.positions[i] = null;
@ -367,7 +369,7 @@ exports.BattleStatuses = {
onStallMove: function () {
// this.effectData.counter should never be undefined here.
// However, just in case, use 1 if it is undefined.
var counter = this.effectData.counter || 1;
let counter = this.effectData.counter || 1;
this.debug("Success chance: " + Math.round(100 / counter) + "%");
return (this.random(counter) === 0);
},
@ -390,7 +392,7 @@ exports.BattleStatuses = {
duration: 1,
onBasePowerPriority: 8,
onBasePower: function (basePower, user, target, move) {
var modifier = 0x1547;
let modifier = 0x1547;
this.debug('Aura Boost');
if (user.volatiles['aurabreak']) {
modifier = 0x0C00;
@ -633,7 +635,7 @@ exports.BattleStatuses = {
// Hackmons.
onSwitchInPriority: 101,
onSwitchIn: function (pokemon) {
var type = 'Normal';
let type = 'Normal';
if (pokemon.ability === 'multitype') {
type = pokemon.getItem().onPlate;
if (!type || type === true) {

View File

@ -44,7 +44,9 @@
* ```
*/
var assert = require('assert');
'use strict';
const assert = require('assert');
module.exports = function () {};
@ -63,10 +65,10 @@ module.exports.prototype = {
check: function (file, errors) {
file.iterateNodesByType('SwitchStatement', function (node) {
var column = node.loc.start.column;
var currentLine = 0;
for (var i = 0; i < node.cases.length; i++) {
var currentCase = node.cases[i];
let column = node.loc.start.column;
let currentLine = 0;
for (let i = 0; i < node.cases.length; i++) {
let currentCase = node.cases[i];
if (currentCase.loc.line === currentLine) continue;
currentLine = currentCase.loc.line;
if (currentCase.loc.start.column === column) continue;

View File

@ -76,7 +76,9 @@
* ```
*/
var assert = require('assert');
'use strict';
const assert = require('assert');
module.exports = function () {};
@ -95,11 +97,11 @@ module.exports.prototype = {
check: function (file, errors) {
file.iterateNodesByType('IfStatement', function (node) {
var consequent = node.consequent;
var statementType = consequent.type;
let consequent = node.consequent;
let statementType = consequent.type;
// Either all `BlockStatement` or none.
var subNode = node;
let subNode = node;
while (subNode.alternate) {
subNode = subNode.alternate;
if (subNode.type === 'IfStatement') {
@ -121,13 +123,13 @@ module.exports.prototype = {
}
// Curly braces iff multiline
var nodesCheck = [consequent];
let nodesCheck = [consequent];
if (node.alternate) nodesCheck.push(node.alternate);
for (var i = 0; i < nodesCheck.length; i++) {
var subNode = nodesCheck[i];
for (let i = 0; i < nodesCheck.length; i++) {
let subNode = nodesCheck[i];
if (subNode.type === 'BlockStatement') {
var openingBrace = file.getFirstNodeToken(subNode);
var closingBrace = file.getLastNodeToken(subNode);
let openingBrace = file.getFirstNodeToken(subNode);
let closingBrace = file.getLastNodeToken(subNode);
if (!subNode.body.length) {
// Empty block
errors.assert.differentLine({
@ -136,8 +138,8 @@ module.exports.prototype = {
});
continue;
}
var nextToken = file.getFirstNodeToken(subNode.body[0]);
var prevToken = file.getPrevToken(closingBrace);
let nextToken = file.getFirstNodeToken(subNode.body[0]);
let prevToken = file.getPrevToken(closingBrace);
errors.assert.differentLine({
token: openingBrace,
@ -151,7 +153,7 @@ module.exports.prototype = {
});
} else if (subNode.type !== 'IfStatement') {
if (subNode === consequent) {
var token = file.getFirstNodeToken(subNode);
let token = file.getFirstNodeToken(subNode);
errors.assert.sameLine({
token: node.test,
nextToken: token,

View File

@ -1,7 +1,9 @@
var EventEmitter = require('events').EventEmitter;
'use strict';
let EventEmitter = require('events').EventEmitter;
function createWorker() {
var fakeWorker = new EventEmitter();
let fakeWorker = new EventEmitter();
fakeWorker.send = function () {};
Sockets.workers[fakeWorker.id] = fakeWorker;
return fakeWorker;
@ -16,14 +18,14 @@ function createConnection(ip, workerid, socketid) {
socketid++;
}
}
var connectionid = workerid + '-' + socketid;
var connection = Users.connections[connectionid] = new Users.Connection(connectionid, Sockets.workers[workerid], socketid, null, ip || '127.0.0.1');
let connectionid = workerid + '-' + socketid;
let connection = Users.connections[connectionid] = new Users.Connection(connectionid, Sockets.workers[workerid], socketid, null, ip || '127.0.0.1');
return connection;
}
function createUser(connection) {
if (!connection) connection = createConnection();
var user = new Users.User(connection);
let user = new Users.User(connection);
connection.user = user;
user.joinRoom('global', connection);
return user;

View File

@ -14,12 +14,12 @@
const BLOCKLISTS = ['sbl.spamhaus.org', 'rbl.efnetrbl.org'];
var dns = require('dns');
let dns = require('dns');
/* global Dnsbl: true */
var Dnsbl = module.exports;
let Dnsbl = module.exports;
var dnsblCache = exports.cache = {
let dnsblCache = exports.cache = {
'127.0.0.1': false
};
@ -29,7 +29,7 @@ function queryDnsblLoop(ip, callback, reversedIpDot, index) {
callback(dnsblCache[ip] = false);
return;
}
var blocklist = BLOCKLISTS[index];
let blocklist = BLOCKLISTS[index];
dns.resolve4(reversedIpDot + blocklist, function (err, addresses) {
if (!err) {
// blocked
@ -53,23 +53,23 @@ exports.query = function queryDnsbl(ip, callback) {
callback(dnsblCache[ip]);
return;
}
var reversedIpDot = ip.split('.').reverse().join('.') + '.';
let reversedIpDot = ip.split('.').reverse().join('.') + '.';
queryDnsblLoop(ip, callback, reversedIpDot, 0);
};
// require cidr and dns separately for ease of hotpatching
var cidr = require('./cidr.js');
var rangeLeaseweb = cidr.checker('207.244.64.0/18');
var rangeLeaseweb2 = cidr.checker('209.58.128.0/18');
var rangeLeaseweb3 = cidr.checker('103.254.152.0/22');
var rangeVoxility = cidr.checker('5.254.64.0/20');
var rangeCenet = cidr.checker('27.111.64.0/21');
var rangeQlded = cidr.checker('203.104.0.0/20');
var rangeCathednet = cidr.checker('180.95.40.0/21');
var rangeTelefonica = cidr.checker('181.64.0.0/14');
var rangeTelstra = cidr.checker('101.160.0.0/11');
var rangeStarhub = cidr.checker(['27.125.128.0/18', '101.127.0.0/17', '116.88.0.0/17', '122.11.192.0/18', '182.19.128.0/17', '182.55.0.0/16', '183.90.0.0/17', '203.116.122.0/23']);
var rangeUltrasurf = cidr.checker('65.49.0.0/17');
let cidr = require('./cidr.js');
let rangeLeaseweb = cidr.checker('207.244.64.0/18');
let rangeLeaseweb2 = cidr.checker('209.58.128.0/18');
let rangeLeaseweb3 = cidr.checker('103.254.152.0/22');
let rangeVoxility = cidr.checker('5.254.64.0/20');
let rangeCenet = cidr.checker('27.111.64.0/21');
let rangeQlded = cidr.checker('203.104.0.0/20');
let rangeCathednet = cidr.checker('180.95.40.0/21');
let rangeTelefonica = cidr.checker('181.64.0.0/14');
let rangeTelstra = cidr.checker('101.160.0.0/11');
let rangeStarhub = cidr.checker(['27.125.128.0/18', '101.127.0.0/17', '116.88.0.0/17', '122.11.192.0/18', '182.19.128.0/17', '182.55.0.0/16', '183.90.0.0/17', '203.116.122.0/23']);
let rangeUltrasurf = cidr.checker('65.49.0.0/17');
Dnsbl.reverse = function reverseDns(ip, callback) {
if (ip) {

View File

@ -1,35 +1,28 @@
var path = require('path');
var util = require('util');
'use strict';
var gulp = require('gulp');
var lazypipe = require('lazypipe');
var merge = require('merge-stream');
var cache = require('gulp-cache');
var jscs = require('gulp-jscs');
var jshint = require('gulp-jshint');
var replace = require('gulp-replace');
var CacheSwap = require('cache-swap');
var jshintStylish = require('jshint-stylish');
const path = require('path');
const util = require('util');
var fileCache = new CacheSwap({tmpDir: '', cacheDirName: 'gulp-cache'});
const gulp = require('gulp');
const lazypipe = require('lazypipe');
const merge = require('merge-stream');
const cache = require('gulp-cache');
const jscs = require('gulp-jscs');
const jshint = require('gulp-jshint');
const replace = require('gulp-replace');
const CacheSwap = require('cache-swap');
const jshintStylish = require('jshint-stylish');
var globals = {};
var globalList = [
const fileCache = new CacheSwap({tmpDir: '', cacheDirName: 'gulp-cache'});
let globals = {};
let globalList = [
'Config', 'Monitor', 'toId', 'Tools', 'LoginServer', 'Users', 'Rooms', 'Verifier',
'CommandParser', 'Simulator', 'Tournaments', 'Dnsbl', 'Cidr', 'Sockets', 'TeamValidator',
'Ladders'
];
globalList.forEach(function (identifier) {globals[identifier] = false;});
function transformLet() {
// Replacing `var` with `let` is sort of a hack that stops jsHint from
// complaining that I'm using `var` like `let` should be used, but
// without having to deal with iffy `let` support.
return lazypipe()
.pipe(replace.bind(null, /\bvar\b/g, 'let'))();
}
function lint(jsHintOptions, jscsOptions) {
function cachedJsHint() {
return cache(jshint(jsHintOptions), {
@ -47,7 +40,7 @@ function lint(jsHintOptions, jscsOptions) {
.pipe(jscs.bind(jscs, jscsOptions))();
}
var jsHintOptions = {};
let jsHintOptions = {};
jsHintOptions.base = {
"nonbsp": true,
"nonew": true,
@ -76,7 +69,7 @@ jsHintOptions.test = util._extend(util._extend({}, jsHintOptions.base), {
"mocha": true
});
var jscsOptions = {};
let jscsOptions = {};
jscsOptions.base = {
"preset": "yandex",
@ -160,7 +153,7 @@ jscsOptions.dataCompactAllIndented = util._extend(util._extend({}, jscsOptions.d
"validateIndentation": '\t'
});
var lintData = [
let lintData = [
{
dirs: ['./*.js', './tournaments/*.js', './chat-plugins/*.js', './config/!(config).js', './data/rulesets.js', './data/statuses.js'],
jsHint: jsHintOptions.base,
@ -200,13 +193,12 @@ lintData.extra = {
}
};
var linter = function () {
let linter = function () {
return (
merge.apply(
null,
lintData.map(function (source) {
return gulp.src(source.dirs)
.pipe(transformLet())
.pipe(lint(source.jsHint, source.jscs));
})
).pipe(jshint.reporter(jshintStylish))
@ -214,11 +206,10 @@ var linter = function () {
);
};
for (var taskName in lintData.extra) {
for (let taskName in lintData.extra) {
gulp.task(taskName, (function (task) {
return function () {
return gulp.src(task.dirs)
.pipe(transformLet())
.pipe(lint(task.jsHint, task.jscs))
.pipe(jshint.reporter(jshintStylish))
.pipe(jshint.reporter('fail'));

View File

@ -8,7 +8,7 @@
*/
/* global Ladders: true */
var Ladders = module.exports = getLadder;
let Ladders = Ladders.get = module.exports = getLadder;
function getLadder(formatid) {
return new Ladder(formatid);
@ -23,8 +23,8 @@ Ladder.prototype.getTop = function () {
};
Ladder.prototype.getRating = function (userid) {
var formatid = this.formatid;
var user = Users.getExact(userid);
let formatid = this.formatid;
let user = Users.getExact(userid);
if (user && user.mmrCache[formatid]) {
return Promise.resolve(user.mmrCache[formatid]);
}
@ -38,7 +38,7 @@ Ladder.prototype.getRating = function (userid) {
return resolve(1000);
}
var mmr = parseInt(data, 10);
let mmr = parseInt(data, 10);
if (isNaN(mmr)) return resolve(1000);
if (user.userid !== userid) return reject(new Error("Expired rating"));
@ -49,8 +49,8 @@ Ladder.prototype.getRating = function (userid) {
};
Ladder.prototype.updateRating = function (p1name, p2name, p1score, room) {
var formatid = this.formatid;
var p1rating, p2rating;
let formatid = this.formatid;
let p1rating, p2rating;
room.update();
room.send('||Ladder updating...');
LoginServer.request('ladderupdate', {
@ -80,9 +80,9 @@ Ladder.prototype.updateRating = function (p1name, p2name, p1score, room) {
p1rating = data.p1rating;
p2rating = data.p2rating;
var oldacre = Math.round(p1rating.oldacre);
var acre = Math.round(p1rating.acre);
var reasons = '' + (acre - oldacre) + ' for ' + (p1score > 0.9 ? 'winning' : (p1score < 0.1 ? 'losing' : 'tying'));
let oldacre = Math.round(p1rating.oldacre);
let acre = Math.round(p1rating.acre);
let reasons = '' + (acre - oldacre) + ' for ' + (p1score > 0.9 ? 'winning' : (p1score < 0.1 ? 'losing' : 'tying'));
if (reasons.charAt(0) !== '-') reasons = '+' + reasons;
room.addRaw(Tools.escapeHTML(p1name) + '\'s rating: ' + oldacre + ' &rarr; <strong>' + acre + '</strong><br />(' + reasons + ')');
@ -92,9 +92,9 @@ Ladder.prototype.updateRating = function (p1name, p2name, p1score, room) {
if (reasons.charAt(0) !== '-') reasons = '+' + reasons;
room.addRaw(Tools.escapeHTML(p2name) + '\'s rating: ' + oldacre + ' &rarr; <strong>' + acre + '</strong><br />(' + reasons + ')');
var p1 = Users.getExact(p1name);
let p1 = Users.getExact(p1name);
if (p1) p1.mmrCache[formatid] = +p1rating.acre;
var p2 = Users.getExact(p2name);
let p2 = Users.getExact(p2name);
if (p2) p2.mmrCache[formatid] = +p2rating.acre;
room.update();
} catch (e) {

View File

@ -8,10 +8,13 @@
*/
/* global Ladders: true */
var Ladders = module.exports = getLadder;
var fs = require('fs');
var readline = require('readline');
'use strict';
let Ladders = module.exports = getLadder;
const fs = require('fs');
const readline = require('readline');
function getLadder(formatid) {
return new Ladder(formatid);
@ -25,7 +28,7 @@ Ladders.formatsListPrefix = '|,LL';
// ladder is basically a 2D array representing the corresponding ladder.tsv
// with userid in front
// ladder = [[userid, elo, username, w, l, t]]
var ladderCaches = Ladders.ladderCaches = Object.create(null);
let ladderCaches = Ladders.ladderCaches = Object.create(null);
function Ladder(formatid) {
this.formatid = toId(formatid);
@ -36,9 +39,9 @@ function Ladder(formatid) {
Ladder.prototype.load = function () {
// ladderCaches[formatid]
if (this.formatid in ladderCaches) {
var cachedLadder = ladderCaches[this.formatid];
let cachedLadder = ladderCaches[this.formatid];
if (cachedLadder.then) {
var self = this;
let self = this;
return cachedLadder.then(function (ladder) {
self.loadedLadder = ladder;
return ladder;
@ -47,7 +50,7 @@ Ladder.prototype.load = function () {
return Promise.resolve(this.loadedLadder = cachedLadder);
}
}
var self = this;
let self = this;
return (ladderCaches[this.formatid] = new Promise(function (resolve, reject) {
fs.readFile('config/ladders/' + self.formatid + '.tsv', function (err, data) {
if (err) {
@ -56,12 +59,12 @@ Ladder.prototype.load = function () {
resolve(self.loadedLadder);
return;
}
var ladder = [];
var dataLines = ('' + data).split('\n');
for (var i = 1; i < dataLines.length; i++) {
var line = dataLines[i].trim();
let ladder = [];
let dataLines = ('' + data).split('\n');
for (let i = 1; i < dataLines.length; i++) {
let line = dataLines[i].trim();
if (!line) continue;
var row = line.split('\t');
let row = line.split('\t');
ladder.push([toId(row[1]), Number(row[0]), row[1], Number(row[2]), Number(row[3]), Number(row[4]), row[5]]);
}
self.loadedLadder = ladderCaches[self.formatid] = ladder;
@ -75,7 +78,7 @@ Ladder.prototype.save = function () {
if (this.saving) return;
this.saving = true;
if (!this.loadedLadder) {
var self = this;
let self = this;
this.ladder.then(function () {
self.save();
});
@ -85,10 +88,10 @@ Ladder.prototype.save = function () {
this.saving = false;
return;
}
var stream = fs.createWriteStream('config/ladders/' + this.formatid + '.tsv');
let stream = fs.createWriteStream('config/ladders/' + this.formatid + '.tsv');
stream.write('Elo\tUsername\tW\tL\tT\tLast update\r\n');
for (var i = 0; i < this.loadedLadder.length; i++) {
var row = this.loadedLadder[i];
for (let i = 0; i < this.loadedLadder.length; i++) {
let row = this.loadedLadder[i];
stream.write(row.slice(1).join('\t') + '\r\n');
}
stream.end();
@ -96,12 +99,12 @@ Ladder.prototype.save = function () {
};
Ladder.prototype.indexOfUser = function (username, createIfNeeded) {
var userid = toId(username);
for (var i = 0; i < this.loadedLadder.length; i++) {
let userid = toId(username);
for (let i = 0; i < this.loadedLadder.length; i++) {
if (this.loadedLadder[i][0] === userid) return i;
}
if (createIfNeeded) {
var index = this.loadedLadder.length;
let index = this.loadedLadder.length;
this.loadedLadder.push([userid, 1000, username, 0, 0, 0]);
return index;
}
@ -109,14 +112,14 @@ Ladder.prototype.indexOfUser = function (username, createIfNeeded) {
};
Ladder.prototype.getTop = function () {
var formatid = this.formatid;
var name = Tools.getFormat(formatid).name;
let formatid = this.formatid;
let name = Tools.getFormat(formatid).name;
return this.ladder.then(function (ladder) {
var buf = '<h3>' + name + ' Top 100</h3>';
let buf = '<h3>' + name + ' Top 100</h3>';
buf += '<table>';
buf += '<tr><th>' + ['', 'Username', '<abbr title="Elo rating">Elo</abbr>', 'W', 'L', 'T'].join('</th><th>') + '</th></tr>';
for (var i = 0; i < ladder.length; i++) {
var row = ladder[i];
for (let i = 0; i < ladder.length; i++) {
let row = ladder[i];
buf += '<tr><td>' + [
i + 1, row[2], '<strong>' + Math.round(row[1]) + '</strong>', row[3], row[4], row[5]
].join('</td><td>') + '</td></tr>';
@ -126,28 +129,28 @@ Ladder.prototype.getTop = function () {
};
Ladder.prototype.getRating = function (userid) {
var formatid = this.formatid;
var user = Users.getExact(userid);
let formatid = this.formatid;
let user = Users.getExact(userid);
if (user && user.mmrCache[formatid]) {
return Promise.resolve(user.mmrCache[formatid]);
}
var self = this;
let self = this;
return this.ladder.then(function () {
if (user.userid !== userid) return;
var index = self.indexOfUser(userid);
let index = self.indexOfUser(userid);
if (index < 0) return (user.mmrCache[formatid] = 1000);
return (user.mmrCache[formatid] = self.loadedLadder[index][1]);
});
};
Ladder.prototype.updateRow = function (row, score, foeElo) {
var elo = row[1];
let elo = row[1];
// The K factor determines how much your Elo changes when you win or
// lose games. Larger K means more change.
// In the "original" Elo, K is constant, but it's common for K to
// get smaller as your rating goes up
var K = 50;
let K = 50;
// dynamic K-scaling (optional)
if (elo < 1200) {
@ -163,7 +166,7 @@ Ladder.prototype.updateRow = function (row, score, foeElo) {
}
// main Elo formula
var E = 1 / (1 + Math.pow(10, (foeElo - elo) / 400));
let E = 1 / (1 + Math.pow(10, (foeElo - elo) / 400));
elo += K * (score - E);
if (elo < 1000) elo = 1000;
@ -180,22 +183,22 @@ Ladder.prototype.updateRow = function (row, score, foeElo) {
};
Ladder.prototype.updateRating = function (p1name, p2name, p1score, room) {
var formatid = this.formatid;
var self = this;
let formatid = this.formatid;
let self = this;
this.ladder.then(function () {
if (!room.battle) {
console.log('room expired before ladder update was received');
return;
}
var p1newElo, p2newElo;
let p1newElo, p2newElo;
try {
var p1id = toId(p1name);
var p1index = self.indexOfUser(p1name, true);
var p1elo = self.loadedLadder[p1index][1];
let p1id = toId(p1name);
let p1index = self.indexOfUser(p1name, true);
let p1elo = self.loadedLadder[p1index][1];
var p2id = toId(p2name);
var p2index = self.indexOfUser(p2name, true);
var p2elo = self.loadedLadder[p2index][1];
let p2id = toId(p2name);
let p2index = self.indexOfUser(p2name, true);
let p2elo = self.loadedLadder[p2index][1];
self.updateRow(self.loadedLadder[p1index], p1score, p2elo);
self.updateRow(self.loadedLadder[p2index], 1 - p1score, p1elo);
@ -206,12 +209,12 @@ Ladder.prototype.updateRating = function (p1name, p2name, p1score, room) {
// console.log('L: ' + self.loadedLadder.map(r => ''+Math.round(r[1])+' '+r[2]).join('\n'));
// move p1 to its new location
var newIndex = p1index;
let newIndex = p1index;
while (newIndex > 0 && self.loadedLadder[newIndex - 1][1] <= p1newElo) newIndex--;
while (newIndex === p1index || (self.loadedLadder[newIndex] && self.loadedLadder[newIndex][1] > p1newElo)) newIndex++;
// console.log('ni='+newIndex+', p1i='+p1index);
if (newIndex !== p1index && newIndex !== p1index + 1) {
var row = self.loadedLadder.splice(p1index, 1)[0];
let row = self.loadedLadder.splice(p1index, 1)[0];
// adjust for removed row
if (newIndex > p1index) newIndex--;
if (p2index > p1index) p2index--;
@ -227,14 +230,14 @@ Ladder.prototype.updateRating = function (p1name, p2name, p1score, room) {
while (newIndex === p2index || (self.loadedLadder[newIndex] && self.loadedLadder[newIndex][1] > p2newElo)) newIndex++;
// console.log('ni='+newIndex+', p2i='+p2index);
if (newIndex !== p2index && newIndex !== p2index + 1) {
var row = self.loadedLadder.splice(p2index, 1)[0];
let row = self.loadedLadder.splice(p2index, 1)[0];
// adjust for removed row
if (newIndex > p2index) newIndex--;
self.loadedLadder.splice(newIndex, 0, row);
}
var reasons = '' + (Math.round(p1newElo) - Math.round(p1elo)) + ' for ' + (p1score > 0.9 ? 'winning' : (p1score < 0.1 ? 'losing' : 'tying'));
let reasons = '' + (Math.round(p1newElo) - Math.round(p1elo)) + ' for ' + (p1score > 0.9 ? 'winning' : (p1score < 0.1 ? 'losing' : 'tying'));
if (reasons.charAt(0) !== '-') reasons = '+' + reasons;
room.addRaw(Tools.escapeHTML(p1name) + '\'s rating: ' + Math.round(p1elo) + ' &rarr; <strong>' + Math.round(p1newElo) + '</strong><br />(' + reasons + ')');
@ -242,9 +245,9 @@ Ladder.prototype.updateRating = function (p1name, p2name, p1score, room) {
if (reasons.charAt(0) !== '-') reasons = '+' + reasons;
room.addRaw(Tools.escapeHTML(p2name) + '\'s rating: ' + Math.round(p2elo) + ' &rarr; <strong>' + Math.round(p2newElo) + '</strong><br />(' + reasons + ')');
var p1 = Users.getExact(p1name);
let p1 = Users.getExact(p1name);
if (p1) p1.mmrCache[formatid] = +p1newElo;
var p2 = Users.getExact(p2name);
let p2 = Users.getExact(p2name);
if (p2) p2.mmrCache[formatid] = +p2newElo;
self.save();
room.update();

View File

@ -7,14 +7,16 @@
* @license MIT license
*/
'use strict';
const LOGIN_SERVER_TIMEOUT = 15000;
const LOGIN_SERVER_BATCH_TIME = 1000;
var http = require("http");
var url = require('url');
const http = require("http");
const url = require('url');
/* global LoginServer: true */
var LoginServer = module.exports = (function () {
let LoginServer = module.exports = (function () {
function LoginServer(uri) {
console.log('Creating LoginServer object for ' + uri + '...');
this.uri = uri;
@ -34,8 +36,8 @@ var LoginServer = module.exports = (function () {
LoginServer.prototype.lastRequest = 0;
LoginServer.prototype.openRequests = 0;
var getLoginServer = function (action) {
var uri;
let getLoginServer = function (action) {
let uri;
if (Config.loginservers) {
uri = Config.loginservers[action] || Config.loginservers[null];
} else {
@ -53,7 +55,7 @@ var LoginServer = module.exports = (function () {
LoginServer.request = function (action, data, callback) {
return getLoginServer(action).request(action, data, callback);
};
var TimeoutError = LoginServer.TimeoutError = function (message) {
let TimeoutError = LoginServer.TimeoutError = function (message) {
Error.captureStackTrace(this, TimeoutError);
this.name = "TimeoutError";
this.message = message || "";
@ -65,9 +67,9 @@ var LoginServer = module.exports = (function () {
return this.name + ": " + this.message;
};
var parseJSON = function (json) {
let parseJSON = function (json) {
if (json[0] === ']') json = json.substr(1);
var data = {error: null};
let data = {error: null};
try {
data.json = JSON.parse(json);
} catch (err) {
@ -86,14 +88,14 @@ var LoginServer = module.exports = (function () {
return;
}
this.openRequests++;
var dataString = '';
let dataString = '';
if (data) {
for (var i in data) {
for (let i in data) {
dataString += '&' + i + '=' + encodeURIComponent('' + data[i]);
}
}
var req = http.get(url.parse(this.uri + 'action.php?act=' + action + '&serverid=' + Config.serverid + '&servertoken=' + encodeURIComponent(Config.servertoken) + '&nocache=' + new Date().getTime() + dataString), function (res) {
var buffer = '';
let req = http.get(url.parse(this.uri + 'action.php?act=' + action + '&serverid=' + Config.serverid + '&servertoken=' + encodeURIComponent(Config.servertoken) + '&nocache=' + new Date().getTime() + dataString), function (res) {
let buffer = '';
res.setEncoding('utf8');
res.on('data', function (chunk) {
@ -101,7 +103,7 @@ var LoginServer = module.exports = (function () {
});
res.on('end', function () {
var data = parseJSON(buffer).json;
let data = parseJSON(buffer).json;
setImmediate(callback, data, res.statusCode);
this.openRequests--;
});
@ -141,36 +143,36 @@ var LoginServer = module.exports = (function () {
};
LoginServer.prototype.makeRequests = function () {
this.requestTimer = null;
var self = this;
var requests = this.requestQueue;
let self = this;
let requests = this.requestQueue;
this.requestQueue = [];
if (!requests.length) return;
var requestCallbacks = [];
for (var i = 0, len = requests.length; i < len; i++) {
var request = requests[i];
let requestCallbacks = [];
for (let i = 0, len = requests.length; i < len; i++) {
let request = requests[i];
requestCallbacks[i] = request.callback;
delete request.callback;
}
this.requestStart(requests.length);
var postData = 'serverid=' + Config.serverid + '&servertoken=' + encodeURIComponent(Config.servertoken) + '&nocache=' + new Date().getTime() + '&json=' + encodeURIComponent(JSON.stringify(requests)) + '\n';
var requestOptions = url.parse(this.uri + 'action.php');
let postData = 'serverid=' + Config.serverid + '&servertoken=' + encodeURIComponent(Config.servertoken) + '&nocache=' + new Date().getTime() + '&json=' + encodeURIComponent(JSON.stringify(requests)) + '\n';
let requestOptions = url.parse(this.uri + 'action.php');
requestOptions.method = 'post';
requestOptions.headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
};
var req = null;
var onReqError = function onReqError(error) {
let req = null;
let onReqError = function onReqError(error) {
if (self.requestTimeoutTimer) {
clearTimeout(self.requestTimeoutTimer);
self.requestTimeoutTimer = null;
}
req.abort();
for (var i = 0, len = requestCallbacks.length; i < len; i++) {
for (let i = 0, len = requestCallbacks.length; i < len; i++) {
setImmediate(requestCallbacks[i], null, null, error);
}
self.requestEnd();
@ -181,21 +183,21 @@ var LoginServer = module.exports = (function () {
clearTimeout(self.requestTimeoutTimer);
self.requestTimeoutTimer = null;
}
var buffer = '';
let buffer = '';
res.setEncoding('utf8');
res.on('data', function onData(chunk) {
buffer += chunk;
});
var endReq = function endRequest() {
let endReq = function endRequest() {
if (self.requestTimeoutTimer) {
clearTimeout(self.requestTimeoutTimer);
self.requestTimeoutTimer = null;
}
//console.log('RESPONSE: ' + buffer);
var data = parseJSON(buffer).json;
for (var i = 0, len = requestCallbacks.length; i < len; i++) {
let data = parseJSON(buffer).json;
for (let i = 0, len = requestCallbacks.length; i < len; i++) {
if (data) {
setImmediate(requestCallbacks[i], data[i], res.statusCode);
} else {

View File

@ -1,6 +1,8 @@
'use strict';
exports.BattleScripts = {
init: function () {
for (var i in this.data.Pokedex) {
for (let i in this.data.Pokedex) {
this.modData('Pokedex', i).baseStats = {hp:100, atk:100, def:100, spa:100, spd:100, spe:100};
}
}

View File

@ -2,6 +2,9 @@
* A lot of Gen 1 moves have to be updated due to different mechanics.
* Some moves have had major changes, such as Bite's typing.
*/
'use strict';
exports.BattleMovedex = {
acid: {
inherit: true,
@ -42,7 +45,7 @@ exports.BattleMovedex = {
},
onHit: function (target, source, move) {
if (source && source !== target && move.category !== 'Physical' && move.category !== 'Special') {
var damage = this.effectData.totalDamage;
let damage = this.effectData.totalDamage;
this.effectData.totalDamage += damage;
this.effectData.lastDamage = damage;
this.effectData.sourcePosition = source.position;
@ -82,7 +85,7 @@ exports.BattleMovedex = {
return false;
}
this.add('-end', pokemon, 'Bide');
var target = this.effectData.sourceSide.active[this.effectData.sourcePosition];
let target = this.effectData.sourceSide.active[this.effectData.sourcePosition];
this.moveHit(target, pokemon, 'bide', {damage: this.effectData.totalDamage * 2});
return false;
}
@ -93,8 +96,8 @@ exports.BattleMovedex = {
if (!pokemon.hasMove('bide')) {
return;
}
var moves = pokemon.moveset;
for (var i = 0; i < moves.length; i++) {
let moves = pokemon.moveset;
for (let i = 0; i < moves.length; i++) {
if (moves[i].id !== 'bide') {
pokemon.disableMove(moves[i].id);
}
@ -180,14 +183,14 @@ exports.BattleMovedex = {
noCopy: true,
onStart: function (target, source) {
this.effectData.typesData = [];
for (var i = 0, l = target.typesData.length; i < l; i++) {
for (let i = 0, l = target.typesData.length; i < l; i++) {
this.effectData.typesData.push(Object.clone(target.typesData[i]));
}
this.add('-start', source, 'typechange', target.getTypes(true).join(', '), '[from] move: Conversion', '[of] ' + target);
},
onRestart: function (target, source) {
this.effectData.typesData = [];
for (var i = 0, l = target.typesData.length; i < l; i++) {
for (let i = 0, l = target.typesData.length; i < l; i++) {
this.effectData.typesData.push(Object.clone(target.typesData[i]));
}
this.add('-start', source, 'typechange', target.getTypes(true).join(', '), '[from] move: Conversion', '[of] ' + target);
@ -206,7 +209,7 @@ exports.BattleMovedex = {
// It will fail if the last move selected by the opponent has base power 0 or is not Normal or Fighting Type.
// If both are true, counter will deal twice the last damage dealt in battle, no matter what was the move.
// That means that, if opponent switches, counter will use last counter damage * 2.
var lastUsedMove = this.getMove(target.side.lastMove);
let lastUsedMove = this.getMove(target.side.lastMove);
if (lastUsedMove && lastUsedMove.basePower > 0 && lastUsedMove.type in {'Normal': 1, 'Fighting': 1} && target.battle.lastDamage > 0) {
return 2 * target.battle.lastDamage;
}
@ -245,15 +248,15 @@ exports.BattleMovedex = {
effect: {
duration: 4,
durationCallback: function (target, source, effect) {
var duration = this.random(1, 7);
let duration = this.random(1, 7);
return duration;
},
onStart: function (pokemon) {
if (!this.willMove(pokemon)) {
this.effectData.duration++;
}
var moves = pokemon.moves;
var move = this.getMove(moves[this.random(moves.length)]);
let moves = pokemon.moves;
let move = this.getMove(moves[this.random(moves.length)]);
this.add('-start', pokemon, 'Disable', move.name);
this.effectData.move = move.id;
return;
@ -269,8 +272,8 @@ exports.BattleMovedex = {
}
},
onDisableMove: function (pokemon) {
var moves = pokemon.moveset;
for (var i = 0; i < moves.length; i++) {
let moves = pokemon.moveset;
for (let i = 0; i < moves.length; i++) {
if (moves[i].id === this.effectData.move) {
pokemon.disableMove(moves[i].id);
}
@ -392,9 +395,9 @@ exports.BattleMovedex = {
shortDesc: "Eliminates all stat changes and status.",
onHit: function (target, source) {
this.add('-clearallboost');
for (var i = 0; i < this.sides.length; i++) {
for (var j = 0; j < this.sides[i].active.length; j++) {
var pokemon = this.sides[i].active[j];
for (let i = 0; i < this.sides.length; i++) {
for (let j = 0; j < this.sides[i].active.length; j++) {
let pokemon = this.sides[i].active[j];
pokemon.clearBoosts();
if (pokemon !== source) {
@ -404,9 +407,9 @@ exports.BattleMovedex = {
if (pokemon.status === 'tox') {
pokemon.setStatus('psn');
}
var volatiles = Object.keys(pokemon.volatiles);
for (var n = 0; n < volatiles.length; n++) {
var id = volatiles[n];
let volatiles = Object.keys(pokemon.volatiles);
for (let n = 0; n < volatiles.length; n++) {
let id = volatiles[n];
if (id === 'residualdmg') {
pokemon.volatiles[id].counter = 0;
} else {
@ -456,19 +459,19 @@ exports.BattleMovedex = {
},
onAfterMoveSelfPriority: 1,
onAfterMoveSelf: function (pokemon) {
var leecher = pokemon.side.foe.active[pokemon.volatiles['leechseed'].sourcePosition];
let leecher = pokemon.side.foe.active[pokemon.volatiles['leechseed'].sourcePosition];
if (!leecher || leecher.fainted || leecher.hp <= 0) {
this.debug('Nothing to leech into');
return;
}
// We check if leeched Pokémon has Toxic to increase leeched damage.
var toxicCounter = 1;
let toxicCounter = 1;
if (pokemon.volatiles['residualdmg']) {
pokemon.volatiles['residualdmg'].counter++;
toxicCounter = pokemon.volatiles['residualdmg'].counter;
}
var toLeech = this.clampIntRange(Math.floor(pokemon.maxhp / 16), 1) * toxicCounter;
var damage = this.damage(toLeech, pokemon, leecher);
let toLeech = this.clampIntRange(Math.floor(pokemon.maxhp / 16), 1) * toxicCounter;
let damage = this.damage(toLeech, pokemon, leecher);
if (damage) this.heal(damage, leecher, pokemon);
}
}
@ -503,19 +506,19 @@ exports.BattleMovedex = {
metronome: {
inherit: true,
onHit: function (target) {
var moves = [];
for (var i in exports.BattleMovedex) {
var move = exports.BattleMovedex[i];
let moves = [];
for (let i in exports.BattleMovedex) {
let move = exports.BattleMovedex[i];
if (i !== move.id) continue;
if (move.isNonstandard) continue;
var noMetronome = {
let noMetronome = {
metronome:1, struggle:1
};
if (!noMetronome[move.id] && move.num <= 165) {
moves.push(move.id);
}
}
var move = '';
let move = '';
if (moves.length) move = moves[this.random(moves.length)];
if (!move) return false;
this.useMove(move, target);
@ -529,10 +532,10 @@ exports.BattleMovedex = {
desc: "This move is replaced by a random move on target's moveset. The copied move has the maximum PP for that move. Ignores a target's Substitute.",
shortDesc: "A random target's move replaces this one.",
onHit: function (target, source) {
var moveslot = source.moves.indexOf('mimic');
let moveslot = source.moves.indexOf('mimic');
if (moveslot < 0) return false;
var moves = target.moves;
var move = moves[this.random(moves.length)];
let moves = target.moves;
let move = moves[this.random(moves.length)];
if (!move) return false;
move = this.getMove(move);
source.moveset[moveslot] = {
@ -552,7 +555,7 @@ exports.BattleMovedex = {
mirrormove: {
inherit: true,
onHit: function (pokemon) {
var foe = pokemon.side.foe.active[0];
let foe = pokemon.side.foe.active[0];
if (!foe || !foe.lastMove || foe.lastMove === 'mirrormove') {
return false;
}
@ -788,7 +791,7 @@ exports.BattleMovedex = {
if (move.category === 'Status') {
// In gen 1 it only blocks:
// poison, confusion, secondary effect confusion, stat reducing moves and Leech Seed.
var SubBlocked = {
let SubBlocked = {
lockon:1, meanlook:1, mindreader:1, nightmare:1
};
if (move.status === 'psn' || move.status === 'tox' || (move.boosts && target !== source) || move.volatileStatus === 'confusion' || SubBlocked[move.id]) {
@ -797,7 +800,7 @@ exports.BattleMovedex = {
return;
}
if (move.volatileStatus && target === source) return;
var damage = this.getDamage(source, target, move);
let damage = this.getDamage(source, target, move);
if (!damage) return null;
damage = this.runEvent('SubDamage', target, source, move, damage);
if (!damage) return damage;

View File

@ -1,9 +1,11 @@
'use strict';
exports.BattleFormats = {
pokemon: {
effectType: 'Banlist',
onValidateSet: function (set, format) {
var template = this.getTemplate(set.species);
var problems = [];
let template = this.getTemplate(set.species);
let problems = [];
if (set.species === set.name) delete set.name;
if (template.gen > this.gen) {
@ -12,8 +14,8 @@ exports.BattleFormats = {
problems.push(set.species + ' is not a real Pokemon.');
}
if (set.moves) {
for (var i = 0; i < set.moves.length; i++) {
var move = this.getMove(set.moves[i]);
for (let i = 0; i < set.moves.length; i++) {
let move = this.getMove(set.moves[i]);
if (move.gen > this.gen) {
problems.push(move.name + ' does not exist in gen ' + this.gen + '.');
} else if (move.isNonstandard) {
@ -92,12 +94,12 @@ exports.BattleFormats = {
],
onValidateSet: function (set) {
// limit one of each move in Standard
var moves = [];
let moves = [];
if (set.moves) {
var hasMove = {};
for (var i = 0; i < set.moves.length; i++) {
var move = this.getMove(set.moves[i]);
var moveid = move.id;
let hasMove = {};
for (let i = 0; i < set.moves.length; i++) {
let move = this.getMove(set.moves[i]);
let moveid = move.id;
if (hasMove[moveid]) continue;
hasMove[moveid] = true;
moves.push(set.moves[i]);

View File

@ -1,3 +1,5 @@
'use strict';
/**
* Gen 1 mechanics are fairly different to those we know on current gen.
* Therefor we need to make a lot of changes to the battle engine for this game simulation.
@ -37,8 +39,8 @@ exports.BattleScripts = {
},
// In generation 1, boosting function increases the stored modified stat and checks for opponent's status.
boostBy: function (boost) {
var changed = false;
for (var i in boost) {
let changed = false;
for (let i in boost) {
this.boosts[i] += boost[i];
if (this.boosts[i] > 6) {
this.boosts[i] = 6;
@ -50,7 +52,7 @@ exports.BattleScripts = {
changed = true;
// Recalculate the modified stat
if (this.stats[i]) {
var stat = this.template.baseStats[i];
let stat = this.template.baseStats[i];
stat = Math.floor(Math.floor(2 * stat + this.set.ivs[i] + Math.floor(this.set.evs[i] / 4)) * this.level / 100 + 5);
this.modifiedStats[i] = this.stats[i] = Math.floor(stat);
if (this.boosts[i] >= 0) {
@ -94,7 +96,7 @@ exports.BattleScripts = {
}
}
pokemon.lastDamage = 0;
var lockedMove = this.runEvent('LockMove', pokemon);
let lockedMove = this.runEvent('LockMove', pokemon);
if (lockedMove === true) lockedMove = false;
if (!lockedMove && (!pokemon.volatiles['partialtrappinglock'] || pokemon.volatiles['partialtrappinglock'].locked !== target)) {
pokemon.deductPP(move, null, target);
@ -129,14 +131,14 @@ exports.BattleScripts = {
} else {
if (pokemon.volatiles['partialtrappinglock'].locked !== target && target !== pokemon) {
// The target switched, therefor, we must re-roll the duration, damage, and accuracy.
var duration = [2, 2, 2, 3, 3, 3, 4, 5][this.random(8)];
let duration = [2, 2, 2, 3, 3, 3, 4, 5][this.random(8)];
pokemon.volatiles['partialtrappinglock'].duration = duration;
pokemon.volatiles['partialtrappinglock'].locked = target;
// Duration reset thus partially trapped at 2 always.
target.volatiles['partiallytrapped'].duration = 2;
// We get the move position for the PP change.
var usedMovePos = -1;
for (var m in pokemon.moveset) {
let usedMovePos = -1;
for (let m in pokemon.moveset) {
if (pokemon.moveset[m].id === move.id) usedMovePos = m;
}
if (usedMovePos > -1 && pokemon.moveset[usedMovePos].pp === 0) {
@ -156,7 +158,7 @@ exports.BattleScripts = {
useMove: function (move, pokemon, target, sourceEffect) {
if (!sourceEffect && this.effect.id) sourceEffect = this.effect;
move = this.getMove(move);
var baseMove = move;
let baseMove = move;
move = this.getMoveCopy(move);
if (!target) target = this.resolveTarget(pokemon, move);
if (move.target === 'self') {
@ -178,8 +180,8 @@ exports.BattleScripts = {
}
if (!move) return false;
var attrs = '';
var missed = false;
let attrs = '';
let missed = false;
if (pokemon.fainted) {
// Removing screens upon faint.
pokemon.side.removeSideCondition('reflect');
@ -205,7 +207,7 @@ exports.BattleScripts = {
move.ignoreImmunity = (move.category === 'Status');
}
var damage = false;
let damage = false;
if (target.fainted) {
this.attrLastMove('[notarget]');
this.add('-notarget');
@ -236,9 +238,9 @@ exports.BattleScripts = {
// This function attempts a move hit and returns the attempt result before the actual hit happens.
// It deals with partial trapping weirdness and accuracy bugs as well.
tryMoveHit: function (target, pokemon, move, spreadHit) {
var boostTable = [1, 4 / 3, 5 / 3, 2, 7 / 3, 8 / 3, 3];
var doSelfDestruct = true;
var damage = 0;
let boostTable = [1, 4 / 3, 5 / 3, 2, 7 / 3, 8 / 3, 3];
let doSelfDestruct = true;
let damage = 0;
// First, check if the Pokémon is immune to this move.
if (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type] && !target.runImmunity(move.type, true)) {
@ -249,7 +251,7 @@ exports.BattleScripts = {
}
// Now, let's calculate the accuracy.
var accuracy = move.accuracy;
let accuracy = move.accuracy;
// Partial trapping moves: true accuracy while it lasts
if (move.volatileStatus === 'partiallytrapped' && pokemon.volatiles['partialtrappinglock'] && target === pokemon.volatiles['partialtrappinglock'].locked) {
@ -303,7 +305,7 @@ exports.BattleScripts = {
if (damage !== false) {
pokemon.lastDamage = 0;
if (move.multihit) {
var hits = move.multihit;
let hits = move.multihit;
if (hits.length) {
// Yes, it's hardcoded... meh
if (hits[0] === 2 && hits[1] === 5) {
@ -314,9 +316,9 @@ exports.BattleScripts = {
}
hits = Math.floor(hits);
// In gen 1, all the hits have the same damage for multihits move
var moveDamage = 0;
var firstDamage;
var i;
let moveDamage = 0;
let firstDamage;
let i;
for (i = 0; i < hits && target.hp && pokemon.hp; i++) {
if (i === 0) {
// First hit, we calculate
@ -370,11 +372,11 @@ exports.BattleScripts = {
// It deals with the actual move hit, as the name indicates, dealing damage and/or effects.
// This function also deals with the Gen 1 Substitute behaviour on the hitting process.
moveHit: function (target, pokemon, move, moveData, isSecondary, isSelf) {
var damage = 0;
let damage = 0;
move = this.getMoveCopy(move);
if (!isSecondary && !isSelf) this.setActiveMove(move, pokemon, target);
var hitResult = true;
let hitResult = true;
if (!moveData) moveData = move;
if (move.ignoreImmunity === undefined) {
@ -382,8 +384,8 @@ exports.BattleScripts = {
}
// We get the sub to the target to see if it existed
var targetSub = (target) ? target.volatiles['substitute'] : false;
var targetHadSub = (targetSub !== null && targetSub !== false && (typeof targetSub !== 'undefined'));
let targetSub = (target) ? target.volatiles['substitute'] : false;
let targetHadSub = (targetSub !== null && targetSub !== false && (typeof targetSub !== 'undefined'));
if (target) {
hitResult = this.singleEvent('TryHit', moveData, {}, target, pokemon, move);
@ -424,7 +426,7 @@ exports.BattleScripts = {
}
if (target) {
var didSomething = false;
let didSomething = false;
damage = this.getDamage(pokemon, target, moveData);
@ -476,7 +478,7 @@ exports.BattleScripts = {
}
}
if (moveData.heal && !target.fainted) {
var d = target.heal(Math.floor(target.maxhp * moveData.heal[0] / moveData.heal[1]));
let d = target.heal(Math.floor(target.maxhp * moveData.heal[0] / moveData.heal[1]));
if (!d) {
this.add('-fail', target);
return false;
@ -534,16 +536,16 @@ exports.BattleScripts = {
return false;
}
}
var targetHasSub = false;
let targetHasSub = false;
if (target) {
var targetSub = target.getVolatile('substitute');
let targetSub = target.getVolatile('substitute');
if (targetSub !== null) {
targetHasSub = (targetSub.hp > 0);
}
}
// Here's where self effects are applied.
var doSelf = (targetHadSub && targetHasSub) || !targetHadSub;
let doSelf = (targetHadSub && targetHasSub) || !targetHadSub;
if (moveData.self && (doSelf || moveData.self.volatileStatus === 'partialtrappinglock')) {
this.moveHit(pokemon, pokemon, move, moveData.self, isSecondary, true);
}
@ -555,13 +557,13 @@ exports.BattleScripts = {
// Apply move secondaries.
if (moveData.secondaries) {
for (var i = 0; i < moveData.secondaries.length; i++) {
for (let i = 0; i < moveData.secondaries.length; i++) {
// We check here whether to negate the probable secondary status if it's para, burn, or freeze.
// In the game, this is checked and if true, the random number generator is not called.
// That means that a move that does not share the type of the target can status it.
// If a move that was not fire-type would exist on Gen 1, it could burn a Pokémon.
if (!(moveData.secondaries[i].status && moveData.secondaries[i].status in {'par':1, 'brn':1, 'frz':1} && target && target.hasType(move.type))) {
var effectChance = Math.floor(moveData.secondaries[i].chance * 255 / 100);
let effectChance = Math.floor(moveData.secondaries[i].chance * 255 / 100);
if (typeof moveData.secondaries[i].chance === 'undefined' || this.random(256) < effectChance) {
this.moveHit(target, pokemon, move, moveData.secondaries[i], true, isSelf);
}
@ -585,11 +587,11 @@ exports.BattleScripts = {
if (!target || !target.hp) return 0;
effect = this.getEffect(effect);
boost = this.runEvent('Boost', target, source, effect, Object.clone(boost));
for (var i in boost) {
var currentBoost = {};
for (let i in boost) {
let currentBoost = {};
currentBoost[i] = boost[i];
if (boost[i] !== 0 && target.boostBy(currentBoost)) {
var msg = '-boost';
let msg = '-boost';
if (boost[i] < 0) {
msg = '-unboost';
boost[i] = -boost[i];
@ -644,7 +646,7 @@ exports.BattleScripts = {
if (!(effect.id in {'recoil':1, 'drain':1}) && effect.effectType !== 'Status') target.battle.lastDamage = damage;
damage = target.damage(damage, source, effect);
if (source) source.lastDamage = damage;
var name = effect.fullname;
let name = effect.fullname;
if (name === 'tox') name = 'psn';
switch (effect.id) {
case 'partiallytrapped':
@ -772,10 +774,10 @@ exports.BattleScripts = {
if (!move.defensiveCategory) move.defensiveCategory = move.category;
// '???' is typeless damage: used for Struggle and Confusion etc
if (!move.type) move.type = '???';
var type = move.type;
let type = move.type;
// We get the base power and apply basePowerCallback if necessary.
var basePower = move.basePower;
let basePower = move.basePower;
if (move.basePowerCallback) {
basePower = move.basePowerCallback.call(this, pokemon, target, move);
}
@ -792,7 +794,7 @@ exports.BattleScripts = {
if (!move.crit) {
// In gen 1, the critical chance is based on speed.
// First, we get the base speed, divide it by 2 and floor it. This is our current crit chance.
var critChance = Math.floor(pokemon.template.baseStats['spe'] / 2);
let critChance = Math.floor(pokemon.template.baseStats['spe'] / 2);
// Now we check for focus energy volatile.
if (pokemon.volatiles['focusenergy']) {
@ -831,15 +833,15 @@ exports.BattleScripts = {
basePower = this.clampIntRange(basePower, 1);
// We now check attacker's and defender's stats.
var level = pokemon.level;
var attacker = pokemon;
var defender = target;
let level = pokemon.level;
let attacker = pokemon;
let defender = target;
if (move.useTargetOffensive) attacker = target;
if (move.useSourceDefensive) defender = pokemon;
var atkType = (move.category === 'Physical') ? 'atk' : 'spa';
var defType = (move.defensiveCategory === 'Physical') ? 'def' : 'spd';
var attack = attacker.getStat(atkType);
var defense = defender.getStat(defType);
let atkType = (move.category === 'Physical') ? 'atk' : 'spa';
let defType = (move.defensiveCategory === 'Physical') ? 'def' : 'spd';
let attack = attacker.getStat(atkType);
let defense = defender.getStat(defType);
// In gen 1, screen effect is applied here.
if ((defType === 'def' && defender.volatiles['reflect']) || (defType === 'spd' && defender.volatiles['lightscreen'])) {
this.debug('Screen doubling (Sp)Def');
@ -881,7 +883,7 @@ exports.BattleScripts = {
// Let's go with the calculation now that we have what we need.
// We do it step by step just like the game does.
var damage = level * 2;
let damage = level * 2;
damage = Math.floor(damage / 5);
damage += 2;
damage *= basePower;
@ -897,7 +899,7 @@ exports.BattleScripts = {
// Type effectiveness.
// The order here is not correct, must change to check the move versus each type.
var totalTypeMod = this.getEffectiveness(type, target);
let totalTypeMod = this.getEffectiveness(type, target);
// Super effective attack
if (totalTypeMod > 0) {
if (!suppressMessages) this.add('-supereffective', target);
@ -936,25 +938,25 @@ exports.BattleScripts = {
// This is random teams making for gen 1.
// Challenge Cup or CC teams are basically fully random teams.
randomCCTeam: function (side) {
var teamdexno = [];
var team = [];
let teamdexno = [];
let team = [];
var hasDexNumber = {};
var formes = [[], [], [], [], [], []];
let hasDexNumber = {};
let formes = [[], [], [], [], [], []];
// Pick six random Pokémon, no repeats.
var num;
for (var i = 0; i < 6; i++) {
let num;
for (let i = 0; i < 6; i++) {
do {
num = this.random(151) + 1;
} while (num in hasDexNumber);
hasDexNumber[num] = i;
}
var formeCounter = 0;
for (var id in this.data.Pokedex) {
let formeCounter = 0;
for (let id in this.data.Pokedex) {
if (!(this.data.Pokedex[id].num in hasDexNumber)) continue;
var template = this.getTemplate(id);
let template = this.getTemplate(id);
if (!template.learnset || template.forme) continue;
formes[hasDexNumber[template.num]].push(template.species);
if (++formeCounter >= 6) {
@ -963,24 +965,24 @@ exports.BattleScripts = {
}
}
for (var i = 0; i < 6; i++) {
for (let i = 0; i < 6; i++) {
// Choose forme.
var poke = formes[i][this.random(formes[i].length)];
var template = this.getTemplate(poke);
let poke = formes[i][this.random(formes[i].length)];
let template = this.getTemplate(poke);
// Level balance: calculate directly from stats rather than using some silly lookup table.
var mbstmin = 1307;
var stats = template.baseStats;
let mbstmin = 1307;
let stats = template.baseStats;
// Modified base stat total assumes 15 DVs, 255 EVs in every stat
var mbst = (stats["hp"] * 2 + 30 + 63 + 100) + 10;
let mbst = (stats["hp"] * 2 + 30 + 63 + 100) + 10;
mbst += (stats["atk"] * 2 + 30 + 63 + 100) + 5;
mbst += (stats["def"] * 2 + 30 + 63 + 100) + 5;
mbst += (stats["spa"] * 2 + 30 + 63 + 100) + 5;
mbst += (stats["spd"] * 2 + 30 + 63 + 100) + 5;
mbst += (stats["spe"] * 2 + 30 + 63 + 100) + 5;
var level = Math.floor(100 * mbstmin / mbst); // Initial level guess will underestimate
let level = Math.floor(100 * mbstmin / mbst); // Initial level guess will underestimate
while (level < 100) {
mbst = Math.floor((stats["hp"] * 2 + 30 + 63 + 100) * level / 100 + 10);
@ -995,7 +997,7 @@ exports.BattleScripts = {
}
// Random DVs.
var ivs = {
let ivs = {
hp: this.random(30),
atk: this.random(30),
def: this.random(30),
@ -1005,13 +1007,13 @@ exports.BattleScripts = {
};
// Maxed EVs.
var evs = {hp: 255, atk: 255, def: 255, spa: 255, spd: 255, spe: 255};
let evs = {hp: 255, atk: 255, def: 255, spa: 255, spd: 255, spe: 255};
// Four random unique moves from movepool. don't worry about "attacking" or "viable".
// Since Gens 1 and 2 learnsets are shared, we need to weed out Gen 2 moves.
var moves;
var pool = [];
for (var move in template.learnset) {
let moves;
let pool = [];
for (let move in template.learnset) {
if (this.getMove(move).gen === 1) pool.push(move);
}
if (pool.length <= 4) {
@ -1039,35 +1041,35 @@ exports.BattleScripts = {
// Random team generation for Gen 1 Random Battles.
randomTeam: function (side) {
// Get what we need ready.
var pokemonLeft = 0;
var pokemon = [];
let pokemonLeft = 0;
let pokemon = [];
var handicapMons = {'magikarp':1, 'weedle':1, 'kakuna':1, 'caterpie':1, 'metapod':1, 'ditto':1};
var nuTiers = {'UU':1, 'BL':1, 'NFE':1, 'LC':1};
var uuTiers = {'NFE':1, 'UU':1, 'BL':1};
let handicapMons = {'magikarp':1, 'weedle':1, 'kakuna':1, 'caterpie':1, 'metapod':1, 'ditto':1};
let nuTiers = {'UU':1, 'BL':1, 'NFE':1, 'LC':1};
let uuTiers = {'NFE':1, 'UU':1, 'BL':1};
var n = 1;
var pokemonPool = [];
for (var id in this.data.FormatsData) {
let n = 1;
let pokemonPool = [];
for (let id in this.data.FormatsData) {
// FIXME: Not ES-compliant
if (n++ > 151 || !this.data.FormatsData[id].randomBattleMoves) continue;
pokemonPool.push(id);
}
// Now let's store what we are getting.
var typeCount = {};
var weaknessCount = {'Electric':0, 'Psychic':0, 'Water':0, 'Ice':0};
var uberCount = 0;
var nuCount = 0;
var hasShitmon = false;
let typeCount = {};
let weaknessCount = {'Electric':0, 'Psychic':0, 'Water':0, 'Ice':0};
let uberCount = 0;
let nuCount = 0;
let hasShitmon = false;
while (pokemonPool.length && pokemonLeft < 6) {
var template = this.getTemplate(this.sampleNoReplace(pokemonPool));
let template = this.getTemplate(this.sampleNoReplace(pokemonPool));
if (!template.exists) continue;
// Bias the tiers so you get less shitmons and only one of the two Ubers.
// If you have a shitmon, you're covered in OUs and Ubers if possible
var tier = template.tier;
let tier = template.tier;
switch (tier) {
case 'LC':
if (nuCount > 1 || hasShitmon) continue;
@ -1080,12 +1082,12 @@ exports.BattleScripts = {
if (uuTiers[tier] && (hasShitmon || (nuCount > 2 && this.random(2) >= 1))) continue;
}
var skip = false;
let skip = false;
// Limit 2 of any type as well. Diversity and minor weakness count.
// The second of a same type has halved chance of being added.
var types = template.types;
for (var t = 0; t < types.length; t++) {
let types = template.types;
for (let t = 0; t < types.length; t++) {
if (typeCount[types[t]] > 1 || (typeCount[types[t]] === 1 && this.random(2))) {
skip = true;
break;
@ -1095,9 +1097,9 @@ exports.BattleScripts = {
// We need a weakness count of spammable attacks to avoid being swept by those.
// Spammable attacks are: Thunderbolt, Psychic, Surf, Blizzard.
var pokemonWeaknesses = [];
for (var type in weaknessCount) {
var increaseCount = Tools.getImmunity(type, template) && Tools.getEffectiveness(type, template) > 0;
let pokemonWeaknesses = [];
for (let type in weaknessCount) {
let increaseCount = Tools.getImmunity(type, template) && Tools.getEffectiveness(type, template) > 0;
if (!increaseCount) continue;
if (weaknessCount[type] >= 2) {
skip = true;
@ -1109,14 +1111,14 @@ exports.BattleScripts = {
if (skip) continue;
// The set passes the limitations.
var set = this.randomSet(template, pokemon.length);
let set = this.randomSet(template, pokemon.length);
pokemon.push(set);
// Now let's increase the counters. First, the Pokémon left.
pokemonLeft++;
// Type counter.
for (var t = 0; t < types.length; t++) {
for (let t = 0; t < types.length; t++) {
if (typeCount[types[t]]) {
typeCount[types[t]]++;
} else {
@ -1125,7 +1127,7 @@ exports.BattleScripts = {
}
// Weakness counter.
for (var t = 0; t < pokemonWeaknesses.length; t++) {
for (let t = 0; t < pokemonWeaknesses.length; t++) {
weaknessCount[pokemonWeaknesses[t]]++;
}
@ -1148,21 +1150,21 @@ exports.BattleScripts = {
template = this.getTemplate(template);
if (!template.exists) template = this.getTemplate('pikachu'); // Because Gen 1.
var movePool = template.randomBattleMoves.slice();
var moves = [];
var hasType = {};
let movePool = template.randomBattleMoves.slice();
let moves = [];
let hasType = {};
hasType[template.types[0]] = true;
if (template.types[1]) hasType[template.types[1]] = true;
var hasMove = {};
var counter = {};
var setupType = '';
let hasMove = {};
let counter = {};
let setupType = '';
// Moves that boost Attack:
var PhysicalSetup = {
let PhysicalSetup = {
swordsdance:1, sharpen:1
};
// Moves which boost Special Attack:
var SpecialSetup = {
let SpecialSetup = {
amnesia:1, growth:1
};
@ -1173,7 +1175,7 @@ exports.BattleScripts = {
do {
// Choose next 4 moves from learnset/viable moves and add them to moves list:
while (moves.length < 4 && movePool.length) {
var moveid = this.sampleNoReplace(movePool);
let moveid = this.sampleNoReplace(movePool);
moves.push(moveid);
}
@ -1181,9 +1183,9 @@ exports.BattleScripts = {
if (movePool.length) {
hasMove = {};
counter = {Physical: 0, Special: 0, Status: 0, physicalsetup: 0, specialsetup: 0};
for (var k = 0; k < moves.length; k++) {
var move = this.getMove(moves[k]);
var moveid = move.id;
for (let k = 0; k < moves.length; k++) {
let move = this.getMove(moves[k]);
let moveid = move.id;
hasMove[moveid] = true;
if (!move.damage && !move.damageCallback) {
counter[move.category]++;
@ -1202,14 +1204,14 @@ exports.BattleScripts = {
setupType = 'Physical';
}
for (var k = 0; k < moves.length; k++) {
var moveid = moves[k];
for (let k = 0; k < moves.length; k++) {
let moveid = moves[k];
if (moveid === template.essentialMove) continue;
var move = this.getMove(moveid);
var rejected = false;
let move = this.getMove(moveid);
let rejected = false;
if (hasMove[moveid]) rejected = true;
if (!template.essentialMove || moveid !== template.essentialMove) {
var isSetup = false;
let isSetup = false;
switch (moveid) {
// bad after setup
@ -1326,7 +1328,7 @@ exports.BattleScripts = {
} // End of the check for more than 4 moves on moveset.
} while (moves.length < 4 && movePool.length);
var levelScale = {
let levelScale = {
LC: 96,
NFE: 90,
NU: 90,
@ -1335,12 +1337,12 @@ exports.BattleScripts = {
Uber: 74
};
// Really bad Pokemon and jokemons, MEWTWO, Pokémon with higher tier in Wrap metas.
var customScale = {
let customScale = {
Caterpie: 99, Kakuna: 99, Magikarp: 99, Metapod: 99, Weedle: 99,
Clefairy: 95, "Farfetch'd": 99, Jigglypuff: 99, Ditto: 99, Mewtwo: 70,
Dragonite: 85, Cloyster: 83, Staryu: 90
};
var level = levelScale[template.tier] || 90;
let level = levelScale[template.tier] || 90;
if (customScale[template.name]) level = customScale[template.name];
if (template.name === 'Mewtwo' && hasMove['amnesia']) level = 68;

View File

@ -7,6 +7,9 @@
* separated as volatile statuses that are applied on switch in, removed
* under certain conditions and re-applied under other conditions.
*/
'use strict';
exports.BattleStatuses = {
brn: {
effectType: 'Status',
@ -16,7 +19,7 @@ exports.BattleStatuses = {
},
onAfterMoveSelfPriority: 2,
onAfterMoveSelf: function (pokemon) {
var toxicCounter = 1;
let toxicCounter = 1;
if (pokemon.volatiles['residualdmg']) {
pokemon.volatiles['residualdmg'].counter++;
toxicCounter = pokemon.volatiles['residualdmg'].counter;
@ -99,7 +102,7 @@ exports.BattleStatuses = {
},
onAfterMoveSelfPriority: 2,
onAfterMoveSelf: function (pokemon) {
var toxicCounter = 1;
let toxicCounter = 1;
if (pokemon.volatiles['residualdmg']) {
pokemon.volatiles['residualdmg'].counter++;
toxicCounter = pokemon.volatiles['residualdmg'].counter;
@ -133,7 +136,7 @@ exports.BattleStatuses = {
confusion: {
// this is a volatile status
onStart: function (target, source, sourceEffect) {
var result = this.runEvent('TryConfusion');
let result = this.runEvent('TryConfusion');
if (!result) return result;
if (sourceEffect && sourceEffect.id === 'lockedmove') {
this.add('-start', target, 'confusion', '[silent]');
@ -154,7 +157,7 @@ exports.BattleStatuses = {
this.add('-activate', pokemon, 'confusion');
if (this.random(256) >= 128) {
// We check here to implement the substitute bug since otherwise we need to change directDamage to take target.
var damage = Math.floor(Math.floor(((Math.floor(2 * pokemon.level / 5) + 2) * pokemon.getStat('atk') * 40) / pokemon.getStat('def', false, false, true)) / 50) + 2;
let damage = Math.floor(Math.floor(((Math.floor(2 * pokemon.level / 5) + 2) * pokemon.getStat('atk') * 40) / pokemon.getStat('def', false, false, true)) / 50) + 2;
if (pokemon.volatiles['substitute']) {
// If there is Substitute, we check for opposing substitute.
if (target.volatiles['substitute']) {
@ -214,7 +217,7 @@ exports.BattleStatuses = {
},
partialtrappinglock: {
durationCallback: function () {
var duration = [2, 2, 2, 3, 3, 3, 4, 5][this.random(8)];
let duration = [2, 2, 2, 3, 3, 3, 4, 5][this.random(8)];
return duration;
},
onResidual: function (target) {
@ -229,8 +232,8 @@ exports.BattleStatuses = {
if (!pokemon.hasMove(this.effectData.move)) {
return;
}
var moves = pokemon.moveset;
for (var i = 0; i < moves.length; i++) {
let moves = pokemon.moveset;
for (let i = 0; i < moves.length; i++) {
if (moves[i].id !== this.effectData.move) {
moves[i].disabled = true;
}
@ -248,15 +251,15 @@ exports.BattleStatuses = {
// this is a side condition
onStart: function (side) {
this.effectData.positions = [];
for (var i = 0; i < side.active.length; i++) {
for (let i = 0; i < side.active.length; i++) {
this.effectData.positions[i] = null;
}
},
onResidualOrder: 3,
onResidual: function (side) {
var finished = true;
for (var i = 0; i < side.active.length; i++) {
var posData = this.effectData.positions[i];
let finished = true;
for (let i = 0; i < side.active.length; i++) {
let posData = this.effectData.positions[i];
if (!posData) continue;
posData.duration--;
@ -267,8 +270,8 @@ exports.BattleStatuses = {
}
// time's up; time to hit! :D
var target = side.foe.active[posData.targetPosition];
var move = this.getMove(posData.move);
let target = side.foe.active[posData.targetPosition];
let move = this.getMove(posData.move);
if (target.fainted) {
this.add('-hint', '' + move.name + ' did not hit because the target is fainted.');
this.effectData.positions[i] = null;
@ -302,7 +305,7 @@ exports.BattleStatuses = {
onStallMove: function () {
// this.effectData.counter should never be undefined here.
// However, just in case, use 1 if it is undefined.
var counter = this.effectData.counter || 1;
let counter = this.effectData.counter || 1;
if (counter >= 256) {
// 2^32 - special-cased because Battle.random(n) can't handle n > 2^16 - 1
return (this.random() * 4294967296 < 1);

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleItems = {
amuletcoin: {
id: "amuletcoin",
@ -55,13 +57,13 @@ exports.BattleItems = {
leppaberry: {
inherit: true,
onEat: function (pokemon) {
var move;
let move;
if (pokemon.volatiles['leppaberry']) {
move = pokemon.volatiles['leppaberry'].move;
pokemon.removeVolatile('leppaberry');
} else {
var pp = 99;
for (var i in pokemon.moveset) {
let pp = 99;
for (let i in pokemon.moveset) {
if (pokemon.moveset[i].pp < pp) {
move = pokemon.moveset[i];
pp = move.pp;

View File

@ -1,6 +1,9 @@
/**
* Gen 2 moves
*/
'use strict';
exports.BattleMovedex = {
aeroblast: {
inherit: true,
@ -69,8 +72,8 @@ exports.BattleMovedex = {
return this.random(3, 7);
},
onStart: function (target) {
var noEncore = {encore:1, metronome:1, mimic:1, mirrormove:1, sketch:1, sleeptalk:1, struggle:1, transform:1};
var moveIndex = target.moves.indexOf(target.lastMove);
let noEncore = {encore:1, metronome:1, mimic:1, mirrormove:1, sketch:1, sleeptalk:1, struggle:1, transform:1};
let moveIndex = target.moves.indexOf(target.lastMove);
if (!target.lastMove || noEncore[target.lastMove] || (target.moveset[moveIndex] && target.moveset[moveIndex].pp <= 0)) {
// it failed
this.add('-fail', target);
@ -101,7 +104,7 @@ exports.BattleMovedex = {
if (!this.effectData.move || !pokemon.hasMove(this.effectData.move)) {
return;
}
for (var i = 0; i < pokemon.moveset.length; i++) {
for (let i = 0; i < pokemon.moveset.length; i++) {
if (pokemon.moveset[i].id !== this.effectData.move) {
pokemon.disableMove(pokemon.moveset[i].id);
}
@ -148,7 +151,7 @@ exports.BattleMovedex = {
inherit: true,
onMoveFail: function (target, source, move) {
if (target.runImmunity('Fighting')) {
var damage = this.getDamage(source, target, move, true);
let damage = this.getDamage(source, target, move, true);
this.damage(this.clampIntRange(damage / 8, 1), source, source, 'highjumpkick');
}
}
@ -157,7 +160,7 @@ exports.BattleMovedex = {
inherit: true,
onMoveFail: function (target, source, move) {
if (target.runImmunity('Fighting')) {
var damage = this.getDamage(source, target, move, true);
let damage = this.getDamage(source, target, move, true);
this.damage(this.clampIntRange(damage / 8, 1), source, source, 'jumpkick');
}
}
@ -174,13 +177,13 @@ exports.BattleMovedex = {
this.add('-start', target, 'move: Leech Seed');
},
onAfterMoveSelf: function (pokemon) {
var leecher = pokemon.side.foe.active[pokemon.volatiles['leechseed'].sourcePosition];
let leecher = pokemon.side.foe.active[pokemon.volatiles['leechseed'].sourcePosition];
if (!leecher || leecher.fainted || leecher.hp <= 0) {
this.debug('Nothing to leech into');
return;
}
var toLeech = this.clampIntRange(pokemon.maxhp / 8, 1);
var damage = this.damage(toLeech, pokemon, leecher);
let toLeech = this.clampIntRange(pokemon.maxhp / 8, 1);
let damage = this.damage(toLeech, pokemon, leecher);
if (damage) {
this.heal(damage, leecher, pokemon);
}
@ -218,19 +221,19 @@ exports.BattleMovedex = {
metronome: {
inherit: true,
onHit: function (target) {
var moves = [];
for (var i in exports.BattleMovedex) {
var move = exports.BattleMovedex[i];
let moves = [];
for (let i in exports.BattleMovedex) {
let move = exports.BattleMovedex[i];
if (i !== move.id) continue;
if (move.isNonstandard) continue;
var noMetronome = {
let noMetronome = {
counter:1, destinybond:1, detect:1, endure:1, metronome:1, mimic:1, mirrorcoat:1, protect:1, sketch:1, sleeptalk:1, struggle:1, thief:1
};
if (!noMetronome[move.id] && move.num < 252) {
moves.push(move.id);
}
}
var move = '';
let move = '';
if (moves.length) move = moves[this.random(moves.length)];
if (!move) return false;
this.useMove(move, target);
@ -267,8 +270,8 @@ exports.BattleMovedex = {
mirrormove: {
inherit: true,
onHit: function (pokemon) {
var noMirror = {metronome: 1, mimic: 1, mirrormove: 1, sketch: 1, sleeptalk: 1, transform: 1};
var foe = pokemon.side.foe.active[0];
let noMirror = {metronome: 1, mimic: 1, mirrormove: 1, sketch: 1, sleeptalk: 1, transform: 1};
let foe = pokemon.side.foe.active[0];
if (!foe || !foe.lastMove || (!pokemon.activeTurns && !foe.moveThisTurn) || noMirror[foe.lastMove] || pokemon.moves.indexOf(foe.lastMove) >= 0) {
return false;
}
@ -383,7 +386,7 @@ exports.BattleMovedex = {
roar: {
inherit: true,
onTryHit: function () {
for (var i = 0; i < this.queue.length; i++) {
for (let i = 0; i < this.queue.length; i++) {
// Roar only works if it is the last action in a turn, including when it's called by Sleep Talk
if (this.queue[i].choice === 'move' || this.queue[i].choice === 'switch') return false;
}
@ -414,10 +417,10 @@ exports.BattleMovedex = {
sleeptalk: {
inherit: true,
onHit: function (pokemon) {
var moves = [];
for (var i = 0; i < pokemon.moveset.length; i++) {
var move = pokemon.moveset[i].id;
var NoSleepTalk = {
let moves = [];
for (let i = 0; i < pokemon.moveset.length; i++) {
let move = pokemon.moveset[i].id;
let NoSleepTalk = {
bide:1, dig:1, fly:1, metronome:1, mirrormove:1,
skullbash:1, skyattack:1, sleeptalk:1, solarbeam:1, razorwind:1
};
@ -425,7 +428,7 @@ exports.BattleMovedex = {
moves.push(move);
}
}
var move = '';
let move = '';
if (moves.length) move = moves[this.random(moves.length)];
if (!move) return false;
move.isSleepTalk = true;
@ -454,10 +457,10 @@ exports.BattleMovedex = {
}
},
onSwitchIn: function (pokemon) {
var side = pokemon.side;
let side = pokemon.side;
if (!pokemon.runImmunity('Ground')) return;
var damageAmounts = [0, 3];
var damage = this.damage(damageAmounts[this.effectData.layers] * pokemon.maxhp / 24);
let damageAmounts = [0, 3];
let damage = this.damage(damageAmounts[this.effectData.layers] * pokemon.maxhp / 24);
}
}
},
@ -485,7 +488,7 @@ exports.BattleMovedex = {
return null;
}
if (move.category === 'Status') {
var SubBlocked = {
let SubBlocked = {
leechseed:1, lockon:1, mindreader:1, nightmare:1, painsplit:1, sketch:1
};
if (move.id === 'swagger') {
@ -498,7 +501,7 @@ exports.BattleMovedex = {
}
return;
}
var damage = this.getDamage(source, target, move);
let damage = this.getDamage(source, target, move);
if (!damage) {
return null;
}
@ -567,7 +570,7 @@ exports.BattleMovedex = {
chance: 20,
onHit: function (target, source) {
if (!target.hasType('Normal')) {
var result = this.random(3);
let result = this.random(3);
if (result === 0) {
target.trySetStatus('brn', source);
} else if (result === 1) {
@ -582,7 +585,7 @@ exports.BattleMovedex = {
whirlwind: {
inherit: true,
onTryHit: function () {
for (var i = 0; i < this.queue.length; i++) {
for (let i = 0; i < this.queue.length; i++) {
// Whirlwind only works if it is the last action in a turn, including when it's called by Sleep Talk
if (this.queue[i].choice === 'move' || this.queue[i].choice === 'switch') return false;
}

View File

@ -1,9 +1,11 @@
'use strict';
exports.BattleFormats = {
pokemon: {
effectType: 'Banlist',
onValidateSet: function (set, format) {
var template = this.getTemplate(set.species);
var problems = [];
let template = this.getTemplate(set.species);
let problems = [];
if (set.species === set.name) delete set.name;
if (template.gen > this.gen) {
@ -11,10 +13,10 @@ exports.BattleFormats = {
} else if (template.isNonstandard) {
problems.push(set.species + ' is not a real Pokemon.');
}
var hasHP = false;
var hasSD = false;
let hasHP = false;
let hasSD = false;
if (set.item) {
var item = this.getItem(set.item);
let item = this.getItem(set.item);
if (item.gen > this.gen) {
problems.push(item.name + ' does not exist in gen ' + this.gen + '.');
} else if (item.isNonstandard) {
@ -22,8 +24,8 @@ exports.BattleFormats = {
}
}
if (set.moves) {
for (var i = 0; i < set.moves.length; i++) {
var move = this.getMove(set.moves[i]);
for (let i = 0; i < set.moves.length; i++) {
let move = this.getMove(set.moves[i]);
if (move.gen > this.gen) {
problems.push(move.name + ' does not exist in gen ' + this.gen + '.');
} else if (move.isNonstandard) {
@ -54,7 +56,7 @@ exports.BattleFormats = {
if (!set.ivs) {
set.ivs = {hp: 30, atk: 30, def: 30, spa: 30, spd: 30, spe: 30};
} else {
for (var iv in set.ivs) {
for (let iv in set.ivs) {
// Since Gen 2 has 0-15 DVs that increase 2 points, we only want pair numbers
if (set.ivs[iv] % 2 !== 0) set.ivs[iv]--;
// This shouldn't even be possible
@ -66,7 +68,7 @@ exports.BattleFormats = {
// Calculate all the IV oddness on gen 2.
// If you use Marowak with Thick Club, we'll be gentle enough to deal with your Attack DVs.
// This is only done because the gen 6 Teambuilder is confusing, using IVs and all.
var marowakClub = false;
let marowakClub = false;
if (toId(set.item) === 'thickclub' && set.species === 'Marowak' && hasSD) {
set.ivs.atk = 26;
marowakClub = true;
@ -130,12 +132,12 @@ exports.BattleFormats = {
],
onValidateSet: function (set) {
// limit one of each move in Standard
var moves = [];
let moves = [];
if (set.moves) {
var hasMove = {};
for (var i = 0; i < set.moves.length; i++) {
var move = this.getMove(set.moves[i]);
var moveid = move.id;
let hasMove = {};
for (let i = 0; i < set.moves.length; i++) {
let move = this.getMove(set.moves[i]);
let moveid = move.id;
if (hasMove[moveid]) continue;
hasMove[moveid] = true;
moves.push(set.moves[i]);

View File

@ -1,3 +1,5 @@
'use strict';
/**
* Gen 2 scripts.
*/
@ -11,24 +13,24 @@ exports.BattleScripts = {
if (statName === 'hp') return this.maxhp;
// base stat
var stat = this.stats[statName];
let stat = this.stats[statName];
// Stat boosts.
if (!unboosted) {
var boost = this.boosts[statName];
let boost = this.boosts[statName];
if (boost > 6) boost = 6;
if (boost < -6) boost = -6;
if (boost >= 0) {
var boostTable = [1, 1.5, 2, 2.5, 3, 3.5, 4];
let boostTable = [1, 1.5, 2, 2.5, 3, 3.5, 4];
stat = Math.floor(stat * boostTable[boost]);
} else {
var numerators = [100, 66, 50, 40, 33, 28, 25];
let numerators = [100, 66, 50, 40, 33, 28, 25];
stat = Math.floor(stat * numerators[-boost] / 100);
}
// On Gen 2 we check modifications here from moves and items
var statTable = {atk:'Atk', def:'Def', spa:'SpA', spd:'SpD', spe:'Spe'};
var statMod = 1;
let statTable = {atk:'Atk', def:'Def', spa:'SpA', spd:'SpD', spe:'Spe'};
let statMod = 1;
statMod = this.battle.runEvent('Modify' + statTable[statName], this, null, null, statMod);
stat = this.battle.modify(stat, statMod);
}
@ -57,7 +59,7 @@ exports.BattleScripts = {
// Battle scripts.
runMove: function (move, pokemon, target, sourceEffect) {
if (!sourceEffect && toId(move) !== 'struggle') {
var changedMove = this.runEvent('OverrideDecision', pokemon, target, move);
let changedMove = this.runEvent('OverrideDecision', pokemon, target, move);
if (changedMove && changedMove !== true) {
move = changedMove;
target = null;
@ -93,7 +95,7 @@ exports.BattleScripts = {
}
}
pokemon.lastDamage = 0;
var lockedMove = this.runEvent('LockMove', pokemon);
let lockedMove = this.runEvent('LockMove', pokemon);
if (lockedMove === true) lockedMove = false;
if (!lockedMove) {
if (!pokemon.deductPP(move, null, target) && (move.id !== 'struggle')) {
@ -108,11 +110,11 @@ exports.BattleScripts = {
if (!move.selfSwitch && target.hp > 0) this.runEvent('AfterMoveSelf', pokemon, target, move);
},
moveHit: function (target, pokemon, move, moveData, isSecondary, isSelf) {
var damage;
let damage;
move = this.getMoveCopy(move);
if (!moveData) moveData = move;
var hitResult = true;
let hitResult = true;
if (move.target === 'all' && !isSelf) {
hitResult = this.singleEvent('TryHitField', moveData, {}, target, pokemon, move);
@ -142,7 +144,7 @@ exports.BattleScripts = {
}
if (target) {
var didSomething = false;
let didSomething = false;
damage = this.getDamage(pokemon, target, moveData);
if ((damage || damage === 0) && !target.fainted) {
@ -169,7 +171,7 @@ exports.BattleScripts = {
didSomething = didSomething || hitResult;
}
if (moveData.heal && !target.fainted) {
var d = target.heal(Math.round(target.maxhp * moveData.heal[0] / moveData.heal[1]));
let d = target.heal(Math.round(target.maxhp * moveData.heal[0] / moveData.heal[1]));
if (!d && d !== 0) {
this.add('-fail', target);
this.debug('heal interrupted');
@ -242,7 +244,7 @@ exports.BattleScripts = {
}
}
if (moveData.self) {
var selfRoll;
let selfRoll;
if (!isSecondary && moveData.self.boosts) selfRoll = this.random(100);
// This is done solely to mimic in-game RNG behaviour. All self drops have a 100% chance of happening but still grab a random number.
if (typeof moveData.self.chance === 'undefined' || selfRoll < moveData.self.chance) {
@ -250,14 +252,14 @@ exports.BattleScripts = {
}
}
if (moveData.secondaries && this.runEvent('TrySecondaryHit', target, pokemon, moveData)) {
for (var i = 0; i < moveData.secondaries.length; i++) {
for (let i = 0; i < moveData.secondaries.length; i++) {
// We check here whether to negate the probable secondary status if it's burn or freeze.
// In the game, this is checked and if true, the random number generator is not called.
// That means that a move that does not share the type of the target can status it.
// This means tri-attack can burn fire-types and freeze ice-types.
// Unlike gen 1, though, paralysis works for all unless the target is immune to direct move (ie. ground-types and t-wave).
if (!(moveData.secondaries[i].status && moveData.secondaries[i].status in {'brn':1, 'frz':1} && target && target.hasType(move.type))) {
var effectChance = Math.floor(moveData.secondaries[i].chance * 255 / 100);
let effectChance = Math.floor(moveData.secondaries[i].chance * 255 / 100);
if (typeof moveData.secondaries[i].chance === 'undefined' || this.random(256) <= effectChance) {
this.moveHit(target, pokemon, move, moveData.secondaries[i], true, isSelf);
}
@ -319,10 +321,10 @@ exports.BattleScripts = {
if (!move.defensiveCategory) move.defensiveCategory = move.category;
// '???' is typeless damage: used for Struggle and Confusion etc
if (!move.type) move.type = '???';
var type = move.type;
let type = move.type;
// We get the base power and apply basePowerCallback if necessary
var basePower = move.basePower;
let basePower = move.basePower;
if (move.basePowerCallback) {
basePower = move.basePowerCallback.call(this, pokemon, target, move);
}
@ -336,7 +338,7 @@ exports.BattleScripts = {
// Checking for the move's Critical Hit ratio
move.critRatio = this.clampIntRange(move.critRatio, 0, 5);
var critMult = [0, 16, 8, 4, 3, 2];
let critMult = [0, 16, 8, 4, 3, 2];
move.crit = move.willCrit || false;
if (typeof move.willCrit === 'undefined') {
if (move.critRatio) {
@ -359,15 +361,15 @@ exports.BattleScripts = {
basePower = this.clampIntRange(basePower, 1);
// We now check for attacker and defender
var level = pokemon.level;
var attacker = pokemon;
var defender = target;
let level = pokemon.level;
let attacker = pokemon;
let defender = target;
if (move.useTargetOffensive) attacker = target;
if (move.useSourceDefensive) defender = pokemon;
var atkType = (move.category === 'Physical') ? 'atk' : 'spa';
var defType = (move.defensiveCategory === 'Physical') ? 'def' : 'spd';
var unboosted = false;
var noburndrop = false;
let atkType = (move.category === 'Physical') ? 'atk' : 'spa';
let defType = (move.defensiveCategory === 'Physical') ? 'def' : 'spd';
let unboosted = false;
let noburndrop = false;
// The move is a critical hit. Several things happen here.
if (move.crit) {
@ -384,8 +386,8 @@ exports.BattleScripts = {
}
}
// Get stats now.
var attack = attacker.getStat(atkType, unboosted, noburndrop);
var defense = defender.getStat(defType, unboosted);
let attack = attacker.getStat(atkType, unboosted, noburndrop);
let defense = defender.getStat(defType, unboosted);
// Moves that ignore offense and defense respectively.
if (move.ignoreOffensive) {
@ -412,7 +414,7 @@ exports.BattleScripts = {
// Let's go with the calculation now that we have what we need.
// We do it step by step just like the game does.
var damage = level * 2;
let damage = level * 2;
damage = Math.floor(damage / 5);
damage += 2;
damage *= basePower;
@ -427,7 +429,7 @@ exports.BattleScripts = {
}
// Type effectiveness
var totalTypeMod = this.getEffectiveness(type, target);
let totalTypeMod = this.getEffectiveness(type, target);
// Super effective attack
if (totalTypeMod > 0) {
if (!suppressMessages) this.add('-supereffective', target);
@ -489,7 +491,7 @@ exports.BattleScripts = {
if (damage !== 0) damage = this.clampIntRange(damage, 1);
damage = target.damage(damage, source, effect);
if (source) source.lastDamage = damage;
var name = effect.fullname;
let name = effect.fullname;
if (name === 'tox') name = 'psn';
switch (effect.id) {
case 'partiallytrapped':
@ -521,34 +523,34 @@ exports.BattleScripts = {
return damage;
},
randomTeam: function (side) {
var pokemonLeft = 0;
var pokemon = [];
let pokemonLeft = 0;
let pokemon = [];
var handicapMons = {'magikarp':1, 'weedle':1, 'kakuna':1, 'caterpie':1, 'metapod':1, 'ditto':1};
var nuTiers = {'UU':1, 'BL':1, 'NFE':1, 'LC':1};
var uuTiers = {'NFE':1, 'UU':1, 'BL':1};
let handicapMons = {'magikarp':1, 'weedle':1, 'kakuna':1, 'caterpie':1, 'metapod':1, 'ditto':1};
let nuTiers = {'UU':1, 'BL':1, 'NFE':1, 'LC':1};
let uuTiers = {'NFE':1, 'UU':1, 'BL':1};
var n = 1;
var pokemonPool = [];
for (var id in this.data.FormatsData) {
let n = 1;
let pokemonPool = [];
for (let id in this.data.FormatsData) {
// FIXME: Not ES-compliant
if (n++ > 251 || !this.data.FormatsData[id].randomBattleMoves) continue;
pokemonPool.push(id);
}
// Setup storage.
var typeCount = {};
var uberCount = 0;
var nuCount = 0;
var hasShitmon = false;
let typeCount = {};
let uberCount = 0;
let nuCount = 0;
let hasShitmon = false;
while (pokemonPool.length && pokemonLeft < 6) {
var template = this.getTemplate(this.sampleNoReplace(pokemonPool));
let template = this.getTemplate(this.sampleNoReplace(pokemonPool));
if (!template.exists) continue;
// Bias the tiers so you get less shitmons and only one of the two Ubers.
// If you have a shitmon, you're covered in OUs and Ubers if possible
var tier = template.tier;
let tier = template.tier;
switch (tier) {
case 'LC':
if (nuCount > 1 || hasShitmon) continue;
@ -563,9 +565,9 @@ exports.BattleScripts = {
// Limit 2 of any type. Diversity and minor weakness count.
// The second of a same type has halved chance of being added.
var types = template.types;
var skip = false;
for (var t = 0; t < types.length; t++) {
let types = template.types;
let skip = false;
for (let t = 0; t < types.length; t++) {
if (typeCount[types[t]] > 1 || (typeCount[types[t]] === 1 && this.random(2) >= 1)) {
skip = true;
break;
@ -574,14 +576,14 @@ exports.BattleScripts = {
if (skip) continue;
// The set passes the limitations.
var set = this.randomSet(template, pokemon.length);
let set = this.randomSet(template, pokemon.length);
pokemon.push(set);
// Now let's increase the counters. First, the Pokémon left.
pokemonLeft++;
// Type counter.
for (var t = 0; t < types.length; t++) {
for (let t = 0; t < types.length; t++) {
if (typeCount[types[t]]) {
typeCount[types[t]]++;
} else {
@ -608,30 +610,30 @@ exports.BattleScripts = {
template = this.getTemplate(template);
if (!template.exists) template = this.getTemplate('unown');
var movePool = template.randomBattleMoves.slice();
var moves = [];
var hasType = {};
let movePool = template.randomBattleMoves.slice();
let moves = [];
let hasType = {};
hasType[template.types[0]] = true;
if (template.types[1]) hasType[template.types[1]] = true;
var hasMove = {};
var counter = {};
var setupType = '';
var item = 'leftovers';
var ivs = {hp: 30, atk: 30, def: 30, spa: 30, spd: 30, spe: 30};
let hasMove = {};
let counter = {};
let setupType = '';
let item = 'leftovers';
let ivs = {hp: 30, atk: 30, def: 30, spa: 30, spd: 30, spe: 30};
// Moves that boost Attack:
var PhysicalSetup = {
let PhysicalSetup = {
swordsdance:1, sharpen:1
};
// Moves which boost Special Attack:
var SpecialSetup = {
let SpecialSetup = {
amnesia:1, growth:1
};
do {
// Keep track of all moves we have:
hasMove = {};
for (var k = 0; k < moves.length; k++) {
for (let k = 0; k < moves.length; k++) {
if (moves[k].substr(0, 11) === 'hiddenpower') {
hasMove['hiddenpower'] = true;
} else {
@ -641,7 +643,7 @@ exports.BattleScripts = {
// Choose next 4 moves from learnset/viable moves and add them to moves list:
while (moves.length < 4 && movePool.length) {
var moveid = this.sampleNoReplace(movePool);
let moveid = this.sampleNoReplace(movePool);
if (moveid.substr(0, 11) === 'hiddenpower') {
if (hasMove['hiddenpower']) continue;
hasMove['hiddenpower'] = true;
@ -652,9 +654,9 @@ exports.BattleScripts = {
}
counter = {Physical: 0, Special: 0, Status: 0, physicalsetup: 0, specialsetup: 0};
for (var k = 0; k < moves.length; k++) {
var move = this.getMove(moves[k]);
var moveid = move.id;
for (let k = 0; k < moves.length; k++) {
let move = this.getMove(moves[k]);
let moveid = move.id;
if (!move.damage && !move.damageCallback) {
counter[move.category]++;
}
@ -672,20 +674,20 @@ exports.BattleScripts = {
setupType = 'Physical';
}
for (var k = 0; k < moves.length; k++) {
var moveid = moves[k];
var move = this.getMove(moveid);
var rejected = false;
for (let k = 0; k < moves.length; k++) {
let moveid = moves[k];
let move = this.getMove(moveid);
let rejected = false;
if (moveid.substr(0, 11) === 'hiddenpower') {
// Check for hidden power DVs
var HPivs = this.getType(move.type).HPivs;
for (var iv in HPivs) {
let HPivs = this.getType(move.type).HPivs;
for (let iv in HPivs) {
ivs[iv] = HPivs[iv];
}
moveid = 'hiddenpower';
}
if (!template.essentialMove || moveid !== template.essentialMove) {
var isSetup = false;
let isSetup = false;
switch (moveid) {
// bad after setup
@ -810,7 +812,7 @@ exports.BattleScripts = {
break;
}
var levelScale = {
let levelScale = {
LC: 96,
NFE: 90,
UU: 85,
@ -819,12 +821,12 @@ exports.BattleScripts = {
Uber: 74
};
// Hollistic judgment.
var customScale = {
let customScale = {
Caterpie: 99, Kakuna: 99, Magikarp: 99, Metapod: 99, Weedle: 99, Pichu: 99, Smoochum: 99,
Clefairy: 95, "Farfetch'd": 99, Igglybuff: 99, Jigglypuff: 99, Ditto: 99, Mewtwo: 70,
Dragonite: 85, Cloyster: 83, Staryu: 90
};
var level = levelScale[template.tier] || 90;
let level = levelScale[template.tier] || 90;
if (customScale[template.name]) level = customScale[template.name];
return {

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleStatuses = {
brn: {
effectType: 'Status',
@ -93,7 +95,7 @@ exports.BattleStatuses = {
confusion: {
inherit: true,
onStart: function (target, source, sourceEffect) {
var result = this.runEvent('TryConfusion', target, source, sourceEffect);
let result = this.runEvent('TryConfusion', target, source, sourceEffect);
if (!result) return result;
if (sourceEffect && sourceEffect.id === 'lockedmove') {
this.add('-start', target, 'confusion', '[silent]');
@ -149,7 +151,7 @@ exports.BattleStatuses = {
return this.effectData.move;
},
onBeforeTurn: function (pokemon) {
var move = this.getMove(this.effectData.move);
let move = this.getMove(this.effectData.move);
if (move.id) {
this.debug('Forcing into ' + move.id);
this.changeDecision(pokemon, {move: move.id});
@ -170,7 +172,7 @@ exports.BattleStatuses = {
},
onStallMove: function () {
// Gen 2 starts counting at x=255, x/256 and then halves x on every turn
var counter = this.effectData.counter || 255;
let counter = this.effectData.counter || 255;
this.debug("Success chance: " + Math.round(counter / 256) + "% (" + counter + "/256)");
return (this.random(counter) === 0);
},

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleAbilities = {
"cutecharm": {
inherit: true,
@ -13,7 +15,7 @@ exports.BattleAbilities = {
inherit: true,
onAfterDamage: function (damage, target, source, move) {
if (move && move.flags['contact'] && !source.status) {
var r = this.random(300);
let r = this.random(300);
if (r < 10) {
source.setStatus('slp');
} else if (r < 20) {
@ -119,7 +121,7 @@ exports.BattleAbilities = {
inherit: true,
onAfterSetStatus: function (status, target, source) {
if (!source || source === target) return;
var id = status.id;
let id = status.id;
if (id === 'slp' || id === 'frz') return;
if (id === 'tox') id = 'psn';
source.trySetStatus(id);
@ -128,10 +130,10 @@ exports.BattleAbilities = {
"trace": {
inherit: true,
onUpdate: function (pokemon) {
var target = pokemon.side.foe.randomActive();
let target = pokemon.side.foe.randomActive();
if (!target || target.fainted) return;
var ability = this.getAbility(target.ability);
var bannedAbilities = {forecast:1, multitype:1, trace:1};
let ability = this.getAbility(target.ability);
let bannedAbilities = {forecast:1, multitype:1, trace:1};
if (bannedAbilities[target.ability]) {
return;
}

View File

@ -1,6 +1,9 @@
/**
* Gen 3 moves
*/
'use strict';
exports.BattleMovedex = {
absorb: {
inherit: true,
@ -23,13 +26,13 @@ exports.BattleMovedex = {
inherit: true,
desc: "The user performs a random move from any of the Pokemon on its team. Assist cannot generate itself, Chatter, Copycat, Counter, Covet, Destiny Bond, Detect, Endure, Feint, Focus Punch, Follow Me, Helping Hand, Me First, Metronome, Mimic, Mirror Coat, Mirror Move, Protect, Sketch, Sleep Talk, Snatch, Struggle, Switcheroo, Thief or Trick.",
onHit: function (target) {
var moves = [];
for (var j = 0; j < target.side.pokemon.length; j++) {
var pokemon = target.side.pokemon[j];
let moves = [];
for (let j = 0; j < target.side.pokemon.length; j++) {
let pokemon = target.side.pokemon[j];
if (pokemon === target) continue;
for (var i = 0; i < pokemon.moves.length; i++) {
var move = pokemon.moves[i];
var noAssist = {
for (let i = 0; i < pokemon.moves.length; i++) {
let move = pokemon.moves[i];
let noAssist = {
assist:1, chatter:1, copycat:1, counter:1, covet:1, destinybond:1, detect:1, endure:1, feint:1, focuspunch:1, followme:1, helpinghand:1, mefirst:1, metronome:1, mimic:1, mirrorcoat:1, mirrormove:1, protect:1, sketch:1, sleeptalk:1, snatch:1, struggle:1, switcheroo:1, thief:1, trick:1
};
if (move && !noAssist[move]) {
@ -37,7 +40,7 @@ exports.BattleMovedex = {
}
}
}
var move = '';
let move = '';
if (moves.length) move = moves[this.random(moves.length)];
if (!move) {
return false;
@ -154,8 +157,8 @@ exports.BattleMovedex = {
if (!pokemon.lastMove) {
return false;
}
var moves = pokemon.moveset;
for (var i = 0; i < moves.length; i++) {
let moves = pokemon.moveset;
for (let i = 0; i < moves.length; i++) {
if (moves[i].id === pokemon.lastMove) {
if (!moves[i].pp) {
return false;
@ -178,8 +181,8 @@ exports.BattleMovedex = {
}
},
onDisableMove: function (pokemon) {
var moves = pokemon.moveset;
for (var i = 0; i < moves.length; i++) {
let moves = pokemon.moveset;
for (let i = 0; i < moves.length; i++) {
if (moves[i].id === this.effectData.move) {
pokemon.disableMove(moves[i].id);
}
@ -215,8 +218,8 @@ exports.BattleMovedex = {
return this.random(3, 7);
},
onStart: function (target) {
var noEncore = {encore:1, mimic:1, mirrormove:1, sketch:1, struggle:1, transform:1};
var moveIndex = target.moves.indexOf(target.lastMove);
let noEncore = {encore:1, mimic:1, mirrormove:1, sketch:1, struggle:1, transform:1};
let moveIndex = target.moves.indexOf(target.lastMove);
if (!target.lastMove || noEncore[target.lastMove] || (target.moveset[moveIndex] && target.moveset[moveIndex].pp <= 0)) {
// it failed
this.add('-fail', target);
@ -247,7 +250,7 @@ exports.BattleMovedex = {
if (!this.effectData.move || !pokemon.hasMove(this.effectData.move)) {
return;
}
for (var i = 0; i < pokemon.moveset.length; i++) {
for (let i = 0; i < pokemon.moveset.length; i++) {
if (pokemon.moveset[i].id !== this.effectData.move) {
pokemon.disableMove(pokemon.moveset[i].id);
}
@ -287,7 +290,7 @@ exports.BattleMovedex = {
flail: {
inherit: true,
basePowerCallback: function (pokemon, target) {
var ratio = pokemon.hp * 48 / pokemon.maxhp;
let ratio = pokemon.hp * 48 / pokemon.maxhp;
if (ratio < 2) {
return 200;
}
@ -368,7 +371,7 @@ exports.BattleMovedex = {
category: "Physical",
onModifyMove: function (move, pokemon) {
move.type = pokemon.hpType || 'Dark';
var specialTypes = {Fire:1, Water:1, Grass:1, Ice:1, Electric:1, Dark:1, Psychic:1, Dragon:1};
let specialTypes = {Fire:1, Water:1, Grass:1, Ice:1, Electric:1, Dark:1, Psychic:1, Dragon:1};
move.category = specialTypes[move.type] ? 'Special' : 'Physical';
}
},
@ -378,7 +381,7 @@ exports.BattleMovedex = {
pp: 20,
onMoveFail: function (target, source, move) {
if (target.runImmunity('Fighting')) {
var damage = this.getDamage(source, target, move, true);
let damage = this.getDamage(source, target, move, true);
this.damage(this.clampIntRange(damage / 2, 1, Math.floor(target.maxhp / 2)), source, source, 'highjumpkick');
}
}
@ -397,7 +400,7 @@ exports.BattleMovedex = {
pp: 25,
onMoveFail: function (target, source, move) {
if (target.runImmunity('Fighting')) {
var damage = this.getDamage(source, target, move, true);
let damage = this.getDamage(source, target, move, true);
this.damage(this.clampIntRange(damage / 2, 1, Math.floor(target.maxhp / 2)), source, source, 'jumpkick');
}
}
@ -413,19 +416,19 @@ exports.BattleMovedex = {
metronome: {
inherit: true,
onHit: function (target) {
var moves = [];
for (var i in exports.BattleMovedex) {
var move = exports.BattleMovedex[i];
let moves = [];
for (let i in exports.BattleMovedex) {
let move = exports.BattleMovedex[i];
if (i !== move.id) continue;
if (move.isNonstandard) continue;
var noMetronome = {
let noMetronome = {
assist:1, counter:1, covet:1, destinybond:1, detect:1, endure:1, focuspunch:1, followme:1, helpinghand:1, metronome:1, mimic:1, mirrorcoat:1, mirrormove:1, protect:1, sketch:1, sleeptalk:1, snatch:1, struggle:1, thief:1, trick:1
};
if (!noMetronome[move.id] && move.num < 355) {
moves.push(move.id);
}
}
var move = '';
let move = '';
if (moves.length) move = moves[this.random(moves.length)];
if (!move) return false;
this.useMove(move, target);
@ -441,7 +444,7 @@ exports.BattleMovedex = {
inherit: true,
onTryHit: function () { },
onHit: function (pokemon) {
var noMirror = {assist:1, curse:1, doomdesire:1, focuspunch:1, futuresight:1, magiccoat:1, metronome:1, mimic:1, mirrormove:1, naturepower:1, psychup:1, roleplay:1, sketch:1, sleeptalk:1, spikes:1, spitup:1, taunt:1, teeterdance:1, transform:1};
let noMirror = {assist:1, curse:1, doomdesire:1, focuspunch:1, futuresight:1, magiccoat:1, metronome:1, mimic:1, mirrormove:1, naturepower:1, psychup:1, roleplay:1, sketch:1, sleeptalk:1, spikes:1, spitup:1, taunt:1, teeterdance:1, transform:1};
if (!pokemon.lastAttackedBy || !pokemon.lastAttackedBy.pokemon.lastMove || noMirror[pokemon.lastAttackedBy.move] || !pokemon.lastAttackedBy.pokemon.hasMove(pokemon.lastAttackedBy.move)) {
return false;
}
@ -523,7 +526,7 @@ exports.BattleMovedex = {
reversal: {
inherit: true,
basePowerCallback: function (pokemon, target) {
var ratio = pokemon.hp * 48 / pokemon.maxhp;
let ratio = pokemon.hp * 48 / pokemon.maxhp;
if (ratio < 2) {
return 200;
}
@ -570,8 +573,8 @@ exports.BattleMovedex = {
skillswap: {
inherit: true,
onHit: function (target, source) {
var targetAbility = this.getAbility(target.ability);
var sourceAbility = this.getAbility(source.ability);
let targetAbility = this.getAbility(target.ability);
let sourceAbility = this.getAbility(source.ability);
if (targetAbility.id === sourceAbility.id) {
return false;
}
@ -598,7 +601,7 @@ exports.BattleMovedex = {
inherit: true,
flags: {protect: 1, mirror: 1, authentic: 1},
onHit: function (target) {
var roll = this.random(2, 6);
let roll = this.random(2, 6);
if (target.deductPP(target.lastMove, roll)) {
this.add("-activate", target, 'move: Spite', target.lastMove, roll);
return;
@ -670,8 +673,8 @@ exports.BattleMovedex = {
this.add('-end', target, 'move: Taunt', '[silent]');
},
onDisableMove: function (pokemon) {
var moves = pokemon.moveset;
for (var i = 0; i < moves.length; i++) {
let moves = pokemon.moveset;
for (let i = 0; i < moves.length; i++) {
if (this.getMove(moves[i].move).category === 'Status') {
pokemon.disableMove(moves[i].id);
}
@ -757,10 +760,10 @@ exports.BattleMovedex = {
duration: 2,
onResidualOrder: 0,
onEnd: function (side) {
var target = side.active[this.effectData.sourcePosition];
let target = side.active[this.effectData.sourcePosition];
if (!target.fainted) {
var source = this.effectData.source;
var damage = this.heal(target.maxhp / 2, target, target);
let source = this.effectData.source;
let damage = this.heal(target.maxhp / 2, target, target);
if (damage) this.add('-heal', target, target.getHealth, '[from] move: Wish', '[wisher] ' + source.name);
}
}

View File

@ -1,13 +1,15 @@
'use strict';
exports.BattleScripts = {
inherit: 'gen5',
gen: 3,
init: function () {
for (var i in this.data.Pokedex) {
for (let i in this.data.Pokedex) {
delete this.data.Pokedex[i].abilities['H'];
}
var specialTypes = {Fire:1, Water:1, Grass:1, Ice:1, Electric:1, Dark:1, Psychic:1, Dragon:1};
var newCategory = '';
for (var i in this.data.Movedex) {
let specialTypes = {Fire:1, Water:1, Grass:1, Ice:1, Electric:1, Dark:1, Psychic:1, Dragon:1};
let newCategory = '';
for (let i in this.data.Movedex) {
if (this.data.Movedex[i].category === 'Status') continue;
newCategory = specialTypes[this.data.Movedex[i].type] ? 'Special' : 'Physical';
if (newCategory !== this.data.Movedex[i].category) {

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleAbilities = {
"angerpoint": {
inherit: true,
@ -27,14 +29,14 @@ exports.BattleAbilities = {
"forewarn": {
inherit: true,
onStart: function (pokemon) {
var targets = pokemon.side.foe.active;
var warnMoves = [];
var warnBp = 1;
for (var i = 0; i < targets.length; i++) {
let targets = pokemon.side.foe.active;
let warnMoves = [];
let warnBp = 1;
for (let i = 0; i < targets.length; i++) {
if (targets[i].fainted) continue;
for (var j = 0; j < targets[i].moveset.length; j++) {
var move = this.getMove(targets[i].moveset[j].move);
var bp = move.basePower;
for (let j = 0; j < targets[i].moveset.length; j++) {
let move = this.getMove(targets[i].moveset[j].move);
let bp = move.basePower;
if (move.ohko) bp = 160;
if (move.id === 'counter' || move.id === 'metalburst' || move.id === 'mirrorcoat') bp = 120;
if (!bp && move.category !== 'Status') bp = 80;
@ -47,7 +49,7 @@ exports.BattleAbilities = {
}
}
if (!warnMoves.length) return;
var warnMove = warnMoves[this.random(warnMoves.length)];
let warnMove = warnMoves[this.random(warnMoves.length)];
this.add('-activate', pokemon, 'ability: Forewarn', warnMove);
}
},
@ -90,11 +92,11 @@ exports.BattleAbilities = {
desc: "This Pokemon's Special Attack receives a 50% boost in double battles if its partner has the Plus ability.",
shortDesc: "If an ally has the Plus Ability, this Pokemon's Sp. Atk is 1.5x.",
onModifySpA: function (spa, pokemon) {
var allyActive = pokemon.side.active;
let allyActive = pokemon.side.active;
if (allyActive.length === 1) {
return;
}
for (var i = 0; i < allyActive.length; i++) {
for (let i = 0; i < allyActive.length; i++) {
if (allyActive[i] && allyActive[i].position !== pokemon.position && !allyActive[i].fainted && allyActive[i].ability === 'plus') {
return spa * 1.5;
}
@ -126,11 +128,11 @@ exports.BattleAbilities = {
desc: "This Pokemon's Special Attack receives a 50% boost in double battles if its partner has the Minus ability.",
shortDesc: "If an ally has the Minus Ability, this Pokemon's Sp. Atk is 1.5x.",
onModifySpA: function (spa, pokemon) {
var allyActive = pokemon.side.active;
let allyActive = pokemon.side.active;
if (allyActive.length === 1) {
return;
}
for (var i = 0; i < allyActive.length; i++) {
for (let i = 0; i < allyActive.length; i++) {
if (allyActive[i] && allyActive[i].position !== pokemon.position && !allyActive[i].fainted && allyActive[i].ability === 'minus') {
return spa * 1.5;
}
@ -159,7 +161,7 @@ exports.BattleAbilities = {
"simple": {
shortDesc: "If this Pokemon's stat stages are raised or lowered, the effect is doubled instead.",
onModifyBoost: function (boosts) {
for (var key in boosts) {
for (let key in boosts) {
boosts[key] *= 2;
}
},
@ -192,7 +194,7 @@ exports.BattleAbilities = {
onAfterSetStatus: function (status, target, source, effect) {
if (!source || source === target) return;
if (effect && effect.id === 'toxicspikes') return;
var id = status.id;
let id = status.id;
if (id === 'slp' || id === 'frz') return;
if (id === 'tox') id = 'psn';
source.trySetStatus(id);
@ -201,10 +203,10 @@ exports.BattleAbilities = {
"trace": {
inherit: true,
onUpdate: function (pokemon) {
var target = pokemon.side.foe.randomActive();
let target = pokemon.side.foe.randomActive();
if (!target || target.fainted) return;
var ability = this.getAbility(target.ability);
var bannedAbilities = {forecast:1, multitype:1, trace:1};
let ability = this.getAbility(target.ability);
let bannedAbilities = {forecast:1, multitype:1, trace:1};
if (bannedAbilities[target.ability]) {
return;
}

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleItems = {
"adamantorb": {
inherit: true,
@ -30,7 +32,7 @@ exports.BattleItems = {
},
onBeforeTurn: function (pokemon) {
if (pokemon.hp <= pokemon.maxhp / 4 || (pokemon.hp <= pokemon.maxhp / 2 && pokemon.ability === 'gluttony')) {
var decision = this.willMove(pokemon);
let decision = this.willMove(pokemon);
if (!decision) return;
this.insertQueue({
choice: 'event',
@ -43,14 +45,14 @@ exports.BattleItems = {
}
},
onCustap: function (pokemon) {
var decision = this.willMove(pokemon);
let decision = this.willMove(pokemon);
this.debug('custap decision: ' + decision);
if (decision) {
pokemon.eatItem();
}
},
onEat: function (pokemon) {
var decision = this.willMove(pokemon);
let decision = this.willMove(pokemon);
this.debug('custap eaten: ' + decision);
if (decision) {
this.cancelDecision(pokemon);

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleMovedex = {
acupressure: {
inherit: true,
@ -7,15 +9,15 @@ exports.BattleMovedex = {
if (target.volatiles['substitute']) {
return false;
}
var stats = [];
for (var i in target.boosts) {
let stats = [];
for (let i in target.boosts) {
if (target.boosts[i] < 6) {
stats.push(i);
}
}
if (stats.length) {
var i = stats[this.random(stats.length)];
var boost = {};
let i = stats[this.random(stats.length)];
let boost = {};
boost[i] = 2;
this.boost(boost);
} else {
@ -27,13 +29,13 @@ exports.BattleMovedex = {
inherit: true,
desc: "The user performs a random move from any of the Pokemon on its team. Assist cannot generate itself, Chatter, Copycat, Counter, Covet, Destiny Bond, Detect, Endure, Feint, Focus Punch, Follow Me, Helping Hand, Me First, Metronome, Mimic, Mirror Coat, Mirror Move, Protect, Sketch, Sleep Talk, Snatch, Struggle, Switcheroo, Thief or Trick.",
onHit: function (target) {
var moves = [];
for (var j = 0; j < target.side.pokemon.length; j++) {
var pokemon = target.side.pokemon[j];
let moves = [];
for (let j = 0; j < target.side.pokemon.length; j++) {
let pokemon = target.side.pokemon[j];
if (pokemon === target) continue;
for (var i = 0; i < pokemon.moves.length; i++) {
var move = pokemon.moves[i];
var noAssist = {
for (let i = 0; i < pokemon.moves.length; i++) {
let move = pokemon.moves[i];
let noAssist = {
assist:1, chatter:1, copycat:1, counter:1, covet:1, destinybond:1, detect:1, endure:1, feint:1, focuspunch:1, followme:1, helpinghand:1, mefirst:1, metronome:1, mimic:1, mirrorcoat:1, mirrormove:1, protect:1, sketch:1, sleeptalk:1, snatch:1, struggle:1, switcheroo:1, thief:1, trick:1
};
if (move && !noAssist[move]) {
@ -41,7 +43,7 @@ exports.BattleMovedex = {
}
}
}
var move = '';
let move = '';
if (moves.length) move = moves[this.random(moves.length)];
if (!move) {
return false;
@ -117,7 +119,7 @@ exports.BattleMovedex = {
return false;
}
this.add('-end', pokemon, 'Bide');
var target = this.effectData.sourceSide.active[this.effectData.sourcePosition];
let target = this.effectData.sourceSide.active[this.effectData.sourcePosition];
this.moveHit(target, pokemon, 'bide', {damage: this.effectData.totalDamage * 2});
return false;
}
@ -167,7 +169,7 @@ exports.BattleMovedex = {
copycat: {
inherit: true,
onHit: function (pokemon) {
var noCopycat = {assist:1, chatter:1, copycat:1, counter:1, covet:1, destinybond:1, detect:1, endure:1, feint:1, focuspunch:1, followme:1, helpinghand:1, mefirst:1, metronome:1, mimic:1, mirrorcoat:1, mirrormove:1, protect:1, sketch:1, sleeptalk:1, snatch:1, struggle:1, switcheroo:1, thief:1, trick:1};
let noCopycat = {assist:1, chatter:1, copycat:1, counter:1, covet:1, destinybond:1, detect:1, endure:1, feint:1, focuspunch:1, followme:1, helpinghand:1, mefirst:1, metronome:1, mimic:1, mirrorcoat:1, mirrormove:1, protect:1, sketch:1, sleeptalk:1, snatch:1, struggle:1, switcheroo:1, thief:1, trick:1};
if (!this.lastMove || noCopycat[this.lastMove]) {
return false;
}
@ -224,7 +226,7 @@ exports.BattleMovedex = {
onTryHit: function (target, source, move) {
if (!move.flags['protect']) return;
this.add('-activate', target, 'Protect');
var lockedmove = source.getVolatile('lockedmove');
let lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is NOT reset
if (source.volatiles['lockedmove'].trueDuration >= 2) {
@ -253,8 +255,8 @@ exports.BattleMovedex = {
if (!pokemon.lastMove) {
return false;
}
var moves = pokemon.moveset;
for (var i = 0; i < moves.length; i++) {
let moves = pokemon.moveset;
for (let i = 0; i < moves.length; i++) {
if (moves[i].id === pokemon.lastMove) {
if (!moves[i].pp) {
return false;
@ -278,8 +280,8 @@ exports.BattleMovedex = {
}
},
onDisableMove: function (pokemon) {
var moves = pokemon.moveset;
for (var i = 0; i < moves.length; i++) {
let moves = pokemon.moveset;
for (let i = 0; i < moves.length; i++) {
if (moves[i].id === this.effectData.move) {
pokemon.disableMove(moves[i].id);
}
@ -325,8 +327,8 @@ exports.BattleMovedex = {
return this.random(4, 9);
},
onStart: function (target) {
var noEncore = {encore:1, mimic:1, mirrormove:1, sketch:1, struggle:1, transform:1};
var moveIndex = target.moves.indexOf(target.lastMove);
let noEncore = {encore:1, mimic:1, mirrormove:1, sketch:1, struggle:1, transform:1};
let moveIndex = target.moves.indexOf(target.lastMove);
if (!target.lastMove || noEncore[target.lastMove] || (target.moveset[moveIndex] && target.moveset[moveIndex].pp <= 0)) {
// it failed
this.add('-fail', target);
@ -357,7 +359,7 @@ exports.BattleMovedex = {
if (!this.effectData.move || !pokemon.hasMove(this.effectData.move)) {
return;
}
for (var i = 0; i < pokemon.moveset.length; i++) {
for (let i = 0; i < pokemon.moveset.length; i++) {
if (pokemon.moveset[i].id !== this.effectData.move) {
pokemon.moveset[i].disabled = true;
}
@ -406,7 +408,7 @@ exports.BattleMovedex = {
flail: {
inherit: true,
basePowerCallback: function (pokemon, target) {
var ratio = pokemon.hp * 64 / pokemon.maxhp;
let ratio = pokemon.hp * 64 / pokemon.maxhp;
if (ratio < 2) {
return 200;
}
@ -485,9 +487,9 @@ exports.BattleMovedex = {
this.add('-start', pokemon, 'move: Heal Block');
},
onDisableMove: function (pokemon) {
var disabledMoves = {healingwish:1, lunardance:1, rest:1, swallow:1, wish:1};
var moves = pokemon.moveset;
for (var i = 0; i < moves.length; i++) {
let disabledMoves = {healingwish:1, lunardance:1, rest:1, swallow:1, wish:1};
let moves = pokemon.moveset;
for (let i = 0; i < moves.length; i++) {
if (disabledMoves[moves[i].id] || this.getMove(moves[i].id).heal) {
pokemon.disableMove(moves[i].id);
}
@ -495,7 +497,7 @@ exports.BattleMovedex = {
},
onBeforeMovePriority: 6,
onBeforeMove: function (pokemon, target, move) {
var disabledMoves = {healingwish:1, lunardance:1, rest:1, swallow:1, wish:1};
let disabledMoves = {healingwish:1, lunardance:1, rest:1, swallow:1, wish:1};
if (disabledMoves[move.id] || move.heal) {
this.add('cant', pokemon, 'move: Heal Block', move);
return false;
@ -529,8 +531,8 @@ exports.BattleMovedex = {
return;
}
if (target.hp > 0) {
var source = this.effectData.source;
var damage = target.heal(target.maxhp);
let source = this.effectData.source;
let damage = target.heal(target.maxhp);
target.setStatus('');
this.add('-heal', target, target.getHealth, '[from] move: Healing Wish');
target.side.removeSideCondition('healingwish');
@ -620,7 +622,7 @@ exports.BattleMovedex = {
shortDesc: "User takes half damage it would have dealt if miss.",
pp: 20,
onMoveFail: function (target, source, move) {
var damage = this.getDamage(source, target, move, true);
let damage = this.getDamage(source, target, move, true);
if (!damage) damage = target.maxhp;
this.damage(this.clampIntRange(damage / 2, 1, Math.floor(target.maxhp / 2)), source, source, 'highjumpkick');
}
@ -633,10 +635,10 @@ exports.BattleMovedex = {
inherit: true,
flags: {authentic: 1},
onTryHit: function (pokemon) {
var targets = pokemon.side.foe.active;
for (var i = 0; i < targets.length; i++) {
let targets = pokemon.side.foe.active;
for (let i = 0; i < targets.length; i++) {
if (!targets[i] || targets[i].fainted) continue;
for (var j = 0; j < pokemon.moves.length; j++) {
for (let j = 0; j < pokemon.moves.length; j++) {
if (targets[i].moves.indexOf(pokemon.moves[j]) >= 0) return;
}
}
@ -650,7 +652,7 @@ exports.BattleMovedex = {
shortDesc: "User takes half damage it would have dealt if miss.",
pp: 25,
onMoveFail: function (target, source, move) {
var damage = this.getDamage(source, target, move, true);
let damage = this.getDamage(source, target, move, true);
if (!damage) damage = target.maxhp;
this.damage(this.clampIntRange(damage / 2, 1, Math.floor(target.maxhp / 2)), source, source, 'jumpkick');
}
@ -680,10 +682,10 @@ exports.BattleMovedex = {
return;
}
if (target.hp > 0) {
var source = this.effectData.source;
var damage = target.heal(target.maxhp);
let source = this.effectData.source;
let damage = target.heal(target.maxhp);
target.setStatus('');
for (var m in target.moveset) {
for (let m in target.moveset) {
target.moveset[m].pp = target.moveset[m].maxpp;
}
this.add('-heal', target, target.getHealth, '[from] move: Lunar Dance');
@ -704,7 +706,7 @@ exports.BattleMovedex = {
return;
}
target.removeVolatile('magiccoat');
var newMove = this.getMoveCopy(move.id);
let newMove = this.getMoveCopy(move.id);
newMove.hasBounced = true;
this.useMove(newMove, target, source);
return null;
@ -738,19 +740,19 @@ exports.BattleMovedex = {
metronome: {
inherit: true,
onHit: function (target) {
var moves = [];
for (var i in exports.BattleMovedex) {
var move = exports.BattleMovedex[i];
let moves = [];
for (let i in exports.BattleMovedex) {
let move = exports.BattleMovedex[i];
if (i !== move.id) continue;
if (move.isNonstandard) continue;
var noMetronome = {
let noMetronome = {
assist:1, chatter:1, copycat:1, counter:1, covet:1, destinybond:1, detect:1, endure:1, feint:1, focuspunch:1, followme:1, helpinghand:1, mefirst:1, metronome:1, mimic:1, mirrorcoat:1, mirrormove:1, protect:1, sketch:1, sleeptalk:1, snatch:1, struggle:1, switcheroo:1, thief:1, trick:1
};
if (!noMetronome[move.id] && move.num < 468) {
moves.push(move.id);
}
}
var move = '';
let move = '';
if (moves.length) move = moves[this.random(moves.length)];
if (!move) return false;
this.useMove(move, target);
@ -759,11 +761,11 @@ exports.BattleMovedex = {
mimic: {
inherit: true,
onHit: function (target, source) {
var disallowedMoves = {chatter:1, metronome:1, mimic:1, sketch:1, struggle:1, transform:1};
let disallowedMoves = {chatter:1, metronome:1, mimic:1, sketch:1, struggle:1, transform:1};
if (source.transformed || !target.lastMove || disallowedMoves[target.lastMove] || source.moves.indexOf(target.lastMove) !== -1 || target.volatiles['substitute']) return false;
var moveslot = source.moves.indexOf('mimic');
let moveslot = source.moves.indexOf('mimic');
if (moveslot < 0) return false;
var move = Tools.getMove(target.lastMove);
let move = Tools.getMove(target.lastMove);
source.moveset[moveslot] = {
move: move.name,
id: move.id,
@ -793,7 +795,7 @@ exports.BattleMovedex = {
inherit: true,
onTryHit: function () { },
onHit: function (pokemon) {
var noMirror = {acupressure:1, aromatherapy:1, assist:1, chatter:1, copycat:1, counter:1, curse:1, doomdesire:1, feint:1, focuspunch:1, futuresight:1, gravity:1, hail:1, haze:1, healbell:1, helpinghand:1, lightscreen:1, luckychant:1, magiccoat:1, mefirst:1, metronome:1, mimic:1, mirrorcoat:1, mirrormove:1, mist:1, mudsport:1, naturepower:1, perishsong:1, psychup:1, raindance:1, reflect:1, roleplay:1, safeguard:1, sandstorm:1, sketch:1, sleeptalk:1, snatch:1, spikes:1, spitup:1, stealthrock:1, struggle:1, sunnyday:1, tailwind:1, toxicspikes:1, transform:1, watersport:1};
let noMirror = {acupressure:1, aromatherapy:1, assist:1, chatter:1, copycat:1, counter:1, curse:1, doomdesire:1, feint:1, focuspunch:1, futuresight:1, gravity:1, hail:1, haze:1, healbell:1, helpinghand:1, lightscreen:1, luckychant:1, magiccoat:1, mefirst:1, metronome:1, mimic:1, mirrorcoat:1, mirrormove:1, mist:1, mudsport:1, naturepower:1, perishsong:1, psychup:1, raindance:1, reflect:1, roleplay:1, safeguard:1, sandstorm:1, sketch:1, sleeptalk:1, snatch:1, spikes:1, spitup:1, stealthrock:1, struggle:1, sunnyday:1, tailwind:1, toxicspikes:1, transform:1, watersport:1};
if (!pokemon.lastAttackedBy || !pokemon.lastAttackedBy.pokemon.lastMove || noMirror[pokemon.lastAttackedBy.move] || !pokemon.lastAttackedBy.pokemon.hasMove(pokemon.lastAttackedBy.move)) {
return false;
}
@ -870,7 +872,7 @@ exports.BattleMovedex = {
onTryHit: function (target, source, move) {
if (!move.flags['protect']) return;
this.add('-activate', target, 'Protect');
var lockedmove = source.getVolatile('lockedmove');
let lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is NOT reset
if (source.volatiles['lockedmove'].trueDuration >= 2) {
@ -892,7 +894,7 @@ exports.BattleMovedex = {
reversal: {
inherit: true,
basePowerCallback: function (pokemon, target) {
var ratio = pokemon.hp * 64 / pokemon.maxhp;
let ratio = pokemon.hp * 64 / pokemon.maxhp;
if (ratio < 2) {
return 200;
}
@ -935,12 +937,12 @@ exports.BattleMovedex = {
sketch: {
inherit: true,
onHit: function (target, source) {
var disallowedMoves = {chatter:1, sketch:1, struggle:1};
let disallowedMoves = {chatter:1, sketch:1, struggle:1};
if (source.transformed || !target.lastMove || disallowedMoves[target.lastMove] || source.moves.indexOf(target.lastMove) >= 0 || target.volatiles['substitute']) return false;
var moveslot = source.moves.indexOf('sketch');
let moveslot = source.moves.indexOf('sketch');
if (moveslot < 0) return false;
var move = Tools.getMove(target.lastMove);
var sketchedMove = {
let move = Tools.getMove(target.lastMove);
let sketchedMove = {
move: move.name,
id: move.id,
pp: move.pp,
@ -957,8 +959,8 @@ exports.BattleMovedex = {
skillswap: {
inherit: true,
onHit: function (target, source) {
var targetAbility = target.ability;
var sourceAbility = source.ability;
let targetAbility = target.ability;
let sourceAbility = source.ability;
if (targetAbility === sourceAbility) {
return false;
}
@ -998,7 +1000,7 @@ exports.BattleMovedex = {
suckerpunch: {
inherit: true,
onTry: function (source, target) {
var decision = this.willMove(target);
let decision = this.willMove(target);
if (!decision || decision.choice !== 'move' || decision.move.category === 'Status' || target.volatiles.mustrecharge) {
this.add('-fail', source);
return null;
@ -1070,8 +1072,8 @@ exports.BattleMovedex = {
this.add('-end', target, 'move: Taunt');
},
onDisableMove: function (pokemon) {
var moves = pokemon.moveset;
for (var i = 0; i < moves.length; i++) {
let moves = pokemon.moveset;
for (let i = 0; i < moves.length; i++) {
if (this.getMove(moves[i].move).category === 'Status') {
pokemon.disableMove(moves[i].id);
}
@ -1157,10 +1159,10 @@ exports.BattleMovedex = {
duration: 2,
onResidualOrder: 0,
onEnd: function (side) {
var target = side.active[this.effectData.sourcePosition];
let target = side.active[this.effectData.sourcePosition];
if (!target.fainted) {
var source = this.effectData.source;
var damage = this.heal(target.maxhp / 2, target, target);
let source = this.effectData.source;
let damage = this.heal(target.maxhp / 2, target, target);
if (damage) this.add('-heal', target, target.getHealth, '[from] move: Wish', '[wisher] ' + source.name);
}
}
@ -1169,7 +1171,7 @@ exports.BattleMovedex = {
worryseed: {
inherit: true,
onTryHit: function (pokemon) {
var bannedAbilities = {multitype:1, truant:1};
let bannedAbilities = {multitype:1, truant:1};
if (bannedAbilities[pokemon.ability]) {
return false;
}

View File

@ -1,15 +1,17 @@
'use strict';
exports.BattleFormats = {
pokemon: {
inherit: true,
effectType: 'Banlist',
onValidateSet: function (set) {
var template = this.getTemplate(set.species);
var item = this.getItem(set.item);
let template = this.getTemplate(set.species);
let item = this.getItem(set.item);
if (item && item.id === 'griseousorb' && template.num !== 487) {
return ['Griseous Orb can only be held by Giratina in Generation 4.'];
}
if (template.num === 493 && set.evs) {
for (var stat in set.evs) {
for (let stat in set.evs) {
if (set.evs[stat] > 100) return ["Arceus may not have more than 100 of any EVs in Generation 4."];
}
}

View File

@ -1,8 +1,10 @@
'use strict';
exports.BattleScripts = {
inherit: 'gen5',
gen: 4,
init: function () {
for (var i in this.data.Pokedex) {
for (let i in this.data.Pokedex) {
delete this.data.Pokedex[i].abilities['H'];
}
}

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleStatuses = {
par: {
inherit: true,

View File

@ -1,10 +1,12 @@
'use strict';
exports.BattleAbilities = {
"frisk": {
inherit: true,
desc: "When this Pokemon enters the field, it identifies the opponent's held item; in double battles, the held item of an unrevealed, randomly selected opponent is identified.",
shortDesc: "On switch-in, this Pokemon identifies a random foe's held item.",
onStart: function (pokemon) {
var target = pokemon.side.foe.randomActive();
let target = pokemon.side.foe.randomActive();
if (target && target.item) {
this.add('-item', target, target.getItem().name, '[from] ability: Frisk', '[of] ' + pokemon);
}

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleMovedex = {
acidarmor: {
inherit: true,
@ -14,8 +16,8 @@ exports.BattleMovedex = {
aromatherapy: {
inherit: true,
onHit: function (pokemon, source) {
var side = pokemon.side;
for (var i = 0; i < side.pokemon.length; i++) {
let side = pokemon.side;
for (let i = 0; i < side.pokemon.length; i++) {
side.pokemon[i].status = '';
}
this.add('-cureteam', source, '[from] move: Aromatherapy');
@ -25,13 +27,13 @@ exports.BattleMovedex = {
inherit: true,
desc: "A random move among those known by the user's party members is selected for use. Does not select Assist, Bestow, Chatter, Circle Throw, Copycat, Counter, Covet, Destiny Bond, Detect, Dragon Tail, Endure, Feint, Focus Punch, Follow Me, Helping Hand, Me First, Metronome, Mimic, Mirror Coat, Mirror Move, Nature Power, Protect, Rage Powder, Sketch, Sleep Talk, Snatch, Struggle, Switcheroo, Thief, Transform, or Trick.",
onHit: function (target) {
var moves = [];
for (var j = 0; j < target.side.pokemon.length; j++) {
var pokemon = target.side.pokemon[j];
let moves = [];
for (let j = 0; j < target.side.pokemon.length; j++) {
let pokemon = target.side.pokemon[j];
if (pokemon === target) continue;
for (var i = 0; i < pokemon.moves.length; i++) {
var move = pokemon.moves[i];
var noAssist = {
for (let i = 0; i < pokemon.moves.length; i++) {
let move = pokemon.moves[i];
let noAssist = {
assist:1, bestow:1, chatter:1, circlethrow:1, copycat:1, counter:1, covet:1, destinybond:1, detect:1, dragontail:1, endure:1, feint:1, focuspunch:1, followme:1, helpinghand:1, mefirst:1, metronome:1, mimic:1, mirrorcoat:1, mirrormove:1, naturepower:1, protect:1, ragepowder:1, sketch:1, sleeptalk:1, snatch:1, struggle:1, switcheroo:1, thief:1, transform:1, trick:1
};
if (move && !noAssist[move]) {
@ -39,7 +41,7 @@ exports.BattleMovedex = {
}
}
}
var move = '';
let move = '';
if (moves.length) move = moves[this.random(moves.length)];
if (!move) {
return false;
@ -126,8 +128,8 @@ exports.BattleMovedex = {
desc: "The user's type changes to match the original type of one of its four moves besides this move, at random, but not either of its current types. Fails if the user cannot change its type, or if this move would only be able to select one of the user's current types.",
shortDesc: "Changes user's type to match a known move.",
onHit: function (target) {
var possibleTypes = target.moveset.map(function (val) {
var move = this.getMove(val.id);
let possibleTypes = target.moveset.map(function (val) {
let move = this.getMove(val.id);
if (move.id !== 'conversion' && !target.hasType(move.type)) {
return move.type;
}
@ -135,7 +137,7 @@ exports.BattleMovedex = {
if (!possibleTypes.length) {
return false;
}
var type = possibleTypes[this.random(possibleTypes.length)];
let type = possibleTypes[this.random(possibleTypes.length)];
if (!target.setType(type)) return false;
this.add('-start', target, 'typechange', type);
@ -146,7 +148,7 @@ exports.BattleMovedex = {
desc: "The user uses the last move used by any Pokemon, including itself. Fails if no move has been used, or if the last move used was Assist, Bestow, Chatter, Circle Throw, Copycat, Counter, Covet, Destiny Bond, Detect, Dragon Tail, Endure, Feint, Focus Punch, Follow Me, Helping Hand, Me First, Metronome, Mimic, Mirror Coat, Mirror Move, Nature Power, Protect, Rage Powder, Sketch, Sleep Talk, Snatch, Struggle, Switcheroo, Thief, Transform, or Trick.",
shortDesc: "Uses the last move used in the battle.",
onHit: function (pokemon) {
var noCopycat = {assist:1, bestow:1, chatter:1, circlethrow:1, copycat:1, counter:1, covet:1, destinybond:1, detect:1, dragontail:1, endure:1, feint:1, focuspunch:1, followme:1, helpinghand:1, mefirst:1, metronome:1, mimic:1, mirrorcoat:1, mirrormove:1, naturepower:1, protect:1, ragepowder:1, sketch:1, sleeptalk:1, snatch:1, struggle:1, switcheroo:1, thief:1, transform:1, trick:1};
let noCopycat = {assist:1, bestow:1, chatter:1, circlethrow:1, copycat:1, counter:1, covet:1, destinybond:1, detect:1, dragontail:1, endure:1, feint:1, focuspunch:1, followme:1, helpinghand:1, mefirst:1, metronome:1, mimic:1, mirrorcoat:1, mirrormove:1, naturepower:1, protect:1, ragepowder:1, sketch:1, sleeptalk:1, snatch:1, struggle:1, switcheroo:1, thief:1, transform:1, trick:1};
if (!this.lastMove || noCopycat[this.lastMove]) {
return false;
}
@ -172,8 +174,8 @@ exports.BattleMovedex = {
shortDesc: "Removes target's hazards, lowers evasion by 1.",
onHit: function (pokemon) {
if (!pokemon.volatiles['substitute']) this.boost({evasion:-1});
var sideConditions = {reflect:1, lightscreen:1, safeguard:1, mist:1, spikes:1, toxicspikes:1, stealthrock:1};
for (var i in sideConditions) {
let sideConditions = {reflect:1, lightscreen:1, safeguard:1, mist:1, spikes:1, toxicspikes:1, stealthrock:1};
for (let i in sideConditions) {
if (pokemon.side.removeSideCondition(i)) {
this.add('-sideend', pokemon.side, this.getEffect(i).name, '[from] move: Defog', '[of] ' + pokemon);
}
@ -333,9 +335,9 @@ exports.BattleMovedex = {
this.add('-start', pokemon, 'move: Heal Block');
},
onDisableMove: function (pokemon) {
var disabledMoves = {healingwish:1, lunardance:1, rest:1, swallow:1, wish:1};
var moves = pokemon.moveset;
for (var i = 0; i < moves.length; i++) {
let disabledMoves = {healingwish:1, lunardance:1, rest:1, swallow:1, wish:1};
let moves = pokemon.moveset;
for (let i = 0; i < moves.length; i++) {
if (disabledMoves[moves[i].id] || this.getMove(moves[i].id).heal) {
pokemon.disableMove(moves[i].id);
}
@ -343,7 +345,7 @@ exports.BattleMovedex = {
},
onBeforeMovePriority: 6,
onBeforeMove: function (pokemon, target, move) {
var disabledMoves = {healingwish:1, lunardance:1, rest:1, swallow:1, wish:1};
let disabledMoves = {healingwish:1, lunardance:1, rest:1, swallow:1, wish:1};
if (disabledMoves[move.id] || move.heal) {
this.add('cant', pokemon, 'move: Heal Block', move);
return false;
@ -468,7 +470,7 @@ exports.BattleMovedex = {
desc: "Deals damage to all adjacent foes and destroys any Berry they may be holding.",
shortDesc: "Destroys the foe(s) Berry.",
onHit: function (pokemon, source) {
var item = pokemon.getItem();
let item = pokemon.getItem();
if (item.isBerry && pokemon.takeItem(source)) {
this.add('-enditem', pokemon, item.name, '[from] move: Incinerate');
}
@ -518,19 +520,19 @@ exports.BattleMovedex = {
metronome: {
inherit: true,
onHit: function (target) {
var moves = [];
for (var i in exports.BattleMovedex) {
var move = exports.BattleMovedex[i];
let moves = [];
for (let i in exports.BattleMovedex) {
let move = exports.BattleMovedex[i];
if (i !== move.id) continue;
if (move.isNonstandard) continue;
var noMetronome = {
let noMetronome = {
afteryou:1, assist:1, bestow:1, chatter:1, copycat:1, counter:1, covet:1, destinybond:1, detect:1, endure:1, feint:1, focuspunch:1, followme:1, freezeschok:1, helpinghand:1, iceburn:1, mefirst:1, metronome:1, mimic:1, mirrorcoat:1, mirrormove:1, naturepower:1, protect:1, quash:1, quickguard:1, ragepowder:1, relicsong:1, secretsword:1, sketch:1, sleeptalk:1, snarl:1, snatch:1, snore:1, struggle:1, switcheroo:1, technoblast:1, thief:1, transform:1, trick:1, vcreate:1, wideguard:1
};
if (!noMetronome[move.id] && move.num < 560) {
moves.push(move.id);
}
}
var move = '';
let move = '';
if (moves.length) move = moves[this.random(moves.length)];
if (!move) return false;
this.useMove(move, target);
@ -660,7 +662,7 @@ exports.BattleMovedex = {
return;
}
this.add('-activate', target, 'Quick Guard');
var lockedmove = source.getVolatile('lockedmove');
let lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is reset
if (source.volatiles['lockedmove'].duration === 2) {
@ -740,8 +742,8 @@ exports.BattleMovedex = {
skillswap: {
inherit: true,
onHit: function (target, source) {
var targetAbility = target.ability;
var sourceAbility = source.ability;
let targetAbility = target.ability;
let sourceAbility = source.ability;
if (targetAbility === sourceAbility) {
return false;
}
@ -840,7 +842,7 @@ exports.BattleMovedex = {
if (target === source || move.flags['authentic']) {
return;
}
var damage = this.getDamage(source, target, move);
let damage = this.getDamage(source, target, move);
if (!damage && damage !== 0) {
this.add('-fail', target);
return null;

View File

@ -1,24 +1,26 @@
'use strict';
exports.BattleScripts = {
gen: 5,
randomSet: function (template, slot) {
if (slot === undefined) slot = 1;
template = this.getTemplate(template);
var name = template.name;
let name = template.name;
if (!template.exists || (!template.randomBattleMoves && !template.learnset)) {
// GET IT? UNOWN? BECAUSE WE CAN'T TELL WHAT THE POKEMON IS
template = this.getTemplate('unown');
var stack = 'Template incompatible with random battles: ' + name;
var fakeErr = {stack: stack};
let stack = 'Template incompatible with random battles: ' + name;
let fakeErr = {stack: stack};
require('./../../crashlogger.js')(fakeErr, 'The randbat set generator');
}
var movePool = (template.randomBattleMoves ? template.randomBattleMoves.slice() : Object.keys(template.learnset));
var moves = [];
var ability = '';
var item = '';
var evs = {
let movePool = (template.randomBattleMoves ? template.randomBattleMoves.slice() : Object.keys(template.learnset));
let moves = [];
let ability = '';
let item = '';
let evs = {
hp: 85,
atk: 85,
def: 85,
@ -26,7 +28,7 @@ exports.BattleScripts = {
spd: 85,
spe: 85
};
var ivs = {
let ivs = {
hp: 31,
atk: 31,
def: 31,
@ -34,25 +36,25 @@ exports.BattleScripts = {
spd: 31,
spe: 31
};
var hasStab = {};
let hasStab = {};
hasStab[template.types[0]] = true;
var hasType = {};
let hasType = {};
hasType[template.types[0]] = true;
if (template.types[1]) {
hasStab[template.types[1]] = true;
hasType[template.types[1]] = true;
}
var damagingMoves = [];
var damagingMoveIndex = {};
var hasMove = {};
var counter = {};
var setupType = '';
let damagingMoves = [];
let damagingMoveIndex = {};
let hasMove = {};
let counter = {};
let setupType = '';
do {
// Choose next 4 moves from learnset/viable moves and add them to moves list:
while (moves.length < 4 && movePool.length) {
var moveid = this.sampleNoReplace(movePool);
let moveid = this.sampleNoReplace(movePool);
if (moveid.substr(0, 11) === 'hiddenpower') {
if (!hasMove['hiddenpower']) {
hasMove['hiddenpower'] = true;
@ -74,9 +76,9 @@ exports.BattleScripts = {
physicalsetup: 0, specialsetup: 0, mixedsetup: 0
};
// Iterate through all moves we've chosen so far and keep track of what they do:
for (var k = 0; k < moves.length; k++) {
var move = this.getMove(moves[k]);
var moveid = move.id;
for (let k = 0; k < moves.length; k++) {
let move = this.getMove(moves[k]);
let moveid = move.id;
// Keep track of all moves we have:
hasMove[moveid] = true;
if (move.damage || move.damageCallback) {
@ -137,22 +139,22 @@ exports.BattleScripts = {
counter['inaccurate']++;
}
// Moves which drop stats:
var ContraryMove = {
let ContraryMove = {
leafstorm: 1, overheat: 1, closecombat: 1, superpower: 1, vcreate: 1
};
if (ContraryMove[moveid]) {
counter['contrary']++;
}
// Moves that boost Attack:
var PhysicalSetup = {
let PhysicalSetup = {
swordsdance:1, dragondance:1, coil:1, bulkup:1, curse:1, bellydrum:1, shiftgear:1, honeclaws:1, howl:1
};
// Moves which boost Special Attack:
var SpecialSetup = {
let SpecialSetup = {
nastyplot:1, tailglow:1, quiverdance:1, calmmind:1, chargebeam:1
};
// Moves which boost Attack AND Special Attack:
var MixedSetup = {
let MixedSetup = {
growth:1, workup:1, shellsmash:1
};
@ -177,11 +179,11 @@ exports.BattleScripts = {
}
// Iterate through the moves again, this time to cull them:
for (var k = 0; k < moves.length; k++) {
var moveid = moves[k];
var move = this.getMove(moveid);
var rejected = false;
var isSetup = false;
for (let k = 0; k < moves.length; k++) {
let moveid = moves[k];
let move = this.getMove(moveid);
let rejected = false;
let isSetup = false;
switch (moveid) {
@ -381,7 +383,7 @@ exports.BattleScripts = {
}
// These moves can be used even if we aren't setting up to use them:
var SetupException = {
let SetupException = {
overheat:1, dracometeor:1, leafstorm:1,
voltswitch:1, uturn:1,
suckerpunch:1, extremespeed:1
@ -409,8 +411,8 @@ exports.BattleScripts = {
// handle HP IVs
if (move.id === 'hiddenpower') {
var HPivs = this.getType(move.type).HPivs;
for (var iv in HPivs) {
let HPivs = this.getType(move.type).HPivs;
for (let iv in HPivs) {
ivs[iv] = HPivs[iv];
}
}
@ -423,9 +425,9 @@ exports.BattleScripts = {
} else if (damagingMoves.length === 1) {
// Night Shade, Seismic Toss, etc. don't count:
if (!damagingMoves[0].damage) {
var damagingid = damagingMoves[0].id;
var damagingType = damagingMoves[0].type;
var replace = false;
let damagingid = damagingMoves[0].id;
let damagingType = damagingMoves[0].type;
let replace = false;
if (damagingid === 'suckerpunch' || damagingid === 'counter' || damagingid === 'mirrorcoat') {
// A player shouldn't be forced to rely upon the opponent attacking them to do damage.
if (!hasMove['encore'] && this.random(2)) replace = true;
@ -452,9 +454,9 @@ exports.BattleScripts = {
}
} else if (damagingMoves.length === 2) {
// If you have two attacks, neither is STAB, and the combo isn't Ice/Electric, Ghost/Fighting, or Dark/Fighting, reject one of them at random.
var type1 = damagingMoves[0].type, type2 = damagingMoves[1].type;
var typeCombo = [type1, type2].sort().join('/');
var rejectCombo = true;
let type1 = damagingMoves[0].type, type2 = damagingMoves[1].type;
let typeCombo = [type1, type2].sort().join('/');
let rejectCombo = true;
if (!(type1 in hasStab) && !(type2 in hasStab)) {
if (typeCombo === 'Electric/Ice' || typeCombo === 'Fighting/Ghost' || typeCombo === 'Dark/Fighting') rejectCombo = false;
} else {
@ -463,8 +465,8 @@ exports.BattleScripts = {
if (rejectCombo) this.sampleNoReplace(moves);
} else {
// If you have three or more attacks, and none of them are STAB, reject one of them at random.
var isStab = false;
for (var l = 0; l < damagingMoves.length; l++) {
let isStab = false;
for (let l = 0; l < damagingMoves.length; l++) {
if (hasStab[damagingMoves[l].type]) {
isStab = true;
break;
@ -477,7 +479,7 @@ exports.BattleScripts = {
// any moveset modification goes here
//moves[0] = 'Safeguard';
var abilities = [template.abilities['0']];
let abilities = [template.abilities['0']];
if (template.abilities['1']) {
abilities.push(template.abilities['1']);
}
@ -487,9 +489,9 @@ exports.BattleScripts = {
abilities.sort(function (a, b) {
return this.getAbility(b).rating - this.getAbility(a).rating;
}.bind(this));
var ability0 = this.getAbility(abilities[0]);
var ability1 = this.getAbility(abilities[1]);
var ability = ability0.name;
let ability0 = this.getAbility(abilities[0]);
let ability1 = this.getAbility(abilities[1]);
ability = ability0.name;
if (abilities[1]) {
if (ability0.rating <= ability1.rating) {
if (this.random(2)) {
@ -501,7 +503,7 @@ exports.BattleScripts = {
}
}
var rejectAbility = false;
let rejectAbility = false;
if (ability === 'Blaze' && !counter['blaze']) {
rejectAbility = true;
}
@ -622,7 +624,7 @@ exports.BattleScripts = {
} else if (hasMove['trick'] && hasMove['gyroball']) {
item = 'Iron Ball';
} else if (hasMove['trick'] || hasMove['switcheroo']) {
var randomNum = this.random(2);
let randomNum = this.random(2);
if (counter.Physical >= 3 && (template.baseStats.spe >= 95 || randomNum)) {
item = 'Choice Band';
} else if (counter.Special >= 3 && (template.baseStats.spe >= 95 || randomNum)) {
@ -664,9 +666,9 @@ exports.BattleScripts = {
item = 'Life Orb';
} else if (ability === 'Unburden' && (counter['Physical'] || counter['Special'])) {
// Give Unburden mons a random Gem of the type of one of their damaging moves
var eligibleTypes = [];
for (var i = 0; i < moves.length; i++) {
var move = this.getMove(moves[i]);
let eligibleTypes = [];
for (let i = 0; i < moves.length; i++) {
let move = this.getMove(moves[i]);
if (!move.basePower && !move.basePowerCallback) continue;
eligibleTypes.push(move.type);
}
@ -679,7 +681,7 @@ exports.BattleScripts = {
}
if ((hasMove['return'] || hasMove['hyperfang']) && !hasMove['facade']) {
// lol no
for (var j = 0; j < moves.length; j++) {
for (let j = 0; j < moves.length; j++) {
if (moves[j] === 'Return' || moves[j] === 'HyperFang') {
moves[j] = 'Facade';
break;
@ -700,9 +702,9 @@ exports.BattleScripts = {
} else if ((hasMove['eruption'] || hasMove['waterspout']) && !counter['Status']) {
item = 'Choice Scarf';
} else if (hasMove['substitute'] && hasMove['reversal']) {
var eligibleTypes = [];
for (var i = 0; i < moves.length; i++) {
var move = this.getMove(moves[i]);
let eligibleTypes = [];
for (let i = 0; i < moves.length; i++) {
let move = this.getMove(moves[i]);
if (!move.basePower && !move.basePowerCallback) continue;
eligibleTypes.push(move.type);
}
@ -747,7 +749,7 @@ exports.BattleScripts = {
}
// 95-86-82-78-74-70
var levelScale = {
let levelScale = {
LC: 95,
NFE: 90,
'LC Uber': 86,
@ -762,7 +764,7 @@ exports.BattleScripts = {
Unreleased: 74,
Uber: 70
};
var customScale = {
let customScale = {
// Really bad Pokemon and jokemons
Azurill: 99, Burmy: 99, Cascoon: 99, Caterpie: 99, Cleffa: 99, Combee: 99, Feebas: 99, Igglybuff: 99, Happiny: 99, Hoppip: 99,
Kakuna: 99, Kricketot: 99, Ledyba: 99, Magikarp: 99, Metapod: 99, Pichu: 99, Ralts: 99, Sentret: 99, Shedinja: 99,
@ -781,7 +783,7 @@ exports.BattleScripts = {
// Holistic judgment
Carvanha: 90, Blaziken: 74, "Deoxys-Defense": 74, "Deoxys-Speed": 74, Garchomp: 74, Thundurus: 74
};
var level = levelScale[template.tier] || 90;
let level = levelScale[template.tier] || 90;
if (customScale[template.name]) level = customScale[template.name];
if (template.name === 'Chandelure' && ability === 'Shadow Tag') level = 70;
@ -801,35 +803,35 @@ exports.BattleScripts = {
};
},
randomTeam: function (side) {
var pokemonLeft = 0;
var pokemon = [];
let pokemonLeft = 0;
let pokemon = [];
var pokemonPool = [];
for (var id in this.data.FormatsData) {
var template = this.getTemplate(id);
let pokemonPool = [];
for (let id in this.data.FormatsData) {
let template = this.getTemplate(id);
if (template.gen >= this.gen || !template.randomBattleMoves) continue;
pokemonPool.push(id);
}
// PotD stuff
var potd;
let potd;
if (Config.potd && 'Rule:potd' in this.getBanlistTable(this.getFormat())) {
potd = this.getTemplate(Config.potd);
}
var typeCount = {};
var typeComboCount = {};
var uberCount = 0;
var nuCount = 0;
let typeCount = {};
let typeComboCount = {};
let uberCount = 0;
let nuCount = 0;
while (pokemonPool.length && pokemonLeft < 6) {
var template = this.getTemplate(this.sampleNoReplace(pokemonPool));
let template = this.getTemplate(this.sampleNoReplace(pokemonPool));
if (!template.exists) continue;
// Not available on BW
if (template.species === 'Pichu-Spiky-eared') continue;
var tier = template.tier;
let tier = template.tier;
// This tries to limit the amount of Ubers and NUs on one team to promote "fun":
// LC Pokemon have a hard limit in place at 2; NFEs/NUs/Ubers are also limited to 2 but have a 20% chance of being added anyway.
// LC/NFE/NU Pokemon all share a counter (so having one of each would make the counter 3), while Ubers have a counter of their own.
@ -859,9 +861,9 @@ exports.BattleScripts = {
}
// Limit 2 of any type
var types = template.types;
var skip = false;
for (var t = 0; t < types.length; t++) {
let types = template.types;
let skip = false;
for (let t = 0; t < types.length; t++) {
if (typeCount[types[t]] > 1 && this.random(5) >= 1) {
skip = true;
break;
@ -883,10 +885,10 @@ exports.BattleScripts = {
}
}
var set = this.randomSet(template, pokemon.length);
let set = this.randomSet(template, pokemon.length);
// Limit 1 of any type combination
var typeCombo = types.join();
let typeCombo = types.join();
if (set.ability === 'Drought' || set.ability === 'Drizzle') {
// Drought and Drizzle don't count towards the type combo limit
typeCombo = set.ability;
@ -900,7 +902,7 @@ exports.BattleScripts = {
pokemonLeft++;
// Increment type counters
for (var t = 0; t < types.length; t++) {
for (let t = 0; t < types.length; t++) {
if (types[t] in typeCount) {
typeCount[types[t]]++;
} else {

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleStatuses = {
slp: {
inherit: true,
@ -29,7 +31,7 @@ exports.BattleStatuses = {
onStallMove: function () {
// this.effectData.counter should never be undefined here.
// However, just in case, use 1 if it is undefined.
var counter = this.effectData.counter || 1;
let counter = this.effectData.counter || 1;
if (counter >= 256) {
// 2^32 - special-cased because Battle.random(n) can't handle n > 2^16 - 1
return (this.random() * 4294967296 < 1);

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleAbilities = {
"swiftswim": {
inherit: true,
@ -27,7 +29,7 @@ exports.BattleAbilities = {
inherit: true,
onModifyMove: function (move) {
if (move.weather) {
var weather = move.weather;
let weather = move.weather;
move.weather = null;
move.onHit = function (target, source) {
this.setWeather(weather, source, this.getAbility('forecast'));
@ -146,7 +148,7 @@ exports.BattleAbilities = {
inherit: true,
onModifyMove: function (move) {
if (move.id === 'sunnyday') {
var weather = move.weather;
let weather = move.weather;
move.weather = null;
move.onHit = function (target, source) {
this.setWeather(weather, source, this.getAbility('flowergift'));
@ -269,7 +271,7 @@ exports.BattleAbilities = {
"clearbody": {
inherit: true,
onBoost: function (boost, target, source) {
for (var i in boost) {
for (let i in boost) {
if (boost[i] < 0) {
delete boost[i];
this.add("-message", target.name + "'s stats were not lowered! (placeholder)");
@ -280,7 +282,7 @@ exports.BattleAbilities = {
"whitesmoke": {
inherit: true,
onBoost: function (boost, target, source) {
for (var i in boost) {
for (let i in boost) {
if (boost[i] < 0) {
delete boost[i];
this.add("-message", target.name + "'s stats were not lowered! (placeholder)");
@ -300,10 +302,10 @@ exports.BattleAbilities = {
if (pokemon.template.baseSpecies === 'Genesect') {
if (!pokemon.getItem().onDrive) return;
}
var foeactive = pokemon.side.foe.active;
var totaldef = 0;
var totalspd = 0;
for (var i = 0; i < foeactive.length; i++) {
let foeactive = pokemon.side.foe.active;
let totaldef = 0;
let totalspd = 0;
for (let i = 0; i < foeactive.length; i++) {
if (!foeactive[i] || foeactive[i].fainted) continue;
totaldef += foeactive[i].stats.def;
totalspd += foeactive[i].stats.spd;
@ -407,7 +409,7 @@ exports.BattleAbilities = {
if (move.category !== "Status") {
this.debug('Adding Stench flinch');
if (!move.secondaries) move.secondaries = [];
for (var i = 0; i < move.secondaries.length; i++) {
for (let i = 0; i < move.secondaries.length; i++) {
if (move.secondaries[i].volatileStatus === 'flinch') return;
}
move.secondaries.push({
@ -508,8 +510,8 @@ exports.BattleAbilities = {
this.add('-start', target, 'move: Imprison');
},
onFoeDisableMove: function (pokemon) {
var foeMoves = this.effectData.target.moveset;
for (var f = 0; f < foeMoves.length; f++) {
let foeMoves = this.effectData.target.moveset;
for (let f = 0; f < foeMoves.length; f++) {
pokemon.disableMove(foeMoves[f].id, true);
}
pokemon.maybeDisabled = true;

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleItems = {
"burndrive": {
id: "burndrive",
@ -99,7 +101,7 @@ exports.BattleItems = {
basePower: 10
},
onDamage: function (damage, target, source, effect) {
var types = target.getTypes();
let types = target.getTypes();
if (types.length === 1 && types[0] === 'Fighting' &&
effect && effect.effectType === 'Move' &&
target.useItem()) {
@ -119,7 +121,7 @@ exports.BattleItems = {
inherit: true,
onBasePower: function (basePower, user, target, move) {
if (move.category === 'Special') {
var types = user.getTypes();
let types = user.getTypes();
if (types.length === 1 && types[0] === 'Psychic') {
return basePower * 1.2;
}
@ -131,7 +133,7 @@ exports.BattleItems = {
inherit: true,
onBasePower: function (basePower, user, target, move) {
if (move.category === 'Physical') {
var types = user.getTypes();
let types = user.getTypes();
if (types.length === 1 && types[0] === 'Fighting') {
return basePower * 1.2;
}
@ -177,7 +179,7 @@ exports.BattleItems = {
}
},
onFoeBasePower: function (basePower, attacker, defender, move) {
var GossamerWingUsers = {"Butterfree":1, "Masquerain":1, "Beautifly":1, "Mothim":1, "Vivillon":1};
let GossamerWingUsers = {"Butterfree":1, "Masquerain":1, "Beautifly":1, "Mothim":1, "Vivillon":1};
if (GossamerWingUsers[defender.template.species]) {
if (move.type === 'Rock' || move.type === 'Electric' || move.type === 'Ice') {
this.add('-message', "The attack was weakened by GoassamerWing!");
@ -186,7 +188,7 @@ exports.BattleItems = {
}
},
onDamage: function (damage, defender, attacker, effect) {
var GossamerWingUsers = {"Butterfree":1, "Masquerain":1, "Beautifly":1, "Mothim":1, "Vivillon":1};
let GossamerWingUsers = {"Butterfree":1, "Masquerain":1, "Beautifly":1, "Mothim":1, "Vivillon":1};
if (GossamerWingUsers[defender.template.species]) {
if (effect && effect.id === 'stealthrock') {
return damage / 2;
@ -194,7 +196,7 @@ exports.BattleItems = {
}
},
onAfterMoveSecondarySelf: function (source, target, move) {
var GossamerWingUsers = {"Butterfree":1, "Masquerain":1, "Beautifly":1, "Mothim":1, "Vivillon":1, "Venomoth":1, "Volcarona":1, "Dustox": 1, "Lilligant":1};
let GossamerWingUsers = {"Butterfree":1, "Masquerain":1, "Beautifly":1, "Mothim":1, "Vivillon":1, "Venomoth":1, "Volcarona":1, "Dustox": 1, "Lilligant":1};
if (move && move.effectType === 'Move' && move.category === 'Status' && GossamerWingUsers[source.template.species]) {
this.heal(source.maxhp / 16);
}

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleMovedex = {
/******************************************************************
Perfect accuracy moves:
@ -147,7 +149,7 @@ exports.BattleMovedex = {
if (target === source || move.flags['authentic'] || move.infiltrates) {
return;
}
var damage = this.getDamage(source, target, move);
let damage = this.getDamage(source, target, move);
if (!damage) {
return null;
}
@ -190,7 +192,7 @@ exports.BattleMovedex = {
onTryHit: function (target, source, move) {
if (target.volatiles.substitute || !move.flags['protect']) return;
this.add('-activate', target, 'Protect');
var lockedmove = source.getVolatile('lockedmove');
let lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is reset
if (source.volatiles['lockedmove'].duration === 2) {
@ -212,7 +214,7 @@ exports.BattleMovedex = {
onTryHit: function (target, source, move) {
if (target.volatiles.substitute || !move.flags['protect'] || move.category === 'Status') return;
this.add('-activate', target, 'Protect');
var lockedmove = source.getVolatile('lockedmove');
let lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is reset
if (source.volatiles['lockedmove'].duration === 2) {
@ -629,7 +631,7 @@ exports.BattleMovedex = {
return false;
}
this.add('-end', pokemon, 'Bide');
var target = this.effectData.sourceSide.active[this.effectData.sourcePosition];
let target = this.effectData.sourceSide.active[this.effectData.sourcePosition];
this.moveHit(target, pokemon, 'bide', {damage: this.effectData.totalDamage * 2});
return false;
}
@ -716,7 +718,7 @@ exports.BattleMovedex = {
if (pokemon.baseTemplate.species !== 'Meloetta' || pokemon.transformed) {
return;
}
var natureChange = {
let natureChange = {
'Modest': 'Adamant',
'Adamant': 'Modest',
'Timid': 'Jolly',
@ -724,22 +726,22 @@ exports.BattleMovedex = {
};
if (pokemon.template.speciesid === 'meloettapirouette' && pokemon.formeChange('Meloetta')) {
this.add('-formechange', pokemon, 'Meloetta');
var tmpAtkEVs = pokemon.set.evs.atk;
let tmpAtkEVs = pokemon.set.evs.atk;
pokemon.set.evs.atk = pokemon.set.evs.spa;
pokemon.set.evs.spa = tmpAtkEVs;
if (natureChange[pokemon.set.nature]) pokemon.set.nature = natureChange[pokemon.set.nature];
var Atk2SpA = (pokemon.boosts.spa || 0) - (pokemon.boosts.atk || 0);
let Atk2SpA = (pokemon.boosts.spa || 0) - (pokemon.boosts.atk || 0);
this.boost({
atk: Atk2SpA,
spa: -Atk2SpA
}, pokemon);
} else if (pokemon.formeChange('Meloetta-Pirouette')) {
this.add('-formechange', pokemon, 'Meloetta-Pirouette');
var tmpAtkEVs = pokemon.set.evs.atk;
let tmpAtkEVs = pokemon.set.evs.atk;
pokemon.set.evs.atk = pokemon.set.evs.spa;
pokemon.set.evs.spa = tmpAtkEVs;
if (natureChange[pokemon.set.nature]) pokemon.set.nature = natureChange[pokemon.set.nature];
var Atk2SpA = (pokemon.boosts.spa || 0) - (pokemon.boosts.atk || 0);
let Atk2SpA = (pokemon.boosts.spa || 0) - (pokemon.boosts.atk || 0);
this.boost({
atk: Atk2SpA,
spa: -Atk2SpA
@ -774,9 +776,9 @@ exports.BattleMovedex = {
this.add('-sidestart', side, 'move: Stealth Rock');
},
onSwitchIn: function (pokemon) {
var factor = 2;
let factor = 2;
if (pokemon.hasType('Flying')) factor = 4;
var damage = this.damage(pokemon.maxhp * factor / 16);
let damage = this.damage(pokemon.maxhp * factor / 16);
}
}
},
@ -808,15 +810,15 @@ exports.BattleMovedex = {
chance: 100,
self: {
onHit: function (target, source) {
var stats = [];
for (var i in target.boosts) {
let stats = [];
for (let i in target.boosts) {
if (i !== 'accuracy' && i !== 'evasion' && i !== 'atk' && target.boosts[i] < 6) {
stats.push(i);
}
}
if (stats.length) {
var i = stats[this.random(stats.length)];
var boost = {};
let i = stats[this.random(stats.length)];
let boost = {};
boost[i] = 1;
this.boost(boost);
} else {
@ -838,15 +840,15 @@ exports.BattleMovedex = {
chance: 100,
self: {
onHit: function (target, source) {
var stats = [];
for (var i in target.boosts) {
let stats = [];
for (let i in target.boosts) {
if (i !== 'accuracy' && i !== 'evasion' && i !== 'atk' && target.boosts[i] < 6) {
stats.push(i);
}
}
if (stats.length) {
var i = stats[this.random(stats.length)];
var boost = {};
let i = stats[this.random(stats.length)];
let boost = {};
boost[i] = 1;
this.boost(boost);
} else {
@ -862,15 +864,15 @@ exports.BattleMovedex = {
chance: 100,
self: {
onHit: function (target, source) {
var stats = [];
for (var i in target.boosts) {
let stats = [];
for (let i in target.boosts) {
if (i !== 'accuracy' && i !== 'evasion' && i !== 'atk' && target.boosts[i] < 6) {
stats.push(i);
}
}
if (stats.length) {
var i = stats[this.random(stats.length)];
var boost = {};
let i = stats[this.random(stats.length)];
let boost = {};
boost[i] = 1;
this.boost(boost);
} else {
@ -1029,7 +1031,7 @@ exports.BattleMovedex = {
inherit: true,
basePower: 80,
onBasePower: function (power, user) {
var GossamerWingUsers = {"Butterfree":1, "Venomoth":1, "Masquerain":1, "Dustox":1, "Beautifly":1, "Mothim":1, "Lilligant":1, "Volcarona":1, "Vivillon":1};
let GossamerWingUsers = {"Butterfree":1, "Venomoth":1, "Masquerain":1, "Dustox":1, "Beautifly":1, "Mothim":1, "Lilligant":1, "Volcarona":1, "Vivillon":1};
if (user.hasItem('stick') && GossamerWingUsers[user.template.species]) {
return power * 1.5;
}
@ -1218,13 +1220,13 @@ exports.BattleMovedex = {
inherit: true,
basePower: 30,
onBasePower: function (power, user) {
var doubled = false;
let doubled = false;
if (user.removeVolatile('leechseed')) {
this.add('-end', user, 'Leech Seed', '[from] move: Rapid Spin', '[of] ' + user);
doubled = true;
}
var sideConditions = {spikes:1, toxicspikes:1, stealthrock:1};
for (var i in sideConditions) {
let sideConditions = {spikes:1, toxicspikes:1, stealthrock:1};
for (let i in sideConditions) {
if (user.side.removeSideCondition(i)) {
this.add('-sideend', user.side, this.getEffect(i).name, '[from] move: Rapid Spin', '[of] ' + user);
doubled = true;
@ -1849,7 +1851,7 @@ exports.BattleMovedex = {
accuracy: 100,
onModifyMove: function (move, user) {
if (user.illusion) {
var illusionMoves = user.illusion.moves.filter(function (move) {
let illusionMoves = user.illusion.moves.filter(function (move) {
return this.getMove(move).category !== 'Status';
}, this);
if (!illusionMoves.length) return;
@ -1909,7 +1911,7 @@ exports.BattleMovedex = {
secondary: {
chance: 10,
onHit: function (target, source) {
var result = this.random(3);
let result = this.random(3);
if (result === 0) {
target.trySetStatus('brn', source);
} else if (result === 1) {

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleScripts = {
init: function () {
this.modData('Pokedex', 'cherrimsunshine').types = ['Grass', 'Fire'];
@ -118,7 +120,7 @@ exports.BattleScripts = {
this.modData('Pokedex', 'crawdaunt').abilities['H'] = 'Tough Claws';
// Every hidden ability becomes released
for (var i in this.data.FormatsData) {
for (let i in this.data.FormatsData) {
this.modData('FormatsData', i).unreleasedHidden = false;
}
}

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleStatuses = {
frz: {
effectType: 'Status',
@ -29,7 +31,7 @@ exports.BattleStatuses = {
return this.random(2, 4);
},
onResidual: function (target) {
var move = this.getMove(target.lastMove);
let move = this.getMove(target.lastMove);
if (!move.self || move.self.volatileStatus !== 'lockedmove') {
// don't lock, and bypass confusion for calming
delete target.volatiles['lockedmove'];
@ -48,7 +50,7 @@ exports.BattleStatuses = {
confusion: {
// this is a volatile status
onStart: function (target, source, sourceEffect) {
var result = this.runEvent('TryConfusion', target, source, sourceEffect);
let result = this.runEvent('TryConfusion', target, source, sourceEffect);
if (!result) return result;
if (sourceEffect && sourceEffect.id === 'lockedmove') {
this.add('-start', target, 'confusion', '[fatigue]');
@ -263,7 +265,7 @@ exports.BattleStatuses = {
// Cryogonal: infinite hail, Ice Body
onModifyMove: function (move) {
if (move.id === 'hail') {
var weather = move.weather;
let weather = move.weather;
move.weather = null;
move.onHit = function (target, source) {
this.setWeather(weather, source, this.getAbility('snowwarning'));
@ -286,7 +288,7 @@ exports.BattleStatuses = {
// Probopass: infinite sand
onModifyMove: function (move) {
if (move.id === 'sandstorm') {
var weather = move.weather;
let weather = move.weather;
move.weather = null;
move.onHit = function (target, source) {
this.setWeather(weather, source, this.getAbility('sandstream'));
@ -300,7 +302,7 @@ exports.BattleStatuses = {
// Phione: infinite rain
onModifyMove: function (move) {
if (move.id === 'raindance') {
var weather = move.weather;
let weather = move.weather;
move.weather = null;
move.onHit = function (target, source) {
this.setWeather(weather, source, this.getAbility('drizzle'));

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleMovedex = {
reflecttype: {
inherit: true,
@ -5,10 +7,10 @@ exports.BattleMovedex = {
if (source.template && source.template.num === 493) return false;
this.add('-start', source, 'typechange', '[from] move: Reflect Type', '[of] ' + target);
var typeMap = {};
let typeMap = {};
source.typesData = [];
for (var i = 0, l = target.typesData.length; i < l; i++) {
var typeData = target.typesData[i];
for (let i = 0, l = target.typesData.length; i < l; i++) {
let typeData = target.typesData[i];
if (typeMap[typeData.type]) continue;
typeMap[typeData.type] = true;

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleScripts = {
pokemon: {
formeChange: function (template, dontRecalculateStats) {
@ -8,7 +10,7 @@ exports.BattleScripts = {
this.template = template;
this.types = template.types;
this.typesData = [];
for (var i = 0, l = this.types.length; i < l; i++) {
for (let i = 0, l = this.types.length; i < l; i++) {
this.typesData.push({
type: this.types[i],
suppressed: false,
@ -25,12 +27,12 @@ exports.BattleScripts = {
}
if (!dontRecalculateStats) {
for (var statName in this.stats) {
var stat = this.template.baseStats[statName];
for (let statName in this.stats) {
let stat = this.template.baseStats[statName];
stat = Math.floor(Math.floor(2 * stat + this.set.ivs[statName] + Math.floor(this.set.evs[statName] / 4)) * this.level / 100 + 5);
// nature
var nature = this.battle.getNature(this.set.nature);
let nature = this.battle.getNature(this.set.nature);
if (statName === nature.plus) stat *= 1.1;
if (statName === nature.minus) stat *= 0.9;
this.baseStats[statName] = this.stats[statName] = Math.floor(stat);
@ -40,7 +42,7 @@ exports.BattleScripts = {
return true;
},
transformInto: function (pokemon, user) {
var template = pokemon.template;
let template = pokemon.template;
if (pokemon.fainted || pokemon.illusion || (pokemon.volatiles['substitute'] && this.battle.gen >= 5)) {
return false;
}
@ -51,10 +53,10 @@ exports.BattleScripts = {
return false;
}
this.transformed = true;
var typeMap = {};
let typeMap = {};
this.typesData = [];
for (var i = 0, l = pokemon.typesData.length; i < l; i++) {
var typeData = pokemon.typesData[i];
for (let i = 0, l = pokemon.typesData.length; i < l; i++) {
let typeData = pokemon.typesData[i];
if (typeMap[typeData.type]) continue;
typeMap[typeData.type] = true;
@ -73,7 +75,7 @@ exports.BattleScripts = {
});
}
}
for (var statName in this.stats) {
for (let statName in this.stats) {
this.stats[statName] = pokemon.stats[statName];
}
this.moveset = [];
@ -81,10 +83,10 @@ exports.BattleScripts = {
this.set.ivs = (this.battle.gen >= 5 ? this.set.ivs : pokemon.set.ivs);
this.hpType = (this.battle.gen >= 5 ? this.hpType : pokemon.hpType);
this.hpPower = (this.battle.gen >= 5 ? this.hpPower : pokemon.hpPower);
for (var i = 0; i < pokemon.moveset.length; i++) {
var move = this.battle.getMove(this.set.moves[i]);
var moveData = pokemon.moveset[i];
var moveName = moveData.move;
for (let i = 0; i < pokemon.moveset.length; i++) {
let move = this.battle.getMove(this.set.moves[i]);
let moveData = pokemon.moveset[i];
let moveName = moveData.move;
if (moveData.id === 'hiddenpower') {
moveName = 'Hidden Power ' + this.hpType;
}
@ -98,7 +100,7 @@ exports.BattleScripts = {
});
this.moves.push(toId(moveName));
}
for (var j in pokemon.boosts) {
for (let j in pokemon.boosts) {
this.boosts[j] = pokemon.boosts[j];
}
this.battle.add('-transform', this, pokemon);

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleMovedex = {
"acid": {
inherit: true,
@ -74,13 +76,13 @@ exports.BattleMovedex = {
},
onAfterMoveSelfPriority: 1,
onAfterMoveSelf: function (pokemon) {
var leecher = pokemon.side.foe.active[pokemon.volatiles['leechseed'].sourcePosition];
let leecher = pokemon.side.foe.active[pokemon.volatiles['leechseed'].sourcePosition];
if (!leecher || leecher.fainted || leecher.hp <= 0) {
this.debug('Nothing to leech into');
return;
}
var toLeech = this.clampIntRange(Math.floor(pokemon.maxhp / 16), 1);
var damage = this.damage(toLeech, pokemon, leecher);
let toLeech = this.clampIntRange(Math.floor(pokemon.maxhp / 16), 1);
let damage = this.damage(toLeech, pokemon, leecher);
if (damage) this.heal(damage, leecher, pokemon);
}
}
@ -163,7 +165,7 @@ exports.BattleMovedex = {
return null;
}
if (move.category === 'Status') {
var SubBlocked = {
let SubBlocked = {
leechseed:1, lockon:1, mindreader:1, nightmare:1
};
if (move.status || move.boosts || move.volatileStatus === 'confusion' || SubBlocked[move.id]) {
@ -173,7 +175,7 @@ exports.BattleMovedex = {
return;
}
if (move.volatileStatus && target === source) return;
var damage = this.getDamage(source, target, move);
let damage = this.getDamage(source, target, move);
if (!damage) return null;
damage = this.runEvent('SubDamage', target, source, move, damage);
if (!damage) return damage;

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleFormats = {
standard: {
effectType: 'Banlist',
@ -5,12 +7,12 @@ exports.BattleFormats = {
banlist: ['Unreleased', 'Illegal'],
onValidateSet: function (set) {
// limit one of each move in Standard
var moves = [];
let moves = [];
if (set.moves) {
var hasMove = {};
for (var i = 0; i < set.moves.length; i++) {
var move = this.getMove(set.moves[i]);
var moveid = move.id;
let hasMove = {};
for (let i = 0; i < set.moves.length; i++) {
let move = this.getMove(set.moves[i]);
let moveid = move.id;
if (hasMove[moveid]) continue;
hasMove[moveid] = true;
moves.push(set.moves[i]);

View File

@ -1,3 +1,5 @@
'use strict';
/**
* Stadium mechanics inherit from gen 1 mechanics, but fixes some stuff.
*/
@ -21,8 +23,8 @@ exports.BattleScripts = {
},
// This is run on Stadium after boosts and status changes.
recalculateStats: function () {
for (var statName in this.stats) {
var stat = this.template.baseStats[statName];
for (let statName in this.stats) {
let stat = this.template.baseStats[statName];
stat = Math.floor(Math.floor(2 * stat + this.set.ivs[statName] + Math.floor(this.set.evs[statName] / 4)) * this.level / 100 + 5);
this.baseStats[statName] = this.stats[statName] = Math.floor(stat);
this.modifiedStats[statName] = Math.floor(stat);
@ -40,9 +42,9 @@ exports.BattleScripts = {
},
// Stadium's fixed boosting function.
boostBy: function (boost) {
var changed = false;
for (var i in boost) {
var delta = boost[i];
let changed = false;
for (let i in boost) {
let delta = boost[i];
this.boosts[i] += delta;
if (this.boosts[i] > 6) {
delta -= this.boosts[i] - 6;
@ -81,7 +83,7 @@ exports.BattleScripts = {
}
}
pokemon.lastDamage = 0;
var lockedMove = this.runEvent('LockMove', pokemon);
let lockedMove = this.runEvent('LockMove', pokemon);
if (lockedMove === true) lockedMove = false;
if (!lockedMove && !pokemon.volatiles['partialtrappinglock']) {
pokemon.deductPP(move, null, target);
@ -113,9 +115,9 @@ exports.BattleScripts = {
}
},
tryMoveHit: function (target, pokemon, move, spreadHit) {
var boostTable = [1, 4 / 3, 5 / 3, 2, 7 / 3, 8 / 3, 3];
var doSelfDestruct = true;
var damage = 0;
let boostTable = [1, 4 / 3, 5 / 3, 2, 7 / 3, 8 / 3, 3];
let doSelfDestruct = true;
let damage = 0;
// First, check if the Pokémon is immune to this move.
if (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type] && !target.runImmunity(move.type, true)) {
@ -126,7 +128,7 @@ exports.BattleScripts = {
}
// Now, let's calculate the accuracy.
var accuracy = move.accuracy;
let accuracy = move.accuracy;
// Partial trapping moves: true accuracy while it lasts
if (pokemon.volatiles['partialtrappinglock']) {
@ -179,7 +181,7 @@ exports.BattleScripts = {
if (damage !== false) {
pokemon.lastDamage = 0;
if (move.multihit) {
var hits = move.multihit;
let hits = move.multihit;
if (hits.length) {
// Yes, it's hardcoded... meh
if (hits[0] === 2 && hits[1] === 5) {
@ -190,9 +192,9 @@ exports.BattleScripts = {
}
hits = Math.floor(hits);
// In gen 1, all the hits have the same damage for multihits move
var moveDamage = 0;
var firstDamage;
var i;
let moveDamage = 0;
let firstDamage;
let i;
for (i = 0; i < hits && target.hp && pokemon.hp; i++) {
if (i === 0) {
// First hit, we calculate
@ -243,11 +245,11 @@ exports.BattleScripts = {
return damage;
},
moveHit: function (target, pokemon, move, moveData, isSecondary, isSelf) {
var damage = 0;
let damage = 0;
move = this.getMoveCopy(move);
if (!isSecondary && !isSelf) this.setActiveMove(move, pokemon, target);
var hitResult = true;
let hitResult = true;
if (!moveData) moveData = move;
if (move.ignoreImmunity === undefined) {
@ -255,8 +257,8 @@ exports.BattleScripts = {
}
// We get the sub to the target to see if it existed
var targetSub = (target) ? target.volatiles['substitute'] : false;
var targetHadSub = (targetSub !== null && targetSub !== false && (typeof targetSub !== 'undefined'));
let targetSub = (target) ? target.volatiles['substitute'] : false;
let targetHadSub = (targetSub !== null && targetSub !== false && (typeof targetSub !== 'undefined'));
if (target) {
hitResult = this.singleEvent('TryHit', moveData, {}, target, pokemon, move);
@ -297,7 +299,7 @@ exports.BattleScripts = {
}
if (target) {
var didSomething = false;
let didSomething = false;
damage = this.getDamage(pokemon, target, moveData);
if ((damage || damage === 0) && !target.fainted) {
@ -317,7 +319,7 @@ exports.BattleScripts = {
this.boost(moveData.boosts, target, pokemon, move);
}
if (moveData.heal && !target.fainted) {
var d = target.heal(Math.floor(target.maxhp * moveData.heal[0] / moveData.heal[1]));
let d = target.heal(Math.floor(target.maxhp * moveData.heal[0] / moveData.heal[1]));
if (!d) {
this.add('-fail', target);
return false;
@ -382,13 +384,13 @@ exports.BattleScripts = {
// Apply move secondaries.
if (moveData.secondaries) {
for (var i = 0; i < moveData.secondaries.length; i++) {
for (let i = 0; i < moveData.secondaries.length; i++) {
// We check here whether to negate the probable secondary status if it's para, burn, or freeze.
// In the game, this is checked and if true, the random number generator is not called.
// That means that a move that does not share the type of the target can status it.
// If a move that was not fire-type would exist on Gen 1, it could burn a Pokémon.
if (!(moveData.secondaries[i].status && moveData.secondaries[i].status in {'par':1, 'brn':1, 'frz':1} && target && target.hasType(move.type))) {
var effectChance = Math.floor(moveData.secondaries[i].chance * 255 / 100);
let effectChance = Math.floor(moveData.secondaries[i].chance * 255 / 100);
if (typeof moveData.secondaries[i].chance === 'undefined' || this.random(256) < effectChance) {
this.moveHit(target, pokemon, move, moveData.secondaries[i], true, isSelf);
}
@ -453,10 +455,10 @@ exports.BattleScripts = {
if (!move.defensiveCategory) move.defensiveCategory = move.category;
// '???' is typeless damage: used for Struggle and Confusion etc
if (!move.type) move.type = '???';
var type = move.type;
let type = move.type;
// We get the base power and apply basePowerCallback if necessary.
var basePower = move.basePower;
let basePower = move.basePower;
if (move.basePowerCallback) {
basePower = move.basePowerCallback.call(this, pokemon, target, move);
}
@ -473,7 +475,7 @@ exports.BattleScripts = {
if (!move.crit) {
// In Stadium, the critical chance is based on speed.
// First, we get the base speed and store it. Then we add 76. This is our current crit chance.
var critChance = pokemon.template.baseStats['spe'] + 76;
let critChance = pokemon.template.baseStats['spe'] + 76;
// Now we right logical shift it two places, essentially dividing by 4 and flooring it.
critChance = critChance >> 2;
@ -524,15 +526,15 @@ exports.BattleScripts = {
basePower = this.clampIntRange(basePower, 1);
// We now check attacker's and defender's stats.
var level = pokemon.level;
var attacker = pokemon;
var defender = target;
let level = pokemon.level;
let attacker = pokemon;
let defender = target;
if (move.useTargetOffensive) attacker = target;
if (move.useSourceDefensive) defender = pokemon;
var atkType = (move.category === 'Physical') ? 'atk' : 'spa';
var defType = (move.defensiveCategory === 'Physical') ? 'def' : 'spd';
var attack = attacker.getStat(atkType);
var defense = defender.getStat(defType);
let atkType = (move.category === 'Physical') ? 'atk' : 'spa';
let defType = (move.defensiveCategory === 'Physical') ? 'def' : 'spd';
let attack = attacker.getStat(atkType);
let defense = defender.getStat(defType);
// In gen 1, screen effect is applied here.
if ((defType === 'def' && defender.volatiles['reflect']) || (defType === 'spd' && defender.volatiles['lightscreen'])) {
this.debug('Screen doubling (Sp)Def');
@ -573,7 +575,7 @@ exports.BattleScripts = {
// Let's go with the calculation now that we have what we need.
// We do it step by step just like the game does.
var damage = level * 2;
let damage = level * 2;
damage = Math.floor(damage / 5);
damage += 2;
damage *= basePower;
@ -589,7 +591,7 @@ exports.BattleScripts = {
// Type effectiveness.
// The order here is not correct, must change to check the move versus each type.
var totalTypeMod = this.getEffectiveness(type, target);
let totalTypeMod = this.getEffectiveness(type, target);
// Super effective attack
if (totalTypeMod > 0) {
if (!suppressMessages) this.add('-supereffective', target);
@ -647,7 +649,7 @@ exports.BattleScripts = {
target.battle.lastDamage = damage;
damage = target.damage(damage, source, effect);
if (source) source.lastDamage = damage;
var name = effect.fullname;
let name = effect.fullname;
if (name === 'tox') name = 'psn';
switch (effect.id) {
case 'partiallytrapped':

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleStatuses = {
brn: {
effectType: 'Status',

View File

@ -1,3 +1,5 @@
'use strict';
exports.BattleMovedex = {
rapidspin: {
inherit: true,
@ -6,8 +8,8 @@ exports.BattleMovedex = {
if (pokemon.hp && pokemon.removeVolatile('leechseed')) {
this.add('-end', pokemon, 'Leech Seed', '[from] move: Rapid Spin', '[of] ' + pokemon);
}
var sideConditions = {spikes:1, toxicspikes:1, stealthrock:1, stickyweb:1};
for (var i in sideConditions) {
let sideConditions = {spikes:1, toxicspikes:1, stealthrock:1, stickyweb:1};
for (let i in sideConditions) {
if (i === 'stealthrock' && pokemon.side.sideConditions[i] && pokemon.side.sideConditions[i].type === 'Ghost') continue;
if (pokemon.hp && pokemon.side.removeSideCondition(i)) {
this.add('-sideend', pokemon.side, this.getEffect(i).name, '[from] move: Rapid Spin', '[of] ' + pokemon);
@ -35,7 +37,7 @@ exports.BattleMovedex = {
pokemon.side.removeSideCondition('stealthrock');
this.add('-sideend', pokemon.side, 'move: Stealth Rock', '[of] ' + pokemon);
} else if (pokemon.runImmunity(this.effectData.type)) {
var typeMod = this.clampIntRange(this.getEffectiveness(this.effectData.type, pokemon), -6, 6);
let typeMod = this.clampIntRange(this.getEffectiveness(this.effectData.type, pokemon), -6, 6);
this.damage(pokemon.maxhp * Math.pow(2, typeMod) / 8);
}
}

View File

@ -1,8 +1,10 @@
'use strict';
exports.BattleScripts = {
init: function () {
for (var i in this.data.Pokedex) {
var tier = null;
var adjustment = 0;
for (let i in this.data.Pokedex) {
let tier = null;
let adjustment = 0;
if (this.data.FormatsData[i]) tier = this.data.FormatsData[i].tier;
if (!tier && this.data.Pokedex[i].baseSpecies) tier = this.data.FormatsData[toId(this.data.Pokedex[i].baseSpecies)].tier;
@ -26,7 +28,7 @@ exports.BattleScripts = {
}
if (adjustment) {
for (var j in this.data.Pokedex[i].baseStats) {
for (let j in this.data.Pokedex[i].baseStats) {
this.modData('Pokedex', i).baseStats[j] = this.clampIntRange(this.data.Pokedex[i].baseStats[j] + adjustment, 1, 255);
}
}

View File

@ -6,12 +6,13 @@
*
* @license MIT license
*/
'use strict';
var fs = require('fs');
var path = require('path');
const fs = require('fs');
const path = require('path');
/* global Monitor: true */
var Monitor = module.exports = {
const Monitor = module.exports = {
/*********************************************************
* Logging
@ -68,8 +69,8 @@ var Monitor = module.exports = {
* Counts a connection. Returns true if the connection should be terminated for abuse.
*/
countConnection: function (ip, name) {
var now = Date.now();
var duration = now - this.connectionTimes[ip];
let now = Date.now();
let duration = now - this.connectionTimes[ip];
name = (name ? ': ' + name : '');
if (ip in this.connections && duration < 30 * 60 * 1000) {
this.connections[ip]++;
@ -78,7 +79,7 @@ var Monitor = module.exports = {
return true;
} else if (this.connections[ip] > 500) {
if (this.connections[ip] % 500 === 0) {
var c = this.connections[ip] / 500;
let c = this.connections[ip] / 500;
if (c < 5 || c % 2 === 0 && c < 10 || c % 5 === 0) {
this.adminlog('[ResourceMonitor] Banned IP ' + ip + ' has connected ' + this.connections[ip] + ' times in the last ' + duration.duration() + name);
}
@ -94,8 +95,8 @@ var Monitor = module.exports = {
* Counts a battle. Returns true if the connection should be terminated for abuse.
*/
countBattle: function (ip, name) {
var now = Date.now();
var duration = now - this.battleTimes[ip];
let now = Date.now();
let duration = now - this.battleTimes[ip];
name = (name ? ': ' + name : '');
if (ip in this.battles && duration < 30 * 60 * 1000) {
this.battles[ip]++;
@ -113,8 +114,8 @@ var Monitor = module.exports = {
* Counts battle prep. Returns true if too much
*/
countPrepBattle: function (ip) {
var now = Date.now();
var duration = now - this.battlePrepTimes[ip];
let now = Date.now();
let duration = now - this.battlePrepTimes[ip];
if (ip in this.battlePreps && duration < 3 * 60 * 1000) {
this.battlePreps[ip]++;
if (this.battlePreps[ip] > 6) {
@ -129,8 +130,8 @@ var Monitor = module.exports = {
* Counts group chat creation. Returns true if too much.
*/
countGroupChat: function (ip) {
var now = Date.now();
var duration = now - this.groupChatTimes[ip];
let now = Date.now();
let duration = now - this.groupChatTimes[ip];
if (ip in this.groupChats && duration < 60 * 60 * 1000) {
this.groupChats[ip]++;
if (this.groupChats[ip] > 4) {
@ -154,8 +155,8 @@ var Monitor = module.exports = {
}
},
writeNetworkUse: function () {
var buf = '';
for (var i in this.networkUse) {
let buf = '';
for (let i in this.networkUse) {
buf += '' + this.networkUse[i] + '\t' + this.networkCount[i] + '\t' + i + '\n';
}
fs.writeFile(path.resolve(__dirname, 'logs/networkuse.tsv'), buf);
@ -168,12 +169,12 @@ var Monitor = module.exports = {
* Counts roughly the size of an object to have an idea of the server load.
*/
sizeOfObject: function (object) {
var objectList = [];
var stack = [object];
var bytes = 0;
let objectList = [];
let stack = [object];
let bytes = 0;
while (stack.length) {
var value = stack.pop();
let value = stack.pop();
if (typeof value === 'boolean') {
bytes += 4;
} else if (typeof value === 'string') {
@ -182,7 +183,7 @@ var Monitor = module.exports = {
bytes += 8;
} else if (typeof value === 'object' && objectList.indexOf(value) < 0) {
objectList.push(value);
for (var i in value) stack.push(value[i]);
for (let i in value) stack.push(value[i]);
}
}
@ -192,8 +193,8 @@ var Monitor = module.exports = {
* Controls the amount of times a cmd command is used
*/
countCmd: function (ip, name) {
var now = Date.now();
var duration = now - this.cmdsTimes[ip];
let now = Date.now();
let duration = now - this.cmdsTimes[ip];
name = (name ? ': ' + name : '');
if (!this.cmdsTotal) this.cmdsTotal = {lastCleanup: 0, count: 0};
if (now - this.cmdsTotal.lastCleanup > 60 * 1000) {

24
repl.js
View File

@ -1,13 +1,15 @@
'use strict';
const REPL_ENABLED = false;
var fs = require('fs');
var path = require('path');
var net = require('net');
const fs = require('fs');
const path = require('path');
const net = require('net');
var sockets = [];
let sockets = [];
function cleanup() {
for (var s = 0; s < sockets.length; ++s) {
for (let s = 0; s < sockets.length; ++s) {
try {
fs.unlinkSync(sockets[s]);
} catch (e) {}
@ -28,23 +30,23 @@ exports.start = function (prefix, suffix, evalFunction) {
if (!REPL_ENABLED) return;
if (process.platform === 'win32') return; // Windows doesn't support sockets mounted in the filesystem
var resolvedPrefix = path.resolve(__dirname, Config.replsocketprefix || 'logs/repl', prefix);
let resolvedPrefix = path.resolve(__dirname, Config.replsocketprefix || 'logs/repl', prefix);
if (!evalFunction) {
evalFunction = suffix;
suffix = "";
}
var name = resolvedPrefix + suffix;
let name = resolvedPrefix + suffix;
if (prefix === 'app') {
// Clear out any old sockets
var directory = path.dirname(resolvedPrefix);
let directory = path.dirname(resolvedPrefix);
fs.readdirSync(directory).forEach(function (file) {
var stat = fs.statSync(directory + '/' + file);
let stat = fs.statSync(directory + '/' + file);
if (!stat.isSocket()) {
return;
}
var socket = net.connect(directory + '/' + file, function () {
let socket = net.connect(directory + '/' + file, function () {
socket.end();
socket.destroy();
}).on('error', function () {
@ -67,7 +69,7 @@ exports.start = function (prefix, suffix, evalFunction) {
}).on('exit', socket.end.bind(socket));
socket.on('error', socket.destroy.bind(socket));
}).listen(name, function () {
fs.chmodSync(name, Config.replsocketmode || 0600);
fs.chmodSync(name, Config.replsocketmode || '0600');
sockets.push(name);
}).on('error', function (e) {
if (e.code === "EADDRINUSE") {

376
rooms.js

File diff suppressed because it is too large Load Diff

View File

@ -11,14 +11,16 @@
* @license MIT license
*/
var battles = Object.create(null);
'use strict';
var SimulatorProcess = (function () {
let battles = Object.create(null);
let SimulatorProcess = (function () {
function SimulatorProcess() {
this.process = require('child_process').fork('battle-engine.js', {cwd: __dirname});
this.process.on('message', function (message) {
var lines = message.split('\n');
var battle = battles[lines[0]];
let lines = message.split('\n');
let battle = battles[lines[0]];
if (battle) {
battle.receive(lines);
}
@ -30,7 +32,7 @@ var SimulatorProcess = (function () {
SimulatorProcess.processes = [];
SimulatorProcess.spawn = function (num) {
if (!num) num = Config.simulatorprocesses || 1;
for (var i = this.processes.length; i < num; ++i) {
for (let i = this.processes.length; i < num; ++i) {
this.processes.push(new SimulatorProcess());
}
};
@ -42,8 +44,8 @@ var SimulatorProcess = (function () {
this.spawn();
};
SimulatorProcess.acquire = function () {
var process = this.processes[0];
for (var i = 1; i < this.processes.length; ++i) {
let process = this.processes[0];
for (let i = 1; i < this.processes.length; ++i) {
if (this.processes[i].load < process.load) {
process = this.processes[i];
}
@ -68,9 +70,9 @@ var SimulatorProcess = (function () {
// Create the initial set of simulator processes.
SimulatorProcess.spawn();
var slice = Array.prototype.slice;
let slice = Array.prototype.slice;
var Battle = (function () {
let Battle = (function () {
function Battle(id, format, rated, room) {
if (battles[id]) {
throw new Error("Battle with ID " + id + " already exists.");
@ -119,7 +121,7 @@ var Battle = (function () {
this.process.send('' + this.id + '|' + slice.call(arguments).join('|'));
};
Battle.prototype.sendFor = function (user, action) {
var player = this.playerTable[toId(user)];
let player = this.playerTable[toId(user)];
if (!player) {
Monitor.debug('SENDFOR FAILED in ' + this.id + ': Player doesn\'t exist: ' + user.name);
return;
@ -128,8 +130,8 @@ var Battle = (function () {
this.send.apply(this, [action, player].concat(slice.call(arguments, 2)));
};
Battle.prototype.sendForOther = function (user, action) {
var opposite = {'p1':'p2', 'p2':'p1'};
var player = this.playerTable[toId(user)];
let opposite = {'p1':'p2', 'p2':'p1'};
let player = this.playerTable[toId(user)];
if (!player) return;
this.send.apply(this, [action, opposite[player]].concat(slice.call(arguments, 2)));
@ -138,7 +140,6 @@ var Battle = (function () {
Battle.prototype.rqid = '';
Battle.prototype.inactiveQueued = false;
Battle.prototype.receive = function (lines) {
var player;
Monitor.activeIp = this.activeIp;
switch (lines[1]) {
case 'update':
@ -160,23 +161,25 @@ var Battle = (function () {
this.inactiveSide = -1;
break;
case 'sideupdate':
player = this.getPlayer(lines[2]);
case 'sideupdate': {
let player = this.getPlayer(lines[2]);
if (player) {
player.sendTo(this.id, lines[3]);
}
break;
}
case 'callback':
player = this.getPlayer(lines[2]);
case 'callback': {
let player = this.getPlayer(lines[2]);
if (player) {
player.sendTo(this.id, '|callback|' + lines[3]);
}
break;
}
case 'request':
player = this.getPlayer(lines[2]);
var rqid = lines[3];
case 'request': {
let player = this.getPlayer(lines[2]);
let rqid = lines[3];
if (player) {
this.requests[player.userid] = lines[4];
player.sendTo(this.id, '|request|' + lines[4]);
@ -186,6 +189,7 @@ var Battle = (function () {
this.inactiveQueued = true;
}
break;
}
case 'log':
this.logData = JSON.parse(lines[2]);
@ -203,7 +207,7 @@ var Battle = (function () {
};
Battle.prototype.resendRequest = function (connection) {
var request = this.requests[connection.user];
let request = this.requests[connection.user];
if (request) {
connection.sendTo(this.id, '|request|' + request);
}
@ -247,7 +251,7 @@ var Battle = (function () {
user.battles[this.id] = true;
}
this.players[slot] = (user || null);
var oldplayerid = this.playerids[slot];
let oldplayerid = this.playerids[slot];
if (oldplayerid) {
if (user) {
this.requests[user.userid] = this.requests[oldplayerid];
@ -257,8 +261,8 @@ var Battle = (function () {
this.playerids[slot] = (user ? user.userid : null);
this.playerTable = {};
this.active = !this.ended;
for (var i = 0, len = this.players.length; i < len; i++) {
var player = this.players[i];
for (let i = 0, len = this.players.length; i < len; i++) {
let player = this.players[i];
this['p' + (i + 1)] = player ? player.name : '';
if (!player) {
this.active = false;
@ -291,13 +295,13 @@ var Battle = (function () {
if (this.players[slot] || slot >= this.players.length) return false;
if (user === this.players[0] || user === this.players[1]) return false;
for (var i = 0; i < user.connections.length; i++) {
var connection = user.connections[i];
for (let i = 0; i < user.connections.length; i++) {
let connection = user.connections[i];
Sockets.subchannelMove(connection.worker, this.id, slot + 1, connection.socketid);
}
this.setPlayer(user, slot);
var message = '' + user.avatar;
let message = '' + user.avatar;
if (!this.started) {
message += "\n" + team;
}
@ -307,9 +311,9 @@ var Battle = (function () {
};
Battle.prototype.rename = function () {
for (var i = 0, len = this.players.length; i < len; i++) {
var player = this.players[i];
var playerid = this.playerids[i];
for (let i = 0, len = this.players.length; i < len; i++) {
let player = this.players[i];
let playerid = this.playerids[i];
if (!player) continue;
if (player.userid !== playerid) {
this.setPlayer(player, i);
@ -319,12 +323,12 @@ var Battle = (function () {
};
Battle.prototype.leave = function (user) {
for (var i = 0, len = this.players.length; i < len; i++) {
var player = this.players[i];
for (let i = 0, len = this.players.length; i < len; i++) {
let player = this.players[i];
if (player === user) {
this.sendFor(user, 'leave');
for (var j = 0; j < user.connections.length; j++) {
var connection = user.connections[j];
for (let j = 0; j < user.connections.length; j++) {
let connection = user.connections[j];
Sockets.subchannelMove(connection.worker, this.id, '0', connection.socketid);
}
this.setPlayer(null, i);

View File

@ -11,7 +11,9 @@
* @license MIT license
*/
var cluster = require('cluster');
'use strict';
const cluster = require('cluster');
global.Config = require('./config/config');
if (cluster.isMaster) {
@ -19,46 +21,55 @@ if (cluster.isMaster) {
exec: require('path').resolve(__dirname, 'sockets.js')
});
var workers = exports.workers = {};
let workers = exports.workers = {};
var spawnWorker = exports.spawnWorker = function () {
var worker = cluster.fork({PSPORT: Config.port, PSBINDADDR: Config.bindaddress || '', PSNOSSL: Config.ssl ? 0 : 1});
var id = worker.id;
let spawnWorker = exports.spawnWorker = function () {
let worker = cluster.fork({PSPORT: Config.port, PSBINDADDR: Config.bindaddress || '', PSNOSSL: Config.ssl ? 0 : 1});
let id = worker.id;
workers[id] = worker;
worker.on('message', function (data) {
// console.log('master received: ' + data);
switch (data.charAt(0)) {
case '*': // *socketid, ip
case '*': {
// *socketid, ip
// connect
var nlPos = data.indexOf('\n');
let nlPos = data.indexOf('\n');
Users.socketConnect(worker, id, data.substr(1, nlPos - 1), data.substr(nlPos + 1));
break;
}
case '!': // !socketid
case '!': {
// !socketid
// disconnect
Users.socketDisconnect(worker, id, data.substr(1));
break;
}
case '<': // <socketid, message
case '<': {
// <socketid, message
// message
var nlPos = data.indexOf('\n');
let nlPos = data.indexOf('\n');
Users.socketReceive(worker, id, data.substr(1, nlPos - 1), data.substr(nlPos + 1));
break;
}
default:
// unhandled
}
});
};
var workerCount = typeof Config.workers !== 'undefined' ? Config.workers : 1;
for (var i = 0; i < workerCount; i++) {
let workerCount = typeof Config.workers !== 'undefined' ? Config.workers : 1;
for (let i = 0; i < workerCount; i++) {
spawnWorker();
}
var killWorker = exports.killWorker = function (worker) {
var idd = worker.id + '-';
var count = 0;
for (var connectionid in Users.connections) {
let killWorker = exports.killWorker = function (worker) {
let idd = worker.id + '-';
let count = 0;
for (let connectionid in Users.connections) {
if (connectionid.substr(idd.length) === idd) {
var connection = Users.connections[connectionid];
let connection = Users.connections[connectionid];
Users.socketDisconnect(worker, worker.id, connection.socketid);
count++;
}
@ -70,10 +81,10 @@ if (cluster.isMaster) {
return count;
};
var killPid = exports.killPid = function (pid) {
let killPid = exports.killPid = function (pid) {
pid = '' + pid;
for (var id in workers) {
var worker = workers[id];
for (let id in workers) {
let worker = workers[id];
if (pid === '' + worker.process.pid) {
return killWorker(worker);
}
@ -89,7 +100,7 @@ if (cluster.isMaster) {
};
exports.channelBroadcast = function (channelid, message) {
for (var workerid in workers) {
for (let workerid in workers) {
workers[workerid].send('#' + channelid + '\n' + message);
}
};
@ -104,7 +115,7 @@ if (cluster.isMaster) {
};
exports.subchannelBroadcast = function (channelid, message) {
for (var workerid in workers) {
for (let workerid in workers) {
workers[workerid].send(':' + channelid + '\n' + message);
}
};
@ -140,18 +151,18 @@ if (cluster.isMaster) {
});
}
var app = require('http').createServer();
var appssl;
let app = require('http').createServer();
let appssl;
if (Config.ssl) {
appssl = require('https').createServer(Config.ssl.options);
}
try {
(function () {
var nodestatic = require('node-static');
var cssserver = new nodestatic.Server('./config');
var avatarserver = new nodestatic.Server('./config/avatars');
var staticserver = new nodestatic.Server('./static');
var staticRequestHandler = function (request, response) {
let nodestatic = require('node-static');
let cssserver = new nodestatic.Server('./config');
let avatarserver = new nodestatic.Server('./config/avatars');
let staticserver = new nodestatic.Server('./static');
let staticRequestHandler = function (request, response) {
// console.log("static rq: " + request.socket.remoteAddress + ":" + request.socket.remotePort + " -> " + request.socket.localAddress + ":" + request.socket.localPort + " - " + request.method + " " + request.url + " " + request.httpVersion + " - " + request.rawHeaders.join('|'));
request.resume();
request.addListener('end', function () {
@ -159,7 +170,7 @@ if (cluster.isMaster) {
Config.customhttpresponse(request, response)) {
return;
}
var server;
let server;
if (request.url === '/custom.css') {
server = cssserver;
} else if (request.url.substr(0, 9) === '/avatars/') {
@ -192,9 +203,9 @@ if (cluster.isMaster) {
// This is the main server that handles users connecting to our server
// and doing things on our server.
var sockjs = require('sockjs');
let sockjs = require('sockjs');
var server = sockjs.createServer({
let server = sockjs.createServer({
sockjs_url: "//play.pokemonshowdown.com/js/lib/sockjs-0.3.min.js",
log: function (severity, message) {
if (severity === 'error') console.log('ERROR: ' + message);
@ -203,13 +214,13 @@ if (cluster.isMaster) {
websocket: !Config.disablewebsocket
});
var sockets = {};
var channels = {};
var subchannels = {};
let sockets = {};
let channels = {};
let subchannels = {};
// Deal with phantom connections.
var sweepClosedSockets = function () {
for (var s in sockets) {
let sweepClosedSockets = function () {
for (let s in sockets) {
if (sockets[s].protocol === 'xhr-streaming' &&
sockets[s]._session &&
sockets[s]._session.recv) {
@ -229,14 +240,14 @@ if (cluster.isMaster) {
}
}
};
var interval = setInterval(sweepClosedSockets, 1000 * 60 * 10);
let interval = setInterval(sweepClosedSockets, 1000 * 60 * 10);
process.on('message', function (data) {
// console.log('worker received: ' + data);
var socket = null;
var channel = null;
var socketid = null;
var channelid = null;
let socket = null, socketid = '';
let channel = null, channelid = '';
let subchannel = null, subchannelid = '';
switch (data.charAt(0)) {
case '$': // $code
eval(data.substr(1));
@ -256,27 +267,32 @@ if (cluster.isMaster) {
}
break;
case '>': // >socketid, message
case '>': {
// >socketid, message
// message
var nlLoc = data.indexOf('\n');
let nlLoc = data.indexOf('\n');
socket = sockets[data.substr(1, nlLoc - 1)];
if (!socket) return;
socket.write(data.substr(nlLoc + 1));
break;
}
case '#': // #channelid, message
case '#': {
// #channelid, message
// message to channel
var nlLoc = data.indexOf('\n');
let nlLoc = data.indexOf('\n');
channel = channels[data.substr(1, nlLoc - 1)];
var message = data.substr(nlLoc + 1);
let message = data.substr(nlLoc + 1);
for (socketid in channel) {
channel[socketid].write(message);
}
break;
}
case '+': // +channelid, socketid
case '+': {
// +channelid, socketid
// add to channel
var nlLoc = data.indexOf('\n');
let nlLoc = data.indexOf('\n');
socketid = data.substr(nlLoc + 1);
socket = sockets[socketid];
if (!socket) return;
@ -285,18 +301,20 @@ if (cluster.isMaster) {
if (!channel) channel = channels[channelid] = Object.create(null);
channel[socketid] = socket;
break;
}
case '-': // -channelid, socketid
case '-': {
// -channelid, socketid
// remove from channel
var nlLoc = data.indexOf('\n');
var channelid = data.slice(1, nlLoc);
let nlLoc = data.indexOf('\n');
channelid = data.slice(1, nlLoc);
channel = channels[channelid];
if (!channel) return;
var socketid = data.slice(nlLoc + 1);
socketid = data.slice(nlLoc + 1);
delete channel[socketid];
if (subchannels[channelid]) delete subchannels[channelid][socketid];
var isEmpty = true;
for (var socketid in channel) {
let isEmpty = true;
for (let socketid in channel) {
isEmpty = false;
break;
}
@ -305,16 +323,18 @@ if (cluster.isMaster) {
delete subchannels[channelid];
}
break;
}
case '.': // .channelid, subchannelid, socketid
case '.': {
// .channelid, subchannelid, socketid
// move subchannel
var nlLoc = data.indexOf('\n');
var channelid = data.slice(1, nlLoc);
var nlLoc2 = data.indexOf('\n', nlLoc + 1);
var subchannelid = data.slice(nlLoc + 1, nlLoc2);
var socketid = data.slice(nlLoc2 + 1);
let nlLoc = data.indexOf('\n');
channelid = data.slice(1, nlLoc);
let nlLoc2 = data.indexOf('\n', nlLoc + 1);
subchannelid = data.slice(nlLoc + 1, nlLoc2);
socketid = data.slice(nlLoc2 + 1);
var subchannel = subchannels[channelid];
subchannel = subchannels[channelid];
if (!subchannel) subchannel = subchannels[channelid] = Object.create(null);
if (subchannelid === '0') {
delete subchannel[socketid];
@ -322,15 +342,17 @@ if (cluster.isMaster) {
subchannel[socketid] = subchannelid;
}
break;
}
case ':': // :channelid, message
case ':': {
// :channelid, message
// message to subchannel
var nlLoc = data.indexOf('\n');
var channelid = data.slice(1, nlLoc);
var channel = channels[channelid];
var subchannel = subchannels[channelid];
var message = data.substr(nlLoc + 1);
var messages = [null, null, null];
let nlLoc = data.indexOf('\n');
channelid = data.slice(1, nlLoc);
channel = channels[channelid];
subchannel = subchannels[channelid];
let message = data.substr(nlLoc + 1);
let messages = [null, null, null];
for (socketid in channel) {
switch (subchannel ? subchannel[socketid] : '0') {
case '1':
@ -355,6 +377,9 @@ if (cluster.isMaster) {
}
break;
}
default:
}
});
process.on('disconnect', function () {
@ -362,8 +387,8 @@ if (cluster.isMaster) {
});
// this is global so it can be hotpatched if necessary
var isTrustedProxyIp = Cidr.checker(Config.proxyip);
var socketCounter = 0;
let isTrustedProxyIp = Cidr.checker(Config.proxyip);
let socketCounter = 0;
server.on('connection', function (socket) {
if (!socket) {
// For reasons that are not entirely clear, SockJS sometimes triggers
@ -376,13 +401,13 @@ if (cluster.isMaster) {
} catch (e) {}
return;
}
var socketid = socket.id = (++socketCounter);
let socketid = socket.id = (++socketCounter);
sockets[socket.id] = socket;
if (isTrustedProxyIp(socket.remoteAddress)) {
var ips = (socket.headers['x-forwarded-for'] || '').split(',');
var ip;
let ips = (socket.headers['x-forwarded-for'] || '').split(',');
let ip;
while ((ip = ips.pop())) {
ip = ip.trim();
if (!isTrustedProxyIp(ip)) {
@ -398,7 +423,7 @@ if (cluster.isMaster) {
// drop empty messages (DDoS?)
if (!message) return;
// drop blank messages (DDoS?)
var pipeIndex = message.indexOf('|');
let pipeIndex = message.indexOf('|');
if (pipeIndex < 0 || pipeIndex === message.length - 1) return;
// drop legacy JSON messages
if (!message.charAt) throw new Error('message: ' + JSON.stringify(message));
@ -409,7 +434,7 @@ if (cluster.isMaster) {
socket.on('close', function () {
process.send('!' + socketid);
delete sockets[socketid];
for (var channelid in channels) {
for (let channelid in channels) {
delete channels[channelid][socketid];
}
});

View File

@ -7,23 +7,25 @@
* @license MIT license
*/
var Validator;
'use strict';
let Validator;
if (!process.send) {
var validationCount = 0;
var pendingValidations = {};
let validationCount = 0;
let pendingValidations = {};
var ValidatorProcess = (function () {
let ValidatorProcess = (function () {
function ValidatorProcess() {
this.process = require('child_process').fork('team-validator.js', {cwd: __dirname});
var self = this;
let self = this;
this.process.on('message', function (message) {
// Protocol:
// success: "[id]|1[details]"
// failure: "[id]|0[details]"
var pipeIndex = message.indexOf('|');
var id = message.substr(0, pipeIndex);
var success = (message.charAt(pipeIndex + 1) === '1');
let pipeIndex = message.indexOf('|');
let id = message.substr(0, pipeIndex);
let success = (message.charAt(pipeIndex + 1) === '1');
if (pendingValidations[id]) {
ValidatorProcess.release(self);
@ -36,8 +38,8 @@ if (!process.send) {
ValidatorProcess.prototype.active = true;
ValidatorProcess.processes = [];
ValidatorProcess.spawn = function () {
var num = Config.validatorprocesses || 1;
for (var i = 0; i < num; ++i) {
let num = Config.validatorprocesses || 1;
for (let i = 0; i < num; ++i) {
this.processes.push(new ValidatorProcess());
}
};
@ -49,8 +51,8 @@ if (!process.send) {
this.spawn();
};
ValidatorProcess.acquire = function () {
var process = this.processes[0];
for (var i = 1; i < this.processes.length; ++i) {
let process = this.processes[0];
for (let i = 1; i < this.processes.length; ++i) {
if (this.processes[i].load < process.load) {
process = this.processes[i];
}
@ -65,7 +67,7 @@ if (!process.send) {
}
};
ValidatorProcess.send = function (format, team, callback) {
var process = this.acquire();
let process = this.acquire();
pendingValidations[validationCount] = callback;
try {
process.process.send('' + validationCount + '|' + format + '|' + team);
@ -85,7 +87,7 @@ if (!process.send) {
ValidatorProcess.send(format, team, callback);
};
var synchronousValidators = {};
let synchronousValidators = {};
exports.validateTeamSync = function (format, team) {
if (!synchronousValidators[format]) synchronousValidators[format] = new Validator(format);
return synchronousValidators[format].validateTeam(team);
@ -132,33 +134,33 @@ if (!process.send) {
require('./repl.js').start('team-validator-', process.pid, function (cmd) { return eval(cmd); });
var validators = {};
let validators = {};
var respond = function respond(id, success, details) {
let respond = function respond(id, success, details) {
process.send(id + (success ? '|1' : '|0') + details);
};
process.on('message', function (message) {
// protocol:
// "[id]|[format]|[team]"
var pipeIndex = message.indexOf('|');
var pipeIndex2 = message.indexOf('|', pipeIndex + 1);
var id = message.substr(0, pipeIndex);
var format = message.substr(pipeIndex + 1, pipeIndex2 - pipeIndex - 1);
let pipeIndex = message.indexOf('|');
let pipeIndex2 = message.indexOf('|', pipeIndex + 1);
let id = message.substr(0, pipeIndex);
let format = message.substr(pipeIndex + 1, pipeIndex2 - pipeIndex - 1);
if (!validators[format]) validators[format] = new Validator(format);
var parsedTeam = [];
let parsedTeam = [];
parsedTeam = Tools.fastUnpackTeam(message.substr(pipeIndex2 + 1));
var problems;
let problems;
try {
problems = validators[format].validateTeam(parsedTeam);
} catch (err) {
var stack = err.stack + '\n\n' +
let stack = err.stack + '\n\n' +
'Additional information:\n' +
'format = ' + format + '\n' +
'team = ' + message.substr(pipeIndex2 + 1) + '\n';
var fakeErr = {stack: stack};
let fakeErr = {stack: stack};
require('./crashlogger.js')(fakeErr, 'A team validation');
problems = ["Your team crashed the team validator. We've been automatically notified and will fix this crash, but you should use a different team for now."];
@ -167,7 +169,7 @@ if (!process.send) {
if (problems && problems.length) {
respond(id, false, problems.join('\n'));
} else {
var packedTeam = Tools.packTeam(parsedTeam);
let packedTeam = Tools.packTeam(parsedTeam);
// console.log('FROM: ' + message.substr(pipeIndex2 + 1));
// console.log('TO: ' + packedTeam);
respond(id, true, packedTeam);
@ -186,16 +188,16 @@ Validator = (function () {
}
Validator.prototype.validateTeam = function (team) {
var format = Tools.getFormat(this.format);
let format = Tools.getFormat(this.format);
if (format.validateTeam) return format.validateTeam.call(this, team);
return this.baseValidateTeam(team);
};
Validator.prototype.baseValidateTeam = function (team) {
var format = this.format;
var tools = this.tools;
let format = this.format;
let tools = this.tools;
var problems = [];
let problems = [];
tools.getBanlistTable(format);
if (format.team) {
return false;
@ -207,7 +209,7 @@ Validator = (function () {
return ["You sent invalid team data. If you're not using a custom client, please report this as a bug."];
}
var lengthRange = format.teamLength && format.teamLength.validate;
let lengthRange = format.teamLength && format.teamLength.validate;
if (!lengthRange) {
lengthRange = [1, 6];
if (format.gameType === 'doubles') lengthRange[0] = 2;
@ -216,32 +218,32 @@ Validator = (function () {
if (team.length < lengthRange[0]) return ["You must bring at least " + lengthRange[0] + " Pok\u00E9mon."];
if (team.length > lengthRange[1]) return ["You may only bring up to " + lengthRange[1] + " Pok\u00E9mon."];
var teamHas = {};
for (var i = 0; i < team.length; i++) {
let teamHas = {};
for (let i = 0; i < team.length; i++) {
if (!team[i]) return ["You sent invalid team data. If you're not using a custom client, please report this as a bug."];
var setProblems = (format.validateSet || this.validateSet).call(this, team[i], teamHas);
let setProblems = (format.validateSet || this.validateSet).call(this, team[i], teamHas);
if (setProblems) {
problems = problems.concat(setProblems);
}
}
for (var i = 0; i < format.teamBanTable.length; i++) {
var bannedCombo = true;
for (var j = 0; j < format.teamBanTable[i].length; j++) {
for (let i = 0; i < format.teamBanTable.length; i++) {
let bannedCombo = true;
for (let j = 0; j < format.teamBanTable[i].length; j++) {
if (!teamHas[format.teamBanTable[i][j]]) {
bannedCombo = false;
break;
}
}
if (bannedCombo) {
var clause = format.name ? " by " + format.name : '';
let clause = format.name ? " by " + format.name : '';
problems.push("Your team has the combination of " + format.teamBanTable[i].join(' + ') + ", which is banned" + clause + ".");
}
}
if (format.ruleset) {
for (var i = 0; i < format.ruleset.length; i++) {
var subformat = tools.getFormat(format.ruleset[i]);
for (let i = 0; i < format.ruleset.length; i++) {
let subformat = tools.getFormat(format.ruleset[i]);
if (subformat.onValidateTeam) {
problems = problems.concat(subformat.onValidateTeam.call(tools, team, format, teamHas) || []);
}
@ -256,29 +258,29 @@ Validator = (function () {
};
Validator.prototype.validateSet = function (set, teamHas, flags) {
var format = this.format;
var tools = this.tools;
let format = this.format;
let tools = this.tools;
var problems = [];
let problems = [];
if (!set) {
return ["This is not a Pokemon."];
}
var template = tools.getTemplate(Tools.getString(set.species));
let template = tools.getTemplate(Tools.getString(set.species));
if (!template.exists) {
return ["The Pokemon '" + set.species + "' does not exist."];
}
set.species = template.species;
set.name = tools.getName(set.name);
var item = tools.getItem(Tools.getString(set.item));
let item = tools.getItem(Tools.getString(set.item));
set.item = item.name;
var ability = tools.getAbility(Tools.getString(set.ability));
let ability = tools.getAbility(Tools.getString(set.ability));
set.ability = ability.name;
if (!Array.isArray(set.moves)) set.moves = [];
var maxLevel = format.maxLevel || 100;
var maxForcedLevel = format.maxForcedLevel || maxLevel;
let maxLevel = format.maxLevel || 100;
let maxForcedLevel = format.maxForcedLevel || maxLevel;
if (!set.level) {
set.level = (format.defaultLevel || maxLevel);
}
@ -291,17 +293,17 @@ Validator = (function () {
set.level = maxLevel;
}
var nameTemplate = tools.getTemplate(set.name);
let nameTemplate = tools.getTemplate(set.name);
if (nameTemplate.exists && nameTemplate.name.toLowerCase() === set.name.toLowerCase()) set.name = null;
set.species = set.species;
set.name = set.name || set.species;
var name = set.species;
let name = set.species;
if (set.species !== set.name) name = set.name + " (" + set.species + ")";
var isHidden = false;
var lsetData = {set:set, format:format};
let isHidden = false;
let lsetData = {set:set, format:format};
if (flags) Object.merge(lsetData, flags);
var setHas = {};
let setHas = {};
if (!template || !template.abilities) {
set.species = 'Unown';
@ -309,8 +311,8 @@ Validator = (function () {
}
if (format.ruleset) {
for (var i = 0; i < format.ruleset.length; i++) {
var subformat = tools.getFormat(format.ruleset[i]);
for (let i = 0; i < format.ruleset.length; i++) {
let subformat = tools.getFormat(format.ruleset[i]);
if (subformat.onChangeSet) {
problems = problems.concat(subformat.onChangeSet.call(tools, set, format) || []);
}
@ -335,10 +337,10 @@ Validator = (function () {
}
}
var banlistTable = tools.getBanlistTable(format);
let banlistTable = tools.getBanlistTable(format);
var check = template.id;
var clause = '';
let check = template.id;
let clause = '';
setHas[check] = true;
if (banlistTable[check]) {
clause = typeof banlistTable[check] === 'string' ? " by " + banlistTable[check] : '';
@ -412,9 +414,9 @@ Validator = (function () {
// in the cartridge-compliant set validator: rulesets.js:pokemon
set.moves = set.moves.slice(0, 24);
for (var i = 0; i < set.moves.length; i++) {
for (let i = 0; i < set.moves.length; i++) {
if (!set.moves[i]) continue;
var move = tools.getMove(Tools.getString(set.moves[i]));
let move = tools.getMove(Tools.getString(set.moves[i]));
if (!move.exists) return ['"' + move.name + '" is an invalid move.'];
set.moves[i] = move.name;
check = move.id;
@ -429,9 +431,9 @@ Validator = (function () {
}
if (banlistTable['illegal']) {
var problem = this.checkLearnset(move, template, lsetData);
let problem = this.checkLearnset(move, template, lsetData);
if (problem) {
var problemString = name + " can't learn " + move.name;
let problemString = name + " can't learn " + move.name;
if (problem.type === 'incompatible') {
if (isHidden) {
problemString = problemString.concat(" because it's incompatible with its ability or another move.");
@ -452,12 +454,12 @@ Validator = (function () {
if (lsetData.sources && lsetData.sources.length === 1 && !lsetData.sourcesBefore) {
// we're restricted to a single source
var source = lsetData.sources[0];
let source = lsetData.sources[0];
if (source.charAt(1) === 'S') {
// it's an event
var eventData = null;
var splitSource = source.substr(2).split(' ');
var eventTemplate = tools.getTemplate(splitSource[1]);
let eventData = null;
let splitSource = source.substr(2).split(' ');
let eventTemplate = tools.getTemplate(splitSource[1]);
if (eventTemplate.eventPokemon) eventData = eventTemplate.eventPokemon[parseInt(splitSource[0], 10)];
if (eventData) {
if (eventData.nature && eventData.nature !== set.nature) {
@ -487,8 +489,8 @@ Validator = (function () {
if (!lsetData.sources && lsetData.sourcesBefore < 5) {
problems.push(name + " has a hidden ability - it can't have moves only learned before gen 5.");
} else if (lsetData.sources && template.gender && template.gender !== 'F' && !{'Nidoran-M':1, 'Nidorino':1, 'Nidoking':1, 'Volbeat':1}[template.species]) {
var compatibleSource = false;
for (var i = 0, len = lsetData.sources.length; i < len; i++) {
let compatibleSource = false;
for (let i = 0, len = lsetData.sources.length; i < len; i++) {
if (lsetData.sources[i].charAt(1) === 'E' || (lsetData.sources[i].substr(0, 2) === '5D' && set.level >= 10)) {
compatibleSource = true;
break;
@ -507,7 +509,7 @@ Validator = (function () {
problems.push(name + " has a gen 4 ability and isn't evolved - it can't use anything from gen 3.");
}
if (!lsetData.sources && lsetData.sourcesBefore >= 3 && (isHidden || tools.gen <= 5) && template.gen <= lsetData.sourcesBefore) {
var oldAbilities = tools.mod('gen' + lsetData.sourcesBefore).getTemplate(set.species).abilities;
let oldAbilities = tools.mod('gen' + lsetData.sourcesBefore).getTemplate(set.species).abilities;
if (ability.name !== oldAbilities['0'] && ability.name !== oldAbilities['1'] && !oldAbilities['H']) {
problems.push(name + " has moves incompatible with its ability.");
}
@ -517,7 +519,7 @@ Validator = (function () {
template = tools.getTemplate(item.megaStone);
}
if (template.tier) {
var tier = template.tier;
let tier = template.tier;
if (tier.charAt(0) === '(') tier = tier.slice(1, -1);
setHas[toId(tier)] = true;
if (banlistTable[tier]) {
@ -526,13 +528,13 @@ Validator = (function () {
}
if (teamHas) {
for (var i in setHas) {
for (let i in setHas) {
teamHas[i] = true;
}
}
for (var i = 0; i < format.setBanTable.length; i++) {
var bannedCombo = true;
for (var j = 0; j < format.setBanTable[i].length; j++) {
for (let i = 0; i < format.setBanTable.length; i++) {
let bannedCombo = true;
for (let j = 0; j < format.setBanTable[i].length; j++) {
if (!setHas[format.setBanTable[i][j]]) {
bannedCombo = false;
break;
@ -545,8 +547,8 @@ Validator = (function () {
}
if (format.ruleset) {
for (var i = 0; i < format.ruleset.length; i++) {
var subformat = tools.getFormat(format.ruleset[i]);
for (let i = 0; i < format.ruleset.length; i++) {
let subformat = tools.getFormat(format.ruleset[i]);
if (subformat.onValidateSet) {
problems = problems.concat(subformat.onValidateSet.call(tools, set, format, setHas, teamHas) || []);
}
@ -565,27 +567,27 @@ Validator = (function () {
};
Validator.prototype.checkLearnset = function (move, template, lsetData) {
var tools = this.tools;
let tools = this.tools;
move = toId(move);
template = tools.getTemplate(template);
lsetData = lsetData || {};
lsetData.eggParents = lsetData.eggParents || [];
var set = (lsetData.set || (lsetData.set = {}));
var format = (lsetData.format || (lsetData.format = {}));
var alreadyChecked = {};
var level = set.level || 100;
let set = (lsetData.set || (lsetData.set = {}));
let format = (lsetData.format || (lsetData.format = {}));
let alreadyChecked = {};
let level = set.level || 100;
var isHidden = false;
let isHidden = false;
if (set.ability && tools.getAbility(set.ability).name === template.abilities['H']) isHidden = true;
var incompatibleHidden = false;
let incompatibleHidden = false;
var limit1 = true;
var sketch = false;
var blockedHM = false;
let limit1 = true;
let sketch = false;
let blockedHM = false;
var sometimesPossible = false; // is this move in the learnset at all?
let sometimesPossible = false; // is this move in the learnset at all?
// This is a pretty complicated algorithm
@ -602,18 +604,18 @@ Validator = (function () {
// source at or before this gen is possible."
// set of possible sources of a pokemon with this move, represented as an array
var sources = [];
let sources = [];
// the equivalent of adding "every source at or before this gen" to sources
var sourcesBefore = 0;
var noPastGen = !!format.requirePentagon;
let sourcesBefore = 0;
let noPastGen = !!format.requirePentagon;
// since Gen 3, Pokemon cannot be traded to past generations
var noFutureGen = tools.gen >= 3 ? true : !!(format.banlistTable && format.banlistTable['tradeback']);
let noFutureGen = tools.gen >= 3 ? true : !!(format.banlistTable && format.banlistTable['tradeback']);
do {
alreadyChecked[template.speciesid] = true;
// STABmons hack to avoid copying all of validateSet to formats
if (move !== 'chatter' && lsetData['ignorestabmoves'] && lsetData['ignorestabmoves'][this.tools.getMove(move).category]) {
var types = template.types;
let types = template.types;
if (template.species === 'Shaymin') types = ['Grass', 'Flying'];
if (template.baseSpecies === 'Hoopa') types = ['Psychic', 'Ghost', 'Dark'];
if (types.indexOf(tools.getMove(move).type) >= 0) return false;
@ -621,7 +623,7 @@ Validator = (function () {
if (template.learnset) {
if (template.learnset[move] || template.learnset['sketch']) {
sometimesPossible = true;
var lset = template.learnset[move];
let lset = template.learnset[move];
if (!lset || template.speciesid === 'smeargle') {
if (tools.getMove(move).noSketch) return true;
lset = template.learnset['sketch'];
@ -629,8 +631,8 @@ Validator = (function () {
}
if (typeof lset === 'string') lset = [lset];
for (var i = 0, len = lset.length; i < len; i++) {
var learned = lset[i];
for (let i = 0, len = lset.length; i < len; i++) {
let learned = lset[i];
if (noPastGen && learned.charAt(0) !== '6') continue;
if (noFutureGen && parseInt(learned.charAt(0), 10) > tools.gen) continue;
if (learned.charAt(0) !== '6' && isHidden && !tools.mod('gen' + learned.charAt(0)).getTemplate(template.species).abilities['H']) {
@ -681,14 +683,14 @@ Validator = (function () {
sources.push(learned);
continue;
}
var eggGroups = template.eggGroups;
let eggGroups = template.eggGroups;
if (!eggGroups) continue;
if (eggGroups[0] === 'Undiscovered') eggGroups = tools.getTemplate(template.evos[0]).eggGroups;
var atLeastOne = false;
var fromSelf = (learned.substr(1) === 'Eany');
let atLeastOne = false;
let fromSelf = (learned.substr(1) === 'Eany');
learned = learned.substr(0, 2);
for (var templateid in tools.data.Pokedex) {
var dexEntry = tools.getTemplate(templateid);
for (let templateid in tools.data.Pokedex) {
let dexEntry = tools.getTemplate(templateid);
if (
// CAP pokemon can't breed
!dexEntry.isNonstandard &&
@ -706,20 +708,20 @@ Validator = (function () {
// If the mon already has an egg move by a father, other different father can't give it another egg move.
if (lsetData.eggParents.indexOf(dexEntry.species) >= 0) {
// We have to test here that the father of both moves doesn't get both by egg breeding
var learnsFrom = false;
var lsetToCheck = (dexEntry.learnset[lsetData.hasEggMove]) ? dexEntry.learnset[lsetData.hasEggMove] : dexEntry.learnset['sketch'];
let learnsFrom = false;
let lsetToCheck = (dexEntry.learnset[lsetData.hasEggMove]) ? dexEntry.learnset[lsetData.hasEggMove] : dexEntry.learnset['sketch'];
if (!lsetToCheck || !lsetToCheck.length) continue;
for (var ltype = 0; ltype < lsetToCheck.length; ltype++) {
for (let ltype = 0; ltype < lsetToCheck.length; ltype++) {
// Save first learning type. After that, only save it if we have egg and it's not egg.
learnsFrom = !learnsFrom || learnsFrom === 'E' ? lsetToCheck[ltype].charAt(1) : learnsFrom;
}
// If the previous egg move was learnt by the father through an egg as well:
if (learnsFrom === 'E') {
var secondLearnsFrom = false;
var lsetToCheck = (dexEntry.learnset[move]) ? dexEntry.learnset[move] : dexEntry.learnset['sketch'];
let secondLearnsFrom = false;
let lsetToCheck = (dexEntry.learnset[move]) ? dexEntry.learnset[move] : dexEntry.learnset['sketch'];
// Have here either the move learnset or sketch learnset for Smeargle.
if (lsetToCheck) {
for (var ltype = 0; ltype < lsetToCheck.length; ltype++) {
for (let ltype = 0; ltype < lsetToCheck.length; ltype++) {
// Save first learning type. After that, only save it if we have egg and it's not egg.
secondLearnsFrom = !secondLearnsFrom || secondLearnsFrom === 'E' ? dexEntry.learnset[move][ltype].charAt(1) : secondLearnsFrom;
}
@ -761,7 +763,7 @@ Validator = (function () {
lsetData.blockedGen2Move = lsetData.hasGen2Move && tools.gen === 2 && (lsetData.sourcesBefore ? lsetData.sourcesBefore : sourcesBefore) > 0 && (lsetData.sourcesBefore ? lsetData.sourcesBefore : sourcesBefore) < parseInt(learned.charAt(0), 10);
} else {
// DW Pokemon are at level 10 or at the evolution level
var minLevel = (template.evoLevel && template.evoLevel > 10) ? template.evoLevel : 10;
let minLevel = (template.evoLevel && template.evoLevel > 10) ? template.evoLevel : 10;
if (set.level < minLevel) continue;
sources.push(learned);
}
@ -770,9 +772,9 @@ Validator = (function () {
}
if (format.mimicGlitch && template.gen < 5) {
// include the Mimic Glitch when checking this mon's learnset
var glitchMoves = {metronome:1, copycat:1, transform:1, mimic:1, assist:1};
var getGlitch = false;
for (var i in glitchMoves) {
let glitchMoves = {metronome:1, copycat:1, transform:1, mimic:1, assist:1};
let getGlitch = false;
for (let i in glitchMoves) {
if (template.learnset[i]) {
if (!(i === 'mimic' && tools.getAbility(set.ability).gen === 4 && !template.prevo)) {
getGlitch = true;
@ -832,10 +834,10 @@ Validator = (function () {
if (sourcesBefore || lsetData.sourcesBefore) {
// having sourcesBefore is the equivalent of having everything before that gen
// in sources, so we fill the other array in preparation for intersection
var learned;
let learned;
if (sourcesBefore && lsetData.sources) {
if (!sources) sources = [];
for (var i = 0, len = lsetData.sources.length; i < len; i++) {
for (let i = 0, len = lsetData.sources.length; i < len; i++) {
learned = lsetData.sources[i];
if (parseInt(learned.charAt(0), 10) <= sourcesBefore) {
sources.push(learned);
@ -845,7 +847,7 @@ Validator = (function () {
}
if (lsetData.sourcesBefore && sources) {
if (!lsetData.sources) lsetData.sources = [];
for (var i = 0, len = sources.length; i < len; i++) {
for (let i = 0, len = sources.length; i < len; i++) {
learned = sources[i];
if (parseInt(learned.charAt(0), 10) <= lsetData.sourcesBefore) {
lsetData.sources.push(learned);
@ -856,7 +858,7 @@ Validator = (function () {
}
if (sources) {
if (lsetData.sources) {
var intersectSources = lsetData.sources.intersect(sources);
let intersectSources = lsetData.sources.intersect(sources);
if (!intersectSources.length && !(sourcesBefore && lsetData.sourcesBefore)) {
return {type:'incompatible'};
}

View File

@ -1,8 +1,10 @@
var assert = require('assert');
var room;
'use strict';
var userUtils = require('./../../dev-tools/users-utils.js');
var User = userUtils.User;
const assert = require('assert');
let room;
let userUtils = require('./../../dev-tools/users-utils.js');
let User = userUtils.User;
describe('Rooms features', function () {
describe('Rooms', function () {
@ -27,16 +29,16 @@ describe('Rooms features', function () {
});
describe('BattleRoom', function () {
var room;
let room;
afterEach(function () {
if (room) room.expire();
});
it('should allow two users to join the battle', function () {
var p1 = new User();
var p2 = new User();
var packedTeam = 'Weavile||lifeorb||swordsdance,knockoff,iceshard,iciclecrash|Jolly|,252,,,4,252|||||';
var options = [{rated: false, tour: false}, {rated: false, tour: true}, {rated: true, tour: false}, {rated: true, tour: true}];
let p1 = new User();
let p2 = new User();
let packedTeam = 'Weavile||lifeorb||swordsdance,knockoff,iceshard,iciclecrash|Jolly|,252,,,4,252|||||';
let options = [{rated: false, tour: false}, {rated: false, tour: true}, {rated: true, tour: false}, {rated: true, tour: true}];
options.forEach(function (option) {
room = Rooms.global.startBattle(p1, p2, 'customgame', packedTeam, packedTeam, option);
if (room.active) return assert.ok(room.battle.players.none(null)); // Automatically joined

View File

@ -1,11 +1,13 @@
var assert = require('assert');
var userUtils = require('./../../dev-tools/users-utils.js');
var User = userUtils.User;
'use strict';
const assert = require('assert');
let userUtils = require('./../../dev-tools/users-utils.js');
let User = userUtils.User;
describe('Simulator abstraction layer features', function () {
describe('Battle', function () {
describe('player identifiers', function () {
var p1, p2, room;
let p1, p2, room;
afterEach(function () {
if (p1) {
p1.disconnectAll();
@ -19,7 +21,7 @@ describe('Simulator abstraction layer features', function () {
});
it('should not get out of sync in rated battles on rename', function () {
var packedTeam = 'Weavile||lifeorb||swordsdance,knockoff,iceshard,iciclecrash|Jolly|,252,,,4,252|||||';
let packedTeam = 'Weavile||lifeorb||swordsdance,knockoff,iceshard,iciclecrash|Jolly|,252,,,4,252|||||';
p1 = new User();
p2 = new User();
p1.forceRename("Missingno."); // Don't do this at home
@ -29,8 +31,8 @@ describe('Simulator abstraction layer features', function () {
room.joinBattle(p2, packedTeam);
}
p1.resetName();
for (var i = 0; i < room.battle.playerids.length; i++) {
var curId = room.battle.playerids[i];
for (let i = 0; i < room.battle.playerids.length; i++) {
let curId = room.battle.playerids[i];
assert.strictEqual(room.battle.playerTable[curId], 'p' + (i + 1));
if (!curId) {
assert.ok(!room.battle.players[i]);

View File

@ -1,8 +1,10 @@
var assert = require('assert');
'use strict';
var userUtils = require('./../../dev-tools/users-utils.js');
var Connection = userUtils.Connection;
var User = userUtils.User;
const assert = require('assert');
let userUtils = require('./../../dev-tools/users-utils.js');
let Connection = userUtils.Connection;
let User = userUtils.User;
describe('Users features', function () {
describe('Users', function () {
@ -28,8 +30,8 @@ describe('Users features', function () {
describe('#disconnectAll', function () {
[1, 2].forEach(function (totalConnections) {
it('should drop all ' + totalConnections + ' connection(s) and mark as inactive', function () {
var user = new User();
var iterations = totalConnections;
let user = new User();
let iterations = totalConnections;
while (--iterations) user.mergeConnection(new Connection());
user.disconnectAll();
@ -38,26 +40,26 @@ describe('Users features', function () {
});
it('should unref all ' + totalConnections + ' connection(s)', function () {
var user = new User();
var iterations = totalConnections;
let user = new User();
let iterations = totalConnections;
while (--iterations) user.mergeConnection(new Connection());
var connections = user.connections.slice();
let connections = user.connections.slice();
user.disconnectAll();
for (var i = 0; i < totalConnections; i++) {
for (let i = 0; i < totalConnections; i++) {
assert.strictEqual(Users.connections[connections[i].id], undefined);
}
});
it('should clear `user` property for all ' + totalConnections + ' connection(s)', function () {
var user = new User();
var iterations = totalConnections;
let user = new User();
let iterations = totalConnections;
while (--iterations) user.mergeConnection(new Connection());
var connections = user.connections.slice();
let connections = user.connections.slice();
user.disconnectAll();
for (var i = 0; i < totalConnections; i++) {
for (let i = 0; i < totalConnections; i++) {
assert.strictEqual(connections[i].user, null);
}
});
@ -65,28 +67,28 @@ describe('Users features', function () {
});
describe('#ban', function () {
afterEach(function () {
for (var ip in Users.bannedIps) {
for (let ip in Users.bannedIps) {
delete Users.bannedIps[ip];
}
});
it('should disconnect every user at that IP', function () {
var users = ['127.0.0.1', '127.0.0.1'].map(function (ip) {return new User(new Connection(ip));});
let users = ['127.0.0.1', '127.0.0.1'].map(function (ip) {return new User(new Connection(ip));});
users[0].ban();
assert.strictEqual(users[0].connected, false);
assert.strictEqual(users[1].connected, false);
});
it('should not disconnect users at other IPs', function () {
var users = ['127.0.0.1', '127.0.0.2'].map(function (ip) {return new User(new Connection(ip));});
let users = ['127.0.0.1', '127.0.0.2'].map(function (ip) {return new User(new Connection(ip));});
users[0].ban();
assert.strictEqual(users[1].connected, true);
});
it('should update IP count properly', function () {
var user = new User();
let user = new User();
user.ban();
for (var ip in user.ips) {
for (let ip in user.ips) {
assert.strictEqual(user.ips[ip], 0);
}
});

View File

@ -1,8 +1,10 @@
var Checker = require('jscs');
var assert = require('assert');
'use strict';
const Checker = require('jscs');
const assert = require('assert');
describe('rules/validate-case-indentation', function () {
var checker;
let checker;
before(function () {
checker = new Checker();
@ -14,7 +16,7 @@ describe('rules/validate-case-indentation', function () {
describe('option value true', function () {
it('should report cases not aligned with switch keyword', function () {
var src = 'switch (Number.isFinite) {\n';
let src = 'switch (Number.isFinite) {\n';
src += '\tcase isFinite:\n';
src += '\t\tbreak;\n';
src += '}';
@ -22,7 +24,7 @@ describe('rules/validate-case-indentation', function () {
});
it('should not report cases aligned with switch keyword', function () {
var src = 'switch (Number.isFinite) {\n';
let src = 'switch (Number.isFinite) {\n';
src += 'case isFinite:\n';
src += '\tbreak;\n';
src += '}';
@ -30,14 +32,14 @@ describe('rules/validate-case-indentation', function () {
});
it('should report default case not aligned with switch keyword', function () {
var src = 'switch (Number.isFinite) {\n';
let src = 'switch (Number.isFinite) {\n';
src += '\tdefault:\n';
src += '}';
assert(!checker.checkString(src).isEmpty());
});
it('should not report default case aligned with switch keyword', function () {
var src = 'switch (Number.isFinite) {\n';
let src = 'switch (Number.isFinite) {\n';
src += 'default:\n';
src += '}';
assert(checker.checkString(src).isEmpty());

View File

@ -1,8 +1,10 @@
var Checker = require('jscs');
var assert = require('assert');
'use strict';
const Checker = require('jscs');
const assert = require('assert');
describe('rules/validate-conditionals', function () {
var checker;
let checker;
before(function () {
checker = new Checker();

View File

@ -1,14 +1,16 @@
var assert = require('assert');
var stream = require('stream');
var path = require('path');
var net = require('net');
var fs = require('fs');
var noop = function () {};
'use strict';
var testPort;
const assert = require('assert');
const stream = require('stream');
const path = require('path');
const net = require('net');
const fs = require('fs');
const noop = function () {};
let testPort;
function getPort(callback) {
var port = testPort;
var server = net.createServer();
let port = testPort;
let server = net.createServer();
server.listen(port, function (err) {
server.once('close', function onclose() {
@ -29,7 +31,7 @@ function init(callback) {
});
// Run the battle engine in the main process to keep our sanity
var BattleEngine = global.BattleEngine = require('./../battle-engine.js');
let BattleEngine = global.BattleEngine = require('./../battle-engine.js');
process.listeners('message').forEach(function (listener) {
process.removeListener('message', listener);
});
@ -38,7 +40,7 @@ function init(callback) {
BattleEngine.Battle.prototype.send = noop;
BattleEngine.Battle.prototype.receive = noop;
var Simulator = global.Simulator;
let Simulator = global.Simulator;
Simulator.Battle.prototype.send = noop;
Simulator.Battle.prototype.receive = noop;
Simulator.SimulatorProcess.processes.forEach(function (process) {
@ -62,7 +64,7 @@ before('initialization', function (done) {
this.timeout(0); // Remove timeout limitation
// Load and override configuration before starting the server
var config;
let config;
try {
config = require('./../config/config.js');
} catch (err) {
@ -75,7 +77,7 @@ before('initialization', function (done) {
config = require('./../config/config.js');
}
try {
var chatRoomsPath = require.resolve('./../config/chatrooms.json');
let chatRoomsPath = require.resolve('./../config/chatrooms.json');
require.cache[chatRoomsPath] = [];
} catch (e) {}
@ -91,8 +93,8 @@ before('initialization', function (done) {
config.logchat = false;
// TODO: Use a proper fs sandbox
var fsMethodsNullify = ['chmod', 'rename', 'rmdir', 'symlink', 'unlink', 'writeFile'];
for (var i = 0; i < fsMethodsNullify.length; i++) {
let fsMethodsNullify = ['chmod', 'rename', 'rmdir', 'symlink', 'unlink', 'writeFile'];
for (let i = 0; i < fsMethodsNullify.length; i++) {
fs[fsMethodsNullify[i]] = noop;
fs[fsMethodsNullify[i] + 'Sync'] = noop;
}
@ -114,7 +116,7 @@ before('initialization', function (done) {
});
describe('Native timer/event loop globals', function () {
var globalList = ['setTimeout', 'clearTimeout', 'setImmediate', 'clearImmediate'];
let globalList = ['setTimeout', 'clearTimeout', 'setImmediate', 'clearImmediate'];
globalList.forEach(function (elem) {
describe('`' + elem + '`', function () {
it('should be a global function', function () {

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Arena Trap', function () {
afterEach(function () {

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Battle Armor', function () {
afterEach(function () {
@ -11,7 +13,7 @@ describe('Battle Armor', function () {
battle.join('p1', 'Guest 1', 1, [{species: 'Slowbro', ability: 'battlearmor', moves: ['quickattack']}]);
battle.join('p2', 'Guest 2', 1, [{species: 'Cyrogonal', ability: 'noguard', moves: ['frostbreath']}]);
battle.commitDecisions(); // Team Preview
var successfulEvent = false;
let successfulEvent = false;
battle.on('ModifyDamage', battle.getFormat(), function (damage, attacker, defender, move) {
if (move.id === 'frostbreath') {
successfulEvent = true;
@ -27,7 +29,7 @@ describe('Battle Armor', function () {
battle.join('p1', 'Guest 1', 1, [{species: 'Slowbro', ability: 'battlearmor', moves: ['quickattack']}]);
battle.join('p2', 'Guest 2', 1, [{species: 'Cyrogonal', ability: 'moldbreaker', item: 'zoomlens', moves: ['frostbreath']}]);
battle.commitDecisions(); // Team Preview
var successfulEvent = false;
let successfulEvent = false;
battle.on('ModifyDamage', battle.getFormat(), function (damage, attacker, defender, move) {
if (move.id === 'frostbreath') {
successfulEvent = true;

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Clear Body', function () {
afterEach(function () {
@ -10,11 +12,11 @@ describe('Clear Body', function () {
battle = BattleEngine.Battle.construct();
battle.join('p1', 'Guest 1', 1, [{species: 'Tentacruel', ability: 'clearbody', moves: ['recover']}]);
battle.join('p2', 'Guest 2', 1, [{species: 'Arbok', ability: 'intimidate', moves: ['acidspray', 'leer', 'icywind', 'charm', 'confide']}]);
var stats = Object.keys(battle.p1.active[0].boosts);
for (var i = 1; i <= 5; i++) {
let stats = Object.keys(battle.p1.active[0].boosts);
for (let i = 1; i <= 5; i++) {
battle.choose('p2', 'move ' + i);
battle.commitDecisions();
for (var j = 0; j < stats.length; j++) {
for (let j = 0; j < stats.length; j++) {
assert.strictEqual(battle.p1.active[0].boosts[stats[j]], 0);
}
}

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Cloud Nine', function () {
afterEach(function () {
@ -18,7 +20,7 @@ describe('Cloud Nine', function () {
it('should negate the effects of Sun on Fire-type and Water-type attacks', function () {
battle = BattleEngine.Battle.construct();
var move, basePower;
let move, basePower;
battle.join('p1', 'Guest 1', 1, [{species: 'Groudon', ability: 'drought', moves: ['rest']}]);
battle.join('p2', 'Guest 2', 1, [{species: 'Golduck', ability: 'cloudnine', moves: ['calmmind']}]);
battle.commitDecisions();
@ -32,7 +34,7 @@ describe('Cloud Nine', function () {
it('should negate the effects of Rain on Fire-type and Water-type attacks', function () {
battle = BattleEngine.Battle.construct();
var move, basePower;
let move, basePower;
battle.join('p1', 'Guest 1', 1, [{species: 'Kyogre', ability: 'drizzle', moves: ['rest']}]);
battle.join('p2', 'Guest 2', 1, [{species: 'Golduck', ability: 'cloudnine', moves: ['calmmind']}]);
battle.commitDecisions();
@ -90,7 +92,7 @@ describe('Cloud Nine', function () {
battle.join('p2', 'Guest 2', 1, [{species: 'Sunkern', ability: 'solarpower', moves: ['sunnyday']}]);
battle.commitDecisions();
assert.strictEqual(battle.log[battle.lastMoveLine + 1], '|-weather|SunnyDay');
for (var i = 0; i < 4; i++) {
for (let i = 0; i < 4; i++) {
assert.strictEqual(battle.log[battle.lastMoveLine + 3], '|-weather|SunnyDay|[upkeep]');
battle.commitDecisions();
}

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Color Change', function () {
afterEach(function () {

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Contrary', function () {
afterEach(function () {

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Damp', function () {
afterEach(function () {

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Delta Stream', function () {
afterEach(function () {
@ -17,7 +19,7 @@ describe('Delta Stream', function () {
battle = BattleEngine.Battle.construct();
battle.join('p1', 'Guest 1', 1, [{species: "Tornadus", ability: 'deltastream', item: 'weaknesspolicy', moves: ['recover']}]);
battle.join('p2', 'Guest 2', 1, [{species: "Smeargle", ability: 'owntempo', moves: ['thundershock', 'powdersnow', 'powergem']}]);
for (var i = 0; i < 3; i++) {
for (let i = 0; i < 3; i++) {
battle.choose('p2', 'move ' + i);
battle.commitDecisions();
assert.strictEqual(battle.p1.active[0].boosts.atk, 0);
@ -44,7 +46,7 @@ describe('Delta Stream', function () {
{species: "Tyranitar", ability: 'sandstream', moves: ['sandstorm']},
{species: "Abomasnow", ability: 'snowwarning', moves: ['hail']}
]);
for (var i = 2; i <= 5; i++) {
for (let i = 2; i <= 5; i++) {
battle.choose('p1', 'switch ' + i);
battle.commitDecisions();
assert.ok(battle.isWeather('deltastream'));

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Desolate Land', function () {
afterEach(function () {
@ -18,8 +20,8 @@ describe('Desolate Land', function () {
battle.join('p1', 'Guest 1', 1, [{species: "Groudon", ability: 'desolateland', moves: ['helpinghand']}]);
battle.join('p2', 'Guest 2', 1, [{species: "Charizard", ability: 'blaze', moves: ['firepledge']}]);
battle.commitDecisions();
var move = Tools.getMove('firepledge');
var basePower = battle.runEvent('BasePower', battle.p2.active[0], battle.p1.active[0], move, move.basePower, true);
let move = Tools.getMove('firepledge');
let basePower = battle.runEvent('BasePower', battle.p2.active[0], battle.p1.active[0], move, move.basePower, true);
assert.strictEqual(basePower, move.basePower);
});
@ -50,7 +52,7 @@ describe('Desolate Land', function () {
{species: "Tyranitar", ability: 'sandstream', moves: ['sandstorm']},
{species: "Abomasnow", ability: 'snowwarning', moves: ['hail']}
]);
for (var i = 2; i <= 5; i++) {
for (let i = 2; i <= 5; i++) {
battle.choose('p1', 'switch ' + i);
battle.commitDecisions();
assert.ok(battle.isWeather('desolateland'));

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Dry Skin', function () {
afterEach(function () {
@ -35,7 +37,7 @@ describe('Dry Skin', function () {
battle.join('p1', 'Guest 1', 1, [{species: 'Toxicroak', ability: 'dryskin', moves: ['bulkup']}]);
battle.join('p2', 'Guest 2', 1, [{species: 'Haxorus', ability: 'unnerve', moves: ['incinerate']}]);
battle.commitDecisions();
var damage = battle.p1.active[0].maxhp - battle.p1.active[0].hp;
let damage = battle.p1.active[0].maxhp - battle.p1.active[0].hp;
assert.ok(damage >= 51 && damage <= 61);
});
@ -44,8 +46,8 @@ describe('Dry Skin', function () {
battle.join('p1', 'Guest 1', 1, [{species: 'Toxicroak', ability: 'dryskin', moves: ['bulkup']}]);
battle.join('p2', 'Guest 2', 1, [{species: 'Haxorus', ability: 'moldbreaker', moves: ['incinerate', 'surf']}]);
battle.commitDecisions();
var pokemon = battle.p1.active[0];
var damage = pokemon.maxhp - pokemon.hp;
let pokemon = battle.p1.active[0];
let damage = pokemon.maxhp - pokemon.hp;
assert.ok(damage >= 41 && damage <= 49);
pokemon.hp = pokemon.maxhp;
battle.choose('p2', 'move 2');

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Flash Fire', function () {
afterEach(function () {
@ -12,7 +14,7 @@ describe('Flash Fire', function () {
battle.join('p2', 'Guest 2', 1, [{species: 'Talonflame', ability: 'galewings', moves: ['flareblitz']}]);
battle.commitDecisions();
assert.strictEqual(battle.p1.active[0].hp, battle.p1.active[0].maxhp);
var damage = battle.p2.active[0].maxhp - battle.p2.active[0].hp;
let damage = battle.p2.active[0].maxhp - battle.p2.active[0].hp;
assert.ok(damage >= 82 && damage <= 97);
});
@ -41,7 +43,7 @@ describe('Flash Fire', function () {
battle.seed = battle.startingSeed.slice();
battle.choose('p1', 'move 2');
battle.choose('p2', 'move 2');
var damage = battle.p2.active[0].maxhp - battle.p2.active[0].hp;
let damage = battle.p2.active[0].maxhp - battle.p2.active[0].hp;
assert.ok(damage >= 54 && damage <= 65);
});
});

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Flower Gift', function () {
afterEach(function () {
@ -17,10 +19,10 @@ describe('Flower Gift', function () {
{species: "Blissey", ability: 'serenegrace', moves: ['healbell']}
]);
battle.commitDecisions();
var cherAtk = battle.p1.active[0].getStat('atk');
var cherSpd = battle.p1.active[0].getStat('spd');
var baseAtk = battle.p1.active[1].getStat('atk');
var baseSpd = battle.p1.active[1].getStat('spd');
let cherAtk = battle.p1.active[0].getStat('atk');
let cherSpd = battle.p1.active[0].getStat('spd');
let baseAtk = battle.p1.active[1].getStat('atk');
let baseSpd = battle.p1.active[1].getStat('spd');
// Set the weather to sun and re-check
battle.setWeather('sunnyday');
@ -43,10 +45,10 @@ describe('Flower Gift', function () {
battle.commitDecisions();
battle.choose('p1', 'move 1 1, move 1');
battle.choose('p2', 'move 1, move 1');
var cherAtk = battle.p1.active[0].getStat('atk');
var cherSpd = battle.p1.active[0].getStat('spd');
var baseAtk = battle.p1.active[1].getStat('atk');
var baseSpd = battle.p1.active[1].getStat('spd');
let cherAtk = battle.p1.active[0].getStat('atk');
let cherSpd = battle.p1.active[0].getStat('spd');
let baseAtk = battle.p1.active[1].getStat('atk');
let baseSpd = battle.p1.active[1].getStat('spd');
// Set the weather to sun and re-check
battle.setWeather('sunnyday');

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Immunity', function () {
afterEach(function () {

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Intimidate', function () {
afterEach(function () {
@ -49,7 +51,7 @@ describe('Intimidate', function () {
battle = BattleEngine.Battle.construct('battle-intimidate-order1', 'customgame');
battle.join('p1', 'Guest 1', 1, [{species: "Arcanine", ability: 'intimidate', moves: ['morningsun']}]);
battle.join('p2', 'Guest 2', 1, [{species: "Gyarados", ability: 'intimidate', moves: ['dragondance']}]);
var intimidateCount = 0;
let intimidateCount = 0;
battle.on('Boost', battle.getFormat(), function (boost, target, source) {
assert.strictEqual(source.template.speciesid, intimidateCount === 0 ? 'arcanine' : 'gyarados');
intimidateCount++;
@ -87,7 +89,7 @@ describe('Intimidate', function () {
{species: "Gyarados", ability: 'intimidate', moves: ['healingwish']},
{species: "Arcanine", ability: 'intimidate', moves: ['healingwish']}
]);
var intimidateCount = 0;
let intimidateCount = 0;
battle.on('Boost', battle.getFormat(), function (boost, target, source) {
assert.strictEqual(source.template.speciesid, intimidateCount % 2 === 0 ? 'arcanine' : 'gyarados');
intimidateCount++;

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Klutz', function () {
afterEach(function () {

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Levitate', function () {
afterEach(function () {

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Lightning Rod', function () {
afterEach(function () {

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Magic Bounce', function () {
afterEach(function () {

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Magic Guard', function () {
afterEach(function () {

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Multiscale', function () {
afterEach(function () {
@ -10,8 +12,8 @@ describe('Multiscale', function () {
battle = BattleEngine.Battle.construct();
battle.join('p1', 'Guest 1', 1, [{species: "Dragonite", ability: 'multiscale', moves: ['splash']}]);
battle.join('p2', 'Guest 2', 1, [{species: "Gyarados", ability: 'moxie', moves: ['incinerate']}]);
var damage, curhp;
var pokemon = battle.p1.active[0];
let damage, curhp;
let pokemon = battle.p1.active[0];
battle.commitDecisions();
damage = pokemon.maxhp - pokemon.hp;
curhp = pokemon.hp;
@ -24,8 +26,8 @@ describe('Multiscale', function () {
battle = BattleEngine.Battle.construct();
battle.join('p1', 'Guest 1', 1, [{species: "Dragonite", ability: 'multiscale', moves: ['splash']}]);
battle.join('p2', 'Guest 2', 1, [{species: "Gyarados", ability: 'moldbreaker', moves: ['incinerate']}]);
var damage, curhp;
var pokemon = battle.p1.active[0];
let damage, curhp;
let pokemon = battle.p1.active[0];
battle.commitDecisions();
damage = pokemon.maxhp - pokemon.hp;
curhp = pokemon.hp;

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Pickup', function () {
afterEach(function () {

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Pressure', function () {
afterEach(function () {
@ -19,7 +21,7 @@ describe('Pressure', function () {
battle.commitDecisions(); // Team Preview
battle.choose('p1', 'move 1, move 1 -1');
battle.choose('p2', 'move 1, move 1 1');
var move = Tools.getMove('peck');
let move = Tools.getMove('peck');
assert.strictEqual(battle.p1.active[1].getMoveData(move).pp, 55);
assert.strictEqual(battle.p2.active[1].getMoveData(move).pp, 54);
});
@ -37,7 +39,7 @@ describe('Pressure', function () {
battle.commitDecisions(); // Team Preview
battle.choose('p1', 'move 1, move 1 2');
battle.choose('p2', 'move 1, move 1 2');
var move = Tools.getMove('peck');
let move = Tools.getMove('peck');
assert.strictEqual(battle.p1.active[1].getMoveData(move).pp, 55);
assert.strictEqual(battle.p2.active[1].getMoveData(move).pp, 54);
});
@ -114,7 +116,7 @@ describe('Pressure [Gen 4]', function () {
]);
battle.choose('p1', 'move 1, move 1 -1');
battle.choose('p2', 'move 1, move 1 1');
var move = Tools.getMove('peck');
let move = Tools.getMove('peck');
assert.strictEqual(battle.p1.active[1].getMoveData(move).pp, 54);
assert.strictEqual(battle.p2.active[1].getMoveData(move).pp, 54);
});
@ -131,7 +133,7 @@ describe('Pressure [Gen 4]', function () {
]);
battle.choose('p1', 'move 1, move 1 2');
battle.choose('p2', 'move 1, move 1 2');
var move = Tools.getMove('peck');
let move = Tools.getMove('peck');
assert.strictEqual(battle.p1.active[1].getMoveData(move).pp, 55);
assert.strictEqual(battle.p2.active[1].getMoveData(move).pp, 54);
});
@ -167,7 +169,7 @@ describe('Pressure [Gen 4]', function () {
battle.join('p1', 'Guest 1', 1, [{species: "Palkia", ability: 'pressure', moves: ['calmmind']}]);
battle.join('p2', 'Guest 2', 1, [{species: "Dialga", ability: 'pressure', moves: ['calmmind']}]);
battle.commitDecisions();
var move = Tools.getMove('calmmind');
let move = Tools.getMove('calmmind');
assert.strictEqual(battle.p1.active[0].getMoveData(move).pp, 31);
assert.strictEqual(battle.p1.active[0].getMoveData(move).pp, 31);
});

View File

@ -1,5 +1,7 @@
var assert = require('assert');
var battle;
'use strict';
const assert = require('assert');
let battle;
describe('Primordial Sea', function () {
afterEach(function () {
@ -18,8 +20,8 @@ describe('Primordial Sea', function () {
battle.join('p1', 'Guest 1', 1, [{species: "Kyogre", ability: 'primordialsea', moves: ['helpinghand']}]);
battle.join('p2', 'Guest 2', 1, [{species: "Blastoise", ability: 'torrent', moves: ['waterpledge']}]);
battle.commitDecisions();
var move = Tools.getMove('waterpledge');
var basePower = battle.runEvent('BasePower', battle.p2.active[0], battle.p1.active[0], move, move.basePower, true);
let move = Tools.getMove('waterpledge');
let basePower = battle.runEvent('BasePower', battle.p2.active[0], battle.p1.active[0], move, move.basePower, true);
assert.strictEqual(basePower, move.basePower);
});
@ -49,7 +51,7 @@ describe('Primordial Sea', function () {
{species: "Tyranitar", ability: 'sandstream', moves: ['sandstorm']},
{species: "Abomasnow", ability: 'snowwarning', moves: ['hail']}
]);
for (var i = 2; i <= 5; i++) {
for (let i = 2; i <= 5; i++) {
battle.choose('p1', 'switch ' + i);
battle.commitDecisions();
assert.ok(battle.isWeather('primordialsea'));

Some files were not shown because too many files have changed in this diff Show More