tildefriends/packages/cory/bbs/bbs.js

316 lines
8.2 KiB
JavaScript
Raw Normal View History

"use strict";
var gOnInput = null;
var kMaxHistory = 20;
var kShowHistory = 20;
var lastTimestamp = null;
if (imports.terminal) {
core.register("onMessage", function(sender, message) {
if (message.message && message.when) {
printMessage(message, true);
}
});
core.register("onSessionBegin", function(user) {
if (user.packageName === core.user.packageName &&
user.index !== core.user.index) {
listUsers(user.name + " has joined the BBS. ");
}
});
core.register("onSessionEnd", function(user) {
if (user.packageName === core.user.packageName &&
user.index !== core.user.index) {
listUsers(user.name + " has left the BBS. ");
}
});
} else {
// Chat service process.
core.register("onMessage", function(sender, message) {
if (message.message && message.when) {
message.sender = sender;
return database.get("board").catch(function() {
return null;
}).then(function(data) {
try {
data = JSON.parse(data);
} catch(error) {
data = [];
}
data.push(message);
while (data.length > kMaxHistory) {
data.shift();
}
return saveBoard(data);
}).then(function() {
return core.broadcast(message);
});
}
});
}
function listUsers() {
return core.getUsers(core.user.packageOwner, core.user.packageName).then(function(users) {
terminal.select("users");
terminal.clear();
terminal.print("Users:");
var counts = {};
for (var i = 0; i < users.length; i++) {
counts[users[i].name] = (counts[users[i].name] || 0) + 1;
}
var names = Object.keys(counts).sort();
for (var i = 0; i < names.length; i++) {
var name = names[i];
var message = [];
if (message.length > 1) {
message.push(", ");
}
message.push({class: "orange", value: name});
if (counts[name] > 1) {
message.push({class: "base01", value: "(x" + counts[name] + ")"});
}
terminal.print(message);
}
terminal.select("terminal");
});
}
function saveBoard(data) {
return database.set("board", JSON.stringify(data)).catch(function(error) {
if (error.message.indexOf("MDB_MAP_FULL") != -1) {
data.shift();
return saveBoard(data);
} else {
throw error;
}
});
}
core.register("onInput", function(input) {
if (gOnInput && typeof input == "string") {
gOnInput(input);
}
});
function logo() {
terminal.clear();
terminal.print("");
terminal.print("");
terminal.print('Welcome to');
terminal.print(' ______ _ ____ ____ _____');
terminal.print(' / ____/___ _______ _( )_____ / __ )/ __ ) ___/');
terminal.print(' / / / __ \\/ ___/ / / /// ___/ / __ / __ \\__ \\ ');
terminal.print('/ /___/ /_/ / / / /_/ / (__ ) / /_/ / /_/ /__/ / ');
terminal.print('\\____/\\____/_/ \\__, / /____/ /_____/_____/____/ ');
terminal.print(' /____/ ');
terminal.print(' yesterday\'s technology...today!');
terminal.print("");
}
function welcome() {
logo();
chat();
}
function main() {
terminal.clear();
logo();
terminal.print("");
terminal.print("Main menu commands:");
terminal.print(" ", {command: "chat"}, " chat message board");
terminal.print(" ", {command: "guess"}, " guess the number game");
terminal.print(" ", {command: "exit"}, " back to that sweet logo");
gOnInput = function(input) {
input = input.toLowerCase();
if (input == "chat") {
chat();
} else if (input == "guess") {
guess();
} else if (input == "exit") {
terminal.print("Goodbye.");
exit(0);
} else {
terminal.print("I didn't understand that: " + input);
main();
}
};
}
function formatMessage(message) {
var result;
if (typeof message == "string") {
result = [];
var regex = /(\w+:\/*\S+?)(?=(?:[\.!?])?(?:$|\s))/gi;
var match;
var lastIndex = 0;
while ((match = regex.exec(message)) !== null) {
result.push({class: "base1", value: message.substring(lastIndex, match.index)});
result.push({href: match[0]});
lastIndex = regex.lastIndex;
}
result.push({class: "base1", value: message.substring(lastIndex)});
} else {
result = message;
}
return result;
}
function niceTime(lastTime, thisTime) {
if (!lastTime) {
return thisTime;
}
let result = [];
let lastParts = lastTime.split(" ");
let thisParts = thisTime.split(" ");
for (let i = 0; i < thisParts.length; i++) {
if (thisParts[i] !== lastParts[i]) {
result.push(thisParts[i]);
}
}
return result.join(" ");
}
function printMessage(message, notify) {
terminal.print(
{class: "base0", value: niceTime(lastTimestamp, message.when)},
" ",
{class: "base00", value: "<"},
{class: "base3", value: (message.sender ? message.sender.name : "unknown")},
{class: "base00", value: ">"},
" ",
formatMessage(message.message));
lastTimestamp = message.when;
if (notify) {
return core.getUser().then(function(user) {
if (message.message.indexOf("!") != -1) {
return terminal.notify("SOMEONE IS SHOUTING!", {body: "<" + (message.sender ? message.sender.name : "unknown") + "> " + message.message});
} else if (message.message.indexOf(user.name + ":") != -1) {
return terminal.notify("Someone is talking at you.", {body: "<" + (message.sender ? message.sender.name : "unknown") + "> " + message.message});
}
});
}
}
function chat() {
terminal.setEcho(false);
terminal.print("");
terminal.print("You are now in a chat. Anything you type will be broadcast to everyone else connected. To leave, say ", {command: "exit"}, ".");
listUsers();
database.get("board").catch(function() {
return null;
}).then(function(board) {
try {
board = JSON.parse(board);
} catch (error) {
board = [];
}
for (let i = Math.max(0, board.length - kShowHistory); i < board.length; i++) {
printMessage(board[i], false);
}
});
gOnInput = function(input) {
if (input == "exit") {
terminal.setEcho(true);
main();
} else {
core.getService("chat").then(function(chatService) {
return chatService.postMessage({when: new Date().toString(), message: input});
}).catch(function(error) {
terminal.print("ERROR: " + JSON.stringify(error));
});
}
};
}
function guess() {
terminal.clear();
var number = Math.round(Math.random() * 100);
var guesses = 0;
terminal.print("OK, I have a number in mind. What do you think it is? Use ", {command: "exit"}, " to stop.");
gOnInput = function(input) {
if (input == "exit") {
main();
} else {
var guess = parseInt(input);
guesses++;
if (input != guess.toString()) {
terminal.print("I'm not sure that's an integer. Please guess only integers.");
} else {
if (guess < number) {
terminal.print("Too low.");
} else if (guess > number) {
terminal.print("Too high.");
} else if (guess == number) {
terminal.print("Wow, you got it in " + guesses + " guesses! It was " + number + ".");
guessEnd(guesses);
}
}
}
};
}
function guessEnd(guesses) {
terminal.print("What's your name, for the high score table?");
gOnInput = function(name) {
var entry = {'guesses': guesses, 'name': name, 'when': new Date().toString()};
database.get("guessHighScores").then(function(data) {
data = JSON.parse(data);
var index = data.length;
for (var i in data) {
if (guesses < data[i].guesses) {
index = i;
break;
}
}
data.splice(index, 0, entry);
printHighScores(data);
database.set("guessHighScores", JSON.stringify(data));
gOnInput = function() {
main();
};
}).catch(function() {
var data = [entry];
printHighScores(data);
database.set("guessHighScores", JSON.stringify(data));
main();
});
};
}
function printTable(data) {
var widths = [];
for (var i in data) {
var row = data[i];
for (var c in row) {
widths[c] = Math.max(widths[c] || 0, row[c].length);
}
}
for (var i in data) {
var row = data[i];
var line = "";
for (var c in row) {
line += row[c];
line += " ".repeat(widths[c] - row[c].length + 2);
}
terminal.print(line);
}
}
function printHighScores(data) {
printTable([["Name", "Guesses", "Date"]].concat(data.map(function(entry) {
return [entry.name, entry.guesses.toString(), entry.when];
})));
}
if (imports.terminal) {
terminal.split([
{type: "horizontal", children: [
{name: "terminal", grow: 1},
{name: "users", grow: 0},
]},
]);
welcome();
}