// redirect Brazilians to the international server //if ((document.referrer.match(/\.br\//) || document.referrer.match(/\.br$/)) && document.location.pathname.substr(0, 7) !== '/~~intl') { // document.location.href = '/~~intl/'; //} // 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 = '/'; var servertoken = Config.server; if (Config.urlPrefix) locPrefix += Config.urlPrefix; // initialize sockets var socket = null; var me = { name: '', named: false, registered: false, userid: '', token: '', users: {}, rooms: {}, ignore: {}, mute: $.cookie('showdown_mute'), lastChallengeNotification: '', pm: {}, curPopup: '', popups: [] }; var prefs = {}; var rooms = {}; var curRoom = null; var curTitle = 'Showdown!'; var battles = {}; var formats = ['']; var teams = []; 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 (!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 === '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('
'); elem = $('#main').children().last(); rooms[tab] = new Lobby(tab, elem); break; case 'teambuilder': $('#main').append('
'); elem = $('#main').children().last(); rooms[tab] = new Teambuilder(tab, elem); break; case 'ladder': $('#main').append('
'); elem = $('#main').children().last(); rooms[tab] = new Ladder(tab, elem); break; case 'battle': $('#main').append('
'); elem = $('#main').children().last(); rooms[tab] = new BattleRoom(tab, elem); break; default: $('#main').append('
error
'); 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('
Battle is here
Connecting...
'); 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('
'); if (selfR.me.side) { selfR.controlsElem.html('
'); } if (selfR.joinElem) { selfR.joinElem.remove(); } //selfR.battleElem.append('
'); //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('

← Your opponent has disconnected. Click this to delay your victory.

'); } else { selfR.controlsElem.html('

← Your opponent has disconnected. Click this if they don\'t reconnect.

'); } } else { if (selfR.joinElem) { selfR.joinElem.remove(); } selfR.battleElem.append('
'); 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('|chatmsg-raw|' + '
' + sanitize(message.name.substr(1)) + ': (Private to ' + sanitize(message.pm) + ') ' + messageSanitize(message.message) + ''); } else if (message.rawMessage) { selfR.add('|chatmsg-raw|' + message.rawMessage); } else if (message.evalRawMessage) { selfR.add('|chatmsg-raw|' + eval(message.evalRawMessage)); } 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 + '

NEW GAME

'); 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; if (selfR.version === 1) { // We maintain this for now, in case a server updated during // the brief period where this was the design. However, this // can probably be removed in a few weeks, if desired. selfR.send('/ackrequest ' + selfR.me.request.rqid); } selfR.me.request.requestType = 'move'; if (selfR.me.request.forceSwitch) { selfR.me.request.requestType = 'switch'; notify({ type: 'yourSwitch', room: selfR.id, user: selfR.battle.yourSide.name }); selfR.notifying = true; updateRoomList(); } else if (selfR.me.request.teamPreview) { selfR.me.request.requestType = 'team'; notify({ type: 'yourSwitch', room: selfR.id, user: selfR.battle.yourSide.name }); selfR.notifying = true; updateRoomList(); } else if (selfR.me.request.wait) { selfR.me.request.requestType = 'wait'; } else { notify({ type: 'yourMove', room: selfR.id, user: selfR.battle.yourSide.name }); selfR.notifying = true; updateRoomList(); } //if (selfR.me.callbackWaiting) selfR.callback(); } if (typeof update.active !== 'undefined') { if (!update.active && selfR.me.side) { selfR.controlsElem.html('
'); } } 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('
'); 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('
'); } 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 += '
'; } if (yourActive[0]) { text += '
'; } if (myActive[0]) { text += '
'; } if (myActive[1]) { text += '
'; } selfR.foeHintElem.html(text); if (!selfR.me.request) { selfR.controlsElem.html('
Waiting for players...
'); 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('
Waiting for opponent...
'); } else { selfR.controlsElem.html('
Waiting for opponent...
'); } 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 = ''; } else if (switchables[pos].hp * 2 / switchables[pos].maxhp < 1) { hpbar = ''; } else { hpbar = ''; } hpbar += ''+switchables[pos].hp+'/'+switchables[pos].maxhp+''; } var active = selfR.me.request; if (active.active) active = active.active[pos]; var moves = active.moves; var trapped = active.trapped; var controls = '
'; if (type === 'move2' || type === 'movetarget') { controls += ' '; } // Target selector if (type === 'movetarget') { controls += 'At who? '+hpbar+'
'; controls += '
'; 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 += ' '; } else if (disabled || pokemon.zerohp) { controls += ' '; } else { controls += ' '; } } controls += '
'; 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 += ' '; } else if (disabled || pokemon.zerohp) { controls += ' '; } else { controls += ' '; } } controls += '
'; controls += '
'; selfR.controlsElem.html(controls); break; } // Move chooser controls += 'What will ' + sanitize(switchables[pos].name) + ' do? '+hpbar+'
'; var hasMoves = false; var hasDisabled = false; controls += '
'; 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 += ' '; } if (!hasMoves) { controls += ' '; } else { controls += movebuttons; } controls += '
'; if (hasDisabled) { // controls += '(grayed out moves have been disabled by Disable, Encore, or something like that)'; } controls += '
'; if (trapped) { controls += 'You are trapped and cannot switch!'; } 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 += ' '; } else { controls += ' '; } } if (selfR.battle.mySide.pokemon.length > 6) { //controls += 'Pokeball data corrupt. Please copy the text from this button: and tell aesoft.'; } } controls += '
'; 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 = '
'; if (type === 'switch2') { controls += ' '; } controls += 'Switch '+sanitize(switchables[pos].name)+' to:
'; controls += '
'; for (var i = 0; i < switchables.length; i++) { var pokemon = switchables[i]; if (i >= 6) { //controls += 'Pokeball data corrupt. Please copy the text from this button: and tell aesoft.'; break; } if (pokemon.zerohp || i < selfR.battle.mySide.active.length || selfR.choiceSwitchFlags[i]) { controls += ' '; } else { controls += ' '; } } controls += '
'; selfR.controlsElem.html(controls); selfR.formSelectSwitch(); selfR.notifying = true; break; case 'team': var controls = '
'; 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?
'; controls += '
'; 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 += ' '; } if (selfR.battle.teamPreviewCount) selfR.teamPreviewCount = parseInt(selfR.battle.teamPreviewCount,10); controls += '
'; } else { controls += ' What about the rest of your team?
'; controls += '
'; for (var i = 0; i < switchables.length; i++) { var pokemon = switchables[selfR.teamPreviewChoice[i]-1]; if (i >= 6) { break; } if (i < selfR.teamPreviewDone) { controls += ' '; } else { controls += ' '; } } controls += '
'; } controls += '
'; 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('
Waiting for opponent...

'); } else { selfR.controlsElem.html('
Waiting for opponent...

'); } 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('
Waiting for opponent...

'); } else { selfR.controlsElem.html('
Waiting for opponent...

'); } 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('
Waiting for opponent...

'); } else { selfR.controlsElem.html('
Waiting for opponent...

'); } 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(); 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 }; this.searcher = null; this.selectedTeam = 0; this.selectedFormat = ''; elem.html('
'); $('#lobbychat').html('
Connecting...
'); 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.updateMainElem(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())) { text = selfR.parseCommand(text); if (text) { var splitText = text.split('\n'); for (var i=0, len=splitText.length; i 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'); prefs.showjoins = true; return false; case 'hidejoins': rooms.lobby.add('Join/leave messages: HIDDEN'); prefs.showjoins = false; return false; case 'showbattles': rooms.lobby.add('Battle messages: ON'); prefs.showbattles = true; return false; case 'hidebattles': rooms.lobby.add('Battle messages: HIDDEN'); prefs.showbattles = false; return false; case 'rank': case 'ranking': case 'rating': case 'ladder': if (!target) target = me.userid; var self = this; $.get('/action.php?act=ladderget&serverid='+Config.serverid+'&user='+target, function(data) { try { var buffer = '
'; buffer += ''; if (!data.length) { buffer += ''; } else { buffer += ''; for (var i=0; i'; } } buffer += '
User: '+target+'
This user has not played any ladder games yet.
FormatACREGXEGlicko2WLT
'+Math.round(row.acre)+''+Math.round(row.gxe,1)+''; if (row.rprd > 50) { buffer += ''+Math.round(row.rpr)+' ± '+Math.round(row.rprd)+' (provisional)'; } else { buffer += ''+Math.round(row.rpr)+' ± '+Math.round(row.rprd)+''; } buffer += ''+row.w+''+row.l+''+row.t+'
'; self.rawMessage(buffer); } catch(e) { } }, 'json'); 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; } 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 = '
'; 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 += '

' + name + '

'; } if (me.curPopup === me.popups[i]) { $('#' + selfR.id + '-pmlog-list').html(popupListCode); } me.curPopup = me.popups[i]; code += popupListCode; code += '
'; var clickableName = '' + sanitize(me.users[me.curPopup] || me.curPopup) + ''; code += '

' + clickableName + '

'; code += '
' + (me.pm[me.curPopup] || '') + '
'; if (!selfR.popupElem.children('.battle-log-add').length) { code += '
'; 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.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') }; updateMe(); break; case 'l': case 'L': log[i] = { action: 'leave', name: row[1], silent: (row[0] === 'L') }; updateMe(); break; case 'n': case 'N': log[i] = { action: 'rename', name: row[1], oldid: row[2], silent: true }; updateMe(); break; case 'raw': log[i] = { rawMessage: row.slice(1).join('|') }; break; case 'formats': var isSection = false; var section = ''; BattleFormats = {}; for (var j=1; j' + sanitize(log[i].name.substr(1)) + ''; var message = log[i].message; if (log[i].name.substr(0, 1) !== ' ') clickableName = '' + sanitize(log[i].name.substr(0, 1)) + ''+clickableName; if (log[i].pm) { var pmuserid = (userid === me.userid ? toUserid(log[i].pm) : userid); if (!me.pm[pmuserid]) me.pm[pmuserid] = ''; var pmcode = '
' + clickableName + ': ' + messageSanitize(message) + '
'; for (var j = 0; j < me.popups.length; j++) { if (pmuserid === me.popups[j]) break; } if (j == me.popups.length) me.popups.unshift(pmuserid); me.pm[pmuserid] += pmcode; if (me.popups.length && me.popups[me.popups.length - 1] === pmuserid) { selfR.updatePopup(pmcode); } else { selfR.updatePopup(); } selfR.chatElem.append('
' + clickableName + ': (Private to ' + sanitize(log[i].pm) + ') ' + messageSanitize(message) + '
'); //} else if (log[i].act) { // selfR.chatElem.append('
' + clickableName + ' ' + message + '
'); } else if (message.substr(0,2) === '//') { selfR.chatElem.append('
' + clickableName + ': ' + messageSanitize(message.substr(1)) + '
'); } else if (message.substr(0,4).toLowerCase() === '/me ') { selfR.chatElem.append('
' + clickableName + ' ' + messageSanitize(message.substr(4)) + '
'); } else if (message.substr(0,5).toLowerCase() === '/mee ') { selfR.chatElem.append('
' + clickableName + '' + messageSanitize(message.substr(5)) + '
'); } else if (message.substr(0,10).toLowerCase() === '/announce ') { selfR.chatElem.append('
' + clickableName + ': ' + messageSanitize(message.substr(10)) + '
'); } else if (message.substr(0,14).toLowerCase() === '/data-pokemon ') { selfR.chatElem.append('
    '+Chart.pokemonRow(Tools.getTemplate(message.substr(14)),'',{})+'
'); } else if (message.substr(0,11).toLowerCase() === '/data-item ') { selfR.chatElem.append('
    '+Chart.itemRow(Tools.getItem(message.substr(11)),'',{})+'
'); } else if (message.substr(0,14).toLowerCase() === '/data-ability ') { selfR.chatElem.append('
    '+Chart.abilityRow(Tools.getAbility(message.substr(14)),'',{})+'
'); } else if (message.substr(0,11).toLowerCase() === '/data-move ') { selfR.chatElem.append('
    '+Chart.moveRow(Tools.getMove(message.substr(11)),'',{})+'
'); } else { selfR.chatElem.append('
' + clickableName + ': ' + messageSanitize(message) + '
'); } } 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(); if (log[i].silent && !prefs.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(''); } else if (log[i].message) { selfR.chatElem.append('
' + sanitize(log[i].message) + '
'); } else if (log[i].rawMessage) { selfR.chatElem.append('
' + log[i].rawMessage + '
'); } else if (log[i].evalRawMessage) { selfR.chatElem.append('
' + eval(log[i].evalRawMessage) + '
'); } 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; } else if (log[i].action === 'leave') { if (me.users[userid]) selfR.userCount.users--; delete me.users[userid]; } else if (log[i].action === 'rename') { if (log[i].oldid) delete me.users[toUserid(log[i].oldid)]; me.users[toUserid(log[i].name)] = log[i].name; continue; } if (log[i].silent && !prefs.showjoins) continue; if (!selfR.joinLeaveElem) { selfR.chatElem.append('
Loading...
'); 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
'; } selfR.joinLeaveElem.html('' + message + ''); } } if (autoscroll) { selfR.chatFrameElem.scrollTop(selfR.chatElem.height()); } var $children = selfR.chatElem.children(); if ($children.length > 900) { $children.slice(0,100).remove(); } }; this.init = function (data) { if (data.log) { selfR.chatElem.html(''); if (!me.registered || me.registered.group !== '2') { if (data.log.length > 100) { data.log = data.log.splice(data.log.length - 100); } } selfR.add(data.log); } selfR.update(data); selfR.chatFrameElem.scrollTop(selfR.chatElem.height()); selfR.updateMe(); }; 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.users !== 'undefined') { selfR.userList = data.users; selfR.userCount.users = 'who knows'; me.users = data.users.list; } if (typeof data.u !== 'undefined') { selfR.userCount = {}; selfR.userList = {}; 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[' + matches[1] + ']

' : ''); var roomDesc = format + '' + sanitize(roomData.p1) + ' vs. ' + sanitize(roomData.p2) + ''; if (!roomData.p1) { matches = id.match(/[^0-9]([0-9]*)$/); roomDesc = format + 'empty room ' + matches[1]; } else if (!roomData.p2) { roomDesc = format + '' + sanitize(roomData.p1) + ''; } roomListCode += '
' + roomDesc + '
'; } var code = ''; if (roomListCode) { roomListCode = '
In rooms:
' + roomListCode + '
'; } if (data.ip) { // Mute and Ban buttons for auths var banMuteBuffer = ''; // var isAuth = me.users[me.userid].substr(0,1) in {'%':1, '@':1, '&':1, '~':1}; if (me.users[userid].substr(0,1) === '!') { banMuteBuffer += '
'; } else { banMuteBuffer += '
'; } banMuteBuffer += ' '; banMuteBuffer += ' '; roomListCode = '
IP: ' + data.ip + ''+banMuteBuffer+'
' + 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 ? '[' + matches[1] + ']
' : ''); var roomDesc = format + '' + sanitize(roomData.p1) + ' vs. ' + sanitize(roomData.p2) + ''; if (!roomData.p1) { matches = id.match(/[^0-9]([0-9]*)$/); roomDesc = format + 'empty room ' + matches[1]; } else if (!roomData.p2) { roomDesc = format + '' + sanitize(roomData.p1) + ''; } roomListCode += '
' + roomDesc + '
'; i++; } if (!roomListCode) { roomListCode = 'No battles are going on right now.'; } $('#' + selfR.id + '-roomlist').html('
(' + i + ' battle' + (i == 1 ? '' : 's') + ')
' + roomListCode + '
'); } else if (data.command === 'savereplay') { var id = data.id; $.post('/action.php?act=uploadreplay', { log: data.log, id: data.id, sid: $.cookie('sid') }, 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 = '
'; text += 'Challenge from: ' + (me.users[challenge.from] || challenge.from) + '
' + sanitize(challenge.format) + '
'; text += '' + selfR.getTeamSelect(challenge.format) + '
'; text += '
'; } else if (me.userForm) { var userid = toUserid(me.userForm); var name = (me.users[userid] || me.userForm); var groupDetails = { '~': "Administrator (~)", '&': "Leader (&)", '@': "Moderator (@)", '%': "Driver (%)", '+': "Voiced (+)", '!': "Muted (!)" }; 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 = '
Loading...
'; selfR.send('/cmd roomlist'); } else { text = '
'; text += '' + sanitize(name) + '
'; text += '' + (group || '') + '
'; text += '
'; if (userid === me.userid) { text += '
'; } else { text += ' '; text += ''; } text += '
'; 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 = '
Challenging: ' + (me.users[me.challengeTo.to] || me.challengeTo.to) + '
Format: ' + me.challengeTo.format + '
Team: ' + teamname + '
'; } else if (selfR.me.searching) { if (selfR.mainTopState === 'searching') return; selfR.mainTopState = 'searching'; text = '
Format: ' + selfR.me.searching.format + '
Searching...
'; } else { var roomListCode = ''; for (var i=selfR.rooms.length-1; i>=0; i--) { var roomData = selfR.rooms[i]; if (!roomListCode) roomListCode += '

Watch battles

'; var roomDesc = '[' + Tools.getEffect(roomData.format).name + ']
' + sanitize(roomData.p1) + ' vs. ' + sanitize(roomData.p2) + ''; roomListCode += '
' + roomDesc + '
'; } if (roomListCode) roomListCode += ''; var searcherText = ''; if (selfR.searcher) { searcherText = 'There ' + (selfR.searcher === 1 ? 'is' : 'are') + ' ' + selfR.searcher + ' other ' + (selfR.searcher === 1 ? 'person' : 'people') + ' searching.'; } 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 = '
'; text += '' + selfR.getFormatSelect('search') + '
'; text += '' + selfR.getTeamSelect(selfR.selectedFormat) + '
'; if (selfR.goDisabled) { text += '
'; } else { text += '
'; } text += '' + searcherText + '
'; text += '
' + roomListCode + '
'; } selfR.mainTopElem.html(text); if (!challenge) { me.lastChallengeNotification = ''; } }; this.debounceUpdateTimeout = null; this.debounceUpdateQueued = false; this.debounceUpdate = function() { if (!selfR.debounceUpdateTimeout) { selfR.updateMainElem(); selfR.debounceUpdateQueued = false; selfR.debounceUpdateTimeout = setTimeout(selfR.debounceUpdateEnd, 600); } else { selfR.debounceUpdateQueued = true; } }; this.debounceUpdateEnd = function() { if (selfR.debounceUpdateQueued) { selfR.updateMainElem(); } selfR.debounceUpdateTimeout = null; }; this.updateMainElem = function (force) { selfR.updateMainTop(force); var text = ''; text += ''; selfR.mainBottomElem.html(text); }; this.updateMe = function () { if (selfR.meIdent.name !== me.name || selfR.meIdent.named !== me.named) { if (me.named) { selfR.chatAddElem.html('
'); 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('
'); } 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())) { text = selfR.parseCommand(text); if (text) { selfR.send(text); } selfR.chatboxElem.val(''); } return false; } return true; }; this.formKeyDown = function (e) { hideTooltip(); // We only handle the tab key. // If shift is held down, then don't tab complete, and instead navigate // away from the chatbox. if ((e.keyCode !== 9) || e.shiftKey) 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 chatbox = $(e.delegateTarget); 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 selfR.userList) { if (!selfR.userList.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; // 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 = selfR.userList[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; }; 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.updateMainElem(); $(window).scrollTop(51); return false; }; this.getFormatSelect = function (selectType) { var text = ''; text += ' '; 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 ' Random Team'; } else { var text = ' '; 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 = ''; selectTeam($('#' + selfR.id + '-team').val()); selfR.send('/challenge '+userid+', '+format); return false; }; this.formCloseUserForm = function (userid) { if (me.userForm) { me.userForm = ''; selfR.updateMainElem(); return false; } selfR.updateMainElem(); 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 = ' '; } */ //var mutebutton = ' '; var mutebutton = ' '; if (me.named) { $('#userbar').html(notifybutton + ' ' + sanitize(me.name) + mutebutton + ' '); $.cookie('showdown_username', me.name, { expires: 14 }); } else { $('#userbar').html(notifybutton + ' ' + sanitize(me.name) + mutebutton + ' '); } $('#userbar').prepend('[Rules] [Report bug] '); if (me.token) $.cookie('showdown_token', me.token, { expires: 14 }); if (rooms.lobby) { rooms.lobby.updateMe(); rooms.lobby.debounceUpdate(); } } function formMute() { me.mute = !me.mute; $.cookie('showdown_mute', me.mute ? '1' : ''); if (curRoom.battle) { curRoom.battle.setMute(me.mute); } updateMe(); } function updateRoomList() { var code = ''; if (!curRoom) curRoom = rooms.lobby; code += '
Lobby'; code += ' Teambuilder'; code += ' Ladder
'; 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 += '
Your rooms
'; yourRooms = true; var roomDesc = id; var roomName = (id.substr(0, 7) === 'battle-' ? id.substr(7) : id); closesize = 'close2'; if (roomName) { roomDesc = '' + roomName + '(inactive)'; 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 = '' + sanitize(p1) + ' vs. ' + sanitize(p2) + ''; closesize = 'close3'; } else if (p1) { roomDesc = '' + sanitize(p1) + ' (inactive)'; rooms[id].notifying = false; closesize = 'close0'; } else if (p2) { roomDesc = '' + sanitize(p2) + ' (inactive)'; rooms[id].notifying = false; closesize = 'close0'; } else { roomDesc = '' + roomName + '(empty)'; rooms[id].notifying = false; closesize = 'close0'; } } code += '
' + roomDesc + '
'; } $('#leftbar').html(code); $('#inline-nav').html('

Your tabs

' + 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 = '
'; text += '

' + move.name + '
'+Tools.getTypeIcon(move.type)+' ' + move.category + '

'; text += '

Base power: ' + basePower + '

'; text += '

Accuracy: ' + accuracy + '

'; if (move.desc) { text += '

' + move.desc + '

'; } text += '
'; 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 = '
'; text += '

' + pokemon.getFullName() + (pokemon.level !== 100 ? ' L' + pokemon.level + '' : '') + '
'; 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 += '(Transformed into '+pokemon.volatiles.formechange[2]+')
'; } else if (pokemon.volatiles.formechange) { template = Tools.getTemplate(pokemon.volatiles.formechange[2]); types = template.types; text += '(Forme: '+pokemon.volatiles.formechange[2]+')
'; } if (pokemon.volatiles.typechange) { text += '(Type changed)
'; types = [pokemon.volatiles.typechange[2]]; } text += Tools.getTypeIcon(types[0]); if (types[1]) { text += ' '+Tools.getTypeIcon(types[1]); } text += '

'; if (!isActive) { text += '

HP: ' + Math.round(100 * pokemon.hp / pokemon.maxhp) + '% ('+pokemon.hp+'/'+pokemon.maxhp+')'+(pokemon.status?' '+pokemon.status.toUpperCase()+'':'')+'

'; } if (!pokemon.baseAbility && (!pokemon.ability || pokemon.ability.substr(0, 2) === '??')) { text += '

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 += '

'; } else if (pokemon.ability) { text += '

Ability: ' + Tools.getAbility(pokemon.ability).name + '

'; } else if (pokemon.baseAbility) { text += '

Ability: ' + Tools.getAbility(pokemon.baseAbility).name + '

'; } if (pokemon.item) { text += '

Item: ' + Tools.getItem(pokemon.item).name + '

'; } if (pokemon.moves && pokemon.moves.length && (!isActive || isActive === 'foe')) { text += '

'; for (var i = 0; i < pokemon.moves.length; i++) { var name = Tools.getMove(pokemon.moves[i]).name; text += '⋅ ' + name + '
'; } text += '

'; } text += '
'; 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 === '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; if (document.location.pathname !== locPrefix + newLoc) { history.pushState(null, null, locPrefix + newLoc); } loc = newLoc; }; window.onpopstate = function (e) { if (document.location.pathname.substr(0, locPrefix.length) === locPrefix) { loc = document.location.pathname.substr(locPrefix.length); if (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('/favicon.ico'); if (activeNotification) { activeNotification.cancel(); activeNotification = null; activeNotificationData = null; } }; notify = function (data) { if (window.focused) return; favicon.animate(['/favicon-notify.ico', '/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 '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) { var message = ''; switch (data.type) { case 'challenge': macgap.growl.notify({ title: "Challenged!", content: ""+data.user+" has challenged you to a battle!" }); 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) { favicon.animate(['/favicon-notify.ico', '/favicon-notify2.ico']); activeNotificationData = data; activeNotification = setInterval(updateNotifyTitle, 500); }; 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 '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 = '

' + data + '

'; contents += '

'; focusElem = '#overlay_ok'; break; case 'replayuploaded': contents = '

Your replay has been uploaded! It\'s available at:

'; contents += '

http://pokemonshowdown.com/replay/'+data+'

'; contents += '

'; focusElem = '#overlay_ok'; break; case 'init': if (data) return; contents = '

Pokemon Showdown is BETA and unfinished. If you are looking for something that isn\'t frequently down for maintenance and bug fixes, please check back in several weeks.

'; contents += '

There is a link to report bugs in the top right. If you find a bug, please report it.

'; contents += '

'; 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 += '

' + data.error + '

'; } else if (data.reason) { contents += '

' + data.reason + '

'; } else { contents += '

Register an account:

'; } contents += '

' + (data.name || me.name) + '

'; contents += '

'; contents += '

'; contents += '

'; contents += '

'; contents += '

'; selectElem = '#overlay_password'; break; case 'login': if (!data) data = {}; if (data.error) { contents += '

' + data.error + '

'; } else if (data.reason) { contents += '

' + data.reason + '

'; } else { contents += '

The name you chose is registered.

'; } contents += '

' + data.name + '

'; contents += '

'; contents += '

'; selectElem = '#overlay_password'; break; case 'betalogin': if (!data) data = {}; contents += '

Pokemon Showdown is in private beta testing.

'; contents += '

Request a beta account

'; if (data.error) { contents += '

' + data.error + '

'; } else if (data.reason) { contents += '

' + data.reason + '

'; } else {} contents += '

'; contents += '

'; contents += '

'; selectElem = '#overlay_username'; break; case 'down': contents += '

Pokemon Showdown is under heavy load.
:(

'; contents += '

Bear with us as we freak out.

'; // contents += '

We\'re currently on a backup server, and it\'s full.

'; contents += '

(Alternatively, reload this page in an hour or two; it should be back up by then.)

'; // contents += '

We WILL fix these performance issues ASAP.

'; // contents += '

Please try back in an hour or so; the server will open and close intermittently until we sort out the remaining performance issues.

'; // contents += '

Pokemon Showdown is confirmed to be under a DDoS attack. :(

'; // contents += '

Bear with us as we freak out.

'; // contents += '

There\'s slightly more information in this Smogon thread.

'; // contents += '

Please try back later today.

'; break; case 'unsupported': contents += '

You have an old version of your browser.

'; contents += '

Please upgrade to one of:

'; contents += '

Internet Explorer 9+, Firefox 4+, Chrome 11+, Safari 4+

'; break; case 'rename': if (!data) data = {}; if (data.error) { contents += '

' + data.error + '

'; } contents += '

'; contents += '

'; selectElem = '#overlay_name'; break; case 'forfeit': contents += '

Are you sure you want to forfeit?

'; contents += '

'; selectElem = '#overlay_cancel'; break; case 'disconnect': if (rooms.teambuilder && rooms.teambuilder.formSave) { rooms.teambuilder.formSave(); } contents += '

You have been disconnected - possibly because the server was restarted.

' contents += '

'; focusElem = '#overlay_refresh'; } $('#overlay').html('
' + contents + '
'); $('#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)) { $.get('/action.php?act=getassertion&userid='+toId(name), function(data){ if (data === ';') { overlay('login', {name: name}); } 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(); renameMe(name); overlayClose(); break; case 'login': case 'betalogin': var name = $('#overlay_username').val(); $.post('/action.php', { act: 'login', name: name, pass: $('#overlay_password').val(), servertoken: servertoken }, function (data) { if (!data) data = {}; 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); /* emit(socket, 'rename', { name: name, token: token }); */ //overlay('message', "Logged in successfully."); } else { overlay(overlayType, { name: name, error: 'Wrong password.' }); } }, 'json'); overlayClose(); break; case 'register': var name = $('#overlay_username').val(); var captcha = $('#overlay_captcha').val(); $.post('/action.php', { act: 'register', username: name, password: $('#overlay_password').val(), cpassword: $('#overlay_cpassword').val(), captcha: captcha, servertoken: servertoken }, function (data) { if (!data) data = {}; 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 }); } }, 'json').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; (function () { var savedTeam = $.parseJSON($.cookie('showdown_team1')); 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); } })(); var name = ($.cookie('showdown_username') || ''); // time to connect if (!Config.down) { function onConnect(data) { 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; } // lib isn't served by servers anymore - security issue, also scalability // var lib = (Config.serverprotocol === 'io' ? window.io : (Config.serverprotocol === 'eio' ? window.eio : window.SockJS)); // if (!lib) { // overlay('message', "

Could not connect to Showdown server at " + Config.server + ':' + Config.serverport + ".

You may have mistyped the address, or the server may be down for maintenance. We apologize for the inconvenience.

"); // return; // } // temporarily relocated connection code /* else if (isAndroid) { alert('Showdown doesn\'t work with the built-in Android browser - please use Firefox for Android instead.'); //socket = io.connect('http://'+Config.server+':'+Config.serverport, {transports:['jsonp-polling']}); if (Config.serverprotocol === 'io') socket = io.connect('http://' + Config.server + ':' + Config.serverport); else socket = new SockJS('http://' + Config.server + ':' + Config.serverport); } */ { if (Config.serverprotocol === 'io') socket = io.connect('http://' + Config.server + ':' + Config.serverport); else if (Config.serverprotocol === 'eio') socket = new eio.Socket({ host: Config.server, port: Config.serverport }); else socket = new SockJS('http://' + 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 (!initialized) // (!initialized && rooms[loc]) { 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('disconnect detected '); overlay('disconnect'); }, nameTaken: function (data) { if (data && data.name) { overlay('login', data); } else if (data) { overlay('rename', { error: data.reason }); } else { alert('nameTaken signal'); $('#userbar').prepend('nameTaken signal '); } }, message: function (message) { if (message.html) { overlay('message', message.html); return; } if (message.message) message = message.message; overlay('message', '
' + message + '
'); }, 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.updateMainElem(); } else { if (curRoom) curRoom.message(message, true); } } }; 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); } rooms[roomid].add(text); return; }); if (!name) token = ''; document.getElementById('loading-message').innerHTML += ' DONE
Connecting to Showdown server...'; emit(socket, 'join', { name: name, room: 'lobby', token: token }); } else { document.getElementById('loading-message').innerHTML += ' DONE
Connecting to Showdown server...'; socket.onopen = function() { if (!name) token = ''; document.getElementById('loading-message').innerHTML += ' DONE
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 (window.console && console.log) console.log('<< '+text); rooms[roomid].add(text); return; } var data = $.parseJSON(msg.data); if (!data) return; if (events[data.type]) events[data.type](data); }; socket.onclose = function () { $('#userbar').prepend('disconnect detected '); overlay('disconnect'); }; } } if (Config.testclient) { onConnect(Config); } else { $.post('/action.php', { act: 'upkeep', name: name, servertoken: servertoken }, onConnect, 'json'); } }