board-game
Version:
an online board game engine
206 lines (204 loc) • 7.42 kB
JavaScript
const extend = require('extend');
const Role = require('./role');
const Team = require('./team');
const Game = require('./game');
const Messages = require('./messages');
const Dispatcher = require('./dispatcher');
class Room extends Dispatcher {
constructor(server, creator, settings) {
super();
this.server = server;
this.creator = creator;
this.status = 'waiting';
let role = new (this.server.config.Role || Role)(this.server, this, creator);
this.roles = [ role ];
this.teams = Team.createTeams(this.server, role);
this.disposed = false;
this.settings = extend(true, { publish: false }, settings);
this.id = Room.newId(this.server);
this.server.rooms.set(this.id, this);
this.messages = new Messages();
console.log(`用户${ creator.name || creator.id }创建了游戏房间${ this.id }`);
}
dispose() {
super.dispose();
this.disposed = true;
this.teams.forEach(team => team.dispose());
this.roles = [];
this.server.rooms.delete(this.id);
this.server.roomIds.push(this.id);
}
join(player) {
if (this.teams.every(team => team.emptyCount === 0)) throw '此房间人数已满';
if (this.status !== 'waiting') throw '此房间可能在游戏中,不能加入此房间';
let team = this.teams.reduce((s, t, i) => this.teams[s].emptyCount >= t.emptyCount ? s : i, 0);
let index = this.teams[team].emptyIndex;
let role = new (this.server.config.Role || Role)(this.server, this, player, team, index);
this.roles.push(role);
this.teams[team].add(role);
player.room = this;
console.log(`用户${ player.name || player.id }加入了游戏房间${ this.id }`);
}
exit(role, focus = false) {
if (this.disposed || !focus && this.game) throw '';
if (!focus && this.creator === role.player) {
this.dispose();
console.log(`用户${ role.player.name || role.player.id }解散了游戏房间${ this.id }`);
} else {
this.roles.splice(this.roles.indexOf(role), 1);
this.teams[role.team].remove(role);
if (this.game) this.game.exit(role);
delete role.player.room;
console.log(`用户${ role.player.name || role.player.id }退出了游戏房间${ this.id }`);
if (this.creator === role.player) {
if (this.roles.length) {
this.creator = this.roles[0].player;
} else {
this.dispose();
}
}
}
}
start(role) {
if (this.disposed) throw '';
if (!this.canStart) throw '';
if (this.creator.id !== role.player.id) throw '';
if (this.server.config.team && this.server.config.team.sort && this.status === 'waiting') {
this.status = 'sorting';
} else {
this.roles.forEach(role => role.confirm());
this.game = new (this.server.config.Game || Game)(this.server, this);
this.status = 'gaming';
console.log(`游戏房间${ this.id }开始了新的游戏`);
}
}
over() {
if (!this.game) throw '';
delete this.game;
this.status = 'waiting';
}
move(role, team, index) {
if (role.player === this.creator) {
throw '';
} else {
if (this.teams[team].roles[index] === true) {
this.teams[role.team].roles[role.index] = true;
this.teams[team].roles[index] = role;
role.team = team;
role.index = index;
} else {
throw '';
}
}
}
disable(role, team, index) {
if (role.player === this.creator && this.teams[team].roles[index] === true) {
this.teams[team].roles[index] = false;
} else {
throw '';
}
}
enable(role, team, index) {
if (role.player === this.creator && this.teams[team].roles[index] === false) {
this.teams[team].roles[index] = true;
} else {
throw '';
}
}
kick(role, team, index) {
if (role.player === this.creator) {
if (this.teams[team].roles[index] instanceof Role) {
this.teams[team].roles[index].exit();
} else {
throw '';
}
} else {
throw '';
}
}
leave(force = false) {
if (this.roles.every(role => role.player.leaved)) {
if (this.roles.length > 1 || force) {
if (this.game) this.game.over();
this.roles.forEach(role => this.exit(role));
} else {
setTimeout(() => this.leave(true), 30000);
}
}
}
message(role, message) {
this.messages.append({
role: role.data,
message: message
});
}
get canStart() {
let config = this.server.config;
return !this.roles.some(role => role.player.leaved)
&& this.teams.every(team => team.count >= (config.team.min || 1))
&& new Set(this.teams.map(team => team.count)).size === 1
&& (!config.team.regroup || this.roles.length % Number(config.team.regroup) === 0);
}
get data() {
return {
id: this.id,
creator: {
id: this.creator.id,
name: this.creator.name
},
settings: this.settings,
canStart: this.canStart,
teams: this.teams.map(team => team.data),
game: this.game && this.game.data,
status: this.status,
messages: []
}
}
get summary() {
return {
id: this.id,
creator: {
id: this.creator.id,
name: this.creator.name
},
length: this.teams.map(team => team.openCount).reduce((s, t) => s + t, 0),
empty: this.teams.map(team => team.emptyCount).reduce((s, t) => s + t, 0),
status: this.status
}
}
static get(server, gameId) {
if (server.rooms.has(gameId)) {
return server.rooms.get(gameId);
} else {
throw '无此游戏房间';
}
}
static newId(server) {
if (server.roomIds.length) return server.roomIds.pop();
let size = Math.max(server.rooms.size, 999);
let base = 10;
while (size % base !== size) base *= 10;
while(true) {
let id = String(parseInt(Math.random() * size) + base);
if (!server.rooms.has(id)) return id;
}
}
static list(server, page) {
let list = [];
let current = 0;
page = page || 0;
for (let room of server.rooms.values()) {
if (room.settings.publish) {
if (current >= page * 20) {
list.push(room);
}
if (list.length === 20) {
return list;
}
current++
}
}
return list;
}
}
module.exports = Room;