forked from cory/tildefriends
202 lines
4.5 KiB
JavaScript
202 lines
4.5 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
class Client {
|
||
|
async start() {
|
||
|
let self = this;
|
||
|
terminal.setTitle("Emoji Push");
|
||
|
terminal.setSendKeyEvents(true);
|
||
|
self.send({action: "ready"});
|
||
|
|
||
|
core.register("key", function(event) {
|
||
|
if (event.type == "keydown") {
|
||
|
switch (event.keyCode) {
|
||
|
case 37:
|
||
|
self.requestMove(-1, 0);
|
||
|
break;
|
||
|
case 38:
|
||
|
self.requestMove(0, -1);
|
||
|
break;
|
||
|
case 39:
|
||
|
self.requestMove(1, 0);
|
||
|
break;
|
||
|
case 40:
|
||
|
self.requestMove(0, 1);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
core.register("onMessage", function(sender, message) {
|
||
|
if (message.action == "display") {
|
||
|
terminal.cork();
|
||
|
terminal.clear();
|
||
|
terminal.print(message.board);
|
||
|
terminal.uncork();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
async send(message) {
|
||
|
(await core.getService("server")).postMessage(message);
|
||
|
}
|
||
|
|
||
|
async requestMove(dx, dy) {
|
||
|
await this.send({action: "move", delta: [dx, dy]});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Server {
|
||
|
constructor() {
|
||
|
this.rows = 17;
|
||
|
this.columns = 17;
|
||
|
this.players = {};
|
||
|
this.objects = [];
|
||
|
|
||
|
for (let i = 2; i < this.rows - 1; i += 2) {
|
||
|
for (let j = 2; j < this.columns - 1; j += 2) {
|
||
|
let block = new Entity();
|
||
|
block.position = [j, i];
|
||
|
block.symbol = '#';
|
||
|
this.objects.push(block);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async start() {
|
||
|
let self = this;
|
||
|
core.register("onMessage", function(sender, message) {
|
||
|
if (!self.players[sender.index]) {
|
||
|
let player = new Entity();
|
||
|
player.symbol = '@';
|
||
|
player.position = self.findNewPlayerPosition();
|
||
|
self.players[sender.index] = player;
|
||
|
self.objects.push(player);
|
||
|
}
|
||
|
switch (message.action) {
|
||
|
case "move":
|
||
|
self.move(sender.index, message.delta);
|
||
|
self.redisplay();
|
||
|
break;
|
||
|
case "ready":
|
||
|
self.redisplay();
|
||
|
break;
|
||
|
}
|
||
|
});
|
||
|
core.register("onSessionEnd", function(session) {
|
||
|
let player = self.players[session.index];
|
||
|
if (player) {
|
||
|
delete self.players[session.index];
|
||
|
self.objects.splice(self.objects.indexOf(player), 1);
|
||
|
self.redisplay();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
occupied(position) {
|
||
|
let board = this.getBoard();
|
||
|
|
||
|
if (position[0] < 0 || position[1] < 0 || position[1] >= board.length || position[0] >= board[position[1]].length) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (board[position[1]].charAt(position[0]) != ' ') {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (this.objects.some(x => position[0] == x.position[0] && position[1] == x.position[1])) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
move(index, delta) {
|
||
|
let newPosition = [
|
||
|
this.players[index].position[0] + delta[0],
|
||
|
this.players[index].position[1] + delta[1],
|
||
|
];
|
||
|
if (!this.occupied(newPosition)) {
|
||
|
this.players[index].position = newPosition;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
findNewPlayerPosition() {
|
||
|
let best = null;
|
||
|
let bestDistance = -1;
|
||
|
let players = Object.values(this.players);
|
||
|
|
||
|
for (let i = 0; i < this.rows; i++) {
|
||
|
for (let j = 0; j < this.columns; j++) {
|
||
|
if (!this.occupied([j, i])) {
|
||
|
let distance = Math.min.apply(null, players.map(x => Math.sqrt(
|
||
|
(x.position[0] - j) * (x.position[0] - j)
|
||
|
+ (x.position[1] - i) * (x.position[1] - i))));
|
||
|
if (distance > bestDistance) {
|
||
|
best = [j, i];
|
||
|
bestDistance = distance;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return best;
|
||
|
}
|
||
|
|
||
|
redisplay() {
|
||
|
let board;
|
||
|
try {
|
||
|
board = this.getBoardString();
|
||
|
} catch (error) {
|
||
|
board = error;
|
||
|
}
|
||
|
core.broadcast({action: "display", board: board});
|
||
|
}
|
||
|
|
||
|
getBoard() {
|
||
|
let board = [];
|
||
|
for (let i = 0; i < this.rows; i++) {
|
||
|
let row = "";
|
||
|
for (let j = 0; j < this.columns; j++) {
|
||
|
if (i == 0 && j == 0) {
|
||
|
row += '┌';
|
||
|
} else if (i == 0 && j == this.columns - 1) {
|
||
|
row += '┐';
|
||
|
} else if (i == this.rows - 1 && j == 0) {
|
||
|
row += '└';
|
||
|
} else if (i == this.rows - 1 && j == this.columns - 1) {
|
||
|
row += '┘';
|
||
|
} else if (i == 0 || i == this.rows - 1) {
|
||
|
row += '─';
|
||
|
} else if (j == 0 || j == this.columns - 1) {
|
||
|
row += '│';
|
||
|
} else {
|
||
|
row += ' ';
|
||
|
}
|
||
|
}
|
||
|
board.push(row);
|
||
|
}
|
||
|
for (let object of this.objects) {
|
||
|
board[object.position[1]] = board[object.position[1]].slice(0, object.position[0]) + object.symbol + board[object.position[1]].slice(object.position[0] + 1);
|
||
|
}
|
||
|
return board;
|
||
|
}
|
||
|
|
||
|
getBoardString() {
|
||
|
let board = this.getBoard();
|
||
|
let colors = board.map(x => x.split("").map(y => '#fff'));
|
||
|
return board.map((r, row) => r.split("").map((v, column) => ({style: "color: " + colors[row][column], value: v})).concat(["\n"]));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Entity {
|
||
|
constructor() {
|
||
|
this.position = [0, 0];
|
||
|
this.symbol = '?';
|
||
|
this.color = '#fff';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (imports.terminal) {
|
||
|
new Client().start().catch(terminal.print);
|
||
|
} else {
|
||
|
new Server().start().catch(print);
|
||
|
}
|