mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-05-06 13:47:24 -05:00
773 lines
29 KiB
JavaScript
773 lines
29 KiB
JavaScript
const MAX_CATEGORY_COUNT = 5;
|
|
const MAX_QUESTION_COUNT = 5;
|
|
const BASE_POINTS = 200;
|
|
|
|
function calculatePoints(category, question) {
|
|
return BASE_POINTS * (question + 1);
|
|
}
|
|
|
|
var jeopardies = {};
|
|
|
|
var JeopardyQuestions = (function () {
|
|
function JeopardyQuestions(room, categoryCount, questionCount) {
|
|
this.room = room;
|
|
this.categoryCount = categoryCount;
|
|
this.questionCount = questionCount;
|
|
|
|
this.categories = this.readPersistentData('categories');
|
|
if (!this.categories) this.categories = {};
|
|
|
|
this.grid = this.readPersistentData('grid');
|
|
this.revealedGrid = {};
|
|
if (!this.grid) this.grid = {};
|
|
for (var c = 0; c < categoryCount; ++c) {
|
|
if (!this.grid[c]) this.grid[c] = {};
|
|
this.revealedGrid[c] = {};
|
|
for (var q = 0; q < questionCount; ++q) {
|
|
if (!this.grid[c][q]) this.grid[c][q] = {};
|
|
this.revealedGrid[c][q] = false;
|
|
}
|
|
}
|
|
if (!this.grid.final) this.grid.final = [{}];
|
|
this.revealedGrid.final = [false];
|
|
}
|
|
|
|
JeopardyQuestions.prototype.readPersistentData = function (key) {
|
|
return this.room.jeopardyData ? this.room.jeopardyData[key] : undefined;
|
|
};
|
|
JeopardyQuestions.prototype.writePersistentData = function (key, value) {
|
|
if (!this.room.jeopardyData) this.room.jeopardyData = {};
|
|
if (this.room.chatRoomData && !this.room.chatRoomData.jeopardyData) this.room.chatRoomData.jeopardyData = {};
|
|
this.room.jeopardyData[key] = value;
|
|
if (this.room.chatRoomData) this.room.chatRoomData.jeopardyData[key] = value;
|
|
Rooms.global.writeChatRoomData();
|
|
};
|
|
JeopardyQuestions.prototype.save = function () {
|
|
this.writePersistentData('categories', this.categories);
|
|
this.writePersistentData('grid', this.grid);
|
|
};
|
|
|
|
JeopardyQuestions.prototype.export = function (category, start, end) {
|
|
var data = [];
|
|
for (var 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;
|
|
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;
|
|
this.grid[category][q1].isDailyDouble = !!data[q2].isDailyDouble;
|
|
}
|
|
return q1 - start;
|
|
};
|
|
|
|
JeopardyQuestions.prototype.getCategory = function (category) {
|
|
return this.categories[category];
|
|
};
|
|
JeopardyQuestions.prototype.setCategory = function (category, value) {
|
|
this.categories[category] = value;
|
|
this.save();
|
|
};
|
|
|
|
JeopardyQuestions.prototype.getQuestion = function (category, question) {
|
|
return {
|
|
value: this.grid[category][question].value,
|
|
answer: this.grid[category][question].answer,
|
|
points: calculatePoints(category, question),
|
|
isDailyDouble: this.grid[category][question].isDailyDouble,
|
|
isRevealed: this.revealedGrid[category][question]
|
|
};
|
|
};
|
|
JeopardyQuestions.prototype.setQuestion = function (category, question, value) {
|
|
this.grid[category][question].value = value;
|
|
this.save();
|
|
};
|
|
JeopardyQuestions.prototype.setAnswer = function (category, question, value) {
|
|
this.grid[category][question].answer = value;
|
|
this.save();
|
|
};
|
|
JeopardyQuestions.prototype.setDailyDouble = function (category, question, isDailyDouble) {
|
|
this.grid[category][question].isDailyDouble = isDailyDouble;
|
|
this.save();
|
|
};
|
|
|
|
JeopardyQuestions.prototype.setRevealed = function (category, question, isRevealed) {
|
|
this.revealedGrid[category][question] = isRevealed;
|
|
};
|
|
|
|
return JeopardyQuestions;
|
|
})();
|
|
|
|
var Jeopardy = (function () {
|
|
function Jeopardy(host, room, categoryCount, questionCount) {
|
|
this.host = host;
|
|
this.room = room;
|
|
this.categoryCount = categoryCount;
|
|
this.questionCount = questionCount;
|
|
|
|
this.users = new Map();
|
|
this.questions = new JeopardyQuestions(room, categoryCount, questionCount);
|
|
|
|
this.isStarted = false;
|
|
this.remainingQuestions = categoryCount * questionCount;
|
|
|
|
this.currentUser = null;
|
|
this.currentCategory = -1;
|
|
this.currentQuestion = -1;
|
|
this.currentAnswerer = null;
|
|
this.currentAnswer = "";
|
|
|
|
this.remainingFinalWagers = 0;
|
|
this.remainingFinalAnswers = 0;
|
|
|
|
this.room.add("A new Jeopardy match has been created by " + host.name);
|
|
}
|
|
|
|
Jeopardy.prototype.checkPermission = function (user, output) {
|
|
var checks = Array.prototype.slice.call(arguments, 2);
|
|
|
|
var currentCheck = '';
|
|
while (!!(currentCheck = checks.pop())) {
|
|
switch (currentCheck) {
|
|
case 'started':
|
|
if (this.isStarted) break;
|
|
output.sendReply("The Jeopardy match has not started yet.");
|
|
return false;
|
|
|
|
case 'notstarted':
|
|
if (!this.isStarted) break;
|
|
output.sendReply("The Jeopardy match has already started.");
|
|
return false;
|
|
|
|
case 'host':
|
|
if (user === this.host) break;
|
|
output.sendReply("You are not the host.");
|
|
return false;
|
|
|
|
case 'user':
|
|
if (this.users.has(user)) break;
|
|
output.sendReply("You are not in the match.");
|
|
return false;
|
|
|
|
default:
|
|
output.sendReply("Unknown check '" + currentCheck + "'.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
Jeopardy.prototype.addUser = function (user, targetUser, output) {
|
|
if (!this.checkPermission(user, output, 'notstarted', 'host')) return;
|
|
if (this.users.has(targetUser)) return output.sendReply("User " + targetUser.name + " is already participating.");
|
|
|
|
this.users.set(targetUser, {
|
|
isAnswered: false,
|
|
points: 0,
|
|
finalWager: -1,
|
|
finalAnswer: ""
|
|
});
|
|
this.room.add("User " + targetUser.name + " has joined the Jeopardy match.");
|
|
};
|
|
Jeopardy.prototype.removeUser = function (user, targetUser, output) {
|
|
if (!this.checkPermission(user, output, 'notstarted', 'host')) return;
|
|
if (!this.users.has(targetUser)) return output.sendReply("User " + targetUser.name + " is not participating.");
|
|
|
|
this.users.delete(targetUser);
|
|
this.room.add("User " + targetUser.name + " has left the Jeopardy match.");
|
|
};
|
|
|
|
Jeopardy.prototype.start = function (user, output) {
|
|
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) {
|
|
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);
|
|
if (!question.value) {
|
|
output.sendReply("Category " + (c + 1) + " Question " + (q + 1) + " is empty.");
|
|
isGridValid = false;
|
|
}
|
|
if (!question.answer) {
|
|
output.sendReply("Category " + (c + 1) + " Question " + (q + 1) + " has no answer.");
|
|
isGridValid = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!this.questions.getCategory('final')) {
|
|
output.sendReply("The final category is missing its name.");
|
|
isGridValid = false;
|
|
}
|
|
var finalQuestion = this.questions.getQuestion('final', 0);
|
|
if (!finalQuestion.value) {
|
|
output.sendReply("The final question is empty.");
|
|
isGridValid = false;
|
|
}
|
|
if (!finalQuestion.answer) {
|
|
output.sendReply("The final question has no answer.");
|
|
isGridValid = false;
|
|
}
|
|
|
|
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) {
|
|
this.currentUser = usersIterator.next().value;
|
|
}
|
|
this.room.add('|raw|<div class="infobox">' + renderGrid(this.questions) + '</div>');
|
|
this.room.add("The Jeopardy match has started! " + this.currentUser.name + " selects the first question.");
|
|
};
|
|
|
|
Jeopardy.prototype.select = function (user, category, question, output) {
|
|
if (!this.checkPermission(user, output, 'started', 'user')) return;
|
|
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);
|
|
if (data.isRevealed) return output.sendReply("That question has already been revealed.");
|
|
|
|
this.questions.setRevealed(category, question, true);
|
|
--this.remainingQuestions;
|
|
|
|
this.users.forEach(function (userData) {
|
|
userData.isAnswered = false;
|
|
});
|
|
|
|
this.currentCategory = category;
|
|
this.currentQuestion = question;
|
|
this.currentAnswerer = null;
|
|
this.currentAnswer = "";
|
|
|
|
if (data.isDailyDouble) {
|
|
this.remainingAnswers = 1;
|
|
this.isDailyDouble = true;
|
|
this.room.add("It's the Daily Double! " + this.currentUser.name + ", please make a wager.");
|
|
} else {
|
|
this.remainingAnswers = this.users.size;
|
|
this.room.add("The question is: " + data.value);
|
|
}
|
|
};
|
|
Jeopardy.prototype.wager = function (user, amount, output) {
|
|
if (!this.checkPermission(user, output, 'started', 'user')) return;
|
|
if (this.currentCategory === 'final') return this.finalWager(user, amount, output);
|
|
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);
|
|
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);
|
|
this.room.add("The question is: " + data.value);
|
|
};
|
|
Jeopardy.prototype.answer = function (user, answer, output) {
|
|
if (!this.checkPermission(user, output, 'started', 'user')) return;
|
|
if (this.currentQuestion === 'final') return this.finalAnswer(user, answer, output);
|
|
if (!answer) return output.sendReply("Please specify an answer.");
|
|
if (this.currentAnswer || isNaN(this.currentCategory) || this.currentCategory < 0 || (this.isDailyDouble && user !== this.currentAnswerer)) return output.sendReply("You cannot answer right now.");
|
|
if (this.users.get(user).isAnswered) return output.sendReply("You already have answered this question.");
|
|
|
|
--this.remainingAnswers;
|
|
this.currentAnswerer = user;
|
|
this.currentAnswer = answer;
|
|
this.users.get(user).isAnswered = true;
|
|
this.room.add("" + user.name + " has answered '" + answer + "'.");
|
|
|
|
if (answer.toLowerCase() === this.questions.getQuestion(this.currentCategory, this.currentQuestion).answer.toLowerCase()) {
|
|
this.mark(this.host, true);
|
|
}
|
|
};
|
|
Jeopardy.prototype.mark = function (user, isCorrect, output) {
|
|
if (!this.checkPermission(user, output, 'started', 'host')) return;
|
|
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;
|
|
if (isCorrect) {
|
|
userData.points += points;
|
|
this.room.add("The answer '" + this.currentAnswer + "' was correct! " + this.currentAnswerer.name + " gains " + points + " points to " + userData.points + "!");
|
|
|
|
this.currentUser = this.currentAnswerer;
|
|
this.currentCategory = -1;
|
|
this.currentQuestion = -1;
|
|
this.currentAnswerer = null;
|
|
this.currentAnswer = "";
|
|
this.isDailyDouble = false;
|
|
|
|
if (this.remainingQuestions === 0) this.autostartFinalRound();
|
|
} else {
|
|
userData.points -= points;
|
|
this.room.add("The answer '" + this.currentAnswer + "' was incorrect! " + this.currentAnswerer.name + " loses " + points + " points to " + userData.points + "!");
|
|
|
|
this.currentAnswerer = null;
|
|
this.currentAnswer = "";
|
|
this.isDailyDouble = false;
|
|
|
|
if (this.remainingAnswers === 0) this.skip(this.host);
|
|
}
|
|
};
|
|
Jeopardy.prototype.skip = function (user, output) {
|
|
if (!this.checkPermission(user, output, 'started', 'host')) return;
|
|
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;
|
|
this.room.add("The correct answer was '" + answer + "'.");
|
|
|
|
if (this.isDailyDouble) {
|
|
var 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;
|
|
}
|
|
|
|
this.currentCategory = -1;
|
|
this.currentQuestion = -1;
|
|
this.currentAnswerer = null;
|
|
this.currentAnswer = "";
|
|
|
|
if (this.remainingQuestions === 0) this.autostartFinalRound();
|
|
};
|
|
|
|
Jeopardy.prototype.autostartFinalRound = function () {
|
|
this.currentUser = null;
|
|
this.currentCategory = 'final';
|
|
this.currentQuestion = -1;
|
|
this.remainingFinalWagers = this.users.size;
|
|
|
|
this.room.add("The final category is: '" + this.questions.getCategory('final') + "'. Please set your wagers.");
|
|
};
|
|
Jeopardy.prototype.finalWager = function (user, amount, output) {
|
|
if (!this.checkPermission(user, output, 'started', 'user')) return;
|
|
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);
|
|
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;
|
|
userData.finalWager = Math.round(amount);
|
|
|
|
output.sendReply("You have wagered " + userData.finalWager + " points.");
|
|
if (!isAlreadyWagered) {
|
|
--this.remainingFinalWagers;
|
|
this.room.add("User " + user.name + " has set their wager.");
|
|
}
|
|
|
|
if (this.remainingFinalWagers !== 0) return;
|
|
|
|
this.currentQuestion = 'final';
|
|
this.remainingFinalAnswers = this.users.size;
|
|
|
|
this.room.add("The final question is: '" + this.questions.getQuestion('final', 0).value + "'. Please set your answers.");
|
|
this.questions.setRevealed('final', 0, true);
|
|
};
|
|
Jeopardy.prototype.finalAnswer = function (user, answer, output) {
|
|
if (!this.checkPermission(user, output, 'started', 'user')) return;
|
|
if (this.currentCategory !== 'final') return output.sendReply("It is not the final round yet.");
|
|
if (this.currentQuestion !== 'final') return output.sendReply("You cannot answer yet.");
|
|
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;
|
|
userData.finalAnswer = answer;
|
|
|
|
output.sendReply("You have answered '" + userData.finalAnswer + "'.");
|
|
if (!isAlreadyAnswered) {
|
|
--this.remainingFinalAnswers;
|
|
this.room.add("User " + user.name + " has set their answer.");
|
|
}
|
|
|
|
if (this.remainingFinalAnswers === 0) this.automarkFinalAnswers();
|
|
};
|
|
Jeopardy.prototype.automarkFinalAnswers = function () {
|
|
if (!this.finalMarkingIterator) this.finalMarkingIterator = this.users.entries();
|
|
|
|
var data = this.finalMarkingData = this.finalMarkingIterator.next().value;
|
|
if (!data) {
|
|
this.end();
|
|
return;
|
|
}
|
|
|
|
this.room.add("User " + data[0].name + " has answered '" + data[1].finalAnswer + "'.");
|
|
|
|
if (data[1].finalAnswer.toLowerCase() === this.questions.getQuestion('final', 0).answer.toLowerCase()) {
|
|
this.finalMark(this.host, true);
|
|
}
|
|
};
|
|
Jeopardy.prototype.finalMark = function (user, isCorrect, output) {
|
|
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;
|
|
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 + "!");
|
|
} else {
|
|
data[1].points -= data[1].finalWager;
|
|
this.room.add("The answer '" + data[1].finalAnswer + "' was incorrect! " + data[0].name + " loses " + data[1].finalWager + " points to " + data[1].points + "!");
|
|
}
|
|
|
|
this.automarkFinalAnswers();
|
|
};
|
|
|
|
Jeopardy.prototype.end = function () {
|
|
var results = [];
|
|
for (var 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();
|
|
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"));
|
|
|
|
delete jeopardies[this.room.id];
|
|
};
|
|
|
|
return Jeopardy;
|
|
})();
|
|
|
|
function renderGrid(questions, mode) {
|
|
var buffer = '<center><table>';
|
|
|
|
buffer += '<tr>';
|
|
for (var c = 0; c < questions.categoryCount; ++c) {
|
|
buffer += '<th>' + (Tools.escapeHTML(questions.getCategory(c)) || ' ') + '</th>';
|
|
}
|
|
buffer += '</tr>';
|
|
|
|
for (var q = 0; q < questions.questionCount; ++q) {
|
|
buffer += '<tr>';
|
|
for (var c = 0; c < questions.categoryCount; ++c) {
|
|
var data = questions.getQuestion(c, q);
|
|
|
|
var cellType = (mode === 'questions' || mode === 'answers') && data.isDailyDouble ? 'th' : 'td';
|
|
buffer += '<' + cellType + '><center>';
|
|
|
|
if (mode === 'questions') {
|
|
buffer += data.value || ' ';
|
|
} else if (mode === 'answers') {
|
|
buffer += data.answer || ' ';
|
|
} else if (data.isRevealed) {
|
|
buffer += ' ';
|
|
} else {
|
|
buffer += data.points;
|
|
}
|
|
|
|
buffer += '</center></' + cellType + '>';
|
|
}
|
|
buffer += '</tr>';
|
|
}
|
|
|
|
buffer += '</table></center>';
|
|
|
|
return buffer;
|
|
}
|
|
|
|
var commands = {
|
|
help: function () {
|
|
if (!this.canBroadcast()) return;
|
|
|
|
this.sendReplyBox(
|
|
"All commands are run under /jeopardy or /jp. For example, /jeopardy viewgrid.<br />" +
|
|
"viewgrid { , questions, answers, final} - Shows the jeopardy grid<br />" +
|
|
"edit - Edits the grid. Run this command by itself for more detailed help<br />" +
|
|
"export [category number], [start], [end] - Exports data from the grid. start and end are optional<br />" +
|
|
"import [category number], [start], [end], [data] - Imports data into the grid. start and end are optional<br />" +
|
|
"create [categories], [questions per category] - Creates a jeopardy match. Parameters are optional, and default to maximum values. Requires: % @ # & ~<br />" +
|
|
"start - Starts the match. Requires: % @ # & ~<br />" +
|
|
"end - Forcibly ends the match. Requires: % @ # & ~<br />" +
|
|
"adduser [user] - Add a user to the match<br />" +
|
|
"removeuser [user] - Remove a user from the match<br />" +
|
|
"select [category number], [question number] - Select a question<br />" +
|
|
"a/answer [answer] - Attempt to answer the question<br />" +
|
|
"incorrect/correct - Marks the current answer as correct or not. Requires: % @ # & ~<br />" +
|
|
"skip - Skips the current question<br />" +
|
|
"wager [amount] - Wager some amount of points. 'all' is also accepted"
|
|
);
|
|
},
|
|
|
|
'': 'viewgrid',
|
|
viewgrid: function (target, room, user) {
|
|
if (!this.canBroadcast()) return;
|
|
|
|
var jeopardy = jeopardies[room.id];
|
|
var questions = null;
|
|
|
|
if (!jeopardy) {
|
|
if (!this.can('jeopardy', null, room)) return;
|
|
questions = new JeopardyQuestions(room, MAX_CATEGORY_COUNT, MAX_QUESTION_COUNT);
|
|
} else {
|
|
if (target && !jeopardy.checkPermission(user, this, 'host')) return;
|
|
questions = jeopardy.questions;
|
|
}
|
|
|
|
if (toId(target) === 'final') {
|
|
this.sendReplyBox(
|
|
"<strong>Final Category:</strong> " + Tools.escapeHTML(questions.getCategory('final') || "") + '<br />' +
|
|
"<strong>Final Question:</strong> " + Tools.escapeHTML(questions.getQuestion('final', 0).value || "") + '<br />' +
|
|
"<strong>Final Answer:</strong> " + Tools.escapeHTML(questions.getQuestion('final', 0).answer || "")
|
|
);
|
|
} else {
|
|
this.sendReplyBox(renderGrid(questions, target));
|
|
}
|
|
},
|
|
|
|
edit: function (target, room, user) {
|
|
var params = target.split(',');
|
|
|
|
var 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]);
|
|
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);
|
|
} else if (params.length < 4) {
|
|
return this.sendReply(usage);
|
|
}
|
|
|
|
var jeopardy = jeopardies[room.id];
|
|
var questions = null;
|
|
|
|
if (!jeopardy) {
|
|
if (!this.can('jeopardy', null, room)) return;
|
|
questions = new JeopardyQuestions(room, MAX_CATEGORY_COUNT, MAX_QUESTION_COUNT);
|
|
} else {
|
|
if (!jeopardy.checkPermission(user, this, 'notstarted', 'host')) return;
|
|
questions = jeopardy.questions;
|
|
}
|
|
|
|
var 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';
|
|
} else {
|
|
--categoryNumber;
|
|
}
|
|
|
|
if (editType === 'category') {
|
|
questions.setCategory(categoryNumber, params.slice(2).join(',').trim());
|
|
this.sendReply("The category name has been updated.");
|
|
} else {
|
|
var 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;
|
|
} else {
|
|
--questionNumber;
|
|
}
|
|
|
|
var value = params.slice(3).join(',').trim();
|
|
switch (editType) {
|
|
case 'question':
|
|
questions.setQuestion(categoryNumber, questionNumber, value);
|
|
this.sendReply("The question has been updated.");
|
|
break;
|
|
|
|
case 'answer':
|
|
questions.setAnswer(categoryNumber, questionNumber, value);
|
|
this.sendReply("The answer has been updated.");
|
|
break;
|
|
|
|
case 'dailydouble':
|
|
var isSet = toId(value) === 'true';
|
|
questions.setDailyDouble(categoryNumber, questionNumber, isSet);
|
|
this.sendReply("The daily double has been " + (isSet ? "set." : "unset."));
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
export: function (target, room, user) {
|
|
var params = target.split(',');
|
|
|
|
var jeopardy = jeopardies[room.id];
|
|
var questions = null;
|
|
|
|
if (!jeopardy) {
|
|
if (!this.can('jeopardy', null, room)) return;
|
|
questions = new JeopardyQuestions(room, MAX_CATEGORY_COUNT, MAX_QUESTION_COUNT);
|
|
} else {
|
|
if (!jeopardy.checkPermission(user, this, 'host')) return;
|
|
questions = jeopardy.questions;
|
|
}
|
|
|
|
var 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;
|
|
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(',');
|
|
if (params.length < 2) return this.sendReply("Usage: import [category number], [start], [end], [data]");
|
|
|
|
var jeopardy = jeopardies[room.id];
|
|
var questions = null;
|
|
|
|
if (!jeopardy) {
|
|
if (!this.can('jeopardy', null, room)) return;
|
|
questions = new JeopardyQuestions(room, MAX_CATEGORY_COUNT, MAX_QUESTION_COUNT);
|
|
} else {
|
|
if (!jeopardy.checkPermission(user, this, 'notstarted', 'host')) return;
|
|
questions = jeopardy.questions;
|
|
}
|
|
|
|
var 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);
|
|
if (!isNaN(start)) {
|
|
++dataStart;
|
|
if (!isNaN(end)) {
|
|
++dataStart;
|
|
}
|
|
}
|
|
if (dataStart <= 1) start = 1;
|
|
if (dataStart <= 2) end = 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.");
|
|
|
|
var data;
|
|
try {
|
|
data = JSON.parse(params.slice(dataStart).join(','));
|
|
} catch (e) {
|
|
return this.sendReply("Failed to parse the data. Please make sure it is correct.");
|
|
}
|
|
|
|
this.sendReply('||' + questions.import(categoryNumber - 1, start - 1, end, data) + " questions have been imported.");
|
|
},
|
|
|
|
create: function (target, room, user) {
|
|
var 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;
|
|
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];
|
|
if (!jeopardy) return this.sendReply("There is no Jeopardy match currently in this room.");
|
|
|
|
jeopardy.start(user, this);
|
|
},
|
|
end: function (target, room, user) {
|
|
if (!jeopardies[room.id]) return this.sendReply("There is no Jeopardy match currently in this room.");
|
|
if (!this.can('jeopardy', null, room)) return;
|
|
|
|
delete jeopardies[room.id];
|
|
room.add("The Jeopardy match was forcibly ended by " + user.name);
|
|
},
|
|
|
|
adduser: function (target, room, user) {
|
|
var targetUser = Users.get(target);
|
|
if (!targetUser) return this.sendReply("User '" + target + "' not found.");
|
|
|
|
var 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);
|
|
if (!targetUser) return this.sendReply("User '" + target + "' not found.");
|
|
|
|
var 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(',');
|
|
if (params.length < 2) return this.sendReply("Usage: select [category number], [question number]");
|
|
|
|
var 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;
|
|
|
|
jeopardy.select(user, category, question, this);
|
|
},
|
|
a: 'answer',
|
|
answer: function (target, room, user) {
|
|
var 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];
|
|
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];
|
|
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];
|
|
if (!jeopardy) return this.sendReply("There is no Jeopardy match currently in this room.");
|
|
|
|
jeopardy.wager(user, target, this);
|
|
}
|
|
};
|
|
|
|
var jeopardyRoom = Rooms.get('academics');
|
|
if (jeopardyRoom) {
|
|
if (jeopardyRoom.plugin) {
|
|
jeopardies = jeopardyRoom.plugin.jeopardies;
|
|
} else {
|
|
jeopardyRoom.plugin = {
|
|
'jeopardies': jeopardies
|
|
};
|
|
}
|
|
}
|
|
|
|
exports.commands = {
|
|
'jp': 'jeopardy',
|
|
'jeopardy': commands
|
|
};
|