diff --git a/js/battle.js b/js/battle.js
index b9a627583..fbeab73eb 100644
--- a/js/battle.js
+++ b/js/battle.js
@@ -75,7 +75,7 @@ function BattleSoundLibrary() {
this.stopBgm();
}
this.bgm = this.loadBgm(url, loopstart, loopstop).setVolume(this.bgmVolume);
- if (!this.mute) {
+ if (!this.muted) {
if (this.bgm.paused) {
this.bgm.resume();
} else {
@@ -97,9 +97,11 @@ function BattleSoundLibrary() {
// setting
this.setMute = function(muted) {
+ muted = !!muted;
+ if (this.muted == muted) return;
this.muted = muted;
if (muted) {
- if (this.bgm) this.bgm.stop();
+ if (this.bgm) this.bgm.pause();
} else {
if (this.bgm) this.bgm.play();
}
@@ -4625,7 +4627,7 @@ function Battle(frame, logFrame, noPreload) {
} else if (message.substr(0,11).toLowerCase() === '/data-move ') {
self.log('
' + Tools.escapeHTML(args[1]) + ': (Private to ' + Tools.escapeHTML(args[3]) + ') ' + messageSanitize(args[4]) + '');
break;
case 'askreg':
- self.log('
Register an account to protect your ladder rating!
');
+ self.log('
Register an account to protect your ladder rating!
');
break;
case 'inactive':
self.kickingInactive = true;
@@ -4787,6 +4789,7 @@ function Battle(frame, logFrame, noPreload) {
return;
}
str = $.trim(str);
+ if (!str) return;
if (str.substr(0,1) === '|') {
var args = ['done'], kwargs = {};
str = $.trim(str.substr(1));
diff --git a/js/client-battle.js b/js/client-battle.js
index b7a8cd0f0..4fc9655df 100644
--- a/js/client-battle.js
+++ b/js/client-battle.js
@@ -15,7 +15,7 @@
this.$join = null;
this.$foeHint = this.$el.find('.foehint');
- // BattleSound.setMute(me.isMuted());
+ BattleSound.setMute(Tools.prefs('mute'));
this.battle = new Battle(this.$battle, this.$chatFrame);
this.$chat = this.$chatFrame.find('.inner');
@@ -601,6 +601,13 @@
skipTurn: function() {
this.battle.skipTurn();
},
+ register: function(userid) {
+ var registered = app.user.get('registered');
+ if (registered && registered.userid !== userid) registered = false;
+ if (!registered && userid === app.user.get('userid')) {
+ app.addPopup('register', RegisterPopup);
+ }
+ },
// choice buttons
chooseMove: function(move) {
@@ -818,4 +825,57 @@
}
});
+ var RegisterPopup = this.RegisterPopup = Popup.extend({
+ type: 'semimodal',
+ initialize: function(data) {
+ var buf = '
';
+ this.$el.html(buf);
+ },
+ submit: function(data) {
+ var name = data.name;
+ var captcha = data.captcha;
+ $.post(app.user.getActionPHP(), {
+ act: 'register',
+ username: name,
+ password: data.password,
+ cpassword: data.cpassword,
+ captcha: captcha,
+ challengekeyid: app.user.challengekeyid,
+ challenge: app.user.challenge
+ }, Tools.safeJSON(function (data) {
+ if (!data) data = {};
+ var token = data.assertion;
+ if (data.curuser && data.curuser.loggedin) {
+ app.user.set('registered', data.curuser);
+ var name = data.curuser.username;
+ if (!app.socket) {
+ document.location.reload();
+ return;
+ }
+ app.send('/trn '+name+',1,'+token);
+ app.addPopupMessage("You have been successfully registered.");
+ } else {
+ app.addPopup('register', RegisterPopup, {
+ name: name,
+ captcha: captcha,
+ error: data.actionerror
+ });
+ }
+ }), 'text');
+ }
+ });
+
}).call(this, jQuery);
diff --git a/js/client.js b/js/client.js
index 909258d9f..23c3ef6b3 100644
--- a/js/client.js
+++ b/js/client.js
@@ -28,6 +28,13 @@
named: false,
avatar: 0
},
+ initialize: function() {
+ app.on('response:userdetails', function(data) {
+ if (data.userid === this.get('userid')) {
+ this.set('avatar', data.avatar);
+ }
+ }, this);
+ },
/**
* Return the path to the login server `action.php` file. AJAX requests
* to this file will always be made on the `play.pokemonshowdown.com`
@@ -873,7 +880,7 @@
while (this.popups.length) {
var prevPopup = this.popups[this.popups.length-1];
if (prevPopup.id === id) {
- var sourceEl = prevPopup.sourceEl[0];
+ var sourceEl = prevPopup.sourceEl ? prevPopup.sourceEl[0] : null;
this.popups.pop().remove();
if ($(data.sourceEl)[0] === sourceEl) return;
} else if (prevPopup.id !== id.substr(0,prevPopup.id.length)) {
@@ -901,9 +908,15 @@
}
}
+ if (popup.domInitialize) popup.domInitialize(data);
this.popups.push(popup);
return popup;
},
+ addPopupMessage: function(message) {
+ // shorthand for adding a popup message
+ // this is the equivalent of alert(message)
+ app.addPopup('message', Popup, {message: message});
+ },
closePopup: function(id) {
if (this.popups.length) {
var popup = this.popups.pop();
@@ -933,7 +946,7 @@
'click button': 'dispatchClickButton'
},
initialize: function() {
- this.$el.html('

');
+ this.$el.html('

');
this.$tabbar = this.$('.maintabbar');
// this.$sidetabbar = this.$('.sidetabbar');
this.$userbar = this.$('.userbar');
@@ -942,24 +955,35 @@
app.user.on('change', this.updateUserbar, this);
this.updateUserbar();
},
- '$tabbar': null,
+
+ // userbar
updateUserbar: function() {
var buf = '';
var name = ' '+app.user.get('name');
var color = hashColor(app.user.get('userid'));
if (app.user.get('named')) {
- buf = '
'+Tools.escapeHTML(name)+' ';
+ buf = '
'+Tools.escapeHTML(name)+' ';
} else {
- buf = '
';
+ buf = '
';
}
this.$userbar.html(buf);
},
login: function() {
app.addPopup('login', LoginPopup);
},
- logout: function() {
- app.user.logout();
+ openSounds: function() {
+ app.addPopup('sounds', SoundsPopup);
},
+ openOptions: function() {
+ app.addPopup('options', OptionsPopup);
+ },
+ clickUsername: function(e) {
+ e.stopPropagation();
+ var name = $(e.currentTarget).data('name');
+ app.addPopup('user', UserPopup, {name: name, sourceEl: e.currentTarget});
+ },
+
+ // tabbar
updateTabbar: function() {
var curId = (app.curRoom ? app.curRoom.id : '');
var curSideId = (app.curSideRoom ? app.curSideRoom.id : '');
@@ -1021,11 +1045,6 @@
delete app.dispatchingButton;
}
},
- clickUsername: function(e) {
- e.stopPropagation();
- var name = $(e.currentTarget).data('name');
- app.addPopup('user', UserPopup, {name: name, sourceEl: e.currentTarget});
- },
click: function(e) {
e.preventDefault();
var $target = $(e.currentTarget);
@@ -1153,6 +1172,9 @@
Backbone.View.apply(this, arguments);
+ // if we have no source, we can't attach to anything
+ if (this.type === 'normal' && !this.sourceEl) this.type = 'semimodal';
+
if (this.type === 'normal') {
// nonmodal popup: should be positioned near source element
var $el = this.$el;
@@ -1186,6 +1208,10 @@
$measurer.remove();
}
},
+ initialize: function(data) {
+ this.type = 'semimodal';
+ this.$el.html('
'+Tools.escapeHTML(data.message)+'
').css('max-width', 480);
+ },
dispatchClickButton: function(e) {
var target = e.currentTarget;
@@ -1237,7 +1263,8 @@
this.update();
},
events: {
- 'click .ilink': 'clickLink'
+ 'click .ilink': 'clickLink',
+ 'click .yours': 'avatars'
},
update: function(data) {
if (data && data.userid === this.data.userid) {
@@ -1261,7 +1288,7 @@
if (group || name.charAt(0) === ' ') name = name.substr(1);
var buf = '
';
- if (avatar) buf += '
+')
';
+ if (avatar) buf += '
+')
';
buf += '
' + Tools.escapeHTML(name) + '';
buf += '
' + (group || ' ') + '';
if (data.rooms) {
@@ -1287,9 +1314,9 @@
buf += '
';
if (userid === app.user.get('userid') || !app.user.get('named')) {
- buf += '
';
+ buf += '
';
} else {
- buf += '
';
+ buf += '
';
}
this.$el.html(buf);
@@ -1301,6 +1328,9 @@
var roomid = $(e.currentTarget).attr('href').substr(app.root.length);
app.tryJoinRoom(roomid);
},
+ avatars: function() {
+ app.addPopup('user:avatars', AvatarsPopup);
+ },
challenge: function() {
this.close();
app.focusRoom('');
@@ -1347,6 +1377,7 @@
this.close();
}
});
+
var LoginPasswordPopup = this.LoginPasswordPopup = Popup.extend({
type: 'semimodal',
initialize: function(data) {
@@ -1389,4 +1420,151 @@
}
});
+ var SoundsPopup = this.SoundsPopup = Popup.extend({
+ initialize: function(data) {
+ var buf = '';
+ var muted = !!Tools.prefs('mute');
+ buf += '
'+(muted?'(muted)':'')+'
';
+ buf += '
'+(muted?'(muted)':'')+'
'
+ buf += '
';
+ this.$el.html(buf).css('min-width', 160);
+ },
+ events: {
+ 'change input[name=muted]': 'setMute'
+ },
+ domInitialize: function() {
+ var self = this;
+ this.$('.effect-volume input').slider({
+ from: 0,
+ to: 100,
+ step: 1,
+ dimension: '%',
+ skin: 'round_plastic',
+ onstatechange: function(val) {
+ self.setEffectVolume(val);
+ }
+ });
+ this.$('.music-volume input').slider({
+ from: 0,
+ to: 100,
+ step: 1,
+ dimension: '%',
+ skin: 'round_plastic',
+ onstatechange: function(val) {
+ self.setMusicVolume(val);
+ }
+ });
+ },
+ setMute: function(e) {
+ var muted = !!e.currentTarget.checked;
+ Tools.prefs('mute', muted);
+ BattleSound.setMute(muted);
+
+ if (!muted) {
+ this.$('.effect-volume').html('
');
+ this.$('.music-volume').html('
');
+ this.domInitialize();
+ } else {
+ this.$('.effect-volume').html('
(muted)');
+ this.$('.music-volume').html('
(muted)');
+ }
+
+ app.topbar.$('button[name=openSounds]').html('
');
+ },
+ setEffectVolume: function(volume) {
+ BattleSound.setEffectVolume(volume);
+ Tools.prefs('effectvolume', volume);
+ },
+ setMusicVolume: function(volume) {
+ BattleSound.setBgmVolume(volume);
+ Tools.prefs('musicvolume', volume);
+ }
+ });
+
+ var OptionsPopup = this.OptionsPopup = Popup.extend({
+ initialize: function(data) {
+ app.user.on('change', this.update, this);
+ app.send('/cmd userdetails '+app.user.get('userid'));
+ this.update();
+ },
+ events: {
+ 'change input[name=noanim]': 'setNoanim',
+ 'change input[name=ignorespects]': 'setIgnoreSpects',
+ 'change select[name=timestamps-lobby]': 'setTimestampsLobby',
+ 'change select[name=timestamps-pms]': 'setTimestampsPMs',
+ 'click img': 'avatars'
+ },
+ update: function() {
+ var name = app.user.get('name');
+ var avatar = app.user.get('avatar');
+
+ var buf = '';
+ buf += '
'+(avatar?'
':'')+''+Tools.escapeHTML(name)+'
';
+ buf += '
';
+
+ buf += '
';
+ buf += '
';
+
+ var timestamps = this.timestamps = (Tools.prefs('timestamps') || {});
+ buf += '
';
+ buf += '
';
+
+ if (app.curRoom.battle) {
+ buf += '
';
+ buf += '
Current room
';
+ buf += '
';
+ }
+
+ buf += '
';
+ buf += '
';
+ this.$el.html(buf).css('min-width', 160);
+ },
+ setNoanim: function(e) {
+ var noanim = !!e.currentTarget.checked;
+ Tools.prefs('noanim', noanim);
+ },
+ setIgnoreSpects: function(e) {
+ if (app.curRoom.battle) {
+ app.curRoom.battle.ignoreSpects = !!e.currentTarget.checked;
+ }
+ },
+ setTimestampsLobby: function(e) {
+ this.timestamps.lobby = e.currentTarget.value;
+ },
+ setTimestampsPMs: function(e) {
+ this.timestamps.pms = e.currentTarget.value;
+ },
+ avatars: function() {
+ app.addPopup('options:avatars', AvatarsPopup);
+ },
+ logout: function() {
+ app.user.logout();
+ this.close();
+ }
+ });
+
+ var AvatarsPopup = this.AvatarsPopup = Popup.extend({
+ type: 'semimodal',
+ initialize: function() {
+ var cur = +app.user.get('avatar');
+ var buf = '';
+ buf += '
Choose an avatar or
';
+
+ buf += '
';
+ for (var i=1; i<=293; i++) {
+ var offset = '-'+(((i-1)%16)*80)+'px -'+(Math.floor((i-1)/16)*80)+'px'
+ buf += '';
+ }
+ buf += '
';
+
+ buf += '
';
+ this.$el.html(buf).css('max-width', 780);
+ },
+ setAvatar: function(i) {
+ app.send('/avatar '+i);
+ app.send('/cmd userdetails '+app.user.get('userid'));
+ this.close();
+ }
+ });
+
}).call(this, jQuery);
diff --git a/style/client.css b/style/client.css
index a9921bed6..716420d10 100644
--- a/style/client.css
+++ b/style/client.css
@@ -88,6 +88,15 @@ body {
.username {
cursor: pointer;
}
+.userbar button {
+ cursor: pointer;
+}
+.userbar button.icon {
+ height: 21px;
+ width: 23px;
+ font-size: 14px;
+ padding: 0;
+}
.tabbar {
position: absolute;
@@ -313,7 +322,7 @@ body {
background: #E1E8E8;
color: black;
border: 1px solid #999999;
- padding: 5px 10px;
+ padding: 2px 10px;
border-radius: 6px;
box-shadow: inset 1px 1px 0 #ffffff, inset -1px -1px 0 #DDDDDD, 2px 2px 3px rgba(0,0,0,.2);
@@ -321,12 +330,16 @@ body {
}
.ps-overlay .ps-popup {
position: static;
- margin: 100px auto 0 auto;
+ margin: 100px auto 20px auto;
max-width: 320px;
}
-.ps-popup p {
+.ps-popup p,
+.ps-popup h3 {
margin: 7px 0;
}
+.ps-popup h3 {
+ font-size: 12pt;
+}
p.or {
font-size: 12pt;
font-style: italic;
@@ -758,24 +771,6 @@ p.or:after {
* Chat
*********************************************************/
-.userdetails {
- min-height: 80px;
- width: 191px;
- padding: 1px 1px 1px 86px;
-}
-.userdetails img {
- float: left;
- margin-left: -85px;
-}
-.userdetails .rooms {
- font-size: 8pt;
-}
-.userdetails .offline {
- color: red;
-}
-.buttonbar {
- clear: both;
-}
.chat-log {
position: absolute;
top: 0;
@@ -1845,3 +1840,71 @@ a.ilink:hover {
width: 95px;
text-align: right;
}
+
+/*********************************************************
+ * Popups
+ *********************************************************/
+
+.userdetails {
+ min-height: 80px;
+ width: 191px;
+ padding: 1px 1px 1px 86px;
+ margin: 5px 0;
+}
+.userdetails img {
+ float: left;
+ margin-left: -85px;
+}
+.userdetails .rooms {
+ font-size: 8pt;
+}
+.userdetails .offline {
+ color: red;
+}
+.trainersprite.yours {
+ cursor: pointer;
+}
+.buttonbar {
+ clear: both;
+}
+
+.avatarlist button {
+ display: block;
+ float: left;
+ margin: 2px;
+ width: 80px;
+ height: 80px;
+
+ border: 1px solid #E1E8E8;
+ background: transparent url(//play.pokemonshowdown.com/sprites/trainers-sheet.png) no-repeat scroll 0px 0px;
+ border-radius: 4px;
+ box-shadow: none;
+ cursor: pointer;
+}
+.avatarlist button.cur {
+ border-color: #999999;
+}
+.avatarlist button:hover,
+.avatarlist button.cur:hover {
+ border: 1px solid #8899AA;
+ background-color: #F1F4F9;
+ box-shadow: 1px 1px 1px #D5D5D5;
+}
+
+.effect-volume,
+.music-volume {
+ height: 39px;
+}
+.effect-volume label,
+.music-volume label {
+ padding-bottom: 12px;
+ font-size: 8pt;
+}
+.effect-volume em,
+.music-volume em {
+ display: block;
+ margin-top: -6px;
+ font-size: 9pt;
+ padding-left: 5px;
+ color: #555555;
+}