mirror of
https://github.com/smogon/pokemon-showdown-client.git
synced 2026-04-12 08:06:19 -05:00
The links in the top right are now separated by whitespace. The previous brackets were visually pretty noisy, and we no longer have a need to draw attention to them.
3615 lines
134 KiB
JavaScript
3615 lines
134 KiB
JavaScript
// some setting-like stuff
|
|
Config.server = Config.server || 'sim.smogon.com';
|
|
Config.serverport = Config.serverport || 8000;
|
|
Config.serverprotocol = Config.serverprotocol || 'ws';
|
|
|
|
var socket;
|
|
var locPrefix = '/';
|
|
if (Config.urlPrefix) locPrefix += Config.urlPrefix;
|
|
var actionphp = (function() {
|
|
var ret = '/~~' + Config.serverid + '/action.php';
|
|
if (Config.testclient) {
|
|
ret = 'http://play.pokemonshowdown.com' + ret;
|
|
}
|
|
return ret;
|
|
})();
|
|
var _gaq = _gaq || [];
|
|
|
|
// initialize sockets
|
|
var socket = null;
|
|
var me = {
|
|
name: '',
|
|
named: false,
|
|
registered: false,
|
|
userid: '',
|
|
token: '',
|
|
challengekeyid: -1,
|
|
challenge: '',
|
|
renameQueued: false,
|
|
users: {},
|
|
rooms: {},
|
|
ignore: {},
|
|
mute: (function(c) {
|
|
if (c !== null) {
|
|
Tools.prefs.set('mute', !!c, true);
|
|
$.cookie('showdown_mute', null);
|
|
return c;
|
|
}
|
|
return Tools.prefs.get('mute');
|
|
})($.cookie('showdown_mute')),
|
|
lastChallengeNotification: '',
|
|
pm: {},
|
|
curPopup: '',
|
|
popups: []
|
|
};
|
|
var rooms = {};
|
|
var curRoom = null;
|
|
var curTitle = 'Showdown!';
|
|
var battles = {};
|
|
var formats = [''];
|
|
var teams = null;
|
|
|
|
var isAndroid = navigator.userAgent.toLowerCase().indexOf("android") > -1 && navigator.userAgent.toLowerCase().indexOf("firefox") <= -1;
|
|
|
|
//
|
|
function selectTab(tab, e) {
|
|
if (e && e.preventDefault) e.preventDefault();
|
|
if (!tab) tab = 'lobby';
|
|
if (!rooms[tab]) {
|
|
joinTab(tab);
|
|
return false;
|
|
}
|
|
if (curRoom && tab !== curRoom.id && curRoom.battle) {
|
|
curRoom.battle.pause();
|
|
}
|
|
curRoom = rooms[tab];
|
|
$('#main').children().hide();
|
|
$('#leftbar a').removeClass('cur');
|
|
$('#tab-' + tab).show();
|
|
if (!$('#tabtab-' + tab).length) {
|
|
updateRoomList();
|
|
}
|
|
$('#tabtab-' + tab).addClass('cur');
|
|
if (curRoom && curRoom.battle) {
|
|
curRoom.battle.setMute(me.mute);
|
|
curRoom.battle.play();
|
|
}
|
|
curRoom.focus();
|
|
$(window).scrollTop(51);
|
|
if (tab === 'lobby') $('#backbutton').addClass('lobby');
|
|
else $('#backbutton').removeClass('lobby');
|
|
changeState(tab);
|
|
updateLobbyChat(tab);
|
|
return false;
|
|
}
|
|
|
|
function joinTab(tab) {
|
|
if (!tab || tab === 'lobby') return;
|
|
if (rooms.lobby) rooms.lobby.send('/join '+tab);
|
|
}
|
|
|
|
function leaveTab(tab, confirm) {
|
|
if (rooms[tab]) {
|
|
if (rooms[tab].me.side && rooms[tab].battle && rooms[tab].battle.rated && !rooms[tab].battleEnded && !confirm) {
|
|
overlay('forfeit', tab);
|
|
return;
|
|
}
|
|
rooms[tab].send('/leave');
|
|
rooms[tab].dealloc();
|
|
delete rooms[tab];
|
|
}
|
|
$('#tab-' + tab).remove();
|
|
if (curRoom.id === tab) {
|
|
curRoom = null;
|
|
selectTab('lobby');
|
|
} else {
|
|
updateRoomList();
|
|
}
|
|
}
|
|
|
|
function addTab(tab, type) {
|
|
if (rooms[tab] && rooms[tab].elem) {
|
|
if (tab !== 'lobby') selectTab(tab);
|
|
return;
|
|
}
|
|
var elem;
|
|
switch (type) {
|
|
case 'lobby':
|
|
$('#main').append('<div id="tab-' + tab + '" class="battle-tab"></div>');
|
|
elem = $('#main').children().last();
|
|
rooms[tab] = new Lobby(tab, elem);
|
|
break;
|
|
case 'teambuilder':
|
|
$('#main').append('<div id="tab-' + tab + '" class="battle-tab"></div>');
|
|
elem = $('#main').children().last();
|
|
rooms[tab] = new Teambuilder(tab, elem);
|
|
break;
|
|
case 'ladder':
|
|
$('#main').append('<div id="tab-' + tab + '" class="battle-tab"></div>');
|
|
elem = $('#main').children().last();
|
|
rooms[tab] = new Ladder(tab, elem);
|
|
break;
|
|
case 'battle':
|
|
$('#main').append('<div id="tab-' + tab + '" class="battle-tab"></div>');
|
|
elem = $('#main').children().last();
|
|
rooms[tab] = new BattleRoom(tab, elem);
|
|
break;
|
|
default:
|
|
$('#main').append('<div id="tab-' + tab + '" class="battle-tab">error</div>');
|
|
var room = {
|
|
id: tab,
|
|
type: 'error'
|
|
};
|
|
room.elem = $('#main').children().last();
|
|
rooms[tab] = room;
|
|
break;
|
|
}
|
|
if (tab === loc || (tab !== 'lobby' && tab !== 'teambuilder' && tab !== 'ladder')) {
|
|
selectTab(tab);
|
|
} else {
|
|
rooms[tab].elem.hide();
|
|
}
|
|
}
|
|
|
|
function emit(socket, type, data) {
|
|
if (Config.serverprotocol === 'io') {
|
|
socket.emit(type, data);
|
|
} else {
|
|
if (typeof data === 'object') data.type = type;
|
|
else data = {type: type, message: data};
|
|
|
|
if (data.type === 'chat') {
|
|
// if (window.console && console.log) console.log('>> '+data.room+'|'+data.message);
|
|
socket.send(''+data.room+'|'+data.message);
|
|
} else {
|
|
socket.send($.toJSON(data));
|
|
}
|
|
}
|
|
}
|
|
|
|
function BattleRoom(id, elem) {
|
|
var selfR = this;
|
|
this.id = id;
|
|
this.elem = elem;
|
|
this.meIdent = {
|
|
name: me.name,
|
|
named: 'init'
|
|
};
|
|
this.notifying = false;
|
|
me.rooms[id] = {};
|
|
selfR.me = me.rooms[id];
|
|
|
|
elem.html('<div class="battlewrapper"><div class="battle">Battle is here</div><div class="foehint"></div><div class="battle-log"></div><div class="battle-log-add">Connecting...</div><div class="replay-controls"></div></div>');
|
|
|
|
this.battleElem = elem.find('.battle');
|
|
this.controlsElem = elem.find('.replay-controls');
|
|
this.chatFrameElem = elem.find('.battle-log');
|
|
this.chatElem = null;
|
|
this.chatAddElem = elem.find('.battle-log-add');
|
|
this.chatboxElem = null;
|
|
this.joinElem = null;
|
|
this.foeHintElem = elem.find('.foehint');
|
|
|
|
this.battleEnded = false;
|
|
|
|
this.dealloc = function () {
|
|
if (selfR.battle) selfR.battle.dealloc();
|
|
};
|
|
this.focus = function () {
|
|
selfR.updateMe();
|
|
if (selfR.chatElem) selfR.chatFrameElem.scrollTop(selfR.chatElem.height());
|
|
if (selfR.chatboxElem) selfR.chatboxElem.focus();
|
|
};
|
|
this.updateJoinButton = function () {
|
|
if (selfR.battle.done) selfR.battleEnded = true;
|
|
if (selfR.battleEnded) {
|
|
selfR.controlsElem.html('<div class="controls"><em><button onclick="return rooms[\'' + selfR.id + '\'].formRestart()">Instant Replay</button><!--button onclick="return rooms[\'' + selfR.id + '\'].formSaveReplay()">Share replay</button--></em></div>');
|
|
if (selfR.me.side) {
|
|
selfR.controlsElem.html('<div class="controls"><em><button onclick="return rooms[\'' + selfR.id + '\'].formRestart()">Instant Replay</button> <button onclick="return rooms[\'' + selfR.id + '\'].formSaveReplay()">Share replay</button> <button onclick="return rooms[\'' + selfR.id + '\'].formLeaveBattle()">Leave this battle</button></em></div>');
|
|
}
|
|
if (selfR.joinElem) {
|
|
selfR.joinElem.remove();
|
|
}
|
|
//selfR.battleElem.append('<div class="playbutton"><button onclick="return rooms[\'' + selfR.id + '\'].formRestart()">Start new game<small style="font-size:12pt"><br />(Unranked)</small></button></div>');
|
|
//selfR.joinElem = selfR.battleElem.children().last();
|
|
} else if (selfR.battle.mySide.initialized && selfR.battle.yourSide.initialized) {
|
|
if (selfR.joinElem) {
|
|
selfR.joinElem.remove();
|
|
}
|
|
selfR.joinElem = null;
|
|
} else if (selfR.me.side) {
|
|
if (selfR.joinElem) {
|
|
selfR.joinElem.remove();
|
|
}
|
|
selfR.joinElem = null;
|
|
if (selfR.battle.kickingInactive) {
|
|
selfR.controlsElem.html('<div class="controls"><button onclick="return rooms[\'' + selfR.id + '\'].formLeaveBattle()">Leave this battle</button> <p><button onclick="rooms[\'' + selfR.id + '\'].formStopBattleTimer();return false"><small>Stop timer</small></button> <small>← Your opponent has disconnected. Click this to delay your victory.</small></p></div>');
|
|
} else {
|
|
selfR.controlsElem.html('<div class="controls"><button onclick="return rooms[\'' + selfR.id + '\'].formLeaveBattle()">Leave this battle</button> <p><button onclick="rooms[\'' + selfR.id + '\'].formKickInactive();return false"><small>Claim victory</small></button> <small>← Your opponent has disconnected. Click this if they don\'t reconnect.</small></p></div>');
|
|
}
|
|
} else {
|
|
if (selfR.joinElem) {
|
|
selfR.joinElem.remove();
|
|
}
|
|
selfR.battleElem.append('<div class="playbutton"><button onclick="return rooms[\'' + selfR.id + '\'].formJoinBattle()">Join Battle</button></div>');
|
|
selfR.joinElem = selfR.battleElem.children().last();
|
|
}
|
|
};
|
|
this.init = function (data) {
|
|
this.version = (data.version !== undefined) ? data.version : 0;
|
|
if (selfR.battle.activityQueue) {
|
|
// re-initialize
|
|
selfR.battleEnded = false;
|
|
selfR.battle = new Battle(selfR.battleElem, selfR.chatFrameElem);
|
|
|
|
if (widthClass !== 'tiny-layout') {
|
|
selfR.battle.messageSpeed = 80;
|
|
}
|
|
|
|
selfR.battle.setMute(me.mute);
|
|
selfR.battle.customCallback = selfR.callback;
|
|
selfR.battle.startCallback = selfR.updateJoinButton;
|
|
selfR.battle.stagnateCallback = selfR.updateJoinButton;
|
|
selfR.battle.endCallback = selfR.updateJoinButton;
|
|
selfR.chatFrameElem.find('.inner').html('');
|
|
selfR.controlsElem.html('');
|
|
}
|
|
selfR.battle.play();
|
|
if (data.battlelog) {
|
|
for (var i = 0; i < data.battlelog.length; i++) {
|
|
selfR.battle.add(data.battlelog[i]);
|
|
}
|
|
selfR.battle.fastForwardTo(-1);
|
|
}
|
|
selfR.updateMe();
|
|
if (selfR.chatElem) {
|
|
selfR.chatFrameElem.scrollTop(selfR.chatElem.height());
|
|
}
|
|
};
|
|
this.rawMessage = function(message) {
|
|
this.message({rawMessage: message});
|
|
};
|
|
this.message = function (message, andLobby) {
|
|
if (message.pm) {
|
|
var pmuserid = (toUserid(message.name) === me.userid ? toUserid(message.pm) : toUserid(message.name))
|
|
if (me.ignore[toUserid(message.name)] && message.name.substr(0, 1) === ' ') return;
|
|
selfR.add('|pm|' + message.name.substr(1) + '|' + pmuserid + '|' + message.pm + '|' + message.message);
|
|
} else if (message.rawMessage) {
|
|
// This is sanitised in battle.js.
|
|
selfR.add('|chatmsg-raw|' + message.rawMessage);
|
|
} else if (message.evalRulesRedirect || message.evalRawMessage) {
|
|
// TODO: This will be removed in due course.
|
|
window.location.href = 'http://pokemonshowdown.com/rules';
|
|
} else if (message.name) {
|
|
selfR.add('|chat|' + message.name.substr(1) + '|' + message.message);
|
|
} else if (message.message) {
|
|
selfR.add('|chatmsg|' + message.message);
|
|
} else {
|
|
selfR.add('|chatmsg|' + message);
|
|
}
|
|
|
|
if (andLobby && rooms.lobby) {
|
|
rooms.lobby.message(message);
|
|
}
|
|
};
|
|
this.send = function (message) {
|
|
emit(socket, 'chat', {room:this.id,message:message});
|
|
};
|
|
// Same as send, but appends the rqid to the message so that the server
|
|
// can verify that the decision is sent in response to the correct request.
|
|
this.sendDecision = function (message) {
|
|
this.send(message + '|' + this.me.request.rqid);
|
|
};
|
|
this.add = function (log) {
|
|
if (typeof log === 'string') log = log.split('\n');
|
|
selfR.update({updates:log});
|
|
};
|
|
this.update = function (update) {
|
|
if (update.updates) {
|
|
var updated = false;
|
|
for (var i = 0; i < update.updates.length; i++) {
|
|
if (!updated && (update.updates[i] === '')) {
|
|
selfR.me.callbackWaiting = false;
|
|
updated = true;
|
|
selfR.controlsElem.html('');
|
|
}
|
|
if (update.updates[i] === 'RESET') {
|
|
selfR.foeHintElem.html('');
|
|
var blog = selfR.chatFrameElem.find('.inner').html();
|
|
delete selfR.me.side;
|
|
selfR.battleEnded = false;
|
|
selfR.battle = new Battle(selfR.battleElem, selfR.chatFrameElem);
|
|
|
|
if (widthClass !== 'tiny-layout') {
|
|
selfR.battle.messageSpeed = 80;
|
|
}
|
|
|
|
selfR.battle.setMute(me.mute);
|
|
selfR.battle.customCallback = selfR.callback;
|
|
selfR.battle.startCallback = selfR.updateJoinButton;
|
|
selfR.battle.stagnateCallback = selfR.updateJoinButton;
|
|
selfR.battle.endCallback = selfR.updateJoinButton;
|
|
selfR.chatFrameElem.find('.inner').html(blog + '<h2>NEW GAME</h2>');
|
|
selfR.chatFrameElem.scrollTop(selfR.chatFrameElem.find('.inner').height());
|
|
selfR.controlsElem.html('');
|
|
selfR.battle.play();
|
|
selfR.updateJoinButton();
|
|
break;
|
|
}
|
|
if (update.updates[i].substr(0, 6) === '|chat|' || update.updates[i].substr(0, 9) === '|chatmsg|' || update.updates[i].substr(0, 10) === '|inactive|') {
|
|
selfR.battle.instantAdd(update.updates[i]);
|
|
} else {
|
|
if (update.updates[i].substr(0,10) === '|callback|') selfR.controlsElem.html('');
|
|
if (update.updates[i].substr(0,12) === '| callback | ') selfR.controlsElem.html('');
|
|
selfR.battle.add(update.updates[i]);
|
|
}
|
|
}
|
|
}
|
|
if (update.request) {
|
|
selfR.me.request = update.request; // currently unused
|
|
selfR.me.request.requestType = 'move';
|
|
var notifyObject = null;
|
|
if (selfR.me.request.forceSwitch) {
|
|
selfR.me.request.requestType = 'switch';
|
|
notifyObject = {
|
|
type: 'yourSwitch',
|
|
room: selfR.id
|
|
};
|
|
} else if (selfR.me.request.teamPreview) {
|
|
selfR.me.request.requestType = 'team';
|
|
notifyObject = {
|
|
type: 'yourSwitch',
|
|
room: selfR.id
|
|
};
|
|
} else if (selfR.me.request.wait) {
|
|
selfR.me.request.requestType = 'wait';
|
|
} else {
|
|
notifyObject = {
|
|
type: 'yourMove',
|
|
room: selfR.id
|
|
};
|
|
}
|
|
if (notifyObject) {
|
|
var doNotify = function() {
|
|
notify(notifyObject);
|
|
selfR.notifying = true;
|
|
updateRoomList();
|
|
};
|
|
if (selfR.battle.yourSide.initialized) {
|
|
// The opponent's name is already known.
|
|
notifyObject.user = selfR.battle.yourSide.name;
|
|
doNotify();
|
|
} else {
|
|
// The opponent's name isn't known yet, so wait until it is
|
|
// known before sending the notification, so that it can include
|
|
// the opponent's name.
|
|
var callback = selfR.battle.stagnateCallback;
|
|
selfR.battle.stagnateCallback = function(battle) {
|
|
notifyObject.user = battle.yourSide.name;
|
|
doNotify();
|
|
battle.stagnateCallback = callback;
|
|
if (callback) callback(battle);
|
|
};
|
|
}
|
|
}
|
|
//if (selfR.me.callbackWaiting) selfR.callback();
|
|
}
|
|
if (typeof update.active !== 'undefined') {
|
|
if (!update.active && selfR.me.side) {
|
|
selfR.controlsElem.html('<div class="controls"><button onclick="return rooms[\'' + selfR.id + '\'].formLeaveBattle()">Leave this battle</button></div>');
|
|
}
|
|
}
|
|
if (update.side) {
|
|
if (update.side === 'none') {
|
|
$('#controls').html('');
|
|
delete selfR.me.side;
|
|
} else {
|
|
selfR.me.side = update.side;
|
|
}
|
|
}
|
|
if (update.sideData) {
|
|
selfR.updateSide(update.sideData, update.midBattle);
|
|
}
|
|
selfR.updateMe();
|
|
};
|
|
this.updateSide = function(sideData, midBattle) {
|
|
var sidesSwitched = false;
|
|
selfR.me.sideData = sideData; // just for easy debugging
|
|
if (selfR.battle.sidesSwitched !== !!(selfR.me.side === 'p2')) {
|
|
sidesSwitched = true;
|
|
selfR.battle.reset();
|
|
selfR.battle.switchSides();
|
|
}
|
|
for (var i = 0; i < sideData.pokemon.length; i++) {
|
|
var pokemonData = sideData.pokemon[i];
|
|
var pokemon;
|
|
if (i == 0) {
|
|
pokemon = selfR.battle.getPokemon(''+pokemonData.ident, pokemonData.details);
|
|
pokemon.slot = 0;
|
|
pokemon.side.pokemon = [pokemon];
|
|
// if (pokemon.side.active[0] && pokemon.side.active[0].ident == pokemon.ident) pokemon.side.active[0] = pokemon;
|
|
} else if (i < selfR.battle.mySide.active.length) {
|
|
pokemon = selfR.battle.getPokemon('new: '+pokemonData.ident, pokemonData.details);
|
|
pokemon.slot = i;
|
|
// if (pokemon.side.active[i] && pokemon.side.active[i].ident == pokemon.ident) pokemon.side.active[i] = pokemon;
|
|
if (pokemon.side.active[i] && pokemon.side.active[i].ident == pokemon.ident) {
|
|
pokemon.side.active[i].item = pokemon.item;
|
|
pokemon.side.active[i].ability = pokemon.ability;
|
|
pokemon.side.active[i].baseAbility = pokemon.baseAbility;
|
|
}
|
|
} else {
|
|
pokemon = selfR.battle.getPokemon('new: '+pokemonData.ident, pokemonData.details);
|
|
}
|
|
pokemon.healthParse(pokemonData.condition);
|
|
if (pokemonData.baseAbility) {
|
|
pokemon.baseAbility = pokemonData.baseAbility;
|
|
if (!pokemon.ability || pokemon.ability.substr(0,2) === '??') pokemon.ability = pokemon.baseAbility;
|
|
}
|
|
pokemon.item = pokemonData.item;
|
|
pokemon.moves = pokemonData.moves;
|
|
}
|
|
selfR.battle.mySide.updateSidebar();
|
|
if (sidesSwitched) {
|
|
if (midBattle) {
|
|
selfR.battle.fastForwardTo(-1);
|
|
} else {
|
|
selfR.battle.play();
|
|
}
|
|
}
|
|
};
|
|
this.updateMe = function () {
|
|
if (selfR.meIdent.name !== me.name || selfR.meIdent.named !== me.named) {
|
|
if (me.named) {
|
|
selfR.chatAddElem.html('<form onsubmit="return false" class="chatbox"><label style="' + hashColor(me.userid) + '">' + sanitize(me.name) + ':</label> <textarea class="textbox" type="text" size="70" autocomplete="off" onkeypress="return rooms[\'' + selfR.id + '\'].formKeyPress(event)"></textarea></form>');
|
|
selfR.chatboxElem = selfR.chatAddElem.find('textarea');
|
|
// The keypress event does not capture tab, so use keydown.
|
|
selfR.chatboxElem.keydown(rooms['lobby'].formKeyDown);
|
|
selfR.chatboxElem.autoResize({
|
|
animateDuration: 100,
|
|
extraSpace: 0
|
|
});
|
|
selfR.chatboxElem.focus();
|
|
} else {
|
|
selfR.chatAddElem.html('<form><button onclick="return rooms[\'' + selfR.id + '\'].formRename()">Join chat</button></form>');
|
|
}
|
|
|
|
selfR.meIdent.name = me.name;
|
|
selfR.meIdent.named = me.named;
|
|
}
|
|
var inner = selfR.chatFrameElem.find('.inner');
|
|
if (inner.length) selfR.chatElem = inner;
|
|
else selfR.chatElem = null;
|
|
selfR.updateJoinButton();
|
|
};
|
|
this.callback = function (battle, type, moveTarget) {
|
|
if (!battle) battle = selfR.battle;
|
|
selfR.notifying = false;
|
|
if (type === 'restart') {
|
|
selfR.me.callbackWaiting = false;
|
|
selfR.battleEnded = true;
|
|
updateRoomList();
|
|
return;
|
|
}
|
|
|
|
var myActive = selfR.battle.mySide.active;
|
|
var yourActive = selfR.battle.yourSide.active;
|
|
var text = '';
|
|
if (yourActive[1]) {
|
|
text += '<div style="position:absolute;top:85px;left:320px;width:90px;height:100px;"' + tooltipAttrs(yourActive[1].getIdent(), 'pokemon', true, 'foe') + '></div>';
|
|
}
|
|
if (yourActive[0]) {
|
|
text += '<div style="position:absolute;top:90px;left:390px;width:100px;height:100px;"' + tooltipAttrs(yourActive[0].getIdent(), 'pokemon', true, 'foe') + '></div>';
|
|
}
|
|
if (myActive[0]) {
|
|
text += '<div style="position:absolute;top:210px;left:130px;width:180px;height:160px;"' + tooltipAttrs(myActive[0].getIdent(), 'pokemon', true, true) + '></div>';
|
|
}
|
|
if (myActive[1]) {
|
|
text += '<div style="position:absolute;top:210px;left:270px;width:160px;height:160px;"' + tooltipAttrs(myActive[1].getIdent(), 'pokemon', true, true) + '></div>';
|
|
}
|
|
selfR.foeHintElem.html(text);
|
|
|
|
if (!selfR.me.request) {
|
|
selfR.controlsElem.html('<div class="controls"><em>Waiting for players...</em></div>');
|
|
selfR.updateJoinButton();
|
|
updateRoomList();
|
|
return;
|
|
}
|
|
if (selfR.me.request.side) {
|
|
selfR.updateSide(selfR.me.request.side, true);
|
|
}
|
|
selfR.me.callbackWaiting = true;
|
|
var active = selfR.battle.mySide.active[0];
|
|
if (!active) active = {};
|
|
if (selfR.battle.kickingInactive) {
|
|
selfR.controlsElem.html('<div class="controls"><em>Waiting for opponent...</em></div> <button onclick="rooms[\'' + selfR.id + '\'].formStopBattleTimer();return false"><small>Stop timer</small></button>');
|
|
} else {
|
|
selfR.controlsElem.html('<div class="controls"><em>Waiting for opponent...</em></div> <button onclick="rooms[\'' + selfR.id + '\'].formKickInactive();return false"><small>Kick inactive player</small></button>');
|
|
}
|
|
var act = '';
|
|
var switchables = [];
|
|
|
|
if (selfR.me.request) {
|
|
act = selfR.me.request.requestType;
|
|
if (selfR.me.request.side) {
|
|
switchables = selfR.battle.mySide.pokemon;
|
|
}
|
|
}
|
|
switch (act) {
|
|
case 'move':
|
|
{
|
|
if (type !== 'move2' && type !== 'movetarget') {
|
|
selfR.choices = [];
|
|
selfR.choiceSwitchFlags = {};
|
|
while (switchables[selfR.choices.length] && switchables[selfR.choices.length].fainted) selfR.choices.push('pass');
|
|
}
|
|
var pos = selfR.choices.length - (type === 'movetarget'?1:0);
|
|
var hpbar = '';
|
|
{
|
|
if (switchables[pos].hp * 5 / switchables[pos].maxhp < 1) {
|
|
hpbar = '<small class="critical">';
|
|
} else if (switchables[pos].hp * 2 / switchables[pos].maxhp < 1) {
|
|
hpbar = '<small class="weak">';
|
|
} else {
|
|
hpbar = '<small class="healthy">';
|
|
}
|
|
hpbar += ''+switchables[pos].hp+'/'+switchables[pos].maxhp+'</small>';
|
|
}
|
|
var active = selfR.me.request;
|
|
if (active.active) active = active.active[pos];
|
|
var moves = active.moves;
|
|
var trapped = active.trapped;
|
|
|
|
var controls = '<div class="controls"><div class="whatdo">';
|
|
if (type === 'move2' || type === 'movetarget') {
|
|
controls += '<button onclick="rooms[\'' + selfR.id + '\'].callback(null,\'move\')">Back</button> ';
|
|
}
|
|
|
|
// Target selector
|
|
|
|
if (type === 'movetarget') {
|
|
controls += 'At who? '+hpbar+'</div>';
|
|
controls += '<div class="switchmenu" style="display:block">';
|
|
|
|
var myActive = selfR.battle.mySide.active;
|
|
var yourActive = selfR.battle.yourSide.active;
|
|
var yourSlot = yourActive.length-1-pos;
|
|
for (var i = yourActive.length-1; i >= 0; i--) {
|
|
var pokemon = yourActive[i];
|
|
|
|
var disabled = false;
|
|
if (moveTarget === 'adjacentAlly' || moveTarget === 'adjacentAllyOrSelf') {
|
|
disabled = true;
|
|
} else if (moveTarget === 'normal' || moveTarget === 'adjacentFoe') {
|
|
if (Math.abs(yourSlot-i) > 1) disabled = true;
|
|
}
|
|
|
|
if (!pokemon) {
|
|
controls += '<button disabled="disabled"></button> ';
|
|
} else if (disabled || pokemon.zerohp) {
|
|
controls += '<button disabled="disabled"' + tooltipAttrs(pokemon.getIdent(), 'pokemon', true, 'foe') + '><span class="pokemonicon" style="display:inline-block;vertical-align:middle;'+Tools.getIcon(pokemon)+'"></span>' + sanitize(pokemon.name) + (!pokemon.zerohp?'<span class="hpbar' + pokemon.getHPColorClass() + '"><span style="width:'+(Math.round(pokemon.hp*92/pokemon.maxhp)||1)+'px"></span></span>'+(pokemon.status?'<span class="status '+pokemon.status+'"></span>':''):'') +'</button> ';
|
|
} else {
|
|
controls += '<button onclick="rooms[\'' + selfR.id + '\'].formSelectTarget(' + i + ', false)"' + tooltipAttrs(pokemon.getIdent(), 'pokemon', true, 'foe') + '><span class="pokemonicon" style="display:inline-block;vertical-align:middle;'+Tools.getIcon(pokemon)+'"></span>' + sanitize(pokemon.name) + '<span class="hpbar' + pokemon.getHPColorClass() + '"><span style="width:'+(Math.round(pokemon.hp*92/pokemon.maxhp)||1)+'px"></span></span>'+(pokemon.status?'<span class="status '+pokemon.status+'"></span>':'')+'</button> ';
|
|
}
|
|
}
|
|
controls += '<div style="clear:both"></div> </div><div class="switchmenu" style="display:block">';
|
|
for (var i = 0; i < myActive.length; i++) {
|
|
var pokemon = myActive[i];
|
|
|
|
var disabled = false;
|
|
if (moveTarget === 'adjacentFoe') {
|
|
disabled = true;
|
|
} else if (moveTarget === 'normal' || moveTarget === 'adjacentAlly' || moveTarget === 'adjacentAllyOrSelf') {
|
|
if (Math.abs(pos-i) > 1) disabled = true;
|
|
}
|
|
if (moveTarget !== 'adjacentAllyOrSelf' && pos == i) disabled = true;
|
|
|
|
if (!pokemon) {
|
|
controls += '<button disabled="disabled"></button> ';
|
|
} else if (disabled || pokemon.zerohp) {
|
|
controls += '<button disabled="disabled"' + tooltipAttrs(i, 'sidepokemon') + '><span class="pokemonicon" style="display:inline-block;vertical-align:middle;'+Tools.getIcon(pokemon)+'"></span>' + sanitize(pokemon.name) + (!pokemon.zerohp?'<span class="hpbar' + pokemon.getHPColorClass() + '"><span style="width:'+(Math.round(pokemon.hp*92/pokemon.maxhp)||1)+'px"></span></span>'+(pokemon.status?'<span class="status '+pokemon.status+'"></span>':''):'') +'</button> ';
|
|
} else {
|
|
controls += '<button onclick="rooms[\'' + selfR.id + '\'].formSelectTarget(' + i + ', true)"' + tooltipAttrs(i, 'sidepokemon') + '><span class="pokemonicon" style="display:inline-block;vertical-align:middle;'+Tools.getIcon(pokemon)+'"></span>' + sanitize(pokemon.name) + '<span class="hpbar' + pokemon.getHPColorClass() + '"><span style="width:'+(Math.round(pokemon.hp*92/pokemon.maxhp)||1)+'px"></span></span>'+(pokemon.status?'<span class="status '+pokemon.status+'"></span>':'')+'</button> ';
|
|
}
|
|
}
|
|
controls += '</div>';
|
|
controls += '</div>';
|
|
selfR.controlsElem.html(controls);
|
|
break;
|
|
}
|
|
|
|
// Move chooser
|
|
|
|
controls += 'What will <strong>' + sanitize(switchables[pos].name) + '</strong> do? '+hpbar+'</div>';
|
|
var hasMoves = false;
|
|
var hasDisabled = false;
|
|
controls += '<div class="movecontrols"><div class="moveselect"><button onclick="rooms[\'' + selfR.id + '\'].formSelectMove()">Attack</button></div><div class="movemenu">';
|
|
var movebuttons = '';
|
|
for (var i = 0; i < moves.length; i++) {
|
|
var moveData = moves[i];
|
|
var move = Tools.getMove(moves[i].move);
|
|
if (!move) {
|
|
move = {
|
|
name: moves[i].move,
|
|
id: moves[i].move,
|
|
type: ''
|
|
};
|
|
}
|
|
var name = move.name;
|
|
var pp = moveData.pp + '/' + moveData.maxpp;
|
|
if (!moveData.maxpp) pp = '–';
|
|
if (move.id === 'Struggle' || move.id === 'Recharge') pp = '–';
|
|
if (move.id === 'Recharge') move.type = '–';
|
|
if (name.substr(0, 12) === 'Hidden Power') name = 'Hidden Power';
|
|
if (moveData.disabled) {
|
|
movebuttons += '<button disabled="disabled"' + tooltipAttrs(moveData.move, 'move') + '>';
|
|
hasDisabled = true;
|
|
} else {
|
|
movebuttons += '<button class="type-' + move.type + '" onclick="rooms[\'' + selfR.id + '\'].formUseMove(\'' + moveData.move.replace(/'/g, '\\\'') + '\', \''+moveData.target+'\')"' + tooltipAttrs(moveData.move, 'move') + '>';
|
|
hasMoves = true;
|
|
}
|
|
movebuttons += name + '<br /><small class="type">' + move.type + '</small> <small class="pp">' + pp + '</small> </button> ';
|
|
}
|
|
if (!hasMoves) {
|
|
controls += '<button class="movebutton" onclick="rooms[\'' + selfR.id + '\'].formUseMove(\'Struggle\')">Struggle<br /><small class="type">Normal</small> <small class="pp">–</small> </button> ';
|
|
} else {
|
|
controls += movebuttons;
|
|
}
|
|
controls += '<div style="clear:left"></div>';
|
|
if (hasDisabled) {
|
|
// controls += '<small>(grayed out moves have been disabled by Disable, Encore, or something like that)</small>';
|
|
}
|
|
controls += '</div></div><div class="switchcontrols"><div class="switchselect"><button onclick="rooms[\'' + selfR.id + '\'].formSelectSwitch()">Switch</button></div><div class="switchmenu">';
|
|
if (trapped) {
|
|
controls += '<em>You are trapped and cannot switch!</em>';
|
|
} else {
|
|
controls += '';
|
|
for (var i = 0; i < switchables.length; i++) {
|
|
var pokemon = switchables[i];
|
|
pokemon.name = pokemon.ident.substr(4);
|
|
if (pokemon.zerohp || i < selfR.battle.mySide.active.length || selfR.choiceSwitchFlags[i]) {
|
|
controls += '<button disabled="disabled"' + tooltipAttrs(i, 'sidepokemon') + '><span class="pokemonicon" style="display:inline-block;vertical-align:middle;'+Tools.getIcon(pokemon)+'"></span>' + sanitize(pokemon.name) + (!pokemon.zerohp?'<span class="hpbar' + pokemon.getHPColorClass() + '"><span style="width:'+(Math.round(pokemon.hp*92/pokemon.maxhp)||1)+'px"></span></span>'+(pokemon.status?'<span class="status '+pokemon.status+'"></span>':''):'') +'</button> ';
|
|
} else {
|
|
controls += '<button onclick="rooms[\'' + selfR.id + '\'].formSwitchTo(' + i + ')"' + tooltipAttrs(i, 'sidepokemon') + '><span class="pokemonicon" style="display:inline-block;vertical-align:middle;'+Tools.getIcon(pokemon)+'"></span>' + sanitize(pokemon.name) + '<span class="hpbar' + pokemon.getHPColorClass() + '"><span style="width:'+(Math.round(pokemon.hp*92/pokemon.maxhp)||1)+'px"></span></span>'+(pokemon.status?'<span class="status '+pokemon.status+'"></span>':'')+'</button> ';
|
|
}
|
|
}
|
|
if (selfR.battle.mySide.pokemon.length > 6) {
|
|
//controls += '<small>Pokeball data corrupt. Please copy the text from this button: <button onclick="prompt(\'copy this text\', curRoom.battle.activityQueue.join(\' :: \'));return false">[click here]</button> and tell aesoft.</small>';
|
|
}
|
|
}
|
|
controls += '</div></div></div>';
|
|
selfR.controlsElem.html(controls);
|
|
}
|
|
selfR.notifying = true;
|
|
break;
|
|
case 'switch':
|
|
if (type !== 'switch2') {
|
|
selfR.choices = [];
|
|
selfR.choiceSwitchFlags = {};
|
|
if (selfR.me.request.forceSwitch !== true) {
|
|
while (!selfR.me.request.forceSwitch[selfR.choices.length] && selfR.choices.length < 6) selfR.choices.push('pass');
|
|
}
|
|
}
|
|
var pos = selfR.choices.length;
|
|
var controls = '<div class="controls"><div class="whatdo">';
|
|
if (type === 'switch2') {
|
|
controls += '<button onclick="rooms[\'' + selfR.id + '\'].callback(null,\'switch\')">Back</button> ';
|
|
}
|
|
controls += 'Switch <strong>'+sanitize(switchables[pos].name)+'</strong> to:</div>';
|
|
controls += '<div class="switchcontrols"><div class="switchselect"><button onclick="rooms[\'' + selfR.id + '\'].formSelectSwitch()">Switch</button></div><div class="switchmenu">';
|
|
for (var i = 0; i < switchables.length; i++) {
|
|
var pokemon = switchables[i];
|
|
if (i >= 6) {
|
|
//controls += '<small>Pokeball data corrupt. Please copy the text from this button: <button onclick="prompt(\'copy this text\', curRoom.battle.activityQueue.join(\' :: \'));return false">[click here]</button> and tell aesoft.</small>';
|
|
break;
|
|
}
|
|
if (pokemon.zerohp || i < selfR.battle.mySide.active.length || selfR.choiceSwitchFlags[i]) {
|
|
controls += '<button disabled="disabled"' + tooltipAttrs(i, 'sidepokemon') + '><span class="pokemonicon" style="display:inline-block;vertical-align:middle;'+Tools.getIcon(pokemon)+'"></span>' + sanitize(pokemon.name) + (!pokemon.zerohp?'<span class="hpbar' + pokemon.getHPColorClass() + '"><span style="width:'+(Math.round(pokemon.hp*92/pokemon.maxhp)||1)+'px"></span></span>'+(pokemon.status?'<span class="status '+pokemon.status+'"></span>':''):'') +'</button> ';
|
|
} else {
|
|
controls += '<button onclick="rooms[\'' + selfR.id + '\'].formSwitchTo(' + i + ')"' + tooltipAttrs(i, 'sidepokemon') + '><span class="pokemonicon" style="display:inline-block;vertical-align:middle;'+Tools.getIcon(pokemon)+'"></span>' + sanitize(pokemon.name) + '<span class="hpbar' + pokemon.getHPColorClass() + '"><span style="width:'+(Math.round(pokemon.hp*92/pokemon.maxhp)||1)+'px"></span></span>'+(pokemon.status?'<span class="status '+pokemon.status+'"></span>':'')+'</button> ';
|
|
}
|
|
}
|
|
controls += '</div></div></div>';
|
|
selfR.controlsElem.html(controls);
|
|
selfR.formSelectSwitch();
|
|
selfR.notifying = true;
|
|
break;
|
|
case 'team':
|
|
var controls = '<div class="controls"><div class="whatdo">';
|
|
if (type !== 'team2') {
|
|
selfR.teamPreviewChoice = [1,2,3,4,5,6].slice(0,switchables.length);
|
|
selfR.teamPreviewDone = 0;
|
|
selfR.teamPreviewCount = 0;
|
|
if (selfR.battle.gameType === 'doubles') {
|
|
selfR.teamPreviewCount = 2;
|
|
}
|
|
controls += 'How will you start the battle?</div>';
|
|
controls += '<div class="switchcontrols"><div class="switchselect"><button onclick="rooms[\'' + selfR.id + '\'].formSelectSwitch()">Choose Lead</button></div><div class="switchmenu">';
|
|
for (var i = 0; i < switchables.length; i++) {
|
|
var pokemon = switchables[i];
|
|
if (i >= 6) {
|
|
break;
|
|
}
|
|
if (toId(pokemon.baseAbility) === 'illusion') {
|
|
selfR.teamPreviewCount = 6;
|
|
}
|
|
controls += '<button onclick="rooms[\'' + selfR.id + '\'].formTeamPreviewSelect(' + i + ')"' + tooltipAttrs(i, 'sidepokemon') + '><span class="pokemonicon" style="display:inline-block;vertical-align:middle;'+Tools.getIcon(pokemon)+'"></span>' + sanitize(pokemon.name) + '</button> ';
|
|
}
|
|
if (selfR.battle.teamPreviewCount) selfR.teamPreviewCount = parseInt(selfR.battle.teamPreviewCount,10);
|
|
controls += '</div>';
|
|
} else {
|
|
controls += '<button onclick="rooms[\'' + selfR.id + '\'].callback(null,\'team\')">Back</button> What about the rest of your team?</div>';
|
|
controls += '<div class="switchcontrols"><div class="switchselect"><button onclick="rooms[\'' + selfR.id + '\'].formSelectSwitch()">Choose a pokemon for slot '+(selfR.teamPreviewDone+1)+'</button></div><div class="switchmenu">';
|
|
for (var i = 0; i < switchables.length; i++) {
|
|
var pokemon = switchables[selfR.teamPreviewChoice[i]-1];
|
|
if (i >= 6) {
|
|
break;
|
|
}
|
|
if (i < selfR.teamPreviewDone) {
|
|
controls += '<button disabled="disabled"' + tooltipAttrs(i, 'sidepokemon') + '><span class="pokemonicon" style="display:inline-block;vertical-align:middle;'+Tools.getIcon(pokemon)+'"></span>' + sanitize(pokemon.name) + '</button> ';
|
|
} else {
|
|
controls += '<button onclick="rooms[\'' + selfR.id + '\'].formTeamPreviewSelect(' + i + ')"' + tooltipAttrs(selfR.teamPreviewChoice[i]-1, 'sidepokemon') + '><span class="pokemonicon" style="display:inline-block;vertical-align:middle;'+Tools.getIcon(pokemon)+'"></span>' + sanitize(pokemon.name) + '</button> ';
|
|
}
|
|
}
|
|
controls += '</div>';
|
|
}
|
|
controls += '</div></div>';
|
|
selfR.controlsElem.html(controls);
|
|
selfR.formSelectSwitch();
|
|
selfR.notifying = true;
|
|
break;
|
|
}
|
|
updateRoomList();
|
|
};
|
|
this.formJoinBattle = function () {
|
|
selfR.send('/joinbattle');
|
|
return false;
|
|
};
|
|
this.formKickInactive = function () {
|
|
selfR.send('/kickinactive');
|
|
return false;
|
|
};
|
|
this.formStopBattleTimer = function () {
|
|
selfR.send('/timer off');
|
|
return false;
|
|
};
|
|
this.formForfeit = function () {
|
|
selfR.send('/forfeit');
|
|
return false;
|
|
};
|
|
this.formSaveReplay = function () {
|
|
selfR.send('/savereplay');
|
|
return false;
|
|
};
|
|
this.formRestart = function () {
|
|
/* hideTooltip();
|
|
selfR.send('/restart'); */
|
|
selfR.me.request = null;
|
|
selfR.battle.reset();
|
|
selfR.battle.play();
|
|
return false;
|
|
};
|
|
this.formUseMove = function (move, target) {
|
|
var myActive = selfR.battle.mySide.active;
|
|
hideTooltip();
|
|
if (move !== undefined) {
|
|
var choosableTargets = {normal:1, any:1, adjacentAlly:1, adjacentAllyOrSelf:1, adjacentFoe:1};
|
|
selfR.choices.push('move '+move);
|
|
if (myActive.length > 1 && target in choosableTargets) {
|
|
selfR.callback(selfR.battle, 'movetarget', target);
|
|
return false;
|
|
}
|
|
}
|
|
while (myActive.length > selfR.choices.length && !myActive[selfR.choices.length]) {
|
|
selfR.choices.push('pass');
|
|
}
|
|
if (myActive.length > selfR.choices.length) {
|
|
selfR.callback(selfR.battle, 'move2');
|
|
return false;
|
|
}
|
|
if (selfR.battle.kickingInactive) {
|
|
selfR.controlsElem.html('<div class="controls"><em>Waiting for opponent...</em> <button onclick="rooms[\'' + selfR.id + '\'].formUndoDecision(); return false">Cancel</button></div> <br /><button onclick="rooms[\'' + selfR.id + '\'].formStopBattleTimer();return false"><small>Stop timer</small></button>');
|
|
} else {
|
|
selfR.controlsElem.html('<div class="controls"><em>Waiting for opponent...</em> <button onclick="rooms[\'' + selfR.id + '\'].formUndoDecision(); return false">Cancel</button></div> <br /><button onclick="rooms[\'' + selfR.id + '\'].formKickInactive();return false"><small>Kick inactive player</small></button>');
|
|
}
|
|
selfR.sendDecision('/choose '+selfR.choices.join(','));
|
|
selfR.notifying = false;
|
|
updateRoomList();
|
|
return false;
|
|
};
|
|
this.formSelectTarget = function (pos, isMySide) {
|
|
var posString;
|
|
if (isMySide) {
|
|
posString = ''+(-(pos+1));
|
|
} else {
|
|
posString = ''+(pos+1);
|
|
}
|
|
selfR.choices[selfR.choices.length-1] += ' '+posString;
|
|
selfR.formUseMove();
|
|
return false;
|
|
};
|
|
this.formSwitchTo = function (pos) {
|
|
hideTooltip();
|
|
selfR.choices.push('switch '+(parseInt(pos,10)+1));
|
|
selfR.choiceSwitchFlags[pos] = true;
|
|
if (selfR.me.request && selfR.me.request.requestType === 'move' && selfR.battle.mySide.active.length > selfR.choices.length) {
|
|
selfR.callback(selfR.battle, 'move2');
|
|
return false;
|
|
}
|
|
if (selfR.me.request && selfR.me.request.requestType === 'switch') {
|
|
if (selfR.me.request.forceSwitch !== true) {
|
|
while (selfR.battle.mySide.active.length > selfR.choices.length && !selfR.me.request.forceSwitch[selfR.choices.length]) selfR.choices.push('pass');
|
|
}
|
|
if (selfR.battle.mySide.active.length > selfR.choices.length) {
|
|
selfR.callback(selfR.battle, 'switch2');
|
|
return false;
|
|
}
|
|
}
|
|
if (selfR.battle.kickingInactive) {
|
|
selfR.controlsElem.html('<div class="controls"><em>Waiting for opponent...</em> <button onclick="rooms[\'' + selfR.id + '\'].formUndoDecision(); return false">Cancel</button></div> <br /><button onclick="rooms[\'' + selfR.id + '\'].formStopBattleTimer();return false"><small>Stop timer</small></button>');
|
|
} else {
|
|
selfR.controlsElem.html('<div class="controls"><em>Waiting for opponent...</em> <button onclick="rooms[\'' + selfR.id + '\'].formUndoDecision(); return false">Cancel</button></div> <br /><button onclick="rooms[\'' + selfR.id + '\'].formKickInactive();return false"><small>Kick inactive player</small></button>');
|
|
}
|
|
selfR.sendDecision('/choose '+selfR.choices.join(','));
|
|
selfR.notifying = false;
|
|
updateRoomList();
|
|
return false;
|
|
};
|
|
this.formTeamPreviewSelect = function (pos) {
|
|
pos = parseInt(pos,10);
|
|
hideTooltip();
|
|
if (selfR.teamPreviewCount) {
|
|
var temp = selfR.teamPreviewChoice[pos];
|
|
selfR.teamPreviewChoice[pos] = selfR.teamPreviewChoice[selfR.teamPreviewDone];
|
|
selfR.teamPreviewChoice[selfR.teamPreviewDone] = temp;
|
|
|
|
selfR.teamPreviewDone++;
|
|
|
|
if (selfR.teamPreviewDone < Math.min(selfR.teamPreviewChoice.length, selfR.teamPreviewCount)) {
|
|
selfR.callback(selfR.battle, 'team2');
|
|
return false;
|
|
}
|
|
pos = selfR.teamPreviewChoice.join('');
|
|
} else {
|
|
pos = pos+1;
|
|
}
|
|
if (selfR.battle.kickingInactive) {
|
|
selfR.controlsElem.html('<div class="controls"><em>Waiting for opponent...</em> <button onclick="rooms[\'' + selfR.id + '\'].formUndoDecision(); return false">Cancel</button></div> <br /><button onclick="rooms[\'' + selfR.id + '\'].formStopBattleTimer();return false"><small>Stop timer</small></button>');
|
|
} else {
|
|
selfR.controlsElem.html('<div class="controls"><em>Waiting for opponent...</em> <button onclick="rooms[\'' + selfR.id + '\'].formUndoDecision(); return false">Cancel</button></div> <br /><button onclick="rooms[\'' + selfR.id + '\'].formKickInactive();return false"><small>Kick inactive player</small></button>');
|
|
}
|
|
selfR.sendDecision('/team '+(pos));
|
|
selfR.notifying = false;
|
|
updateRoomList();
|
|
return false;
|
|
};
|
|
this.formUndoDecision = function (pos) {
|
|
selfR.send('/undo');
|
|
selfR.notifying = true;
|
|
selfR.callback(selfR.battle, 'decision');
|
|
return false;
|
|
};
|
|
// Key press in the battle chat textbox.
|
|
this.formKeyPress = function (e) {
|
|
hideTooltip();
|
|
if (e.keyCode === 13) {
|
|
if (selfR.chatboxElem.val()) {
|
|
var text = selfR.chatboxElem.val();
|
|
rooms.lobby.tabComplete.reset();
|
|
rooms.lobby.chatHistory.push(text);
|
|
text = rooms.lobby.parseCommand(text);
|
|
if (text) {
|
|
selfR.send(text);
|
|
}
|
|
selfR.chatboxElem.val('');
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
this.formRename = function () {
|
|
overlay('rename');
|
|
return false;
|
|
};
|
|
this.formLeaveBattle = function () {
|
|
hideTooltip();
|
|
selfR.send('/leavebattle');
|
|
selfR.notifying = false;
|
|
updateRoomList();
|
|
return false;
|
|
};
|
|
this.formSelectSwitch = function () {
|
|
hideTooltip();
|
|
selfR.controlsElem.find('.controls').attr('class', 'controls switch-controls');
|
|
return false;
|
|
};
|
|
this.formSelectMove = function () {
|
|
hideTooltip();
|
|
selfR.controlsElem.find('.controls').attr('class', 'controls move-controls');
|
|
return false;
|
|
};
|
|
|
|
this.battle = new Battle(this.battleElem, this.chatFrameElem);
|
|
|
|
if (widthClass !== 'tiny-layout') {
|
|
this.battle.messageSpeed = 80;
|
|
}
|
|
|
|
this.battle.setMute(me.mute);
|
|
this.battle.customCallback = this.callback;
|
|
this.battle.endCallback = this.endCallback;
|
|
this.battle.startCallback = this.updateMe;
|
|
this.battle.stagnateCallback = this.updateMe;
|
|
}
|
|
var lobbyChatElem = null;
|
|
|
|
function updateLobbyChat(tab) {
|
|
if (!tab && curRoom) tab = curRoom.id;
|
|
if (tab === 'lobby') {
|
|
$('#lobbychat').prop('class', 'lobbychat mainlobbychat');
|
|
$('#lobbychat').show();
|
|
if (rooms.lobby && rooms.lobby.chatElem) rooms.lobby.chatFrameElem.scrollTop(rooms.lobby.chatElem.height());
|
|
if (rooms.lobby && rooms.lobby.chatboxElem) rooms.lobby.chatboxElem.focus();
|
|
} else if (tab === 'teambuilder' || tab === 'ladder') {
|
|
$('#lobbychat').prop('class', 'lobbychat sidelobbychat');
|
|
$('#lobbychat').show();
|
|
if (rooms.lobby && rooms.lobby.chatElem) rooms.lobby.chatFrameElem.scrollTop(rooms.lobby.chatElem.height());
|
|
if (rooms.lobby && rooms.lobby.chatboxElem) rooms.lobby.chatboxElem.focus();
|
|
} else if (widthClass === 'huge-layout') {
|
|
$('#lobbychat').prop('class', 'lobbychat secondarylobbychat');
|
|
$('#lobbychat').show();
|
|
} else $('#lobbychat').hide();
|
|
}
|
|
|
|
function Lobby(id, elem) {
|
|
var selfR = this;
|
|
this.id = id;
|
|
this.elem = elem;
|
|
this.meIdent = {
|
|
name: me.name,
|
|
named: 'init'
|
|
};
|
|
me.rooms[id] = {};
|
|
this.me = me.rooms[id];
|
|
this.joinLeave = {
|
|
'join': [],
|
|
'leave': []
|
|
};
|
|
this.joinLeaveElem = null;
|
|
this.userCount = {};
|
|
this.userList = {};
|
|
this.userActivity = [];
|
|
this.tabComplete = {
|
|
candidates: null,
|
|
index: 0,
|
|
prefix: null,
|
|
cursor: -1,
|
|
reset: function() {
|
|
this.cursor = -1;
|
|
}
|
|
};
|
|
this.chatHistory = (function() {
|
|
var self = {
|
|
lines: [],
|
|
index: 0,
|
|
push: function(line) {
|
|
if (self.lines.length > 100) {
|
|
self.lines.splice(0, 20);
|
|
}
|
|
self.lines.push(line);
|
|
self.index = self.lines.length;
|
|
}
|
|
};
|
|
return self;
|
|
})();
|
|
this.highlightRegExp = null;
|
|
this.searcher = null;
|
|
this.selectedTeam = 0;
|
|
this.selectedFormat = '';
|
|
|
|
elem.html('<div class="mainsection"><div class="maintop"></div><div class="mainbottom"></div><div class="mainpopup" style="display:none"></div></div><div id="inline-nav"></div>');
|
|
$('#lobbychat').html('<div class="battle-log"><div class="inner"></div><div class="inner-after"></div></div><div class="battle-log-add">Connecting...</div>');
|
|
|
|
this.mainElem = elem.find('.mainsection');
|
|
this.mainTopElem = elem.find('.maintop');
|
|
this.mainBottomElem = elem.find('.mainbottom');
|
|
this.popupElem = elem.find('.mainpopup');
|
|
this.chatFrameElem = $('#lobbychat').find('.battle-log');
|
|
this.chatElem = $('#lobbychat').find('.battle-log .inner');
|
|
this.chatAddElem = $('#lobbychat').find('.battle-log-add');
|
|
this.chatboxElem = null;
|
|
|
|
this.dealloc = function () {};
|
|
this.focus = function () {
|
|
selfR.updateMe();
|
|
selfR.updateMainTop(true);
|
|
selfR.chatFrameElem.scrollTop(selfR.chatElem.height());
|
|
if (selfR.chatboxElem) selfR.chatboxElem.focus();
|
|
};
|
|
this.rawMessage = function(message) {
|
|
this.message({rawMessage: message});
|
|
};
|
|
this.message = function (message) {
|
|
if (typeof message !== 'string') {
|
|
selfR.add([message]);
|
|
} else {
|
|
selfR.add([{
|
|
message: message
|
|
}]);
|
|
}
|
|
};
|
|
this.send = function (message) {
|
|
emit(socket, 'chat', {room:'',message:message});
|
|
};
|
|
this.clear = function () {
|
|
selfR.chatElem.html('');
|
|
};
|
|
this.popupClose = function (i) {
|
|
if (!me.popups.length) return;
|
|
if (typeof i === 'undefined') i = me.popups.length - 1;
|
|
me.popups.splice(i, 1);
|
|
selfR.updatePopup();
|
|
selfR.popupChatboxElem.val('');
|
|
if (selfR.chatboxElem) {
|
|
selfR.chatboxElem.focus();
|
|
}
|
|
};
|
|
this.popupKeyUp = function (e) {
|
|
if (e.keyCode === 27) {
|
|
selfR.popupClose();
|
|
return false;
|
|
}
|
|
};
|
|
this.popupKeyPress = function (e) {
|
|
hideTooltip();
|
|
if (e.keyCode === 13) {
|
|
var text;
|
|
if ((text = selfR.popupChatboxElem.val())) {
|
|
selfR.tabComplete.reset();
|
|
selfR.chatHistory.push(text);
|
|
text = selfR.parseCommand(text);
|
|
if (text) {
|
|
var splitText = text.split('\n');
|
|
for (var i=0, len=splitText.length; i<len; i++) if (splitText[i]) splitText[i] = '/msg ' + me.curPopup + ', ' + splitText[i];
|
|
selfR.send(splitText.join('\n'));
|
|
}
|
|
selfR.popupChatboxElem.val('');
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
this.parseCommand = function(text) {
|
|
var cmd = '';
|
|
var target = '';
|
|
if (text.substr(0,2) !== '//' && text.substr(0,1) === '/') {
|
|
var spaceIndex = text.indexOf(' ');
|
|
if (spaceIndex > 0) {
|
|
cmd = text.substr(1, spaceIndex-1);
|
|
target = text.substr(spaceIndex+1);
|
|
} else {
|
|
cmd = text.substr(1);
|
|
target = '';
|
|
}
|
|
}
|
|
|
|
switch (cmd.toLowerCase()) {
|
|
case 'challenge':
|
|
case 'user':
|
|
case 'open':
|
|
if (!target) target = prompt('Who?');
|
|
if (target) rooms.lobby.formChallenge(target);
|
|
return false;
|
|
|
|
case 'ignore':
|
|
if (me.ignore[toUserid(target)]) {
|
|
this.message('User ' + target + ' is already on your ignore list. (Moderator messages will not be ignored.)');
|
|
} else {
|
|
me.ignore[toUserid(target)] = 1;
|
|
this.message('User ' + target + ' ignored. (Moderator messages will not be ignored.)');
|
|
}
|
|
return false;
|
|
|
|
case 'unignore':
|
|
if (!me.ignore[toUserid(target)]) {
|
|
this.message('User ' + target + ' isn\'t on your ignore list.');
|
|
} else {
|
|
delete me.ignore[toUserid(target)];
|
|
this.message('User ' + target + ' no longer ignored.');
|
|
}
|
|
return false;
|
|
|
|
case 'clear':
|
|
if (this.clear) this.clear();
|
|
return false;
|
|
|
|
case 'nick':
|
|
if (target) {
|
|
renameMe(target);
|
|
} else {
|
|
rooms.lobby.formRename();
|
|
}
|
|
return false;
|
|
|
|
case 'showjoins':
|
|
rooms.lobby.add('Join/leave messages: ON');
|
|
Tools.prefs.set('showjoins', true, true);
|
|
return false;
|
|
case 'hidejoins':
|
|
rooms.lobby.add('Join/leave messages: HIDDEN');
|
|
Tools.prefs.set('showjoins', false, true);
|
|
return false;
|
|
|
|
case 'showbattles':
|
|
rooms.lobby.add('Battle messages: ON');
|
|
Tools.prefs.set('showbattles', true, true);
|
|
return false;
|
|
case 'hidebattles':
|
|
rooms.lobby.add('Battle messages: HIDDEN');
|
|
Tools.prefs.set('showbattles', false, true);
|
|
return false;
|
|
|
|
case 'timestamps':
|
|
var targets = target.split(',');
|
|
if ((['all', 'lobby', 'pms'].indexOf(targets[0]) === -1)
|
|
|| (targets.length < 2)
|
|
|| (['off', 'minutes', 'seconds'].indexOf(
|
|
targets[1] = targets[1].trim()) === -1)) {
|
|
rooms.lobby.add('Error: Invalid /timestamps command');
|
|
return '/help timestamps'; // show help
|
|
}
|
|
var timestamps = Tools.prefs.get('timestamps') || {};
|
|
if (typeof timestamps === 'string') {
|
|
// The previous has a timestamps preference from the previous
|
|
// regime. We can't set properties of a string, so set it to
|
|
// an empty object.
|
|
timestamps = {};
|
|
}
|
|
switch (targets[0]) {
|
|
case 'all':
|
|
timestamps.lobby = targets[1];
|
|
timestamps.pms = targets[1];
|
|
break;
|
|
case 'lobby':
|
|
timestamps.lobby = targets[1];
|
|
break;
|
|
case 'pms':
|
|
timestamps.pms = targets[1];
|
|
break;
|
|
}
|
|
rooms.lobby.add('Timestamps preference set to: `' + targets[1] + '` for `' + targets[0] + '`.');
|
|
Tools.prefs.set('timestamps', timestamps, true);
|
|
return false;
|
|
|
|
case 'highlight':
|
|
var highlights = Tools.prefs.get('highlights') || [];
|
|
if (target.indexOf(',') > -1) {
|
|
var targets = target.split(',');
|
|
// trim the targets to be safe
|
|
for (var i=0, len=targets.length; i<len; i++) {
|
|
targets[i] = targets[i].trim();
|
|
}
|
|
switch (targets[0]) {
|
|
case 'add':
|
|
for (var i=1, len=targets.length; i<len; i++) {
|
|
highlights.push(targets[i].trim());
|
|
}
|
|
rooms.lobby.add("Now highlighting on: " + highlights.join(', '));
|
|
// We update the regex
|
|
this.highlightRegExp = new RegExp('\\b('+highlights.join('|')+')\\b', 'i');
|
|
break;
|
|
case 'delete':
|
|
var newHls = [];
|
|
for (var i=0, len=highlights.length; i<len; i++) {
|
|
if (targets.indexOf(highlights[i]) === -1) {
|
|
newHls.push(highlights[i]);
|
|
}
|
|
}
|
|
highlights = newHls;
|
|
rooms.lobby.add("Now highlighting on: " + highlights.join(', '));
|
|
// We update the regex
|
|
this.highlightRegExp = new RegExp('\\b('+highlights.join('|')+')\\b', 'i');
|
|
break;
|
|
}
|
|
Tools.prefs.set('highlights', highlights, true);
|
|
} else {
|
|
if (target === 'delete') {
|
|
Tools.prefs.set('highlights', false, true);
|
|
rooms.lobby.add("All highlights cleared");
|
|
} else if (target === 'show' || target === 'list') {
|
|
// Shows a list of the current highlighting words
|
|
if (highlights.length > 0) {
|
|
var hls = highlights.join(', ');
|
|
rooms.lobby.add('Current highlight list: ' + hls);
|
|
} else {
|
|
rooms.lobby.add('Your highlight list is empty.');
|
|
}
|
|
} else {
|
|
// Wrong command
|
|
rooms.lobby.add('Error: Invalid /highlight command.');
|
|
return '/help highlight'; // show help
|
|
}
|
|
}
|
|
return false;
|
|
|
|
case 'rank':
|
|
case 'ranking':
|
|
case 'rating':
|
|
case 'ladder':
|
|
if (!target) target = me.userid;
|
|
var self = this;
|
|
$.get(actionphp + '?act=ladderget&user='+target, Tools.safeJson(function(data) {
|
|
try {
|
|
var buffer = '<div class="ladder"><table>';
|
|
buffer += '<tr><td colspan="7">User: <strong>'+target+'</strong></td></tr>';
|
|
if (!data.length) {
|
|
buffer += '<tr><td colspan="7"><em>This user has not played any ladder games yet.</em></td></tr>';
|
|
} else {
|
|
buffer += '<tr><th>Format</th><th>ACRE</th><th>GXE</th><th>Glicko2</th><th>W</th><th>L</th><th>T</th></tr>';
|
|
for (var i=0; i<data.length; i++) {
|
|
var row = data[i];
|
|
buffer += '<tr><td>'+row.formatid+'</td><td><strong>'+Math.round(row.acre)+'</strong></td><td>'+Math.round(row.gxe,1)+'</td><td>';
|
|
if (row.rprd > 50) {
|
|
buffer += '<span><em>'+Math.round(row.rpr)+'<small> ± '+Math.round(row.rprd)+'</small></em> <small>(provisional)</small></span>';
|
|
} else {
|
|
buffer += '<em>'+Math.round(row.rpr)+'<small> ± '+Math.round(row.rprd)+'</small></em>';
|
|
}
|
|
buffer += '</td><td>'+row.w+'</td><td>'+row.l+'</td><td>'+row.t+'</td></tr>';
|
|
}
|
|
}
|
|
buffer += '</table></div>';
|
|
self.rawMessage(buffer);
|
|
} catch(e) {
|
|
}
|
|
}), 'text');
|
|
return false;
|
|
|
|
case 'buttonban':
|
|
var reason = prompt('Why do you wish to ban this user?');
|
|
if (reason === null) return false;
|
|
if (reason === false) reason = '';
|
|
rooms.lobby.send('/ban ' + target + ', ' + reason);
|
|
return false;
|
|
|
|
case 'buttonmute':
|
|
var reason = prompt('Why do you wish to mute this user?');
|
|
if (reason === null) return false;
|
|
if (reason === false) reason = '';
|
|
rooms.lobby.send('/mute ' + target + ', ' + reason);
|
|
return false;
|
|
|
|
case 'buttonunmute':
|
|
rooms.lobby.send('/unmute ' + target);
|
|
return false;
|
|
|
|
case 'buttonkick':
|
|
var reason = prompt('Why do you wish to kick this user?');
|
|
if (reason === null) return false;
|
|
if (reason === false) reason = '';
|
|
rooms.lobby.send('/kick ' + target + ', ' + reason);
|
|
return false;
|
|
|
|
case 'avatar':
|
|
var parts = target.split(',');
|
|
var avatar = parseInt(parts[0], 10);
|
|
if (avatar) {
|
|
Tools.prefs.set('avatar', avatar, true);
|
|
}
|
|
return text; // Send the /avatar command through to the server.
|
|
|
|
}
|
|
|
|
return text;
|
|
};
|
|
this.popupOpen = function (userid) {
|
|
userid = toUserid(userid);
|
|
for (var i = 0; i < me.popups.length; i++) {
|
|
if (me.popups[i] === userid) return selfR.popupFocus(i);
|
|
}
|
|
me.popups.push(userid);
|
|
selfR.updatePopup();
|
|
selfR.popupChatboxElem.focus();
|
|
};
|
|
this.popupFocus = function (i) {
|
|
if (!me.popups.length) return;
|
|
if (i == me.popups.length - 1) return;
|
|
me.popups = me.popups.concat(me.popups.splice(i, 1));
|
|
selfR.updatePopup();
|
|
selfR.popupChatboxElem.focus();
|
|
};
|
|
this.updatePopup = function (data) {
|
|
if (selfR.popupState && !me.popups.length) {
|
|
selfR.popupElem.html('');
|
|
selfR.popupElem.hide();
|
|
selfR.popupState = '';
|
|
} else if (selfR.popupState !== 'pm-' + me.popups.join(',')) {
|
|
var code = '<div id="' + selfR.id + '-pmlog-list">';
|
|
var popupListCode = '';
|
|
var name;
|
|
for (var i = 0; i < me.popups.length - 1; i++) {
|
|
name = sanitize(me.users[me.popups[i]] || me.popups[i]);
|
|
popupListCode += '<h3><button class="closebutton" onclick="rooms[\'' + selfR.id + '\'].popupClose(' + i + ');return false;"><i class="icon-remove-sign"></i></button><a onclick="rooms[\'' + selfR.id + '\'].popupFocus(' + i + ');return false;">' + name + '</a></h3>';
|
|
}
|
|
if (me.curPopup === me.popups[i]) {
|
|
$('#' + selfR.id + '-pmlog-list').html(popupListCode);
|
|
}
|
|
me.curPopup = me.popups[i];
|
|
code += popupListCode;
|
|
code += '</div>';
|
|
var clickableName = '<a onclick="return rooms.lobby.formChallenge(\'' + me.curPopup + '\');">' + sanitize(me.users[me.curPopup] || me.curPopup) + '</a>';
|
|
code += '<h3><button class="closebutton" onclick="rooms[\'' + selfR.id + '\'].popupClose(' + i + ');return false"><i class="icon-remove-sign"></i></button>' + clickableName + '</h3>';
|
|
code += '<div id="' + selfR.id + '-pmlog-frame" class="battle-log" onclick="rooms[\'' + selfR.id + '\'].popupChatboxElem.focus()"><div id="' + selfR.id + '-pmlog" class="inner">' + (me.pm[me.curPopup] || '') + '</div><div class="inner-after"></div></div>';
|
|
if (!selfR.popupElem.children('.battle-log-add').length) {
|
|
code += '<div class="battle-log-add"><form onsubmit="return false" class="chatbox"><textarea class="textbox" type="text" size="70" autocomplete="off" onkeypress="return rooms[\'' + selfR.id + '\'].popupKeyPress(event)" onkeyup="return rooms[\'' + selfR.id + '\'].popupKeyUp(event)"></textarea></form></div>';
|
|
selfR.popupElem.html(code);
|
|
} else {
|
|
selfR.popupElem.contents().not('.battle-log-add').remove();
|
|
selfR.popupElem.prepend(code);
|
|
}
|
|
selfR.popupChatboxElem = selfR.popupElem.find('textarea').last();
|
|
selfR.popupChatboxElem.keydown(rooms['lobby'].formKeyDown);
|
|
selfR.popupElem.show();
|
|
$('#' + selfR.id + '-pmlog-frame').scrollTop($('#' + selfR.id + '-pmlog').height());
|
|
selfR.popupChatboxElem.autoResize({
|
|
animateDuration: 100,
|
|
extraSpace: 0
|
|
});
|
|
selfR.popupState = 'pm-' + me.popups.join(',');
|
|
} else if (me.popups.length) {
|
|
if ($('#' + selfR.id + '-pmlog-frame').scrollTop() + 60 >= $('#' + selfR.id + '-pmlog').height() - $('#' + selfR.id + '-pmlog-frame').height()) {
|
|
autoscroll = true;
|
|
}
|
|
$('#' + selfR.id + '-pmlog').append(data);
|
|
if (autoscroll) {
|
|
$('#' + selfR.id + '-pmlog-frame').scrollTop($('#' + selfR.id + '-pmlog').height());
|
|
}
|
|
}
|
|
};
|
|
// Mark a user as active for the purpose of tab complete.
|
|
this.markUserActive = function (userid) {
|
|
var idx = selfR.userActivity.indexOf(userid);
|
|
if (idx !== -1) {
|
|
selfR.userActivity.splice(idx, 1);
|
|
}
|
|
selfR.userActivity.push(userid);
|
|
if (selfR.userActivity.length > 100) {
|
|
// Prune the list.
|
|
selfR.userActivity.splice(0, 20);
|
|
}
|
|
};
|
|
this.getTimestamp = function (section) {
|
|
var pref = Tools.prefs.get('timestamps') || {};
|
|
var sectionPref = ((section === 'pms') ? pref.pms : pref.lobby) || 'off';
|
|
if ((sectionPref === 'off') || (sectionPref === undefined)) return '';
|
|
var date = new Date();
|
|
var components = [ date.getHours(), date.getMinutes() ];
|
|
if (sectionPref === 'seconds') {
|
|
components.push(date.getSeconds());
|
|
}
|
|
return '[' + components.map(
|
|
function(x) { return (x < 10) ? '0' + x : x; }
|
|
).join(':') + '] ';
|
|
};
|
|
this.getHighlight = function (message) {
|
|
var highlights = Tools.prefs.get('highlights') || [];
|
|
if (!this.highlightRegExp) {
|
|
try {
|
|
this.highlightRegExp = new RegExp('\\b('+highlights.join('|')+')\\b', 'i');
|
|
} catch (e) {
|
|
// If the expression above is not a regexp, we'll get here.
|
|
// Don't throw an exception because that would prevent the chat
|
|
// message from showing up, or, when the lobby is initialising,
|
|
// it will prevent the initialisation from completing.
|
|
return false;
|
|
}
|
|
}
|
|
return ((highlights.length > 0) && this.highlightRegExp.test(message));
|
|
};
|
|
this.add = function (log) {
|
|
if (typeof log === 'string') log = log.split('\n');
|
|
var autoscroll = false;
|
|
if (selfR.chatFrameElem.scrollTop() + 60 >= selfR.chatElem.height() - selfR.chatFrameElem.height()) {
|
|
autoscroll = true;
|
|
}
|
|
selfR.lastUpdate = log;
|
|
for (var i = 0; i < log.length; i++) {
|
|
if (typeof log[i] === 'string') {
|
|
if (log[i].substr(0,1) !== '|') log[i] = '||'+log[i];
|
|
var row = log[i].substr(1).split('|');
|
|
switch (row[0]) {
|
|
case 'c':
|
|
case 'chat':
|
|
log[i] = {
|
|
name: row[1],
|
|
message: row.slice(2).join('|')
|
|
};
|
|
break;
|
|
case 'b':
|
|
case 'B':
|
|
log[i] = {
|
|
action: 'battle',
|
|
room: row[1],
|
|
name: row[2],
|
|
name2: row[3],
|
|
silent: (row[0] === 'B')
|
|
};
|
|
break;
|
|
case 'j':
|
|
case 'J':
|
|
log[i] = {
|
|
action: 'join',
|
|
name: row[1],
|
|
silent: (row[0] === 'J')
|
|
};
|
|
break;
|
|
case 'l':
|
|
case 'L':
|
|
log[i] = {
|
|
action: 'leave',
|
|
name: row[1],
|
|
silent: (row[0] === 'L')
|
|
};
|
|
break;
|
|
case 'n':
|
|
case 'N':
|
|
log[i] = {
|
|
action: 'rename',
|
|
name: row[1],
|
|
oldid: row[2],
|
|
silent: true
|
|
};
|
|
break;
|
|
case 'raw':
|
|
log[i] = {
|
|
rawMessage: row.slice(1).join('|')
|
|
};
|
|
break;
|
|
case 'refresh':
|
|
// refresh the page
|
|
document.location.reload(true);
|
|
break;
|
|
case 'formats':
|
|
var isSection = false;
|
|
var section = '';
|
|
BattleFormats = {};
|
|
for (var j=1; j<row.length; j++) {
|
|
if (isSection) {
|
|
section = row[j];
|
|
isSection = false;
|
|
} else if (row[j] === '') {
|
|
isSection = true;
|
|
} else {
|
|
var searchShow = true;
|
|
var challengeShow = true;
|
|
var team = null;
|
|
var name = row[j];
|
|
if (name.substr(name.length-2) === ',#') { // preset teams
|
|
team = 'preset';
|
|
name = name.substr(0,name.length-2);
|
|
}
|
|
if (name.substr(name.length-2) === ',,') { // search-only
|
|
challengeShow = false;
|
|
name = name.substr(0,name.length-2);
|
|
} else if (name.substr(name.length-1) === ',') { // challenge-only
|
|
searchShow = false;
|
|
name = name.substr(0,name.length-1);
|
|
}
|
|
BattleFormats[toId(name)] = {
|
|
id: toId(name),
|
|
name: name,
|
|
team: team,
|
|
section: section,
|
|
searchShow: searchShow,
|
|
challengeShow: challengeShow,
|
|
rated: challengeShow && searchShow,
|
|
isTeambuilderFormat: challengeShow && searchShow && !team,
|
|
effectType: 'Format'
|
|
};
|
|
}
|
|
}
|
|
selfR.updateMainTop(true);
|
|
break;
|
|
case '':
|
|
default:
|
|
log[i] = {
|
|
message: row.slice(1).join('|')
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
if (log[i].name && log[i].message) {
|
|
var userid = toUserid(log[i].name);
|
|
var color = hashColor(userid);
|
|
|
|
if (me.ignore[userid] && log[i].name.substr(0, 1) === ' ') continue;
|
|
|
|
// Add this user to the list of people who have spoken recently.
|
|
selfR.markUserActive(userid);
|
|
|
|
selfR.joinLeaveElem = null;
|
|
selfR.joinLeave = {
|
|
'join': [],
|
|
'leave': []
|
|
};
|
|
var clickableName = '<span style="cursor:pointer" onclick="return rooms.lobby.formChallenge(\'' + userid + '\');">' + sanitize(log[i].name.substr(1)) + '</span>';
|
|
var message = log[i].message;
|
|
var isHighlighted = selfR.getHighlight(message);
|
|
if (isHighlighted) {
|
|
notify({
|
|
type: 'highlight',
|
|
user: log[i].name
|
|
});
|
|
}
|
|
var highlight = isHighlighted ? ' style="background-color:#FDA;"' : '';
|
|
var chatDiv = '<div class="chat"' + highlight + '>';
|
|
var timestamp = selfR.getTimestamp(log[i].pm ? 'pms' : 'lobby');
|
|
if (log[i].name.substr(0, 1) !== ' ') clickableName = '<small>' + sanitize(log[i].name.substr(0, 1)) + '</small>'+clickableName;
|
|
if (log[i].pm) {
|
|
var pmuserid = (userid === me.userid ? toUserid(log[i].pm) : userid);
|
|
if (!me.pm[pmuserid]) me.pm[pmuserid] = '';
|
|
var pmcode = '<div class="chat">' + timestamp + '<strong style="' + color + '">' + clickableName + ':</strong> <em> ' + messageSanitize(message) + '</em></div>';
|
|
for (var j = 0; j < me.popups.length; j++) {
|
|
if (pmuserid === me.popups[j]) break;
|
|
}
|
|
if (j == me.popups.length) {
|
|
// This is a new PM.
|
|
me.popups.unshift(pmuserid);
|
|
notify({
|
|
type: 'pm',
|
|
user: log[i].name
|
|
});
|
|
}
|
|
me.pm[pmuserid] += pmcode;
|
|
if (me.popups.length && me.popups[me.popups.length - 1] === pmuserid) {
|
|
selfR.updatePopup(pmcode);
|
|
} else {
|
|
selfR.updatePopup();
|
|
}
|
|
selfR.chatElem.append('<div class="chat">' + timestamp + '<strong style="' + color + '">' + clickableName + ':</strong> <span class="message-pm"><i style="cursor:pointer" onclick="selectTab(\'lobby\');rooms.lobby.popupOpen(\'' + pmuserid + '\')">(Private to ' + sanitize(log[i].pm) + ')</i> ' + messageSanitize(message) + '</span></div>');
|
|
//} else if (log[i].act) {
|
|
// selfR.chatElem.append('<div class="chat"><strong style="' + color + '">•</strong> <em' + (log[i].name.substr(1) === me.name ? ' class="mine"' : '') + '>' + clickableName + ' <i>' + message + '</i></em></div>');
|
|
} else if (message.substr(0,2) === '//') {
|
|
selfR.chatElem.append(chatDiv + timestamp + '<strong style="' + color + '">' + clickableName + ':</strong> <em' + (log[i].name.substr(1) === me.name ? ' class="mine"' : '') + '>' + messageSanitize(message.substr(1)) + '</em></div>');
|
|
} else if (message.substr(0,4).toLowerCase() === '/me ') {
|
|
selfR.chatElem.append(chatDiv + timestamp + '<strong style="' + color + '">•</strong> <em' + (log[i].name.substr(1) === me.name ? ' class="mine"' : '') + '>' + clickableName + ' <i>' + messageSanitize(message.substr(4)) + '</i></em></div>');
|
|
} else if (message.substr(0,5).toLowerCase() === '/mee ') {
|
|
selfR.chatElem.append(chatDiv + timestamp + '<strong style="' + color + '">•</strong> <em' + (log[i].name.substr(1) === me.name ? ' class="mine"' : '') + '>' + clickableName + '<i>' + messageSanitize(message.substr(5)) + '</i></em></div>');
|
|
} else if (message.substr(0,10).toLowerCase() === '/announce ') {
|
|
selfR.chatElem.append(chatDiv + timestamp + '<strong style="' + color + '">' + clickableName + ':</strong> <span class="message-announce">' + messageSanitize(message.substr(10)) + '</span></div>');
|
|
} else if (message.substr(0,14).toLowerCase() === '/data-pokemon ') {
|
|
selfR.chatElem.append('<div class="message"><ul class=\"utilichart\">'+Chart.pokemonRow(Tools.getTemplate(message.substr(14)),'',{})+'<li style=\"clear:both\"></li></ul></div>');
|
|
} else if (message.substr(0,11).toLowerCase() === '/data-item ') {
|
|
selfR.chatElem.append('<div class="message"><ul class=\"utilichart\">'+Chart.itemRow(Tools.getItem(message.substr(11)),'',{})+'<li style=\"clear:both\"></li></ul></div>');
|
|
} else if (message.substr(0,14).toLowerCase() === '/data-ability ') {
|
|
selfR.chatElem.append('<div class="message"><ul class=\"utilichart\">'+Chart.abilityRow(Tools.getAbility(message.substr(14)),'',{})+'<li style=\"clear:both\"></li></ul></div>');
|
|
} else if (message.substr(0,11).toLowerCase() === '/data-move ') {
|
|
selfR.chatElem.append('<div class="message"><ul class=\"utilichart\">'+Chart.moveRow(Tools.getMove(message.substr(11)),'',{})+'<li style=\"clear:both\"></li></ul></div>');
|
|
} else {
|
|
// Normal chat message.
|
|
selfR.chatElem.append(chatDiv + timestamp + '<strong style="' + color + '">' + clickableName + ':</strong> <em' + (log[i].name.substr(1) === me.name ? ' class="mine"' : '') + '>' + messageSanitize(message) + '</em></div>');
|
|
}
|
|
} else if (log[i].name && log[i].action === 'battle') {
|
|
var id = log[i].room;
|
|
var matches = id.match(/^battle\-([a-z0-9]*[a-z])[0-9]*$/);
|
|
var format = (matches ? matches[1] : '');
|
|
selfR.rooms.push({
|
|
id: id,
|
|
format: format,
|
|
p1: log[i].name,
|
|
p2: log[i].name2
|
|
});
|
|
if (selfR.rooms.length > 8) selfR.rooms.shift();
|
|
|
|
selfR.debounceUpdate();
|
|
|
|
if (log[i].silent && !Tools.prefs.get('showbattles')) continue;
|
|
|
|
selfR.joinLeaveElem = null;
|
|
selfR.joinLeave = {
|
|
'join': [],
|
|
'leave': []
|
|
};
|
|
var id = log[i].room;
|
|
var battletype = 'Battle';
|
|
if (log[i].format) {
|
|
battletype = log[i].format + ' battle';
|
|
if (log[i].format === 'Random Battle') battletype = 'Random Battle';
|
|
}
|
|
selfR.chatElem.append('<div class="message"><a href="' + locPrefix+id + '" onclick="selectTab(\'' + id + '\'); return false" class="battle-start">' + battletype + ' started between <strong style="' + hashColor(toUserid(log[i].name)) + '">' + sanitize(log[i].name) + '</strong> and <strong style="' + hashColor(toUserid(log[i].name2)) + '">' + sanitize(log[i].name2) + '</strong>.</a></div>');
|
|
} else if (log[i].message) {
|
|
selfR.chatElem.append('<div class="message">' + sanitize(log[i].message) + '</div>');
|
|
} else if (log[i].rawMessage) {
|
|
// This is so that the register link continues to work on old servers.
|
|
// It can be removed later.
|
|
if (log[i].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:\''+me.userid+'\'});return false"><b>Register</b></button></div>') {
|
|
selfR.chatElem.append('<div class="message">' + log[i].rawMessage + '</div>');
|
|
} else {
|
|
selfR.chatElem.append('<div class="message">' + Tools.htmlSanitize(log[i].rawMessage) + '</div>');
|
|
}
|
|
} else if (log[i].evalRulesRedirect || log[i].evalRawMessage) {
|
|
// TODO: This will be removed in due course.
|
|
window.location.href = 'http://pokemonshowdown.com/rules';
|
|
} else if (log[i].name && (log[i].action === 'join' || log[i].action === 'leave' || log[i].action === 'rename')) {
|
|
var userid = toUserid(log[i].name);
|
|
if (log[i].action === 'join') {
|
|
if (log[i].oldid) delete me.users[toUserid(log[i].oldid)];
|
|
if (!me.users[userid]) selfR.userCount.users++;
|
|
me.users[userid] = log[i].name;
|
|
selfR.userList.add(userid);
|
|
selfR.userList.updateUserCount();
|
|
selfR.userList.updateNoUsersOnline();
|
|
} else if (log[i].action === 'leave') {
|
|
if (me.users[userid]) selfR.userCount.users--;
|
|
delete me.users[userid];
|
|
selfR.userList.remove(userid);
|
|
selfR.userList.updateUserCount();
|
|
selfR.userList.updateNoUsersOnline();
|
|
} else if (log[i].action === 'rename') {
|
|
if (log[i].oldid) delete me.users[toUserid(log[i].oldid)];
|
|
me.users[userid] = log[i].name;
|
|
selfR.userList.remove(log[i].oldid);
|
|
selfR.userList.add(userid);
|
|
continue;
|
|
}
|
|
if (log[i].silent && !Tools.prefs.get('showjoins')) continue;
|
|
if (!selfR.joinLeaveElem) {
|
|
selfR.chatElem.append('<div class="message"><small>Loading...</small></div>');
|
|
selfR.joinLeaveElem = selfR.chatElem.children().last();
|
|
}
|
|
selfR.joinLeave[log[i].action].push(log[i].name);
|
|
var message = '';
|
|
if (selfR.joinLeave['join'].length) {
|
|
var preList = selfR.joinLeave['join'];
|
|
var list = [];
|
|
var named = {};
|
|
for (var j = 0; j < preList.length; j++) {
|
|
if (!named[preList[j]]) list.push(preList[j]);
|
|
named[preList[j]] = true;
|
|
}
|
|
for (var j = 0; j < list.length; j++) {
|
|
if (j >= 5) {
|
|
message += ', and ' + (list.length - 5) + ' others';
|
|
break;
|
|
}
|
|
if (j > 0) {
|
|
if (j == 1 && list.length == 2) {
|
|
message += ' and ';
|
|
} else if (j == list.length - 1) {
|
|
message += ', and ';
|
|
} else {
|
|
message += ', ';
|
|
}
|
|
}
|
|
message += sanitize(list[j]);
|
|
}
|
|
message += ' joined';
|
|
}
|
|
if (selfR.joinLeave['leave'].length) {
|
|
if (selfR.joinLeave['join'].length) {
|
|
message += '; ';
|
|
}
|
|
var preList = selfR.joinLeave['leave'];
|
|
var list = [];
|
|
var named = {};
|
|
for (var j = 0; j < preList.length; j++) {
|
|
if (!named[preList[j]]) list.push(preList[j]);
|
|
named[preList[j]] = true;
|
|
}
|
|
for (var j = 0; j < list.length; j++) {
|
|
if (j >= 5) {
|
|
message += ', and ' + (list.length - 5) + ' others';
|
|
break;
|
|
}
|
|
if (j > 0) {
|
|
if (j == 1 && list.length == 2) {
|
|
message += ' and ';
|
|
} else if (j == list.length - 1) {
|
|
message += ', and ';
|
|
} else {
|
|
message += ', ';
|
|
}
|
|
}
|
|
message += sanitize(list[j]);
|
|
}
|
|
message += ' left<br />';
|
|
}
|
|
selfR.joinLeaveElem.html('<small style="color: #555555">' + message + '</small>');
|
|
}
|
|
}
|
|
if (autoscroll) {
|
|
selfR.chatFrameElem.scrollTop(selfR.chatElem.height());
|
|
}
|
|
var $children = selfR.chatElem.children();
|
|
if ($children.length > 900) {
|
|
$children.slice(0,100).remove();
|
|
}
|
|
};
|
|
// Lobby init
|
|
this.init = function (data) {
|
|
if (data.log) {
|
|
selfR.chatElem.html('');
|
|
// Disable timestamps for the past log because the server doesn't
|
|
// tell us what time the messages were sent at.
|
|
var timestamps = Tools.prefs.get('timestamps');
|
|
Tools.prefs.set('timestamps', 'off');
|
|
selfR.add(data.log); // Add past log.
|
|
Tools.prefs.set('timestamps', timestamps);
|
|
}
|
|
selfR.update(data);
|
|
selfR.chatFrameElem.scrollTop(selfR.chatElem.height());
|
|
selfR.updateMe();
|
|
if (me.named) {
|
|
// Preferred avatar feature
|
|
var avatar = Tools.prefs.get('avatar');
|
|
if (avatar) {
|
|
// This will be compatible even with servers that don't support
|
|
// the second argument for /avatar yet.
|
|
selfR.send('/avatar ' + avatar + ',1');
|
|
}
|
|
}
|
|
if (me.renameQueued) {
|
|
renameMe(me.renameQueued);
|
|
me.renameQueued = false;
|
|
}
|
|
};
|
|
this.update = function (data) {
|
|
if (data.logUpdate) {
|
|
selfR.add(data.logUpdate);
|
|
}
|
|
if (typeof data.searching !== 'undefined') {
|
|
selfR.me.searching = data.searching;
|
|
selfR.updateMainTop();
|
|
}
|
|
if (typeof data.searcher !== 'undefined') {
|
|
selfR.searcher = data.searcher;
|
|
}
|
|
if (typeof data.u !== 'undefined') {
|
|
selfR.userCount = {};
|
|
me.users = {};
|
|
var commaIndex = data.u.indexOf(',');
|
|
if (commaIndex >= 0) {
|
|
selfR.userCount.users = parseInt(data.u.substr(0,commaIndex),10);
|
|
var users = data.u.substr(commaIndex+1).split(',');
|
|
for (var i=0,len=users.length; i<len; i++) {
|
|
if (users[i]) me.users[toId(users[i])] = users[i];
|
|
}
|
|
} else {
|
|
selfR.userCount.users = parseInt(data.u);
|
|
selfR.userCount.guests = selfR.userCount.users;
|
|
}
|
|
selfR.userList.construct();
|
|
}
|
|
if (data.rooms) {
|
|
selfR.rooms = [];
|
|
for (var id in data.rooms) {
|
|
var room = data.rooms[id];
|
|
var matches = id.match(/^battle\-([a-z0-9]*[a-z])[0-9]*$/);
|
|
room.format = (matches ? matches[1] : '');
|
|
room.id = id;
|
|
selfR.rooms.unshift(room);
|
|
}
|
|
}
|
|
//selfR.updateMainTop();
|
|
selfR.updateMe();
|
|
};
|
|
this.mainTopState = '';
|
|
this.command = function (data) {
|
|
if (data.command === 'userdetails') {
|
|
var userid = data.userid;
|
|
if (!$('#' + selfR.id + '-userdetails-' + userid).length) return;
|
|
|
|
var roomListCode = '';
|
|
for (var id in data.rooms) {
|
|
var roomData = data.rooms[id];
|
|
var matches = id.match(/^battle\-([a-z0-9]*[a-z])[0-9]*$/);
|
|
var format = (matches ? '<small>[' + matches[1] + ']</small><br />' : '');
|
|
var roomDesc = format + '<em class="p1">' + sanitize(roomData.p1) + '</em> <small class="vs">vs.</small> <em class="p2">' + sanitize(roomData.p2) + '</em>';
|
|
if (!roomData.p1) {
|
|
matches = id.match(/[^0-9]([0-9]*)$/);
|
|
roomDesc = format + 'empty room ' + matches[1];
|
|
} else if (!roomData.p2) {
|
|
roomDesc = format + '<em class="p1">' + sanitize(roomData.p1) + '</em>';
|
|
}
|
|
roomListCode += '<div><a href="' + locPrefix + '' + id + '" onclick="selectTab(\'' + id + '\');return false">' + roomDesc + '</a></div>';
|
|
}
|
|
|
|
var code = '<img src="' + Tools.resourcePrefix + 'sprites/trainers/' + data.avatar + '.png" />';
|
|
if (roomListCode) {
|
|
roomListCode = '<div class="action-form">In rooms:<br /><div class="roomlist">' + roomListCode + '</div></div>';
|
|
}
|
|
if (data.ip || data.ips) {
|
|
var ips = data.ips || [data.ip];
|
|
// Mute and Ban buttons for auths
|
|
var banMuteBuffer = '';
|
|
var mygroup = me.users[me.userid].substr(0, 1);
|
|
if ([' ', '!', '#', '+'].indexOf(mygroup) === -1) {
|
|
banMuteBuffer += '<br /><br />';
|
|
if (me.users[userid].substr(0, 1) === '!') {
|
|
banMuteBuffer += '<button onclick="rooms[\'' + selfR.id + '\'].parseCommand(\'/buttonunmute ' + userid + '\');">Unmute</button>';
|
|
} else {
|
|
banMuteBuffer += '<button onclick="rooms[\'' + selfR.id + '\'].parseCommand(\'/buttonmute ' + userid + '\');">Mute</button>';
|
|
}
|
|
if (mygroup !== '%') {
|
|
banMuteBuffer += ' <button onclick="rooms[\'' + selfR.id + '\'].parseCommand(\'/buttonban ' + userid + '\');">Ban</button>';
|
|
banMuteBuffer += ' <button onclick="rooms[\'' + selfR.id + '\'].parseCommand(\'/buttonkick ' + userid + '\');">Kick</button>';
|
|
}
|
|
}
|
|
var ipbits = [];
|
|
for (var i = 0; i < ips.length; ++i) {
|
|
ipbits.push('<a href="http://www.geoiptool.com/en/?IP=' + ips[i] + '" target="iplookup">' + ips[i] + '</a>');
|
|
}
|
|
roomListCode = '<div class="action-form"><small>IP' + ((ips.length > 1) ? 's' : '') + ': ' + ipbits.join(', ') + '</small>' + banMuteBuffer + '</div>' + roomListCode;
|
|
}
|
|
$('#' + selfR.id + '-userrooms-' + userid).html(roomListCode);
|
|
$('#' + selfR.id + '-userdetails-' + userid).html(code);
|
|
} else if (data.command === 'roomlist') {
|
|
if (!$('#' + selfR.id + '-roomlist').length) return;
|
|
var roomListCode = '';
|
|
var i = 0;
|
|
for (var id in data.rooms) {
|
|
var roomData = data.rooms[id];
|
|
var matches = id.match(/^battle\-([a-z0-9]*[a-z])[0-9]*$/);
|
|
var format = (matches ? '<small>[' + matches[1] + ']</small><br />' : '');
|
|
var roomDesc = format + '<em class="p1">' + sanitize(roomData.p1) + '</em> <small class="vs">vs.</small> <em class="p2">' + sanitize(roomData.p2) + '</em>';
|
|
if (!roomData.p1) {
|
|
matches = id.match(/[^0-9]([0-9]*)$/);
|
|
roomDesc = format + 'empty room ' + matches[1];
|
|
} else if (!roomData.p2) {
|
|
roomDesc = format + '<em class="p1">' + sanitize(roomData.p1) + '</em>';
|
|
}
|
|
roomListCode += '<div><a href="' + locPrefix+id + '" onclick="selectTab(\'' + id + '\');return false">' + roomDesc + '</a></div>';
|
|
i++;
|
|
}
|
|
|
|
if (!roomListCode) {
|
|
roomListCode = 'No battles are going on right now.';
|
|
}
|
|
$('#' + selfR.id + '-roomlist').html('<div class="roomlist"><div><small>(' + i + ' battle' + (i == 1 ? '' : 's') + ')</small></div>' + roomListCode + '</div>');
|
|
} else if (data.command === 'savereplay') {
|
|
var id = data.id;
|
|
$.post(actionphp + '?act=uploadreplay', {
|
|
log: data.log,
|
|
id: data.id
|
|
}, function(data) {
|
|
if (data === 'success') {
|
|
overlay('replayuploaded', id);
|
|
} else {
|
|
overlay('message', "Error while uploading replay: "+data);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
this.rooms = [];
|
|
this.updateMainTop = function (force) {
|
|
var text = '';
|
|
var challenge = null;
|
|
if (me.challengesFrom) {
|
|
for (var i in me.challengesFrom) {
|
|
challenge = me.challengesFrom[i];
|
|
break;
|
|
}
|
|
}
|
|
if (force) selfR.mainTopState = '';
|
|
selfR.notifying = !! challenge;
|
|
updateRoomList();
|
|
if (challenge) {
|
|
if (selfR.mainTopState === 'challenge-' + challenge.from) return;
|
|
selfR.mainTopState = 'challenge-' + challenge.from;
|
|
|
|
if (me.lastChallengeNotification !== challenge.from) {
|
|
notify({
|
|
type: 'challenge',
|
|
room: selfR.id,
|
|
user: (me.users[challenge.from] || challenge.from),
|
|
userid: challenge.from
|
|
});
|
|
me.lastChallengeNotification = challenge.from;
|
|
}
|
|
selfR.selectedFormat = toId(challenge.format);
|
|
text = '<div class="action-notify"><button class="closebutton" style="float:right;margin:-6px -10px 0 0" onclick="return rooms[\'' + selfR.id + '\'].formRejectChallenge(\'' + sanitize(challenge.from) + '\')"><i class="icon-remove-sign"></i></button>';
|
|
text += 'Challenge from: ' + (me.users[challenge.from] || challenge.from) + '<br /><label class="label">Format:</label> ' + sanitize(challenge.format) + '</br >';
|
|
text += '' + selfR.getTeamSelect(challenge.format) + '<br />';
|
|
text += '<button onclick="return rooms[\'' + selfR.id + '\'].formAcceptChallenge(\'' + sanitize(challenge.from) + '\')" id="' + selfR.id + '-gobutton"' + (selfR.goDisabled ? ' disabled="disabled"' : '') + '>Accept</button> <button onclick="return rooms[\'' + selfR.id + '\'].formRejectChallenge(\'' + sanitize(challenge.from) + '\')"><small>Reject</small></button></div>';
|
|
} else if (me.userForm) {
|
|
var userid = toUserid(me.userForm);
|
|
var name = (me.users[userid] || me.userForm);
|
|
var groupDetails = {
|
|
'~': "Administrator (~)",
|
|
'&': "Leader (&)",
|
|
'@': "Moderator (@)",
|
|
'%': "Driver (%)",
|
|
'+': "Voiced (+)",
|
|
'!': "<span style='color:#777777'>Muted (!)</span>"
|
|
};
|
|
var group = groupDetails[name.substr(0, 1)];
|
|
if (group) name = name.substr(1);
|
|
if (selfR.mainTopState === 'userform-' + userid) return;
|
|
selfR.mainTopState = 'userform-' + userid;
|
|
|
|
if (me.userForm === '#lobby-rooms') {
|
|
text = '<div><button onclick="rooms[\'' + selfR.id + '\'].formCloseUserForm();return false"><i class="icon-chevron-left"></i> Back to lobby</button> <button onclick="rooms[\'' + selfR.id + '\'].send(\'/cmd roomlist\');return false"><i class="icon-refresh"></i> Refresh</button></div><div id="' + selfR.id + '-roomlist"><em>Loading...</em></div>';
|
|
selfR.send('/cmd roomlist');
|
|
} else {
|
|
text = '<div class="action-form"><button style="float:right;margin:-6px -10px 0 0" class="closebutton" onclick="return rooms[\'' + selfR.id + '\'].formCloseUserForm()"><i class="icon-remove-sign"></i></button>';
|
|
text += '<strong>' + sanitize(name) + '</strong><br />';
|
|
text += '<small>' + (group || '') + '</small><br />';
|
|
text += '<div id="' + selfR.id + '-userdetails-' + userid + '" style="height:85px"></div>';
|
|
if (userid === me.userid) {
|
|
text += '<button onclick="return rooms[\'' + selfR.id + '\'].formCloseUserForm()">Close</button></div>';
|
|
} else {
|
|
text += '<button onclick="$(\'#' + selfR.id + '-challengeform\').toggle();return false"><strong>Challenge</strong></button> <button onclick="rooms[\'' + selfR.id + '\'].popupOpen(\'' + userid + '\');rooms[\'' + selfR.id + '\'].formCloseUserForm();return false"><strong>PM</strong></button> <button onclick="return rooms[\'' + selfR.id + '\'].formCloseUserForm()">Close</button>';
|
|
text += '</div><div class="action-form" style="display:none" id="' + selfR.id + '-challengeform">';
|
|
text += selfR.getFormatSelect('challenge') + '<br />';
|
|
text += '' + selfR.getTeamSelect(selfR.selectedFormat) + '<br />';
|
|
text += '<button onclick="return rooms[\'' + selfR.id + '\'].formMakeChallenge(\'' + sanitize(userid) + '\')" id="' + selfR.id + '-gobutton"' + (selfR.goDisabled ? ' disabled="disabled"' : '') + '><strong>Make challenge</strong></button> <button onclick="$(\'#' + selfR.id + '-challengeform\').hide();return false">Cancel</button></div>';
|
|
}
|
|
text += '<div id="' + selfR.id + '-userrooms-' + userid + '"></div>';
|
|
selfR.send('/cmd userdetails '+userid);
|
|
}
|
|
} else if (me.challengeTo) {
|
|
if (selfR.mainTopState === 'challenging') return;
|
|
selfR.mainTopState = 'challengeto';
|
|
|
|
var teamname = 'Random team';
|
|
if (selectedTeam >= 0) teamname = teams[selectedTeam].name;
|
|
text = '<div class="action-waiting">Challenging: ' + (me.users[me.challengeTo.to] || me.challengeTo.to) + '<br />Format: ' + me.challengeTo.format + '<br />Team: ' + teamname + '<br /><button onclick="return rooms[\'' + selfR.id + '\'].formCloseUserForm(\'' + sanitize(me.challengeTo.to) + '\')"><small>Cancel</small></button></div>';
|
|
} else if (selfR.me.searching) {
|
|
if (selfR.mainTopState === 'searching') return;
|
|
selfR.mainTopState = 'searching';
|
|
|
|
text = '<div class="action-waiting">Format: ' + selfR.me.searching.format + '<br />Searching...<br /><button onclick="return rooms[\'' + selfR.id + '\'].formSearchBattle(false)"><small>Cancel</small></button></div>';
|
|
} else {
|
|
var roomListCode = '';
|
|
for (var i=selfR.rooms.length-1; i>=0; i--) {
|
|
var roomData = selfR.rooms[i];
|
|
if (!roomListCode) roomListCode += '<h3>Watch battles</h3>';
|
|
var roomDesc = '<small>[' + Tools.getEffect(roomData.format).name + ']</small><br /><em class="p1">' + sanitize(roomData.p1) + '</em> <small class="vs">vs.</small> <em class="p2">' + sanitize(roomData.p2) + '</em>';
|
|
roomListCode += '<div><a href="' + locPrefix + '' + roomData.id + '" onclick="selectTab(\'' + roomData.id + '\');return false">' + roomDesc + '</a></div>';
|
|
}
|
|
if (roomListCode) roomListCode += '<button onclick="rooms[\'' + selfR.id + '\'].formChallenge(\'#lobby-rooms\');return false">All battles →</button>';
|
|
|
|
var searcherText = '';
|
|
if (selfR.searcher) {
|
|
searcherText = '<small>There ' + (selfR.searcher === 1 ? 'is' : 'are') + ' ' + selfR.searcher + ' other ' + (selfR.searcher === 1 ? 'person' : 'people') + ' searching.</small>';
|
|
}
|
|
if (selfR.mainTopState === 'search-'+selfR.selectedFormat+(!selfR.goDisabled?'-nogo':'')) {
|
|
$('#' + selfR.id + '-searcher').html(searcherText);
|
|
$('#' + selfR.id + '-roomlist').html(roomListCode);
|
|
return;
|
|
}
|
|
selfR.mainTopState = 'search-'+selfR.selectedFormat+(!selfR.goDisabled?'-nogo':'');
|
|
|
|
text = '<div class="action-default">';
|
|
text += '' + selfR.getFormatSelect('search') + '<br />';
|
|
text += '' + selfR.getTeamSelect(selfR.selectedFormat) + '<br />';
|
|
if (selfR.goDisabled)
|
|
{
|
|
text += '</select><br /><button class="mainbutton disabled" onclick="overlay(\'message\',\'You need to make a team in the teambuilder.\');return false" id="'+selfR.id+'-gobutton"><strong><span class="pokemonicon" style="display:inline-block;vertical-align:middle;'+Tools.getIcon('Meloetta-Pirouette')+'"></span>Look for a battle</strong></button></div>';
|
|
}
|
|
else
|
|
{
|
|
text += '</select><br /><button class="mainbutton" onclick="return rooms[\''+selfR.id+'\'].formSearchBattle(true)" id="'+selfR.id+'-gobutton"><strong><span class="pokemonicon" style="display:inline-block;vertical-align:middle;'+Tools.getIcon('Meloetta-Pirouette')+'"></span>Look for a battle</strong></button></div>';
|
|
}
|
|
text += '<span id="' + selfR.id + '-searcher">' + searcherText + '</span><br />';
|
|
|
|
text += '<div id="' + selfR.id + '-roomlist" class="roomlist">' + roomListCode + '</div>';
|
|
}
|
|
selfR.mainTopElem.html(text);
|
|
|
|
if (!challenge) {
|
|
me.lastChallengeNotification = '';
|
|
}
|
|
};
|
|
this.debounceUpdateTimeout = null;
|
|
this.debounceUpdateQueued = false;
|
|
this.debounceUpdate = function() {
|
|
if (!selfR.debounceUpdateTimeout) {
|
|
selfR.updateMainTop();
|
|
selfR.debounceUpdateQueued = false;
|
|
selfR.debounceUpdateTimeout = setTimeout(selfR.debounceUpdateEnd, 3000);
|
|
} else {
|
|
selfR.debounceUpdateQueued = true;
|
|
}
|
|
};
|
|
this.debounceUpdateEnd = function() {
|
|
selfR.debounceUpdateTimeout = null;
|
|
if (selfR.debounceUpdateQueued) {
|
|
selfR.debounceUpdate();
|
|
}
|
|
};
|
|
this.timeEvent = (function() {
|
|
var data = [];
|
|
var last;
|
|
var current;
|
|
var starts = [];
|
|
return {
|
|
start: function() {
|
|
last = +new Date();
|
|
starts.push(last);
|
|
data.push(current = [0]);
|
|
},
|
|
end: function() {
|
|
},
|
|
checkpoint: function() {
|
|
var now = +new Date();
|
|
current.push(now - last);
|
|
last = now;
|
|
},
|
|
getResults: function() {
|
|
var average = [];
|
|
var total = [];
|
|
var trials = data.length;
|
|
for (var i = 0; i < data[0].length; ++i) {
|
|
var sum = 0;
|
|
for (var j = 0; j < trials; ++j) {
|
|
sum += data[j][i];
|
|
}
|
|
average[i] = Math.round(sum / trials * 10) / 10;
|
|
total[i] = sum;
|
|
}
|
|
var intervals = [];
|
|
for (var i = 0; i < starts.length - 1; ++i) {
|
|
intervals[i] = starts[i + 1] - starts[i];
|
|
}
|
|
return {average: average, total: total, intervals: intervals};
|
|
}
|
|
};
|
|
})();
|
|
this.userList = {
|
|
ranks: {
|
|
'~': 2,
|
|
'&': 2,
|
|
'@': 1,
|
|
'%': 1,
|
|
'+': 1,
|
|
' ': 0,
|
|
'!': 0,
|
|
'#': 0
|
|
},
|
|
rankOrder: {
|
|
'~': 1,
|
|
'&': 2,
|
|
'@': 3,
|
|
'%': 4,
|
|
'+': 5,
|
|
' ': 6,
|
|
'!': 7,
|
|
'#': 8
|
|
},
|
|
updateUserCount: function() {
|
|
$('#usercount-users').html(selfR.userCount.users || '0');
|
|
},
|
|
updateCurrentUser: function() {
|
|
$('.userlist > .cur').attr('class', '');
|
|
$('#userlist-user-' + me.userForm).attr('class', 'cur');
|
|
},
|
|
add: function(userid) {
|
|
var users = $('.userlist').children();
|
|
// Determine where to insert the user using a binary search.
|
|
var left = 0;
|
|
var right = users.length - 1;
|
|
while (right >= left) {
|
|
var mid = Math.floor((right - left) / 2 + left);
|
|
var cmp = this.elemComparator(users[mid], userid);
|
|
if (cmp < 0) {
|
|
left = mid + 1;
|
|
} else if (cmp > 0) {
|
|
right = mid - 1;
|
|
} else {
|
|
// The user is already in the list.
|
|
return;
|
|
}
|
|
}
|
|
$(this.constructItem(userid)).insertAfter($(users[right]));
|
|
},
|
|
remove: function(userid) {
|
|
$('#userlist-user-' + userid).remove();
|
|
},
|
|
buttonOnClick: function(userid) {
|
|
if (me.named) {
|
|
return selfR.formChallenge(userid);
|
|
}
|
|
return selfR.formRename();
|
|
},
|
|
constructItem: function(userid) {
|
|
var group = me.users[userid].substr(0, 1);
|
|
var text = '';
|
|
// Sanitising the `userid` here is probably unnecessary, because
|
|
// IDs can't contain anything dangerous.
|
|
text += '<li' + (me.userForm === userid ? ' class="cur"' : '') + ' id="userlist-user-' + sanitize(userid) + '">';
|
|
text += '<button class="userbutton" onclick="return rooms.lobby.userList.buttonOnClick(\'' + sanitize(userid) + '\')">';
|
|
text += '<em class="group' + (this.ranks[group]===2 ? ' staffgroup' : '') + '">' + sanitize(group) + '</em>';
|
|
if (group === '~' || group === '&') {
|
|
text += '<strong><em style="' + hashColor(userid) + '">' + sanitize(me.users[userid].substr(1)) + '</em></strong>';
|
|
} else if (group === '%' || group === '@') {
|
|
text += '<strong style="' + hashColor(userid) + '">' + sanitize(me.users[userid].substr(1)) + '</strong>';
|
|
} else {
|
|
text += '<span style="' + hashColor(userid) + '">' + sanitize(me.users[userid].substr(1)) + '</span>';
|
|
}
|
|
text += '</button>';
|
|
text += '</li>';
|
|
return text;
|
|
},
|
|
elemComparator: function(elem, userid) {
|
|
var id = elem.id;
|
|
switch (id) {
|
|
case 'userlist-users':
|
|
return -1; // `elem` comes first
|
|
case 'userlist-empty':
|
|
case 'userlist-unregistered':
|
|
case 'userlist-guests':
|
|
return 1; // `userid` comes first
|
|
}
|
|
// extract the portion of the `id` after 'userlist-user-'
|
|
var elemuserid = id.substr(14);
|
|
return this.comparator(elemuserid, userid);
|
|
},
|
|
comparator: function(a, b) {
|
|
if (a === b) return 0;
|
|
var aRank = this.rankOrder[me.users[a] ? me.users[a].substr(0, 1) : ' '];
|
|
var bRank = this.rankOrder[me.users[b] ? me.users[b].substr(0, 1) : ' '];
|
|
if (aRank !== bRank) return aRank - bRank;
|
|
return (a > b ? 1 : -1);
|
|
},
|
|
noNamedUsersOnline: '<li id="userlist-empty">No named users online</li>',
|
|
updateNoUsersOnline: function() {
|
|
var elem = $('#userlist-empty');
|
|
if ($("[id^=userlist-user-]").length === 0) {
|
|
if (elem.length === 0) {
|
|
var guests = $('#userlist-guests');
|
|
if (guests.length === 0) {
|
|
$('.userlist').append($(this.noNamedUsersOnline));
|
|
} else {
|
|
guests.before($(this.noNamedUsersOnline));
|
|
}
|
|
}
|
|
} else {
|
|
elem.remove();
|
|
}
|
|
},
|
|
construct: function() {
|
|
var text = '';
|
|
text += '<ul class="userlist">';
|
|
text += '<li id="userlist-users" style="text-align:center;padding:2px 0"><small><span id="usercount-users">' + (selfR.userCount.users || '0') + '</span> users online:</small></li>';
|
|
var users = [];
|
|
if (me.users) {
|
|
var self = this;
|
|
users = Object.keys(me.users).sort(function(a, b) {
|
|
return self.comparator(a, b);
|
|
});
|
|
}
|
|
for (var i=0, len=users.length; i<users.length; i++) {
|
|
var userid = users[i];
|
|
text += this.constructItem(userid);
|
|
}
|
|
if (!users.length) {
|
|
text += this.noNamedUsersOnline;
|
|
}
|
|
if (selfR.userCount.unregistered) {
|
|
text += '<li id="userlist-unregistered" style="height:auto;padding-top:5px;padding-bottom:5px">';
|
|
text += '<span style="font-size:10pt;display:block;text-align:center;padding-bottom:5px;font-style:italic">Due to lag, <span id="usercount-unregistered">' + selfR.userCount.unregistered + '</span> unregistered users are hidden.</span>';
|
|
text += ' <button' + (me.challengeTo ? ' disabled="disabled"' : ' onclick="var gname=prompt(\'Challenge who?\');if (gname) rooms[\'' + selfR.id + '\'].formChallenge(gname);return false"') + '>Challenge an unregistered user</button>';
|
|
text += '<div style="clear:both"></div>';
|
|
text += '</li>';
|
|
}
|
|
if (selfR.userCount.guests) {
|
|
text += '<li id="userlist-guests" style="text-align:center;padding:2px 0"><small>(<span id="usercount-guests">' + selfR.userCount.guests + '</span> guest' + (selfR.userCount.guests == 1 ? '' : 's') + ')</small></li>';
|
|
}
|
|
text += '</ul>';
|
|
selfR.mainBottomElem.html(text);
|
|
}
|
|
};
|
|
this.updateMe = function () {
|
|
if (selfR.meIdent.name !== me.name || selfR.meIdent.named !== me.named) {
|
|
if (me.named) {
|
|
selfR.chatAddElem.html('<form onsubmit="return false" class="chatbox"><label style="' + hashColor(me.userid) + '">' + sanitize(me.name) + ':</label> <textarea class="textbox" type="text" size="70" autocomplete="off" onkeypress="return rooms[\'' + selfR.id + '\'].formKeyPress(event)"></textarea></form>');
|
|
selfR.chatboxElem = selfR.chatAddElem.find('textarea');
|
|
// The keypress event does not capture tab, so use keydown.
|
|
selfR.chatboxElem.keydown(this.formKeyDown);
|
|
selfR.chatboxElem.autoResize({
|
|
animateDuration: 100,
|
|
extraSpace: 0
|
|
});
|
|
selfR.chatboxElem.focus();
|
|
} else {
|
|
selfR.chatAddElem.html('<form><button onclick="return rooms[\'' + selfR.id + '\'].formRename()">Join chat</button></form>');
|
|
}
|
|
|
|
selfR.meIdent.name = me.name;
|
|
selfR.meIdent.named = me.named;
|
|
}
|
|
};
|
|
// Key press in the chat textbox.
|
|
this.formKeyPress = function (e) {
|
|
hideTooltip();
|
|
if (e.keyCode === 13) { // Enter
|
|
var text;
|
|
if ((text = selfR.chatboxElem.val())) {
|
|
selfR.tabComplete.reset();
|
|
selfR.chatHistory.push(text);
|
|
text = selfR.parseCommand(text);
|
|
if (text) {
|
|
selfR.send(text);
|
|
}
|
|
selfR.chatboxElem.val('');
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
this.formKeyDown = function (e) {
|
|
hideTooltip();
|
|
var chatbox = $(e.delegateTarget);
|
|
switch (e.keyCode) {
|
|
case 9: // Tab key
|
|
// don't do anything if a modifier is pressed
|
|
if (e.shiftKey) return true;
|
|
if (e.ctrlKey) return true;
|
|
|
|
// We don't want to tab away from this box.
|
|
e.preventDefault();
|
|
|
|
// Don't tab complete at the start of the text box.
|
|
var idx = chatbox.prop('selectionStart');
|
|
if (idx === 0) return true;
|
|
|
|
var text = chatbox.val();
|
|
|
|
if (idx === selfR.tabComplete.cursor) {
|
|
// The user is cycling through the candidate names.
|
|
if (++selfR.tabComplete.index >= selfR.tabComplete.candidates.length) {
|
|
selfR.tabComplete.index = 0;
|
|
}
|
|
} else {
|
|
// This is a new tab completion.
|
|
|
|
// There needs to be non-whitespace to the left of the cursor.
|
|
var m = /^(.*?)([^ ]*)$/.exec(text.substr(0, idx));
|
|
if (!m) return true;
|
|
|
|
selfR.tabComplete.prefix = m[1];
|
|
var idprefix = toId(m[2]);
|
|
var candidates = [];
|
|
|
|
for (var i in me.users) {
|
|
if (!me.users.hasOwnProperty(i)) continue;
|
|
if (!(typeof i === 'string')) continue;
|
|
if (i.substr(0, idprefix.length) !== idprefix) continue;
|
|
candidates.push(i);
|
|
}
|
|
|
|
// Sort by most recent to speak in the chat, or, in the case of a tie,
|
|
// in alphabetical order.
|
|
candidates.sort(function(a, b) {
|
|
var aidx = selfR.userActivity.indexOf(a);
|
|
var bidx = selfR.userActivity.indexOf(b);
|
|
if (aidx !== -1) {
|
|
if (bidx !== -1) {
|
|
return bidx - aidx;
|
|
}
|
|
return -1; // a comes first
|
|
} else if (bidx != -1) {
|
|
return 1; // b comes first
|
|
}
|
|
return (a < b) ? -1 : 1; // alphabetical order
|
|
});
|
|
selfR.tabComplete.candidates = candidates;
|
|
selfR.tabComplete.index = 0;
|
|
}
|
|
|
|
// Substitute in the tab-completed name.
|
|
var substituteUserId = selfR.tabComplete.candidates[selfR.tabComplete.index];
|
|
var name = me.users[substituteUserId].substr(1);
|
|
chatbox.val(selfR.tabComplete.prefix + name + text.substr(idx));
|
|
var pos = selfR.tabComplete.prefix.length + name.length;
|
|
chatbox[0].setSelectionRange(pos, pos);
|
|
selfR.tabComplete.cursor = pos;
|
|
return true;
|
|
|
|
case 38: // Up key
|
|
// don't do anything if a modifier is pressed
|
|
if (e.shiftKey) return true;
|
|
if (e.ctrlKey) return true;
|
|
|
|
e.preventDefault();
|
|
if (selfR.chatHistory.index > 0) {
|
|
var line = chatbox.val();
|
|
if (selfR.chatHistory.index === selfR.chatHistory.lines.length) {
|
|
if (line !== '') {
|
|
selfR.chatHistory.push(line);
|
|
--selfR.chatHistory.index;
|
|
}
|
|
} else {
|
|
selfR.chatHistory.lines[selfR.chatHistory.index] = line;
|
|
}
|
|
chatbox.val(selfR.chatHistory.lines[--selfR.chatHistory.index]);
|
|
}
|
|
return true;
|
|
|
|
case 40: // Down key
|
|
// don't do anything if a modifier is pressed
|
|
if (e.shiftKey) return true;
|
|
if (e.ctrlKey) return true;
|
|
|
|
e.preventDefault();
|
|
|
|
if (selfR.chatHistory.index === selfR.chatHistory.lines.length) {
|
|
var line = chatbox.val();
|
|
if (line !== '') {
|
|
selfR.chatHistory.push(line);
|
|
chatbox.val('');
|
|
}
|
|
} else if (selfR.chatHistory.index === selfR.chatHistory.lines.length - 1) {
|
|
selfR.chatHistory.lines[selfR.chatHistory.index] = chatbox.val();
|
|
chatbox.val('');
|
|
++selfR.chatHistory.index;
|
|
} else {
|
|
selfR.chatHistory.lines[selfR.chatHistory.index] = chatbox.val();
|
|
chatbox.val(selfR.chatHistory.lines[++selfR.chatHistory.index]);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return true;
|
|
};
|
|
this.formRename = function () {
|
|
overlay('rename');
|
|
return false;
|
|
};
|
|
this.formSearchBattle = function (search, name) {
|
|
|
|
requestNotify();
|
|
if (!search) {
|
|
selfR.send('/search');
|
|
} else {
|
|
if (!me.named) {
|
|
overlay('rename');
|
|
return false;
|
|
}
|
|
var format = $('#' + selfR.id + '-format').val();
|
|
selectTeam($('#' + selfR.id + '-team').val());
|
|
selfR.send('/search '+toId(format));
|
|
}
|
|
return false;
|
|
};
|
|
this.formChallenge = function (user) {
|
|
me.userForm = user;
|
|
selfR.userList.updateCurrentUser();
|
|
selfR.updateMainTop();
|
|
$(window).scrollTop(51);
|
|
return false;
|
|
};
|
|
this.getFormatSelect = function (selectType) {
|
|
var text = '';
|
|
text += '<label class="label">Format:</label> <select id="' + selfR.id + '-format" onchange="return rooms[\'' + selfR.id + '\'].formSelectFormat()">';
|
|
var curSection = '';
|
|
for (var i in exports.BattleFormats) {
|
|
var format = exports.BattleFormats[i];
|
|
var selected = false;
|
|
if (format.effectType !== 'Format') continue;
|
|
if (selectType && !format[selectType + 'Show']) continue;
|
|
|
|
if (!selfR.selectedFormat) {
|
|
if (selectType) selected = format[selectType + 'Default'];
|
|
if (selected && !format.team && !teams.length) selected = false;
|
|
if (selected) {
|
|
selfR.selectedFormat = i;
|
|
}
|
|
} else {
|
|
selected = (selfR.selectedFormat === i);
|
|
}
|
|
var details = '';
|
|
if (format.rated && selectType === 'search') {
|
|
//details = ' (rated)';
|
|
}
|
|
if (format.section && format.section !== curSection) {
|
|
if (curSection) text += '</optgroup>';
|
|
text += '<optgroup label="'+sanitize(format.section)+'">';
|
|
curSection = format.section;
|
|
}
|
|
if (!format.section && curSection) text += '</optgroup>';
|
|
text += '<option value="' + sanitize(i) + '"' + (selected ? ' selected="selected"' : '') + '>' + sanitize(format.name) + details + '</option>';
|
|
}
|
|
if (curSection) text += '</optgroup>';
|
|
text += '</select>';
|
|
return text;
|
|
};
|
|
this.getTeamSelect = function (format) {
|
|
if (!format) format = selfR.selectedFormat;
|
|
var formatid = '';
|
|
if (!format.name) {
|
|
formatid = format;
|
|
format = exports.BattleFormats[toId(format)];
|
|
if (!format) format = {id:formatid, name:formatid};
|
|
}
|
|
|
|
selfR.goDisabled = false;
|
|
if (format.team) {
|
|
var gobutton = $('#' + selfR.id + '-gobutton');
|
|
if (gobutton.length) gobutton[0].disabled = false;
|
|
return '<span id="' + selfR.id + '-teamselect"><label class="label">Team:</label> Random Team</span>';
|
|
} else {
|
|
var text = '<span id="' + selfR.id + '-teamselect"><label class="label">Team:</label> <select id="' + selfR.id + '-team" onchange="return rooms[\'' + selfR.id + '\'].formSelectTeam()">';
|
|
if (!teams.length) {
|
|
text += '<option value="0">You have no teams</option>';
|
|
selfR.goDisabled = true;
|
|
} else {
|
|
var teamFormat = (format.teambuilderFormat || (format.isTeambuilderFormat ? formatid : false));
|
|
for (var i = 0; i < teams.length; i++) {
|
|
var selected = (i === selfR.selectedTeam);
|
|
if ((!teams[i].format && !teamFormat) || teams[i].format === teamFormat) {
|
|
text += '<option value="' + i + '"' + (selected ? ' selected="selected"' : '') + '>' + sanitize(teams[i].name) + '</option>';
|
|
}
|
|
}
|
|
text += '<optgroup label="Other teams">';
|
|
for (var i = 0; i < teams.length; i++) {
|
|
if ((!teams[i].format && !teamFormat) || teams[i].format === teamFormat) continue;
|
|
text += '<option value="' + i + '">' + sanitize(teams[i].name) + '</option>';
|
|
}
|
|
text += '</optgroup>';
|
|
}
|
|
if (format.canUseRandomTeam) {
|
|
text += '<option value="-1">Random Team</option>';
|
|
}
|
|
text += '</select></span>';
|
|
var gobutton = $('#' + selfR.id + '-gobutton');
|
|
if (gobutton.length) gobutton[0].disabled = selfR.goDisabled;
|
|
return text;
|
|
}
|
|
};
|
|
this.formSelectTeam = function () {
|
|
var i = parseInt($('#' + selfR.id + '-team').val());
|
|
if (i === 0 && !teams.length) selfR.goDisabled = true;
|
|
else selfR.goDisabled = false;
|
|
|
|
selfR.selectedTeam = i;
|
|
|
|
selfR.updateMainTop();
|
|
};
|
|
this.formSelectFormat = function (format) {
|
|
selfR.selectedFormat = $('#' + selfR.id + '-format').val();
|
|
$('#' + selfR.id + '-teamselect').replaceWith(selfR.getTeamSelect());
|
|
|
|
selfR.updateMainTop();
|
|
};
|
|
this.formMakeChallenge = function (userid) {
|
|
requestNotify();
|
|
var format = $('#' + selfR.id + '-format').val();
|
|
me.userForm = '';
|
|
selfR.userList.updateCurrentUser();
|
|
selectTeam($('#' + selfR.id + '-team').val());
|
|
selfR.send('/challenge '+userid+', '+format);
|
|
return false;
|
|
};
|
|
this.formCloseUserForm = function (userid) {
|
|
if (me.userForm) {
|
|
me.userForm = '';
|
|
selfR.userList.updateCurrentUser();
|
|
selfR.updateMainTop();
|
|
return false;
|
|
}
|
|
selfR.updateMainTop();
|
|
selfR.send('/cancelchallenge '+userid);
|
|
return false;
|
|
};
|
|
this.formAcceptChallenge = function (userid) {
|
|
requestNotify();
|
|
selectTeam($('#' + selfR.id + '-team').val());
|
|
selfR.send('/accept '+userid);
|
|
return false;
|
|
};
|
|
this.formRejectChallenge = function (userid) {
|
|
selfR.send('/reject '+userid);
|
|
return false;
|
|
};
|
|
}
|
|
|
|
function updateMe() {
|
|
var notifybutton = '';
|
|
/* if (needEnableNotify())
|
|
{
|
|
notifybutton = '<button onclick="return requestNotify()"><strong style="color:red">ENABLE NOTIFICATIONS</strong></button> ';
|
|
} */
|
|
|
|
//var mutebutton = ' <button onclick="return formMute()" style="height:20px;vertical-align:middle;">' + (me.mute ? '<img src="/fx/mute.png" width="18" height="18" alt="Unmute" />' : '<img src="/fx/sound.png" width="18" height="18" alt="Mute" />') + '</button>';
|
|
var mutebutton = ' <button onclick="return formMute()" style="width:30px;font-size:9pt">' + (me.mute ? '<i class="icon-volume-off" title="Unmute"></i>' : '<i class="icon-volume-up" title="Mute"></i>') + '</button>';
|
|
if (me.named) {
|
|
$('#userbar').html(notifybutton + '<i class="icon-user" style="color:#779EC5"></i> ' + sanitize(me.name) + mutebutton + ' <button onclick="return rooms[\'lobby\'].formRename()" style="font-size:9pt">Change name</button>');
|
|
$.cookie('showdown_username', me.name, {
|
|
expires: 14
|
|
});
|
|
Tools.postCrossDomainMessage({username: me.name});
|
|
} else {
|
|
$('#userbar').html(notifybutton + '<i class="icon-user" style="color:#999"></i> ' + sanitize(me.name) + mutebutton + ' <button onclick="return rooms[\'lobby\'].formRename()" style="font-size:9pt">Choose name</button>');
|
|
}
|
|
$('#userbar').prepend('<small><a href="http://pokemonshowdown.com/" target="_blank">Website</a> <a href="http://pokemonshowdown.com/rules" target="_blank">Rules</a> <a href="http://www.smogon.com/forums/showthread.php?t=3469932" target="_blank" onclick="_gaq.push([\'_trackEvent\', \'Report bug link\', Config.serverid]); return true;">Report bug</a> </small> ');
|
|
if (rooms.lobby) {
|
|
rooms.lobby.updateMe();
|
|
rooms.lobby.debounceUpdate();
|
|
}
|
|
}
|
|
|
|
function formMute() {
|
|
me.mute = !me.mute;
|
|
Tools.prefs.set('mute', !!me.mute, true);
|
|
if (curRoom.battle) {
|
|
curRoom.battle.setMute(me.mute);
|
|
}
|
|
updateMe();
|
|
}
|
|
|
|
function updateRoomList() {
|
|
var code = '';
|
|
if (!curRoom) curRoom = rooms.lobby;
|
|
code += '<div><a id="tabtab-lobby" class="tab' + (curRoom.id === 'lobby' ? ' cur' : '') + (rooms.lobby && rooms.lobby.notifying ? ' notifying' : '') + '" href="' + locPrefix + '" onclick="selectTab(\'lobby\'); return false"><i class="icon-comments-alt"></i> Lobby</a>';
|
|
code += '<a id="tabtab-teambuilder"' + (curRoom.id === 'teambuilder' ? ' class="cur"' : '') + ' href="' + locPrefix + 'teambuilder" onclick="selectTab(\'teambuilder\', event);return false"><i class="icon-edit"></i> Teambuilder</a>';
|
|
code += '<a id="tabtab-ladder"' + (curRoom.id === 'ladder' ? ' class="cur"' : '') + ' href="' + locPrefix + 'ladder" onclick="selectTab(\'ladder\');return false"><i class="icon-list-ol"></i> Ladder</a></div>';
|
|
|
|
var shownRooms = {
|
|
lobby: true,
|
|
teambuilder: true,
|
|
ladder: true
|
|
};
|
|
var yourRooms = false;
|
|
for (var id in rooms) {
|
|
if (shownRooms[id]) continue;
|
|
shownRooms[id] = true;
|
|
if (!yourRooms) code += '<div><small>Your rooms</small></div>';
|
|
yourRooms = true;
|
|
var roomDesc = id;
|
|
var roomName = (id.substr(0, 7) === 'battle-' ? id.substr(7) : id);
|
|
closesize = 'close2';
|
|
if (roomName) {
|
|
roomDesc = '' + roomName + '<small>(inactive)</small>';
|
|
closesize = 'close0';
|
|
}
|
|
if (rooms[id].battle) {
|
|
var p1 = '';
|
|
var p2 = '';
|
|
if (rooms[id].battle.p1 && rooms[id].battle.p1.initialized) p1 = rooms[id].battle.p1.name;
|
|
if (rooms[id].battle.p2 && rooms[id].battle.p2.initialized) p2 = rooms[id].battle.p2.name;
|
|
if (p1 && p2) {
|
|
roomDesc = '<em class="p1">' + sanitize(p1) + '</em> <small class="vs">vs.</small> <em class="p2">' + sanitize(p2) + '</em>';
|
|
closesize = 'close3';
|
|
} else if (p1) {
|
|
roomDesc = '<em class="p1">' + sanitize(p1) + '</em> <small>(inactive)</small>';
|
|
rooms[id].notifying = false;
|
|
closesize = 'close0';
|
|
} else if (p2) {
|
|
roomDesc = '<em class="p1">' + sanitize(p2) + '</em> <small>(inactive)</small>';
|
|
rooms[id].notifying = false;
|
|
closesize = 'close0';
|
|
} else {
|
|
roomDesc = '' + roomName + '<small>(empty)</small>';
|
|
rooms[id].notifying = false;
|
|
closesize = 'close0';
|
|
}
|
|
}
|
|
code += '<div><a id="tabtab-' + id + '" class="tab battletab' + (curRoom.id === id ? ' cur' : '') + (rooms[id] && rooms[id].notifying ? ' notifying' : '') + '" href="' + locPrefix + '' + id + '" onclick="selectTab(\'' + id + '\');return false">' + roomDesc + '</a><span onclick="leaveTab(\'' + id + '\')" class="close ' + closesize + '"></span></div>';
|
|
}
|
|
$('#leftbar').html(code);
|
|
$('#inline-nav').html('<h3>Your tabs</h3>' + code.replace(/ id="[^"]*"/g, ''));
|
|
}
|
|
var widthClass = 'normal-layout';
|
|
var heightClass = 'normal-height';
|
|
var fixedWidth = true;
|
|
|
|
function updateResize() {
|
|
if (window.screen && screen.width && screen.width >= 640) {
|
|
if (fixedWidth) {
|
|
document.getElementById('viewport').setAttribute('content','width=device-width');
|
|
fixedWidth = false;
|
|
}
|
|
} else {
|
|
if (!fixedWidth) {
|
|
document.getElementById('viewport').setAttribute('content','width=640');
|
|
fixedWidth = true;
|
|
}
|
|
}
|
|
|
|
if ($(window).width() < 740) {
|
|
$('body').prop('class', 'tiny-layout');
|
|
widthClass = 'tiny-layout';
|
|
} else if ($(window).width() < 870) {
|
|
$('body').prop('class', 'small-layout');
|
|
widthClass = 'small-layout';
|
|
} else if ($(window).width() < 1420) {
|
|
$('body').prop('class', 'normal-layout');
|
|
widthClass = 'normal-layout';
|
|
} else {
|
|
$('body').prop('class', 'huge-layout');
|
|
widthClass = 'huge-layout';
|
|
}
|
|
|
|
if ($(window).height() < 575) {
|
|
$('body').addClass('tiny-height');
|
|
heightClass = 'tiny-height';
|
|
} else {
|
|
$('body').addClass('normal-height');
|
|
heightClass = 'normal-height';
|
|
}
|
|
updateLobbyChat();
|
|
}
|
|
|
|
function tooltipAttrs(thing, type, ownHeight, isActive) {
|
|
return ' onmouseover="return showTooltip(\'' + sanitize(''+thing, true) + '\',\'' + type + '\', this, ' + (ownHeight ? 'true' : 'false') + ', ' + (isActive ? 'true' : 'false') + ')" onmouseout="return hideTooltip()" onmouseup="hideTooltip()"';
|
|
}
|
|
|
|
function showTooltip(thing, type, elem, ownHeight, isActive) {
|
|
var offset = {
|
|
left: 150,
|
|
top: 500
|
|
};
|
|
if (elem) offset = $(elem).offset();
|
|
var x = offset.left - 25;
|
|
if (elem) {
|
|
if (ownHeight) offset = $(elem).offset();
|
|
else offset = $(elem).parent().offset();
|
|
}
|
|
var y = offset.top - 15;
|
|
|
|
if (widthClass === 'tiny-layout') {
|
|
if (x > 360) x = 360;
|
|
}
|
|
if (y < 140) y = 140;
|
|
$('#tooltipwrapper').css({
|
|
left: x,
|
|
top: y
|
|
});
|
|
|
|
var text = '';
|
|
switch (type) {
|
|
case 'move':
|
|
var move = Tools.getMove(thing);
|
|
if (!move) return;
|
|
var basePower = move.basePower;
|
|
if (!basePower) basePower = '—';
|
|
var accuracy = move.accuracy;
|
|
if (!accuracy || accuracy === true) accuracy = '—';
|
|
else accuracy = '' + accuracy + '%';
|
|
text = '<div class="tooltipinner"><div class="tooltip">';
|
|
text += '<h2>' + move.name + '<br />'+Tools.getTypeIcon(move.type)+' <img src="' + Tools.resourcePrefix + 'sprites/categories/' + move.category + '.png" alt="' + move.category + '" /></h2>';
|
|
text += '<p>Base power: ' + basePower + '</p>';
|
|
text += '<p>Accuracy: ' + accuracy + '</p>';
|
|
if (move.desc) {
|
|
text += '<p class="section">' + move.desc + '</p>';
|
|
}
|
|
text += '</div></div>';
|
|
break;
|
|
case 'pokemon':
|
|
var pokemon = curRoom.battle.getPokemon(thing);
|
|
if (!pokemon) return;
|
|
//fallthrough
|
|
case 'sidepokemon':
|
|
if (!pokemon) pokemon = curRoom.battle.mySide.pokemon[parseInt(thing)];
|
|
text = '<div class="tooltipinner"><div class="tooltip">';
|
|
text += '<h2>' + pokemon.getFullName() + (pokemon.level !== 100 ? ' <small>L' + pokemon.level + '</small>' : '') + '<br />';
|
|
|
|
var types = pokemon.types;
|
|
var template = pokemon;
|
|
if (pokemon.volatiles.transform && pokemon.volatiles.formechange) {
|
|
template = Tools.getTemplate(pokemon.volatiles.formechange[2]);
|
|
types = template.types;
|
|
text += '<small>(Transformed into '+pokemon.volatiles.formechange[2]+')</small><br />';
|
|
} else if (pokemon.volatiles.formechange) {
|
|
template = Tools.getTemplate(pokemon.volatiles.formechange[2]);
|
|
types = template.types;
|
|
text += '<small>(Forme: '+pokemon.volatiles.formechange[2]+')</small><br />';
|
|
}
|
|
if (pokemon.volatiles.typechange) {
|
|
text += '<small>(Type changed)</small><br />';
|
|
types = [pokemon.volatiles.typechange[2]];
|
|
}
|
|
text += Tools.getTypeIcon(types[0]);
|
|
if (types[1]) {
|
|
text += ' '+Tools.getTypeIcon(types[1]);
|
|
}
|
|
text += '</h2>';
|
|
var exacthp = '';
|
|
if (pokemon.maxhp != 100 && pokemon.maxhp != 1000 && pokemon.maxhp != 48) exacthp = ' ('+pokemon.hp+'/'+pokemon.maxhp+')';
|
|
if (pokemon.maxhp == 48 && isActive) exacthp = ' <small>('+pokemon.hp+'/'+pokemon.maxhp+' pixels)</small>';
|
|
text += '<p>HP: ' + Math.round(100 * pokemon.hp / pokemon.maxhp) + '%'+exacthp+(pokemon.status?' <span class="status '+pokemon.status+'">'+pokemon.status.toUpperCase()+'</span>':'')+'</p>';
|
|
if (!pokemon.baseAbility && (!pokemon.ability || pokemon.ability.substr(0, 2) === '??')) {
|
|
text += '<p>Possible abilities: ' + Tools.getAbility(template.abilities['0']).name;
|
|
if (template.abilities['1']) text += ', ' + Tools.getAbility(template.abilities['1']).name;
|
|
if (template.abilities['DW']) text += ', ' + Tools.getAbility(template.abilities['DW']).name;
|
|
text += '</p>';
|
|
} else if (pokemon.ability) {
|
|
text += '<p>Ability: ' + Tools.getAbility(pokemon.ability).name + '</p>';
|
|
} else if (pokemon.baseAbility) {
|
|
text += '<p>Ability: ' + Tools.getAbility(pokemon.baseAbility).name + '</p>';
|
|
}
|
|
if (pokemon.item) {
|
|
text += '<p>Item: ' + Tools.getItem(pokemon.item).name + '</p>';
|
|
}
|
|
if (pokemon.moves && pokemon.moves.length && (!isActive || isActive === 'foe')) {
|
|
text += '<p class="section">';
|
|
for (var i = 0; i < pokemon.moves.length; i++) {
|
|
var name = Tools.getMove(pokemon.moves[i]).name;
|
|
text += '⋅ ' + name + '<br />';
|
|
}
|
|
text += '</p>';
|
|
}
|
|
text += '</div></div>';
|
|
break;
|
|
}
|
|
$('#tooltipwrapper').html(text);
|
|
return true;
|
|
}
|
|
|
|
function hideTooltip() {
|
|
$('#tooltipwrapper').html('');
|
|
return true;
|
|
}
|
|
|
|
var initialized = false;
|
|
|
|
var socketInit = null;
|
|
|
|
$(window).resize(updateResize);
|
|
|
|
var changeState = function () {};
|
|
|
|
var loc = 'lobby';
|
|
if (document.location.pathname.substr(0, locPrefix.length) === locPrefix) {
|
|
loc = document.location.pathname.substr(locPrefix.length);
|
|
if (!loc || loc === 'test.html' || loc === 'temp.html' || loc.substr(loc.length-15) === 'testclient.html') loc = 'lobby';
|
|
}
|
|
|
|
if (window.history && history.pushState) {
|
|
// HTML5 history
|
|
changeState = function (newLoc) {
|
|
if (!initialized) return;
|
|
var urlLoc = newLoc;
|
|
if (urlLoc === 'lobby') urlLoc = '';
|
|
if (document.location.pathname !== locPrefix + urlLoc) {
|
|
try {
|
|
history.pushState(null, null, locPrefix + urlLoc);
|
|
} catch (e) {
|
|
// Throws insecure operation when running on local filesystem.
|
|
}
|
|
}
|
|
loc = newLoc;
|
|
};
|
|
window.onpopstate = function (e) {
|
|
if (document.location.pathname.substr(0, locPrefix.length) === locPrefix) {
|
|
loc = document.location.pathname.substr(locPrefix.length);
|
|
if (!loc || loc === 'test.html' || loc === 'temp.html' || loc.substr(loc.length-15) === 'testclient.html') loc = 'lobby';
|
|
if (!socket) {
|
|
return; // haven't even initted yet
|
|
}
|
|
selectTab(loc);
|
|
}
|
|
};
|
|
}
|
|
|
|
var notify = function () {};
|
|
var requestNotify = function () {};
|
|
var dismissNotify = function () {};
|
|
var needEnableNotify = function () {
|
|
return false;
|
|
};
|
|
var activeNotification = null;
|
|
var activeNotificationData = null;
|
|
|
|
window.focused = true;
|
|
$(window).focus(function () {
|
|
window.focused = true;
|
|
dismissNotify();
|
|
});
|
|
$(window).click(function () {
|
|
window.focused = true;
|
|
dismissNotify();
|
|
});
|
|
$(window).blur(function () {
|
|
window.focused = false;
|
|
});
|
|
|
|
var favicon = {
|
|
|
|
// -- "PUBLIC" ----------------------------------------------------------------
|
|
defaultPause: 500,
|
|
|
|
change: function (iconURL, optionalDocTitle) {
|
|
clearTimeout(this.loopTimer);
|
|
if (optionalDocTitle) {
|
|
document.title = optionalDocTitle;
|
|
}
|
|
this.addLink(iconURL, true);
|
|
},
|
|
|
|
animate: function (iconSequence, optionalDelay) {
|
|
this.preloadIcons(iconSequence);
|
|
this.iconSequence = iconSequence;
|
|
this.sequencePause = (optionalDelay) ? optionalDelay : this.defaultPause;
|
|
favicon.index = 0;
|
|
favicon.change(iconSequence[0]);
|
|
this.loopTimer = setInterval(function () {
|
|
favicon.index = (favicon.index + 1) % favicon.iconSequence.length;
|
|
favicon.addLink(favicon.iconSequence[favicon.index], false);
|
|
}, favicon.sequencePause);
|
|
},
|
|
|
|
// -- "PRIVATE" ---------------------------------------------------------------
|
|
loopTimer: null,
|
|
|
|
preloadIcons: function (iconSequence) {
|
|
var dummyImageForPreloading = document.createElement("img");
|
|
for (var i = 0; i < iconSequence.length; i++) {
|
|
dummyImageForPreloading.src = iconSequence[i];
|
|
}
|
|
},
|
|
|
|
addLink: function (iconURL) {
|
|
var link = document.createElement("link");
|
|
link.type = "image/x-icon";
|
|
link.rel = "shortcut icon";
|
|
link.href = iconURL;
|
|
this.removeLinkIfExists();
|
|
this.docHead.appendChild(link);
|
|
},
|
|
|
|
removeLinkIfExists: function () {
|
|
var links = this.docHead.getElementsByTagName("link");
|
|
for (var i = 0; i < links.length; i++) {
|
|
var link = links[i];
|
|
if (link.type == "image/x-icon" && link.rel == "shortcut icon") {
|
|
this.docHead.removeChild(link);
|
|
return; // Assuming only one match at most.
|
|
}
|
|
}
|
|
},
|
|
|
|
docHead: document.getElementsByTagName("head")[0]
|
|
}
|
|
|
|
{
|
|
// HTML5 notifications
|
|
if (window.Notification) {
|
|
needEnableNotify = function () {
|
|
if (Notification.permissionLevel) return (Notification.permissionLevel() !== 'granted');
|
|
if (window.webkitNotifications) return (window.webkitNotifications.checkPermission() != 0);
|
|
return false;
|
|
};
|
|
requestNotify = function () {
|
|
/* if (Notification.permissionLevel && Notification.requestPermission) {
|
|
if (Notification.permissionLevel() !== 'granted') {
|
|
try {
|
|
Notification.requestPermission();
|
|
} catch (e) {};
|
|
}
|
|
return false;
|
|
} */
|
|
/* if (window.webkitNotifications && window.webkitNotifications.requestPermission && window.webkitNotifications.checkPermission() != 0) {
|
|
webkitNotifications.requestPermission();
|
|
} */
|
|
return false;
|
|
};
|
|
dismissNotify = function () {
|
|
favicon.change(Tools.resourcePrefix + 'favicon.ico');
|
|
if (activeNotification) {
|
|
activeNotification.cancel();
|
|
activeNotification = null;
|
|
activeNotificationData = null;
|
|
}
|
|
};
|
|
notify = function (data) {
|
|
if (window.focused) return;
|
|
favicon.animate([Tools.resourcePrefix + 'favicon-notify.ico', Tools.resourcePrefix + 'favicon-notify2.ico']);
|
|
if (needEnableNotify()) {
|
|
requestNotify();
|
|
} else {
|
|
var message = 'Something has happened!';
|
|
switch (data.type) {
|
|
case 'challenge':
|
|
message = ""+data.user+" has challenged you to a battle!";
|
|
break;
|
|
case 'highlight':
|
|
message = 'You have been highlighted by ' + data.user + '!';
|
|
break;
|
|
case 'pm':
|
|
message = 'You have received a PM from ' + data.user + '!';
|
|
break;
|
|
case 'yourMove':
|
|
case 'yourSwitch':
|
|
message = "It's your move in your battle against "+data.user+".";
|
|
break;
|
|
}
|
|
//var notification = window.webkitNotifications.createHTMLNotification('http://play.pokemonshowdown.com/notification.php?type=' + data.type + '&person=' + encodeURIComponent(data.user) + '&personid=' + data.userid + '&room=' + data.room)
|
|
var notification = new Notification("Pokemon Showdown", {
|
|
iconUrl: "/favicon-notify.gif",
|
|
body: message,
|
|
tag: data.type+'-'+data.room+'-'+data.user,
|
|
onclose: function (event) {
|
|
window.focus();
|
|
}
|
|
});
|
|
notification.show();
|
|
dismissNotify();
|
|
activeNotification = notification;
|
|
activeNotificationData = data;
|
|
}
|
|
};
|
|
} else if (window.macgap) {
|
|
// MacGap notifications! :o
|
|
notify = function (data) {
|
|
if (window.focused) return;
|
|
var message = '';
|
|
switch (data.type) {
|
|
case 'challenge':
|
|
macgap.growl.notify({
|
|
title: "Challenged!",
|
|
content: ""+data.user+" has challenged you to a battle!"
|
|
});
|
|
break;
|
|
case 'highlight':
|
|
macgap.growl.notify({
|
|
title: 'Highlighted!',
|
|
content: 'You have been highlighted by ' + data.user + '!'
|
|
});
|
|
break;
|
|
case 'pm':
|
|
macgap.growl.notify({
|
|
title: 'PM!',
|
|
content: 'You have received a PM from ' + data.user + '!'
|
|
});
|
|
break;
|
|
case 'yourMove':
|
|
case 'yourSwitch':
|
|
macgap.growl.notify({
|
|
title: "Your move!",
|
|
content: "It's your move in your battle against "+data.user+"."
|
|
});
|
|
break;
|
|
default:
|
|
macgap.growl.notify({
|
|
title: "Pokemon Showdown",
|
|
content: "Something has happened!"
|
|
});
|
|
break;
|
|
}
|
|
macgap.dock.badge = "1";
|
|
}
|
|
dismissNotify = function () {
|
|
macgap.dock.badge = "";
|
|
}
|
|
} else {
|
|
var activeNotificationData = null;
|
|
notify = function (data) {
|
|
if (window.focused) return;
|
|
favicon.animate(['/favicon-notify.ico', '/favicon-notify2.ico']);
|
|
activeNotificationData = data;
|
|
activeNotification = setInterval(updateNotifyTitle, 1500);
|
|
};
|
|
dismissNotify = function () {
|
|
favicon.change('/favicon.ico');
|
|
if (activeNotification) {
|
|
clearTimeout(activeNotification);
|
|
document.title = curTitle;
|
|
activeNotification = null;
|
|
activeNotificationData = null;
|
|
}
|
|
};
|
|
updateNotifyTitle = function () {
|
|
if (!activeNotification) return false;
|
|
if (!activeNotificationData) return false;
|
|
window.notifying = !window.notifying;
|
|
if (window.notifying) {
|
|
switch (activeNotificationData.type) {
|
|
case 'challenge':
|
|
document.title = 'CHALLENGED';
|
|
break;
|
|
case 'highlight':
|
|
document.title = 'HIGHLIGHTED';
|
|
break;
|
|
case 'pm':
|
|
document.title = 'PM';
|
|
break;
|
|
case 'yourMove':
|
|
case 'yourSwitch':
|
|
document.title = 'YOUR MOVE';
|
|
break;
|
|
default:
|
|
document.title = 'ACTIVITY';
|
|
break;
|
|
}
|
|
} else {
|
|
document.title = curTitle;
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
function notificationClick(button, data) {
|
|
switch (button) {
|
|
case 'accept':
|
|
rooms[data.room].formAcceptChallenge(data.userid);
|
|
break;
|
|
case 'reject':
|
|
rooms[data.room].formRejectChallenge(data.userid);
|
|
break;
|
|
}
|
|
};
|
|
|
|
// overlay
|
|
function overlay(overlayType, data) {
|
|
var contents = '';
|
|
var focusElem = '';
|
|
var selectElem = '';
|
|
switch (overlayType) {
|
|
case 'message':
|
|
contents = '<p>' + data + '</p>';
|
|
contents += '<p><button onclick="overlayClose();return false" id="overlay_ok">OK</button></p>';
|
|
focusElem = '#overlay_ok';
|
|
break;
|
|
case 'replayuploaded':
|
|
contents = '<p>Your replay has been uploaded! It\'s available at:</p>';
|
|
contents += '<p><a href="http://pokemonshowdown.com/replay/'+data+'" target="_blank" onclick="overlayClose()">http://pokemonshowdown.com/replay/'+data+'</a></p>';
|
|
contents += '<p><button onclick="window.open(\'/replay/battle-'+data+'\',\'_blank\');overlayClose();return false" id="overlay_ok"><strong>Open</strong></button> <button onclick="overlayClose();return false" id="overlay_cancel">Cancel</button></p>';
|
|
focusElem = '#overlay_ok';
|
|
break;
|
|
case 'init':
|
|
if (data) return;
|
|
contents = '<p><strong>Pokemon Showdown is BETA</strong> and unfinished. If you are looking for something that isn\'t frequently down for maintenance and bug fixes, please check back in several weeks.</p>';
|
|
contents += '<p>There is a link to report bugs in the top right. If you find a bug, please report it.</p>';
|
|
contents += '<p><button onclick="overlayClose();return false" id="overlay_ok"><strong>I understand</strong></button> <button onclick="document.location.href = \'http://www.zombo.com/\';return false">I don\'t understand</button></p>';
|
|
focusElem = '#overlay_ok';
|
|
break;
|
|
case 'register':
|
|
if (!data) data = {};
|
|
if (me.registered && me.registered.userid === me.userid) return;
|
|
if (data.ifuserid !== me.userid) return;
|
|
if (data.error) {
|
|
contents += '<p class="error">' + data.error + '</p>';
|
|
} else if (data.reason) {
|
|
contents += '<p>' + data.reason + '</p>';
|
|
} else {
|
|
contents += '<p>Register an account:</p>';
|
|
}
|
|
contents += '<p><label class="label">Username:</label> ' + (data.name || me.name) + '<input type="hidden" id="overlay_username" value="' + sanitize(data.name || me.name) + '" /></p>';
|
|
contents += '<p><label class="label">Password:</label> <input class="textbox" type="password" id="overlay_password" /></p>';
|
|
contents += '<p><label class="label">Password (confirm):</label> <input class="textbox" type="password" id="overlay_cpassword" /></p>';
|
|
contents += '<p><img src="' + Tools.resourcePrefix + 'sprites/bwani/pikachu.gif" /></p>';
|
|
contents += '<p><label class="label">What is this pokemon?</label> <input class="textbox" type="text" id="overlay_captcha" value="' + sanitize(data.captcha) + '" /></p>';
|
|
contents += '<p><button type="submit"><strong>Register</strong></button> <button onclick="overlayClose();return false">Cancel</button></p>';
|
|
selectElem = '#overlay_password';
|
|
break;
|
|
case 'login':
|
|
if (!data) data = {};
|
|
if (data.error) {
|
|
contents += '<p class="error">' + data.error + '</p>';
|
|
} else if (data.reason) {
|
|
contents += '<p>' + data.reason + '</p>';
|
|
} else {
|
|
contents += '<p>The name you chose is registered.</p>';
|
|
}
|
|
contents += '<p><label class="label">Username:</label> ' + data.name + '<input type="hidden" id="overlay_username" value="' + sanitize(data.name) + '" /></p>';
|
|
contents += '<p><label class="label">Password:</label> <input class="textbox" type="password" id="overlay_password" /></p>';
|
|
contents += '<p><button type="submit"><strong>Log in</strong></button> <button onclick="overlayClose();return false">Cancel</button></p>';
|
|
selectElem = '#overlay_password';
|
|
break;
|
|
case 'testclientgetassertion':
|
|
contents += '<p>Because of the <a href="https://en.wikipedia.org/wiki/Same-origin_policy" target="_blank">same-origin policy</a>, some manual work is required to log in using <code>testclient.html</code>.</p>';
|
|
contents += '<iframe id="overlay_iframe" src="' + data.query + '" style="width: 100%; height: 50px;" class="textbox"></iframe>';
|
|
contents += '<p>Please copy <strong>all the text</strong> from the box above and paste it in the box below. If the box above just shows a semi-colon (;), log in using the <a href="http://play.pokemonshowdown.com" target="_blank">official client</a> and then refresh this page.</p>';
|
|
if (data.error) {
|
|
contents += '<p><strong>' + data.error + '</strong></p>';
|
|
}
|
|
contents += '<input class="textbox" type="hidden" id="overlay_username" value="' + data.name + '" />';
|
|
contents += '<p><label class="label">Data from the box above:</label> <input style="width: 100%;" class="textbox" type="text" id="overlay_assertion" /></p>';
|
|
contents += '<p><button type="submit"><strong>Log in</strong></button> <button onclick="overlayClose();return false">Cancel</button></p>';
|
|
selectElem = '#overlay_assertion';
|
|
break;
|
|
case 'betalogin':
|
|
if (!data) data = {};
|
|
contents += '<p><strong>Pokemon Showdown is in private beta testing.</strong></p>';
|
|
contents += '<p><a href="http://www.smogon.com/forums/showthread.php?p=3948327#post3948327">Request a beta account</a></p>';
|
|
if (data.error) {
|
|
contents += '<p class="error">' + data.error + '</p>';
|
|
} else if (data.reason) {
|
|
contents += '<p>' + data.reason + '</p>';
|
|
} else {}
|
|
contents += '<p><label class="label">Username:</label> <input class="textbox" type="text" id="overlay_username" value="' + sanitize(data.name || '') + '" /></p>';
|
|
contents += '<p><label class="label">Password:</label> <input class="textbox" type="password" id="overlay_password" /></p>';
|
|
contents += '<p><button type="submit"><strong>Log in</strong></button> <button onclick="overlayClose();return false">Cancel</button></p>';
|
|
selectElem = '#overlay_username';
|
|
break;
|
|
case 'down':
|
|
contents += '<p style="font-size:14pt"><strong>Pokemon Showdown is under heavy load.<br />:(</strong></p>';
|
|
contents += '<p>Bear with us as we freak out.</p>';
|
|
// contents += '<p><a href="http://www.smogon.com/forums/showthread.php?p=4319109#post4319109">We\'re currently on a backup server, and it\'s full.</a></p>';
|
|
contents += '<p>(Alternatively, reload this page in an hour or two; it should be back up by then.)</p>';
|
|
// contents += '<p><strong>We WILL fix these performance issues ASAP.</strong></p>';
|
|
// contents += '<p>Please try back in an hour or so; the server will open and close intermittently until we sort out the remaining performance issues.</p>';
|
|
// contents += '<p style="font-size:14pt"><strong>Pokemon Showdown is confirmed to be under a DDoS attack. :(</strong></p>';
|
|
// contents += '<p>Bear with us as we freak out.</p>';
|
|
// contents += '<p><a href="http://www.smogon.com/forums/showthread.php?t=3469851">There\'s slightly more information in this Smogon thread.</a></p>';
|
|
// contents += '<p>Please try back later today.</p>';
|
|
break;
|
|
case 'unsupported':
|
|
contents += '<p><strong>You have an old version of your browser.</strong></p>';
|
|
contents += '<p>Please upgrade to one of:</p>';
|
|
contents += '<p>Internet Explorer 9+, Firefox 4+, Chrome 11+, Safari 4+</p>';
|
|
break;
|
|
case 'rename':
|
|
if (!data) data = {};
|
|
if (data.error) {
|
|
contents += '<p class="error">' + data.error + '</p>';
|
|
if (data.error.indexOf(' forced you to change ') >= 0) {
|
|
contents += '<p>Keep in mind these rules:</p>';
|
|
contents += '<ol>';
|
|
contents += '<li>Usernames may not be derogatory or insulting in nature, to an individual or group (insulting yourself is okay as long as it\'s not too serious).</li>';
|
|
contents += '<li>Usernames may not reference sexual activity, directly or indirectly.</li>';
|
|
contents += '<li>Usernames may not impersonate a recognized user (a user with %, @, &, or ~ next to their name).</li>';
|
|
contents += '</ol>';
|
|
}
|
|
}
|
|
contents += '<p><label class="label">Username:</label> <input class="textbox" type="text" id="overlay_name" value="' + (me.named ? sanitize(me.name) : '') + '" /></p>';
|
|
contents += '<p><button type="submit"><strong>Choose name</strong></button> <button onclick="overlayClose();return false">Cancel</button></p>';
|
|
selectElem = '#overlay_name';
|
|
break;
|
|
case 'forfeit':
|
|
contents += '<p>Are you sure you want to forfeit? <input type="hidden" id="overlay_room" value="' + data + '" /></p>';
|
|
contents += '<p><button type="submit"><strong>Forfeit</strong></button> <button onclick="overlayClose();return false" id="overlay_cancel">Cancel</button></p>';
|
|
selectElem = '#overlay_cancel';
|
|
break;
|
|
case 'disconnect':
|
|
if (rooms.teambuilder && rooms.teambuilder.formSave) {
|
|
rooms.teambuilder.formSave();
|
|
}
|
|
contents += '<p>You have been disconnected - possibly because the server was restarted.</p>'
|
|
contents += '<p><button onclick="document.location.reload();return false" id="overlay_refresh"><strong>Reconnect</strong></button> <button onclick="overlayClose();return false">Cancel</button></p>';
|
|
focusElem = '#overlay_refresh';
|
|
}
|
|
$('#overlay').html('<form id="messagebox" onsubmit="overlaySubmit(event, \'' + overlayType + '\'); return false">' + contents + '</form>');
|
|
$('#overlay').show();
|
|
if (selectElem) $(selectElem).select();
|
|
else if (focusElem) $(focusElem).focus();
|
|
};
|
|
|
|
function overlayClose() {
|
|
$('#overlay').html('');
|
|
$('#overlay').hide();
|
|
};
|
|
|
|
function renameMe(name) {
|
|
if (me.userid !== toId(name)) {
|
|
var query = actionphp + '?act=getassertion&userid=' + toId(name) +
|
|
'&challengekeyid=' + me.challengekeyid +
|
|
'&challenge=' + me.challenge;
|
|
if (Config.testclient) {
|
|
overlay('testclientgetassertion', { name: name, query: query });
|
|
return;
|
|
}
|
|
if (name === '') {
|
|
return;
|
|
}
|
|
$.get(query, function(data) {
|
|
if (data === ';') {
|
|
overlay('login', {name: name});
|
|
} else if (data.substr(0, 2) === ';;') {
|
|
overlay('rename', {error: data.substr(2)});
|
|
} else if (data.indexOf('\n') >= 0) {
|
|
alert("The login server is overloaded. Please try again later.");
|
|
} else {
|
|
rooms.lobby.send('/trn '+name+',0,'+data);
|
|
}
|
|
});
|
|
} else {
|
|
rooms.lobby.send('/trn '+name);
|
|
}
|
|
}
|
|
function overlaySubmit(e, overlayType) {
|
|
switch (overlayType) {
|
|
case 'rename':
|
|
var name = $('#overlay_name').val();
|
|
overlayClose();
|
|
renameMe(name);
|
|
break;
|
|
case 'login':
|
|
case 'betalogin':
|
|
var name = $('#overlay_username').val();
|
|
$.post(actionphp, {
|
|
act: 'login',
|
|
name: name,
|
|
pass: $('#overlay_password').val(),
|
|
challengekeyid: me.challengekeyid,
|
|
challenge: me.challenge
|
|
}, Tools.safeJson(function (data) {
|
|
if (!data) data = {};
|
|
if (data.sid !== undefined) {
|
|
Tools.postCrossDomainMessage({sid: data.sid});
|
|
}
|
|
var token = data.assertion;
|
|
if (data.curuser && data.curuser.loggedin) {
|
|
me.registered = data.curuser;
|
|
name = data.curuser.username;
|
|
if (!socket) {
|
|
document.location.reload();
|
|
return;
|
|
}
|
|
rooms.lobby.send('/trn '+name+',0,'+token);
|
|
} else {
|
|
overlay(overlayType, {
|
|
name: name,
|
|
error: 'Wrong password.'
|
|
});
|
|
}
|
|
}), 'text');
|
|
overlayClose();
|
|
break;
|
|
case 'testclientgetassertion':
|
|
var assertion = $('#overlay_assertion').val();
|
|
var query = $('#overlay_iframe').attr('src');
|
|
var name = $('#overlay_username').val();
|
|
overlayClose();
|
|
if (!assertion.split(';')[1]) {
|
|
// The user only selected part of the textbox.
|
|
overlay('testclientgetassertion', {
|
|
name: name,
|
|
query: query,
|
|
error: 'You didn\'t select all the text last time. Try again.' });
|
|
} else {
|
|
if (name === '') {
|
|
// Get the userid from the assertion (assume challenge-response).
|
|
name = assertion.split(',')[1];
|
|
}
|
|
rooms.lobby.send('/trn ' + name + ',0,' + assertion);
|
|
}
|
|
break;
|
|
case 'register':
|
|
var name = $('#overlay_username').val();
|
|
var captcha = $('#overlay_captcha').val();
|
|
$.post(actionphp, {
|
|
act: 'register',
|
|
username: name,
|
|
password: $('#overlay_password').val(),
|
|
cpassword: $('#overlay_cpassword').val(),
|
|
captcha: captcha,
|
|
challengekeyid: me.challengekeyid,
|
|
challenge: me.challenge
|
|
}, Tools.safeJson(function (data) {
|
|
if (!data) data = {};
|
|
if (data.sid !== undefined) {
|
|
Tools.postCrossDomainMessage({sid: data.sid});
|
|
}
|
|
var token = data.assertion;
|
|
if (data.curuser && data.curuser.loggedin) {
|
|
me.registered = data.curuser;
|
|
name = data.curuser.username;
|
|
if (!socket) {
|
|
document.location.reload();
|
|
return;
|
|
}
|
|
rooms.lobby.send('/trn '+name+',1,'+token);
|
|
overlay('message', "You have been successfully registered.");
|
|
} else {
|
|
overlay('register', {
|
|
ifuserid: me.userid,
|
|
name: name,
|
|
captcha: captcha,
|
|
error: data.actionerror
|
|
});
|
|
}
|
|
}), 'text').error(function (e) {
|
|
alert('error: ' + e);
|
|
});
|
|
overlayClose();
|
|
break;
|
|
case 'forfeit':
|
|
var room = rooms[$('#overlay_room').val()];
|
|
if (room) {
|
|
room.formForfeit();
|
|
leaveTab(room.id, true);
|
|
}
|
|
overlayClose();
|
|
break;
|
|
}
|
|
}
|
|
|
|
function init() {
|
|
addTab('teambuilder', 'teambuilder');
|
|
addTab('ladder', 'ladder');
|
|
|
|
if (socketInit) socketInit();
|
|
|
|
initialized = true;
|
|
}
|
|
|
|
var cookieTeams = true;
|
|
teams = (function() {
|
|
var savedTeam = $.parseJSON($.cookie('showdown_team1'));
|
|
var teams = [];
|
|
if (savedTeam) {
|
|
teams.push(savedTeam);
|
|
}
|
|
savedTeam = $.parseJSON($.cookie('showdown_team2'));
|
|
if (savedTeam) {
|
|
teams.push(savedTeam);
|
|
}
|
|
savedTeam = $.parseJSON($.cookie('showdown_team3'));
|
|
if (savedTeam) {
|
|
teams.push(savedTeam);
|
|
}
|
|
if (window.localStorage) {
|
|
cookieTeams = false;
|
|
var teamString = localStorage.getItem('showdown_teams');
|
|
if (teamString) teams = JSON.parse(teamString);
|
|
}
|
|
return teams;
|
|
})();
|
|
|
|
// time to connect
|
|
(function() {
|
|
var connect = function(data, name) {
|
|
if (Config.down) return;
|
|
|
|
if (!data) data = {};
|
|
var token = data.assertion || '';
|
|
|
|
if (data.curuser && data.curuser.loggedin) {
|
|
me.registered = data.curuser;
|
|
name = data.curuser.username;
|
|
} else if (Config.oldie) {
|
|
overlay('unsupported');
|
|
return;
|
|
} else if (Config.requirelogin) {
|
|
document.getElementById('loading-message').innerHTML = '';
|
|
overlay('betalogin');
|
|
return;
|
|
}
|
|
|
|
var constructSocket = function(host, port) {
|
|
if (Config.serverprotocol === 'io') return io.connect('http://' + host + ':' + port);
|
|
else if (Config.serverprotocol === 'eio') return new eio.Socket({ host: host, port: port });
|
|
else return new SockJS('http://' + host + ':' + port);
|
|
};
|
|
|
|
socket = constructSocket(Config.server, Config.serverport);
|
|
|
|
var events = {
|
|
init: function (data) {
|
|
if (data.name) {
|
|
me.name = data.name;
|
|
me.named = data.named;
|
|
me.userid = data.userid;
|
|
me.renamePending = !! data.renamePending;
|
|
if (data.token) me.token = data.token;
|
|
}
|
|
if (data.notFound) {
|
|
selectTab('lobby');
|
|
return;
|
|
}
|
|
var tempInitialize = function () {
|
|
addTab(data.room, data.roomType);
|
|
var room = rooms[data.room];
|
|
room.init(data);
|
|
updateMe(data);
|
|
$('#loading-message').remove();
|
|
if (loc && loc !== 'lobby') {
|
|
selectTab(loc);
|
|
}
|
|
};
|
|
if (!initialized) {
|
|
socketInit = tempInitialize;
|
|
} else {
|
|
tempInitialize();
|
|
}
|
|
},
|
|
update: function (data) {
|
|
if (typeof data.name !== 'undefined') {
|
|
me.name = data.name;
|
|
me.named = data.named;
|
|
me.userid = data.userid;
|
|
me.renamePending = !! data.renamePending;
|
|
if (data.token) me.token = data.token;
|
|
}
|
|
if (typeof data.challengesFrom !== 'undefined') {
|
|
me.challengesFrom = data.challengesFrom;
|
|
rooms.lobby.notifying = false;
|
|
for (var i in me.challengesFrom) {
|
|
rooms.lobby.notifying = true;
|
|
break;
|
|
}
|
|
updateRoomList();
|
|
rooms.lobby.updateMainTop();
|
|
}
|
|
if (typeof data.challengeTo !== 'undefined') {
|
|
me.challengeTo = data.challengeTo;
|
|
rooms.lobby.updateMainTop();
|
|
}
|
|
updateMe(data);
|
|
if (data.room && rooms[data.room]) {
|
|
rooms[data.room].update(data);
|
|
} else if (curRoom) {
|
|
//curRoom.update(data);
|
|
}
|
|
},
|
|
disconnect: function () {
|
|
$('#userbar').prepend('<strong style="color:#BB0000;border:1px solid #BB0000;padding:0px 2px;font-size:10pt;">disconnect detected</strong> ');
|
|
overlay('disconnect');
|
|
},
|
|
nameTaken: function (data) {
|
|
if (data && data.permanent) {
|
|
overlay('message', data.reason);
|
|
} else if (data && data.name) {
|
|
overlay('login', data);
|
|
} else if (data) {
|
|
overlay('rename', {
|
|
error: data.reason
|
|
});
|
|
} else {
|
|
alert('nameTaken signal');
|
|
$('#userbar').prepend('<strong style="color:#BB0000;border:1px solid #BB0000;padding:0px 2px;font-size:10pt;">nameTaken signal</strong> ');
|
|
}
|
|
},
|
|
message: function (message) {
|
|
if (message.html) {
|
|
overlay('message', message.html);
|
|
return;
|
|
}
|
|
if (message.message) message = message.message;
|
|
overlay('message', '<div style="white-space:pre-wrap">' + message + '</div>');
|
|
},
|
|
command: function (message) {
|
|
if (message.room && rooms[message.room]) {
|
|
rooms[message.room].command(message);
|
|
}
|
|
},
|
|
console: function (message) {
|
|
var room = null;
|
|
if (message.room && rooms[message.room]) {
|
|
room = rooms[message.room];
|
|
if (room) room.add(message);
|
|
//if (room.id === 'lobby' && message.silent) room.updateMainTop();
|
|
} else {
|
|
if (curRoom) curRoom.message(message, true);
|
|
}
|
|
}
|
|
};
|
|
|
|
function parseSpecialData(text) {
|
|
var parts = text.split('|');
|
|
if (parts.length < 2) return false;
|
|
|
|
switch (parts[1]) {
|
|
case 'challenge-string':
|
|
case 'challstr':
|
|
me.challengekeyid = parseInt(parts[2], 10);
|
|
me.challenge = parts[3];
|
|
if (rooms.lobby !== undefined) {
|
|
renameMe(name);
|
|
} else {
|
|
me.renameQueued = name;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (Config.serverprotocol === 'io') {
|
|
for (var e in events) {
|
|
socket.on(e, (function(type) {
|
|
return function(data) {
|
|
events[type](data);
|
|
};
|
|
})(e));
|
|
}
|
|
socket.on('data', function(text) {
|
|
var roomid = 'lobby';
|
|
if (text.substr(0,1) === '>') {
|
|
var nlIndex = text.indexOf('\n');
|
|
if (nlIndex < 0) return;
|
|
roomid = text.substr(1,nlIndex-1);
|
|
text = text.substr(nlIndex+1);
|
|
}
|
|
if (!parseSpecialData(text) && (rooms[roomid] !== undefined)) {
|
|
rooms[roomid].add(text);
|
|
}
|
|
});
|
|
if (!name) token = '';
|
|
document.getElementById('loading-message').innerHTML += ' DONE<br />Connecting to Showdown server...';
|
|
emit(socket, 'join', {
|
|
name: name,
|
|
room: 'lobby',
|
|
token: token
|
|
});
|
|
} else {
|
|
var socketopened = false;
|
|
var altport = (Config.serverport === Config.serveraltport);
|
|
document.getElementById('loading-message').innerHTML += ' DONE<br />Connecting to Showdown server...';
|
|
socket.onopen = function() {
|
|
socketopened = true;
|
|
if (altport) {
|
|
_gaq.push(['_trackEvent', 'Alt port connection', Config.serverid]);
|
|
}
|
|
if (!name) token = '';
|
|
document.getElementById('loading-message').innerHTML += ' DONE<br />Joining Showdown server...';
|
|
emit(socket, 'join', {
|
|
name: name,
|
|
room: 'lobby',
|
|
token: token
|
|
});
|
|
};
|
|
socket.onmessage = function(msg) {
|
|
if (msg.data.substr(0,1) !== '{') {
|
|
var text = msg.data;
|
|
var roomid = 'lobby';
|
|
if (text.substr(0,1) === '>') {
|
|
var nlIndex = text.indexOf('\n');
|
|
if (nlIndex < 0) return;
|
|
roomid = text.substr(1,nlIndex-1);
|
|
text = text.substr(nlIndex+1);
|
|
}
|
|
if (!parseSpecialData(text) && (rooms[roomid] !== undefined)) {
|
|
rooms[roomid].add(text);
|
|
}
|
|
return;
|
|
}
|
|
var data = $.parseJSON(msg.data);
|
|
if (!data) return;
|
|
if (events[data.type]) events[data.type](data);
|
|
};
|
|
socket.onclose = function () {
|
|
if (!socketopened && Config.serveraltport && !altport) {
|
|
altport = true;
|
|
Config.serverport = Config.serveraltport;
|
|
socket = (function() {
|
|
var s = constructSocket(Config.server, Config.serverport);
|
|
s.onopen = socket.onopen;
|
|
s.onmessage = socket.onmessage;
|
|
s.onclose = socket.onclose;
|
|
return s;
|
|
})();
|
|
return;
|
|
}
|
|
$('#userbar').prepend('<strong style="color:#BB0000;border:1px solid #BB0000;padding:0px 2px;font-size:10pt;">disconnect detected</strong> ');
|
|
overlay('disconnect');
|
|
};
|
|
}
|
|
};
|
|
if ((Config.crossdomain === undefined) || (window.postMessage === undefined)) {
|
|
connect(Config.upkeep, $.cookie('showdown_username') || '');
|
|
} else {
|
|
var origin = 'http://play.pokemonshowdown.com';
|
|
$(window).on('message', function($e) {
|
|
var e = $e.originalEvent;
|
|
if (e.origin !== origin) return;
|
|
Tools.postCrossDomainMessage = function(data) {
|
|
return e.source.postMessage(data, origin);
|
|
};
|
|
// sid
|
|
$.cookie('sid', e.data.sid);
|
|
// teams
|
|
if (e.data.teams) {
|
|
cookieTeams = false;
|
|
teams = $.parseJSON(e.data.teams);
|
|
}
|
|
Teambuilder.writeTeams = function() {
|
|
Tools.postCrossDomainMessage({teams: $.toJSON(teams)});
|
|
};
|
|
if (rooms.teambuilder) {
|
|
rooms.teambuilder.init();
|
|
}
|
|
// prefs
|
|
if (e.data.prefs) {
|
|
Tools.prefs.data = $.parseJSON(e.data.prefs);
|
|
}
|
|
Tools.prefs.save = function() {
|
|
Tools.postCrossDomainMessage({prefs: $.toJSON(this.data)});
|
|
};
|
|
// connect
|
|
connect(e.data.upkeep, e.data.username);
|
|
});
|
|
var $iframe = $(
|
|
'<iframe src="//play.pokemonshowdown.com/crossdomain.php?prefix=' +
|
|
encodeURIComponent(Config.crossdomain.prefix) +
|
|
'&challengeresponse=' +
|
|
encodeURIComponent(Config.crossdomain.challengeresponse) +
|
|
'&server=' +
|
|
encodeURIComponent(Config.server) +
|
|
'" style="display: none;"></iframe>'
|
|
);
|
|
$('body').append($iframe);
|
|
}
|
|
})();
|