mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-04-24 23:09:10 -05:00
1339 lines
37 KiB
JavaScript
1339 lines
37 KiB
JavaScript
require('sugar');
|
|
|
|
fs = require('fs');
|
|
path = require('path');
|
|
|
|
request = require('request');
|
|
|
|
// Synchronously copy config-example.js over to config.js if it doesn't exist
|
|
if (!path.existsSync('./config/config.js')) {
|
|
console.log("config.js doesn't exist - creating one with default settings...");
|
|
var BUF_LENGTH, buff, bytesRead, fdr, fdw, pos;
|
|
BUF_LENGTH = 64 * 1024;
|
|
buff = new Buffer(BUF_LENGTH);
|
|
fdr = fs.openSync('./config/config-example.js', 'r');
|
|
fdw = fs.openSync('./config/config.js', 'w');
|
|
bytesRead = 1;
|
|
pos = 0;
|
|
while (bytesRead > 0) {
|
|
bytesRead = fs.readSync(fdr, buff, 0, BUF_LENGTH, pos);
|
|
fs.writeSync(fdw, buff, 0, bytesRead);
|
|
pos += bytesRead;
|
|
}
|
|
fs.closeSync(fdr);
|
|
}
|
|
|
|
config = require('./config/config.js');
|
|
serverid = config.serverid;
|
|
servertoken = config.servertoken;
|
|
|
|
/*
|
|
var app = require('http').createServer()
|
|
, io = require('socket.io').listen(app)
|
|
, fs = require('fs');
|
|
|
|
function handler (req, res) {
|
|
fs.readFile(__dirname + '/index.html',
|
|
function (err, data) {
|
|
if (err) {
|
|
res.writeHead(500);
|
|
return res.end('Error loading index.html');
|
|
}
|
|
|
|
res.writeHead(200);
|
|
res.end(data);
|
|
});
|
|
}
|
|
|
|
app.listen(8000); */
|
|
|
|
if (process.argv[2] && parseInt(process.argv[2])) {
|
|
config.port = parseInt(process.argv[2]);
|
|
}
|
|
|
|
var io = require('socket.io').listen(config.port).set('log level', 1);
|
|
console.log("Server started on port "+config.port);
|
|
console.log("Test your server at http://psim.tk/~~localhost:"+config.port);
|
|
|
|
function getTime() {
|
|
return new Date().getTime();
|
|
}
|
|
|
|
// Sugar mixins
|
|
|
|
String.extend({
|
|
toId: function() {
|
|
return this.toLowerCase().replace(/[^a-z0-9]+/g, '');
|
|
},
|
|
toUserid: function() {
|
|
return this.toId();
|
|
},
|
|
sanitize: function(strEscape) {
|
|
var str = this.escapeHTML();
|
|
if (strEscape) str = str.replace(/'/g, '\\\'');
|
|
return str;
|
|
}
|
|
});
|
|
|
|
Number.extend({
|
|
clampIntRange: function(min, max) {
|
|
var num = Math.floor(this);
|
|
if (num < min) num = min;
|
|
if (typeof max !== 'undefined' && num > max) num = max;
|
|
return num;
|
|
}
|
|
});
|
|
|
|
BattlePokedex = require('./pokedex.js').BattlePokedex;
|
|
BattleMovedex = require('./movedex.js').BattleMovedex;
|
|
BattleStatuses = require('./statuses.js').BattleStatuses;
|
|
BattleTypeChart = require('./typechart.js').BattleTypeChart;
|
|
BattleScripts = require('./scripts.js').BattleScripts;
|
|
BattleItems = require('./items.js').BattleItems;
|
|
BattleAbilities = require('./abilities.js').BattleAbilities;
|
|
BattleFormats = require('./formats.js').BattleFormats;
|
|
BattleFormatsData = require('./formats-data.js').BattleFormatsData;
|
|
BattleLearnsets = require('./learnsets.js').BattleLearnsets;
|
|
try {
|
|
BattleAliases = require('./aliases.js').BattleAliases;
|
|
} catch (e) {
|
|
BattleAliases = {};
|
|
}
|
|
|
|
var sim = require('./simulator.js');
|
|
|
|
BattlePokemon = sim.BattlePokemon;
|
|
BattleSide = sim.BattleSide;
|
|
Battle = sim.Battle;
|
|
|
|
BattleTools = require('./tools.js').BattleTools;
|
|
|
|
Tools = new BattleTools();
|
|
|
|
Users = require('./users.js');
|
|
getUser = Users.getUser;
|
|
parseCommand = require('./chat-commands.js').parseCommand;
|
|
|
|
lockdown = false;
|
|
|
|
function reloadEngine() {
|
|
for (var i in require.cache) {
|
|
delete require.cache[i];
|
|
}
|
|
BattlePokedex = require('./pokedex.js').BattlePokedex;
|
|
BattleMovedex = require('./movedex.js').BattleMovedex;
|
|
BattleStatuses = require('./statuses.js').BattleStatuses;
|
|
BattleTypeChart = require('./typechart.js').BattleTypeChart;
|
|
BattleScripts = require('./scripts.js').BattleScripts;
|
|
BattleItems = require('./items.js').BattleItems;
|
|
BattleAbilities = require('./abilities.js').BattleAbilities;
|
|
BattleFormats = require('./formats.js').BattleFormats;
|
|
BattleFormatsData = require('./formats-data.js').BattleFormatsData;
|
|
BattleLearnsets = require('./learnsets.js').BattleLearnsets;
|
|
|
|
sim = require('./simulator.js');
|
|
|
|
BattlePokemon = sim.BattlePokemon;
|
|
BattleSide = sim.BattleSide;
|
|
Battle = sim.Battle;
|
|
|
|
BattleTools = require('./tools.js').BattleTools;
|
|
|
|
Tools = new BattleTools();
|
|
}
|
|
|
|
function Room(roomid, format, p1, p2, parentid, rated) {
|
|
var selfR = this;
|
|
|
|
format = ''+(format||'');
|
|
|
|
this.type = 'room';
|
|
this.id = roomid;
|
|
this.i = {};
|
|
this.users = {};
|
|
this.format = format;
|
|
console.log("NEW BATTLE");
|
|
|
|
var formatid = format.toId();
|
|
|
|
if (rated && BattleFormats[formatid] && BattleFormats[formatid].rated) {
|
|
rated = {
|
|
p1: p1.userid,
|
|
p2: p2.userid,
|
|
format: format
|
|
};
|
|
} else {
|
|
rated = false;
|
|
}
|
|
|
|
this.rated = rated;
|
|
this.battle = new Battle(selfR.id, format, rated);
|
|
this.resetTimer = null;
|
|
this.destroyTimer = null;
|
|
this.graceTime = 0;
|
|
|
|
this.parentid = parentid||'';
|
|
this.p1 = p1 || '';
|
|
this.p2 = p2 || '';
|
|
|
|
this.sideTicksLeft = [8, 8];
|
|
this.sideFreeTicks = [0, 0];
|
|
this.inactiveTicksLeft = 0;
|
|
|
|
this.active = false;
|
|
|
|
this.update = function(excludeUser) {
|
|
update = selfR.battle.getUpdates();
|
|
if (!update) return;
|
|
|
|
if (selfR.battle.ended && selfR.rated) {
|
|
var p1score = 0.5;
|
|
|
|
if (selfR.battle.winner === selfR.rated.p1) {
|
|
p1score = 1;
|
|
} else if (selfR.battle.winner === selfR.rated.p2) {
|
|
p1score = 0;
|
|
}
|
|
|
|
var p1 = selfR.rated.p1;
|
|
if (getUser(selfR.rated.p1)) p1 = getUser(selfR.rated.p1).name;
|
|
var p2 = selfR.rated.p2;
|
|
if (getUser(selfR.rated.p2)) p2 = getUser(selfR.rated.p2).name;
|
|
|
|
//update.updates.push('[DEBUG] uri: '+config.loginserver+'action.php?act=ladderupdate&serverid='+serverid+'&p1='+encodeURIComponent(p1)+'&p2='+encodeURIComponent(p2)+'&score='+p1score+'&format='+selfR.rated.format.toId()+'&servertoken=[token]');
|
|
|
|
if (!selfR.rated.p1 || !selfR.rated.p2) {
|
|
update.updates.push('| chatmsg | ERROR: Ladder not updated: a player does not exist');
|
|
} else {
|
|
var winner = getUser(selfR.battle.winner);
|
|
if (winner && !winner.authenticated) {
|
|
winner.emit('console', {rawMessage: '<div style="background-color:#6688AA;color:white;padding:2px 4px"><b>Register an account to protect your ladder rating!</b><br /><button onclick="overlay(\'register\',{ifuserid:\''+winner.userid+'\'});return false"><b>Register</b></button></div>'});
|
|
}
|
|
// update rankings
|
|
request({
|
|
uri: config.loginserver+'action.php?act=ladderupdate&serverid='+serverid+'&p1='+encodeURIComponent(p1)+'&p2='+encodeURIComponent(p2)+'&score='+p1score+'&format='+selfR.rated.format.toId()+'&servertoken='+servertoken+'&nocache='+getTime(),
|
|
}, function(error, response, body) {
|
|
if (body) {
|
|
try {
|
|
var data = JSON.parse(body);
|
|
// we don't actually do much with this data
|
|
selfR.add("Ladder updated.");
|
|
selfR.update();
|
|
} catch(e) {
|
|
}
|
|
} else {
|
|
}
|
|
});
|
|
fs.writeFile('logs/lastbattle.txt', ''+lobby.numRooms);
|
|
var logData = {
|
|
p1score: p1score,
|
|
turns: selfR.battle.turn,
|
|
p1: selfR.battle.p1.name,
|
|
p2: selfR.battle.p2.name,
|
|
p1team: selfR.battle.p1.team,
|
|
p2team: selfR.battle.p2.team
|
|
};
|
|
fs.writeFile('logs/'+selfR.format.toLowerCase().replace(/[^a-z0-9]+/g,'')+'/'+selfR.id+'.log.json',
|
|
JSON.stringify(logData)
|
|
);
|
|
}
|
|
|
|
selfR.rated = false;
|
|
}
|
|
|
|
update.room = roomid;
|
|
var hasUsers = false;
|
|
for (var i in selfR.users) {
|
|
hasUsers = true;
|
|
if (selfR.users[i] === excludeUser) continue;
|
|
selfR.users[i].emit('update', update);
|
|
}
|
|
|
|
// empty rooms time out after ten minutes
|
|
if (!hasUsers) {
|
|
if (!selfR.destroyTimer) {
|
|
selfR.destroyTimer = setTimeout(selfR.tryDestroy, 600000);
|
|
}
|
|
} else if (selfR.destroyTimer) {
|
|
clearTimeout(selfR.destroyTimer);
|
|
selfR.destroyTimer = null;
|
|
}
|
|
};
|
|
this.emit = function(type, message, user) {
|
|
if (type === 'console' || type === 'update') {
|
|
if (typeof message === 'string') {
|
|
message = {message: message};
|
|
}
|
|
message.room = selfR.id;
|
|
}
|
|
if (user && user.emit) {
|
|
user.emit(type, message);
|
|
} else {
|
|
for (var i in selfR.users) {
|
|
selfR.users[i].emit(type, message);
|
|
}
|
|
}
|
|
};
|
|
this.tryDestroy = function() {
|
|
for (var i in selfR.users) {
|
|
// don't destroy ourselves if there are users in this room
|
|
// theoretically, Room.update should've stopped tryDestroy's timer
|
|
// well before we get here
|
|
return;
|
|
}
|
|
selfR.destroy();
|
|
};
|
|
this.broadcastError = function(message) {
|
|
for (var i in selfR.users) {
|
|
selfR.users.emit('connectionError', message);
|
|
}
|
|
};
|
|
this.reset = function(reload) {
|
|
clearTimeout(selfR.resetTimer);
|
|
selfR.resetTimer = null;
|
|
|
|
if (lockdown) {
|
|
selfR.add('The battle was not restarted because the server is preparing to shut down.');
|
|
return;
|
|
}
|
|
|
|
selfR.battle.add('RESET');
|
|
selfR.update();
|
|
|
|
if (selfR.battle.p1 && selfR.battle.p1.user) delete selfR.battle.p1.user.sides[selfR.id];
|
|
if (selfR.battle.p2 && selfR.battle.p2.user) delete selfR.battle.p2.user.sides[selfR.id];
|
|
|
|
console.log("NEW BATTLE (reset)");
|
|
selfR.battle = new Battle(selfR.id, selfR.format, false);
|
|
selfR.active = selfR.battle.active;
|
|
if (selfR.parentid) {
|
|
getRoom(selfR.parentid).updateRooms();
|
|
}
|
|
};
|
|
this.getInactiveSide = function() {
|
|
var inactiveSide = -1;
|
|
if (!selfR.battle.p1.user && selfR.battle.p2.user) {
|
|
inactiveSide = 0;
|
|
} else if (selfR.battle.p1.user && !selfR.battle.p2.user) {
|
|
inactiveSide = 1;
|
|
} else if (!selfR.battle.p1.decision && selfR.battle.p2.decision) {
|
|
inactiveSide = 0;
|
|
} else if (selfR.battle.p1.decision && !selfR.battle.p2.decision) {
|
|
inactiveSide = 1;
|
|
}
|
|
return inactiveSide;
|
|
};
|
|
// side can be a side or user
|
|
this.forfeit = function(side, message) {
|
|
var forfeitSide = -1;
|
|
if (!selfR.battle || selfR.battle.ended || !selfR.battle.started) return false;
|
|
|
|
if (side === selfR.battle.sides[0]) forfeitSide = 0;
|
|
else if (side === selfR.battle.sides[1]) forfeitSide = 1;
|
|
else if (side === 0) forfeitSide = 0;
|
|
else if (side === 1) forfeitSide = 1;
|
|
else if (side === selfR.battle.sides[0].user) forfeitSide = 0;
|
|
else if (side === selfR.battle.sides[1].user) forfeitSide = 1;
|
|
else return false;
|
|
|
|
if (!message) message = ' forfeited.';
|
|
|
|
selfR.battle.add('-message', selfR.battle.sides[forfeitSide].name+message);
|
|
selfR.battle.win(selfR.battle.sides[forfeitSide].foe);
|
|
selfR.active = selfR.battle.active;
|
|
selfR.update();
|
|
return true;
|
|
}
|
|
this.kickInactive = function() {
|
|
clearTimeout(selfR.resetTimer);
|
|
selfR.resetTimer = null;
|
|
|
|
var action = 'be kicked';
|
|
if (selfR.rated) {
|
|
action = 'forfeit';
|
|
}
|
|
|
|
var inactiveSide = selfR.getInactiveSide();
|
|
|
|
if (!selfR.battle || selfR.battle.ended || !selfR.battle.started) return false;
|
|
|
|
if (inactiveSide == -1) {
|
|
selfR.add('Both players are inactive, so neither player was kicked.');
|
|
selfR.update();
|
|
return;
|
|
}
|
|
if (!selfR.battle.curCallback) {
|
|
selfR.add('We are experiencing a bug. Please notify a system operator (people with & next to their name).');
|
|
selfR.update();
|
|
return;
|
|
}
|
|
|
|
// now to see how much time we have left
|
|
if (selfR.inactiveTicksLeft) {
|
|
selfR.inactiveTicksLeft--;
|
|
}
|
|
if (selfR.sideFreeTicks[inactiveSide]) {
|
|
selfR.sideFreeTicks[inactiveSide]--;
|
|
} else {
|
|
selfR.sideTicksLeft[inactiveSide]--;
|
|
}
|
|
if (selfR.inactiveTicksLeft) {
|
|
selfR.add('Inactive players will '+action+' in '+(selfR.inactiveTicksLeft*30)+' seconds.'+(selfR.sideFreeTicks[inactiveSide]?selfR.inactiveAtrrib:''));
|
|
selfR.update();
|
|
selfR.resetTimer = setTimeout(selfR.kickInactive, 30*1000);
|
|
return;
|
|
}
|
|
|
|
if (selfR.battle.rated) {
|
|
selfR.forfeit(inactiveSide,' lost because of their inactivity.');
|
|
} else {
|
|
if (selfR.battle.sides[0].user && selfR.battle.sides[1].user) {
|
|
selfR.add('Kicking inactive players.');
|
|
selfR.battle.leave(selfR.battle.sides[inactiveSide].user);
|
|
selfR.active = selfR.battle.active;
|
|
selfR.update();
|
|
} else {
|
|
selfR.add('There are already empty slots; no kicks are necessary.');
|
|
}
|
|
}
|
|
|
|
if (selfR.parentid) {
|
|
getRoom(selfR.parentid).updateRooms();
|
|
}
|
|
}
|
|
this.requestReset = function(user) {
|
|
if (selfR.resetTimer) return;
|
|
if (!selfR.battle.started) return; // no point
|
|
if (user) attrib = ' (requested by '+user.name+')';
|
|
if (selfR.rated) {
|
|
selfR.add('The battle cannot be restarted because it is a rated battle'+attrib+'.');
|
|
return;
|
|
}
|
|
var elapsedTime = getTime() - selfR.graceTime;
|
|
|
|
// tickTime is in chunks of 30
|
|
var tickTime = 1;
|
|
|
|
if (elapsedTime < 60000) {
|
|
tickTime = 6;
|
|
} else if (elapsedTime < 120000) {
|
|
tickTime = 4;
|
|
} else if (elapsedTime < 150000) {
|
|
tickTime = 2;
|
|
} else {
|
|
tickTime = 1;
|
|
}
|
|
selfR.add('The battle will restart if there is no activity for '+(tickTime*30)+' seconds.'+attrib);
|
|
selfR.update();
|
|
selfR.resetTimer = setTimeout(selfR.reset, tickTime*30*1000);
|
|
};
|
|
this.requestKickInactive = function(user) {
|
|
if (selfR.resetTimer) {
|
|
user.emit('console', {room:selfR.id, message: 'The inactivity timer is already counting down.'});
|
|
return;
|
|
}
|
|
if ((!selfR.battle.p1.user || !selfR.battle.p2.user) && !selfR.rated) {
|
|
selfR.add('This isn\'t a rated battle; victory doesn\'t mean anything.');
|
|
selfR.add('Do you just want to see the text "you win"? Okay. You win.');
|
|
selfR.update();
|
|
return;
|
|
}
|
|
|
|
selfR.inactiveAtrrib = '';
|
|
if (user) selfR.inactiveAtrrib = ' (requested by '+user.name+')';
|
|
|
|
var action = 'be kicked';
|
|
if (selfR.rated) {
|
|
action = 'forfeit';
|
|
}
|
|
|
|
// a tick is 30 seconds
|
|
|
|
var elapsedTicks = Math.floor((getTime() - selfR.graceTime) / 30000);
|
|
tickTime = 6 - elapsedTicks;
|
|
if (tickTime < 1) {
|
|
tickTime = 1;
|
|
}
|
|
|
|
if (tickTime > 2 && (!selfR.battle.p1.user || !selfR.battle.p2.user)) {
|
|
// if a player has left, don't wait longer than 2 ticks (60 seconds)
|
|
tickTime = 2;
|
|
}
|
|
|
|
if (elapsedTicks >= 8) selfR.sideTicksLeft[inactiveSide]--;
|
|
if (elapsedTicks >= 6) selfR.sideTicksLeft[inactiveSide]--;
|
|
if (elapsedTicks >= 4) selfR.sideTicksLeft[inactiveSide]--;
|
|
if (elapsedTicks >= 2) selfR.sideTicksLeft[inactiveSide]--;
|
|
var inactiveSide = selfR.getInactiveSide();
|
|
if (tickTime > 2 && selfR.sideTicksLeft[inactiveSide] < tickTime) {
|
|
tickTime = selfR.sideTicksLeft[inactiveSide];
|
|
if (tickTime < 2) tickTime = 2;
|
|
}
|
|
|
|
selfR.inactiveTicksLeft = tickTime;
|
|
var message = 'Inactive players will '+action+' in '+(tickTime*30)+' seconds.'+selfR.inactiveAtrrib;
|
|
if (elapsedTicks < 1 && tickTime >= 2 && selfR.sideTicksLeft[inactiveSide] > -4) {
|
|
// the foe has at least a minute left, and hasn't been given 30 seconds to make a move yet
|
|
// we'll wait another 30 seconds before notifying them that they have a time limit
|
|
user.emit('console', {room:selfR.id, message: message});
|
|
selfR.sideFreeTicks[inactiveSide] = 1;
|
|
} else {
|
|
selfR.add(message);
|
|
selfR.sideFreeTicks[inactiveSide] = 0;
|
|
}
|
|
selfR.update();
|
|
selfR.resetTimer = setTimeout(selfR.kickInactive, 30*1000);
|
|
};
|
|
this.cancelReset = function() {
|
|
if (selfR.resetTimer) {
|
|
selfR.add('The restart or kick was interrupted by activity.');
|
|
selfR.update();
|
|
clearTimeout(selfR.resetTimer);
|
|
selfR.resetTimer = null;
|
|
}
|
|
selfR.graceTime = getTime();
|
|
};
|
|
this.decision = function(user, choice, data) {
|
|
selfR.cancelReset();
|
|
selfR.battle.decision(user, choice, data);
|
|
if (selfR.battle.ended) {
|
|
selfR.battle.add('callback', 'restart');
|
|
}
|
|
if (selfR.active !== selfR.battle.active) {
|
|
selfR.active = selfR.battle.active;
|
|
if (selfR.parentid) {
|
|
getRoom(selfR.parentid).updateRooms();
|
|
}
|
|
}
|
|
selfR.update();
|
|
};
|
|
this.battleEndRestart = function() {
|
|
selfR.add('Rematch support has been temporarily disabled. Please challenge this user again in the lobby.');
|
|
return;
|
|
|
|
if (selfR.resetTimer) return;
|
|
if (selfR.battle.ended) {
|
|
selfR.add('A new game will start in 5 seconds.');
|
|
// reset in 5 seconds
|
|
selfR.resetTimer = setTimeout(selfR.reset, 5000);
|
|
}
|
|
};
|
|
this.initSocket = function(user, socket) {
|
|
var initdata = {
|
|
name: user.name,
|
|
userid: user.userid,
|
|
named: user.named,
|
|
renamePending: user.renamePending,
|
|
token: user.token,
|
|
room: selfR.id,
|
|
roomType: 'battle',
|
|
battlelog: selfR.battle.log
|
|
};
|
|
socket.emit('init', initdata);
|
|
};
|
|
this.join = function(user) {
|
|
if (!user) return false;
|
|
if (selfR.users[user.userid]) return user;
|
|
|
|
selfR.users[user.userid] = user;
|
|
|
|
if (user.named) {
|
|
selfR.battle.add('join', user.name);
|
|
selfR.update(user);
|
|
}
|
|
|
|
var initdata = {
|
|
name: user.name,
|
|
userid: user.userid,
|
|
named: user.named,
|
|
renamePending: user.renamePending,
|
|
token: user.token,
|
|
room: selfR.id,
|
|
roomType: 'battle',
|
|
battlelog: selfR.battle.log
|
|
};
|
|
user.emit('init', initdata);
|
|
|
|
return user;
|
|
};
|
|
this.rename = function(user, oldid, joining) {
|
|
if (joining) {
|
|
selfR.battle.add('join', user.name);
|
|
}
|
|
if (user.sides[selfR.id]) {
|
|
selfR.battle.rename(user);
|
|
}
|
|
delete selfR.users[oldid];
|
|
selfR.users[user.userid] = user;
|
|
selfR.update();
|
|
return user;
|
|
};
|
|
this.joinBattle = function(user) {
|
|
var slot = 0;
|
|
if (selfR.rated) {
|
|
if (selfR.rated.p1 === user.userid) {
|
|
slot = 1;
|
|
} else if (selfR.rated.p2 === user.userid) {
|
|
slot = 2;
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
selfR.cancelReset();
|
|
selfR.battle.join(user, slot);
|
|
selfR.active = selfR.battle.active;
|
|
selfR.update();
|
|
|
|
if (selfR.parentid) {
|
|
getRoom(selfR.parentid).updateRooms();
|
|
}
|
|
};
|
|
this.leaveBattle = function(user) {
|
|
if (!user) return; // ...
|
|
if (user.sides[selfR.id]) {
|
|
selfR.battle.leave(user);
|
|
}
|
|
selfR.active = selfR.battle.active;
|
|
selfR.update();
|
|
|
|
if (selfR.parentid) {
|
|
getRoom(selfR.parentid).updateRooms();
|
|
}
|
|
};
|
|
this.leave = function(user) {
|
|
if (!user) return; // ...
|
|
if (user.sides[selfR.id]) {
|
|
selfR.battle.leave(user);
|
|
selfR.active = selfR.battle.active;
|
|
if (selfR.parentid) {
|
|
getRoom(selfR.parentid).updateRooms();
|
|
}
|
|
} else if (!user.named) {
|
|
delete selfR.users[user.userid];
|
|
return;
|
|
}
|
|
delete selfR.users[user.userid];
|
|
selfR.battle.add('leave', user.name);
|
|
selfR.update();
|
|
};
|
|
this.isEmpty = function() {
|
|
if (selfR.battle.p1 && selfR.battle.p1.user) return false;
|
|
if (selfR.battle.p2 && selfR.battle.p2.user) return false;
|
|
return true;
|
|
};
|
|
this.isFull = function() {
|
|
if (selfR.battle.p1 && selfR.battle.p1.user && selfR.battle.p2 && selfR.battle.p2.user) return true;
|
|
return false;
|
|
};
|
|
this.add = function(message) {
|
|
if (message.rawMessage) {
|
|
selfR.battle.add('chatmsg-raw', message.rawMessage);
|
|
} else if (message.name) {
|
|
selfR.battle.add('chat', message.name.substr(1), message.message);
|
|
} else {
|
|
selfR.battle.add('chatmsg', message);
|
|
}
|
|
};
|
|
this.addRaw = function(message) {
|
|
selfR.battle.add('chatmsg-raw', message);
|
|
};
|
|
this.chat = function(user, message, socket) {
|
|
var cmd = '', target = '';
|
|
if (message.length > 511 && !user.can('ignorelimits')) {
|
|
socket.emit('message', "Your message is too long:\n\n"+message);
|
|
return;
|
|
}
|
|
if (message.substr(0,2) === '//') {
|
|
message = message.substr(1);
|
|
} else if (message.substr(0,1) === '/') {
|
|
var spaceIndex = message.indexOf(' ');
|
|
if (spaceIndex > 0) {
|
|
cmd = message.substr(1, spaceIndex-1);
|
|
target = message.substr(spaceIndex+1);
|
|
} else {
|
|
cmd = message.substr(1);
|
|
target = '';
|
|
}
|
|
} else if (message.substr(0,1) === '!') {
|
|
var spaceIndex = message.indexOf(' ');
|
|
if (spaceIndex > 0) {
|
|
cmd = message.substr(0, spaceIndex);
|
|
target = message.substr(spaceIndex+1);
|
|
} else {
|
|
cmd = message;
|
|
target = '';
|
|
}
|
|
}
|
|
|
|
var parsedMessage = parseCommand(user, cmd, target, selfR, socket, message);
|
|
if (typeof parsedMessage === 'string') {
|
|
message = parsedMessage;
|
|
}
|
|
if (parsedMessage === false) {
|
|
// do nothing
|
|
} else if (message.substr(0,3) === '>> ') {
|
|
var cmd = message.substr(3);
|
|
|
|
var room = selfR;
|
|
var battle = selfR.battle;
|
|
var selfB = battle;
|
|
var p2;
|
|
var p1;
|
|
var p2active;
|
|
var p1active;
|
|
var me = user;
|
|
if (battle) {
|
|
p2 = battle.p2;
|
|
p1 = battle.p1;
|
|
if (p2) {
|
|
p2active = p2.active[0];
|
|
}
|
|
if (p1) {
|
|
p1active = p1.active[0];
|
|
}
|
|
}
|
|
selfR.battle.add('chat', user.name, '>> '+cmd);
|
|
if (user.can('console')) {
|
|
try {
|
|
selfR.battle.add('chat', user.name, '<< '+eval(cmd));
|
|
} catch (e) {
|
|
selfR.battle.add('chat', user.name, '<< error: '+e.message);
|
|
var stack = (""+e.stack).split("\n");
|
|
for (var i=0; i<stack.length; i++) {
|
|
user.emit('console', '<< '+stack[i]);
|
|
}
|
|
}
|
|
} else {
|
|
selfR.battle.add('chat', user.name, '<< Access denied.');
|
|
}
|
|
} else {
|
|
selfR.battle.add('chat', user.name, message);
|
|
}
|
|
selfR.update();
|
|
};
|
|
|
|
this.destroy = function() {
|
|
// deallocate ourself
|
|
|
|
// remove references to ourself
|
|
for (var i in selfR.users) {
|
|
selfR.users[i].leaveRoom(selfR);
|
|
delete selfR.users[i];
|
|
}
|
|
selfR.users = null;
|
|
|
|
// deallocate children and get rid of references to them
|
|
if (selfR.battle) {
|
|
selfR.battle.destroy();
|
|
}
|
|
selfR.battle = null;
|
|
|
|
if (selfR.resetTimer) {
|
|
clearTimeout(selfR.resetTimer);
|
|
}
|
|
selfR.resetTimer = null;
|
|
|
|
// get rid of some possibly-circular references
|
|
delete rooms[selfR.id];
|
|
|
|
selfR = null;
|
|
}
|
|
}
|
|
|
|
function Lobby(roomid) {
|
|
var selfR = this; // a lobby is like a room, selfR makes things simpler
|
|
this.type = 'lobby';
|
|
this.id = roomid;
|
|
this.i = {};
|
|
this.log = [];
|
|
this.lastUpdate = 0;
|
|
this.users = {};
|
|
this.rooms = [];
|
|
this.numRooms = 0;
|
|
this.searchers = [];
|
|
|
|
this.usersChanged = true;
|
|
this.roomsChanged = true;
|
|
|
|
// Never do any other file IO synchronously
|
|
// but this is okay to prevent race conditions as we start up PS
|
|
this.numRooms = 0;
|
|
try {
|
|
parseInt(fs.readFileSync('logs/lastbattle.txt')) || 0;
|
|
} catch (e) {} // file doesn't exist [yet]
|
|
|
|
this.getUpdate = function(since, omitUsers, omitRoomList) {
|
|
var update = {room: roomid};
|
|
var i = since;
|
|
if (!i) i = selfR.log.length - 100;
|
|
if (i<0) i = 0;
|
|
update.logStart = i;
|
|
update.logUpdate = [];
|
|
for (;i<selfR.log.length;i++) {
|
|
update.logUpdate.push(selfR.log[i]);
|
|
}
|
|
if (!omitRoomList) update.rooms = selfR.getRoomList();
|
|
if (!omitUsers) update.users = selfR.getUserList();
|
|
update.searcher = selfR.searchers.length;
|
|
return update;
|
|
};
|
|
this.getUserList = function() {
|
|
var userList = {list: {}, users: 0, unregistered: 0, guests: 0};
|
|
for (var i in selfR.users) {
|
|
if (!selfR.users[i].named) {
|
|
userList.guests++;
|
|
continue;
|
|
}
|
|
userList.users++;
|
|
userList.list[selfR.users[i].userid] = selfR.users[i].getIdentity();
|
|
}
|
|
return userList;
|
|
};
|
|
this.getRoomList = function(filter) {
|
|
var roomList = {};
|
|
var total = 0;
|
|
for (i=selfR.rooms.length-1; i>=0; i--) {
|
|
var room = selfR.rooms[i];
|
|
if (!room || !room.active) continue;
|
|
if (filter && filter !== room.format && filter !== true) continue;
|
|
var roomData = {};
|
|
if (room.battle && room.battle.sides[0] && room.battle.sides[1]) {
|
|
if (room.battle.sides[0].user && room.battle.sides[1].user) {
|
|
roomData.p1 = room.battle.sides[0].user.getIdentity();
|
|
roomData.p2 = room.battle.sides[1].user.getIdentity();
|
|
} else if (room.battle.sides[0].user) {
|
|
roomData.p1 = room.battle.sides[0].user.getIdentity();
|
|
} else if (room.battle.sides[1].user) {
|
|
roomData.p1 = room.battle.sides[1].user.getIdentity();
|
|
}
|
|
}
|
|
roomList[selfR.rooms[i].id] = roomData;
|
|
|
|
total++;
|
|
if (total >= 8 && !filter) break;
|
|
}
|
|
return roomList;
|
|
};
|
|
this.cancelSearch = function(user, noUpdate) {
|
|
user.cancelChallengeTo();
|
|
for (var i=0; i<selfR.searchers.length; i++) {
|
|
var search = selfR.searchers[i];
|
|
if (!search.user.connected) {
|
|
selfR.searchers.splice(i,1);
|
|
i--;
|
|
continue;
|
|
}
|
|
if (search.user === user) {
|
|
selfR.searchers.splice(i,1);
|
|
search.user.emit('update', {searching: false, room: selfR.id});
|
|
if (!noUpdate) {
|
|
selfR.update();
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
this.searchBattle = function(user, format) {
|
|
if (!user.connected) return;
|
|
if (lockdown) {
|
|
user.emit('message', 'The server is shutting down. Battles cannot be started at this time.');
|
|
return;
|
|
}
|
|
|
|
var problems = Tools.validateTeam(user.team, format);
|
|
if (problems) {
|
|
user.emit('message', "Your team was rejected for the following reasons:\n\n- "+problems.join("\n- "));
|
|
return;
|
|
}
|
|
|
|
for (var i=0; i<selfR.searchers.length; i++) {
|
|
var search = selfR.searchers[i];
|
|
if (!search.user.connected) {
|
|
selfR.searchers.splice(i,1);
|
|
i--;
|
|
continue;
|
|
}
|
|
if (format === search.format) {
|
|
if (search.user === user) {
|
|
return;
|
|
}
|
|
selfR.searchers.splice(i,1);
|
|
search.user.emit('update', {searching: false, room: selfR.id});
|
|
search.user.team = search.team;
|
|
selfR.startBattle(search.user, user, format, true);
|
|
return;
|
|
}
|
|
}
|
|
var newSearch = {
|
|
user: user,
|
|
format: format,
|
|
room: selfR.id,
|
|
team: user.team
|
|
};
|
|
var newSearchData = {
|
|
userid: user.userid,
|
|
format: format,
|
|
room: selfR.id
|
|
};
|
|
selfR.searchers.push(newSearch);
|
|
user.emit('update', {searching: newSearchData, room: selfR.id});
|
|
selfR.update();
|
|
};
|
|
this.update = function(excludeUser) {
|
|
var update = selfR.getUpdate(selfR.lastUpdate, !selfR.usersChanged, !selfR.roomsChanged);
|
|
update.room = selfR.id;
|
|
selfR.lastUpdate = selfR.log.length;
|
|
for (var i in selfR.users) {
|
|
if (selfR.users[i] === excludeUser) continue;
|
|
selfR.users[i].emit('update', update);
|
|
}
|
|
selfR.usersChanged = false;
|
|
selfR.roomsChanged = false;
|
|
};
|
|
this.emit = function(type, message, user) {
|
|
if (type === 'console' || type === 'update') {
|
|
if (typeof message === 'string') {
|
|
message = {message: message};
|
|
}
|
|
message.room = selfR.id;
|
|
}
|
|
if (user && user.emit) {
|
|
user.emit(type, message);
|
|
} else {
|
|
for (var i in selfR.users) {
|
|
selfR.users[i].emit(type, message);
|
|
}
|
|
}
|
|
};
|
|
this.updateRooms = function(excludeUser) {
|
|
var update = {
|
|
rooms: selfR.getRoomList()
|
|
};
|
|
update.room = selfR.id;
|
|
for (var i in selfR.users) {
|
|
if (selfR.users[i] === excludeUser) continue;
|
|
selfR.users[i].emit('update', update);
|
|
}
|
|
selfR.roomsChanged = false;
|
|
};
|
|
this.add = function(message) {
|
|
if (typeof message === 'string') {
|
|
selfR.log.push({
|
|
message: message
|
|
});
|
|
} else {
|
|
selfR.log.push(message);
|
|
}
|
|
selfR.update();
|
|
};
|
|
this.addRaw = function(message) {
|
|
selfR.log.push({
|
|
rawMessage: message
|
|
});
|
|
selfR.update();
|
|
};
|
|
this.initSocket = function(user, socket) {
|
|
var initdata = {
|
|
name: user.name,
|
|
userid: user.userid,
|
|
named: user.named,
|
|
renamePending: user.renamePending,
|
|
token: user.token,
|
|
room: selfR.id,
|
|
rooms: selfR.getRoomList(),
|
|
users: selfR.getUserList(),
|
|
roomType: 'lobby',
|
|
log: selfR.log.slice(-100),
|
|
searcher: selfR.searchers.length,
|
|
}
|
|
socket.emit('init', initdata);
|
|
};
|
|
this.join = function(user) {
|
|
if (!user) return false; // ???
|
|
if (selfR.users[user.userid]) return user;
|
|
|
|
selfR.users[user.userid] = user;
|
|
if (user.named && config.reportjoins) {
|
|
selfR.log.push({name: user.getIdentity(), action: 'join'});
|
|
selfR.update(user);
|
|
} else if (user.named) {
|
|
selfR.emit('console', {name: user.getIdentity(), action: 'join', silent: 1});
|
|
}
|
|
|
|
var initdata = {
|
|
name: user.name,
|
|
userid: user.userid,
|
|
named: user.named,
|
|
renamePending: user.renamePending,
|
|
token: user.token,
|
|
room: selfR.id,
|
|
rooms: selfR.getRoomList(),
|
|
users: selfR.getUserList(),
|
|
roomType: 'lobby',
|
|
log: selfR.log.slice(-100),
|
|
searcher: selfR.searchers.length,
|
|
}
|
|
user.emit('init', initdata);
|
|
|
|
return user;
|
|
};
|
|
this.rename = function(user, oldid, joining) {
|
|
delete selfR.users[oldid];
|
|
selfR.users[user.userid] = user;
|
|
if (joining && config.reportjoins) {
|
|
selfR.log.push({name: user.getIdentity(), oldid: oldid, action: 'join'});
|
|
selfR.update();
|
|
} else if (joining) {
|
|
selfR.emit('console', {name: user.getIdentity(), oldid: oldid, action: 'join', silent: 1});
|
|
} else if (!user.named) {
|
|
selfR.emit('console', {name: oldid, action: 'leave', silent: 1});
|
|
} else {
|
|
selfR.emit('console', {name: user.getIdentity(), oldid: oldid, action: 'rename', silent: 1});
|
|
}
|
|
return user;
|
|
};
|
|
this.leave = function(user) {
|
|
if (!user) return; // ...
|
|
delete selfR.users[user.userid];
|
|
selfR.cancelSearch(user, true);
|
|
if (config.reportjoins) {
|
|
selfR.log.push({name: user.getIdentity(), action: 'leave'});
|
|
selfR.update();
|
|
} else if (user.named) {
|
|
selfR.emit('console', {name: user.getIdentity(), action: 'leave', silent: 1});
|
|
}
|
|
};
|
|
this.startBattle = function(p1, p2, format, rated) {
|
|
var newRoom;
|
|
p1 = getUser(p1);
|
|
p2 = getUser(p2);
|
|
|
|
if (p1 === p2) {
|
|
selfR.cancelSearch(p1, true);
|
|
selfR.cancelSearch(p2, true);
|
|
p1.emit('message', 'You can\'t battle your own account. Please use Private Browsing to battle yourself.');
|
|
return;
|
|
}
|
|
|
|
if (lockdown) {
|
|
selfR.cancelSearch(p1, true);
|
|
selfR.cancelSearch(p2, true);
|
|
p1.emit('message', 'The server is shutting down. Battles cannot be started at this time.');
|
|
p2.emit('message', 'The server is shutting down. Battles cannot be started at this time.');
|
|
selfR.update();
|
|
return;
|
|
}
|
|
|
|
//console.log('BATTLE START BETWEEN: '+p1.userid+' '+p2.userid);
|
|
var i = selfR.numRooms+1;
|
|
var formaturlid = format.toLowerCase().replace(/[^a-z0-9]+/g,'');
|
|
while(rooms['battle-'+formaturlid+i]) {
|
|
i++;
|
|
}
|
|
selfR.numRooms = i;
|
|
newRoom = selfR.addRoom('battle-'+formaturlid+i, format, p1, p2, selfR.id, rated);
|
|
p1.joinRoom(newRoom);
|
|
p2.joinRoom(newRoom);
|
|
newRoom.joinBattle(p1);
|
|
newRoom.joinBattle(p2);
|
|
selfR.cancelSearch(p1, true);
|
|
selfR.cancelSearch(p2, true);
|
|
selfR.roomsChanged = true;
|
|
if (config.reportbattles) {
|
|
selfR.log.push({
|
|
name: p1.name,
|
|
name2: p2.name,
|
|
room: newRoom.id,
|
|
format: format,
|
|
action: 'battle'
|
|
});
|
|
selfR.update();
|
|
}
|
|
};
|
|
this.addRoom = function(room, format, p1, p2, parent, rated) {
|
|
room = newRoom(room, format, p1, p2, parent, rated);
|
|
if (typeof room.i[selfR.id] !== 'undefined') return;
|
|
room.i[selfR.id] = selfR.rooms.length;
|
|
selfR.rooms.push(room);
|
|
return room;
|
|
};
|
|
this.removeRoom = function(room) {
|
|
room = getRoom(room);
|
|
if (typeof room.i[selfR.id] !== 'undefined') {
|
|
selfR.rooms = selfR.rooms.splice(room.i[selfR.id],1);
|
|
delete room.i[selfR.id];
|
|
for (var i=0; i<selfR.rooms.length; i++) {
|
|
selfR.rooms[i].i[selfR.id] = i;
|
|
}
|
|
}
|
|
};
|
|
this.isEmpty = function() { return false; };
|
|
this.isFull = function() { return false; };
|
|
this.chat = function(user, message, socket) {
|
|
if (!user.named || !message || !message.trim || !message.trim().length) return;
|
|
if (message.length > 255 && !user.can('ignorelimits')) {
|
|
socket.emit('message', "Your message is too long:\n\n"+message);
|
|
return;
|
|
}
|
|
var cmd = '', target = '';
|
|
if (message.substr(0,2) === '//') {
|
|
message = message.substr(1);
|
|
} else if (message.substr(0,1) === '/') {
|
|
var spaceIndex = message.indexOf(' ');
|
|
if (spaceIndex > 0) {
|
|
cmd = message.substr(1, spaceIndex-1);
|
|
target = message.substr(spaceIndex+1);
|
|
} else {
|
|
cmd = message.substr(1);
|
|
target = '';
|
|
}
|
|
} else if (message.substr(0,1) === '!') {
|
|
var spaceIndex = message.indexOf(' ');
|
|
if (spaceIndex > 0) {
|
|
cmd = message.substr(0, spaceIndex);
|
|
target = message.substr(spaceIndex+1);
|
|
} else {
|
|
cmd = message;
|
|
target = '';
|
|
}
|
|
}
|
|
|
|
var parsedMessage = parseCommand(user, cmd, target, selfR, socket, message);
|
|
if (typeof parsedMessage === 'string') message = parsedMessage;
|
|
if (parsedMessage === false) {
|
|
// do nothing
|
|
} else if (message.substr(0,3) === '>> ') {
|
|
var cmd = message.substr(3);
|
|
|
|
var room = selfR;
|
|
var me = user;
|
|
selfR.log.push({
|
|
name: user.getIdentity(),
|
|
message: '>> '+cmd
|
|
});
|
|
if (user.can('console')) {
|
|
try {
|
|
selfR.log.push({
|
|
name: user.getIdentity(),
|
|
message: '<< '+eval(cmd)
|
|
});
|
|
} catch (e) {
|
|
selfR.log.push({
|
|
name: user.getIdentity(),
|
|
message: '<< error: '+e.message
|
|
});
|
|
var stack = (""+e.stack).split("\n");
|
|
for (var i=0; i<stack.length; i++) {
|
|
user.emit('console', '<< '+stack[i]);
|
|
}
|
|
}
|
|
} else {
|
|
selfR.log.push({
|
|
name: user.getIdentity(),
|
|
message: '<< Access denied.'
|
|
});
|
|
}
|
|
} else if (!user.muted) {
|
|
selfR.log.push({
|
|
name: user.getIdentity(),
|
|
message: message
|
|
});
|
|
}
|
|
selfR.update();
|
|
};
|
|
}
|
|
|
|
|
|
rooms = {};
|
|
console.log("NEW LOBBY: lobby");
|
|
var lobby = new Lobby('lobby');
|
|
rooms.lobby = lobby;
|
|
|
|
getRoom = function(roomid) {
|
|
if (roomid && roomid.id) return roomid;
|
|
if (!roomid) roomid = 'default';
|
|
if (!rooms[roomid]) {
|
|
return rooms.lobby;
|
|
}
|
|
return rooms[roomid];
|
|
}
|
|
newRoom = function(roomid, format, p1, p2, parent, rated) {
|
|
if (roomid && roomid.id) return roomid;
|
|
if (!roomid) roomid = 'default';
|
|
if (!rooms[roomid]) {
|
|
console.log("NEW ROOM: "+roomid);
|
|
rooms[roomid] = new Room(roomid, format, p1, p2, parent, rated);
|
|
}
|
|
return rooms[roomid];
|
|
}
|
|
|
|
mutedIps = {
|
|
};
|
|
bannedIps = {
|
|
};
|
|
nameLockedIps = {
|
|
};
|
|
|
|
function resolveUser(you, socket) {
|
|
if (!you) {
|
|
socket.emit('connectionError', 'There has been a connection error. Please refresh the page.');
|
|
return false;
|
|
}
|
|
return you.user;
|
|
}
|
|
|
|
if (config.crashguard) {
|
|
// graceful crash - allow current battles to finish before restarting
|
|
process.on('uncaughtException', function (err) {
|
|
console.log("\n"+err.stack+"\n");
|
|
fs.createWriteStream('logs/errors.txt', {'flags': 'a'}).on("open", function(fd) {
|
|
this.write("\n"+err.stack+"\n")
|
|
this.end();
|
|
});
|
|
var stack = (""+err.stack).split("\n").slice(0,2).join("<br />");
|
|
lobby.addRaw('<div style="background-color:#BB6655;color:white;padding:2px 4px"><b>THE SERVER HAS CRASHED:</b> '+stack+'<br />Please restart the server.</div>');
|
|
lobby.addRaw('<div style="background-color:#BB6655;color:white;padding:2px 4px">You will not be able to talk in the lobby or start new battles until the server restarts.</div>');
|
|
config.modchat = 'crash';
|
|
lockdown = true;
|
|
});
|
|
}
|
|
|
|
io.sockets.on('connection', function (socket) {
|
|
var you = null;
|
|
console.log('INIT SOCKET: '+socket.id);
|
|
|
|
if (socket.handshake && socket.handshake.address && socket.handshake.address.address) {
|
|
if (bannedIps[socket.handshake.address.address]) {
|
|
console.log('IP BANNED: '+socket.handshake.address.address);
|
|
return;
|
|
}
|
|
}
|
|
|
|
socket.on('join', function(data) {
|
|
if (typeof data.room !== 'string') return;
|
|
if (!you) {
|
|
you = Users.connectUser(data.name, socket, data.token, data.room);
|
|
console.log('JOIN: '+data.name+' => '+you.name+' ['+data.token+']');
|
|
} else {
|
|
var youUser = resolveUser(you, socket);
|
|
if (!youUser) return;
|
|
youUser.joinRoom(data.room, socket);
|
|
}
|
|
});
|
|
socket.on('rename', function(data) {
|
|
data.name = ''+data.name;
|
|
var youUser = resolveUser(you, socket);
|
|
if (!youUser) return;
|
|
youUser.rename(data.name, data.token, data.auth);
|
|
});
|
|
socket.on('chat', function(message) {
|
|
if (typeof message.room !== 'string') return;
|
|
var youUser = resolveUser(you, socket);
|
|
if (!youUser) return;
|
|
if (!message) return;
|
|
var room = getRoom(message.room);
|
|
room.chat(youUser, message.message, socket);
|
|
});
|
|
socket.on('leave', function(data) {
|
|
if (typeof data.room !== 'string') return;
|
|
var youUser = resolveUser(you, socket);
|
|
if (!youUser) return;
|
|
if (!data) return;
|
|
youUser.leaveRoom(getRoom(data.room), socket);
|
|
});
|
|
socket.on('leaveBattle', function(data) {
|
|
if (typeof data.room !== 'string') return;
|
|
var youUser = resolveUser(you, socket);
|
|
if (!youUser) return;
|
|
if (!data) return;
|
|
var room = getRoom(data.room);
|
|
if (room.leaveBattle) room.leaveBattle(youUser);
|
|
});
|
|
socket.on('joinBattle', function(data) {
|
|
if (typeof data.room !== 'string') return;
|
|
var youUser = resolveUser(you, socket);
|
|
if (!youUser) return;
|
|
var room = getRoom(data.room);
|
|
if (room.joinBattle) room.joinBattle(youUser);
|
|
});
|
|
|
|
socket.on('command', function(data) {
|
|
if (typeof data.room !== 'string') return;
|
|
var youUser = resolveUser(you, socket);
|
|
if (!youUser) return;
|
|
parseCommand(youUser, 'command', data, getRoom(data.room), socket);
|
|
});
|
|
socket.on('disconnect', function() {
|
|
var youUser = resolveUser(you, socket);
|
|
if (!youUser) return;
|
|
youUser.disconnect(socket);
|
|
});
|
|
socket.on('challenge', function(data) {
|
|
var youUser = resolveUser(you, socket);
|
|
if (!youUser) return;
|
|
console.log('CHALLENGE: '+youUser.name+' => '+data.userid+' ('+data.act+')');
|
|
switch (data.act) {
|
|
case 'make':
|
|
if (typeof data.format !== 'string') data.format = 'debugmode';
|
|
if (typeof data.userid !== 'string') return;
|
|
var problems = Tools.validateTeam(youUser.team, data.format);
|
|
if (problems) {
|
|
socket.emit('message', "Your team was rejected for the following reasons:\n\n- "+problems.join("\n- "));
|
|
return;
|
|
}
|
|
if (!getUser(data.userid) || !getUser(data.userid).connected) {
|
|
socket.emit('message', "The user '"+data.userid+"' was not found.");
|
|
}
|
|
youUser.makeChallenge(data.userid, data.format);
|
|
break;
|
|
case 'cancel':
|
|
youUser.cancelChallengeTo(data.userid);
|
|
break;
|
|
case 'accept':
|
|
if (typeof data.userid !== 'string') return;
|
|
var format = 'debugmode';
|
|
if (youUser.challengesFrom[data.userid]) format = youUser.challengesFrom[data.userid].format;
|
|
var problems = Tools.validateTeam(youUser.team, format);
|
|
if (problems) {
|
|
socket.emit('message', "Your team was rejected for the following reasons:\n\n- "+problems.join("\n- "));
|
|
return;
|
|
}
|
|
youUser.acceptChallengeFrom(data.userid);
|
|
break;
|
|
case 'reject':
|
|
if (typeof data.userid !== 'string') return;
|
|
youUser.rejectChallengeFrom(data.userid);
|
|
break;
|
|
}
|
|
});
|
|
socket.on('decision', function(data) {
|
|
var youUser = resolveUser(you, socket);
|
|
if (!youUser) return;
|
|
var room = getRoom(data.room);
|
|
switch (data.choice) {
|
|
case 'move':
|
|
case 'switch':
|
|
case 'undo':
|
|
case 'team':
|
|
if (room.decision) room.decision(youUser,data.choice,data.move);
|
|
break;
|
|
case 'search':
|
|
if (data.search) {
|
|
if (typeof data.format !== 'string') return;
|
|
if (room.searchBattle) room.searchBattle(youUser, data.format);
|
|
} else {
|
|
if (room.cancelSearch) room.cancelSearch(youUser);
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
socket.on('saveTeam', function(data) {
|
|
var youUser = resolveUser(you, socket);
|
|
if (!youUser) return;
|
|
youUser.team = data.team;
|
|
youUser.emit('update', {team: 'saved', room: 'teambuilder'});
|
|
});
|
|
});
|