diff --git a/js/client-battle.js b/js/client-battle.js index 204556f96..7873e90a9 100644 --- a/js/client-battle.js +++ b/js/client-battle.js @@ -8,6 +8,9 @@ maxWidth: 1180, initialize: function (data) { this.me = {}; + this.choice = undefined; + /** are move/switch/team-preview controls currently being shown? */ + this.controlsShown = false; this.battlePaused = false; this.autoTimerActivated = false; @@ -23,12 +26,19 @@ this.$foeHint = this.$el.find('.foehint'); BattleSound.setMute(Dex.prefs('mute')); - this.battle = new Battle(this.$battle, this.$chatFrame, this.id); + this.battle = new Battle({ + id: this.id, + $frame: this.$battle, + $logFrame: this.$chatFrame + }); + this.battle.roomid = this.id; + this.battle.joinButtons = true; this.tooltips = this.battle.scene.tooltips; this.tooltips.listen(this.$controls); - this.battle.roomid = this.id; - this.battle.joinButtons = true; + var self = this; + this.battle.subscribe(function () { self.updateControls(); }); + this.users = {}; this.userCount = {users: 0}; this.$userList = this.$('.userlist'); @@ -41,14 +51,6 @@ this.$chat = this.$chatFrame.find('.inner'); this.$options = this.battle.scene.$options.html('
'); - - var self = this; - this.battle.customCallback = function () { self.updateControls(); }; - this.battle.endCallback = function () { self.updateControls(); }; - this.battle.startCallback = function () { self.updateControls(); }; - this.battle.stagnateCallback = function () { self.updateControls(); }; - - this.battle.play(); }, events: { 'click .replayDownloadButton': 'clickReplayDownloadButton', @@ -108,9 +110,9 @@ }, focus: function (e) { this.tooltips.hideTooltip(); - if (this.battle.playbackState === 3 && !this.battlePaused) { + if (this.battle.paused && !this.battlePaused) { + if (Dex.prefs('noanim')) this.battle.seekTurn(Infinity); this.battle.play(); - if (Dex.prefs('noanim')) this.battle.fastForwardTo(-1); } ConsoleRoom.prototype.focus.call(this, e); }, @@ -125,10 +127,9 @@ log.shift(); app.roomTitleChanged(this); } - if (this.battle.activityQueue.length) return; - this.battle.activityQueue = log; - this.battle.fastForwardTo(-1); - this.battle.play(); + if (this.battle.stepQueue.length) return; + this.battle.stepQueue = log; + this.battle.seekTurn(Infinity, true); if (this.battle.ended) this.battleEnded = true; this.updateLayout(); this.updateControls(); @@ -190,12 +191,12 @@ var args = logLine.substr(10).split('|'); var pokemon = isNaN(Number(args[1])) ? this.battle.getPokemon(args[1]) : this.battle.nearSide.active[args[1]]; var requestData = this.request.active[pokemon ? pokemon.slot : 0]; - delete this.choice; + this.choice = undefined; switch (args[0]) { case 'trapped': requestData.trapped = true; var pokeName = pokemon.side.n === 0 ? BattleLog.escapeHTML(pokemon.name) : "The opposing " + (this.battle.ignoreOpponent || this.battle.ignoreNicks ? pokemon.speciesForme : BattleLog.escapeHTML(pokemon.name)); - this.battle.activityQueue.push('|message|' + pokeName + ' is trapped and cannot switch!'); + this.battle.stepQueue.push('|message|' + pokeName + ' is trapped and cannot switch!'); break; case 'cant': for (var i = 0; i < requestData.moves.length; i++) { @@ -204,20 +205,21 @@ } } args.splice(1, 1, pokemon.getIdent()); - this.battle.activityQueue.push('|' + args.join('|')); + this.battle.stepQueue.push('|' + args.join('|')); break; } } else if (logLine.substr(0, 7) === '|title|') { // eslint-disable-line no-empty } else if (logLine.substr(0, 5) === '|win|' || logLine === '|tie') { this.battleEnded = true; - this.battle.activityQueue.push(logLine); + this.battle.stepQueue.push(logLine); } else if (logLine.substr(0, 6) === '|chat|' || logLine.substr(0, 3) === '|c|' || logLine.substr(0, 4) === '|c:|' || logLine.substr(0, 9) === '|chatmsg|' || logLine.substr(0, 10) === '|inactive|') { this.battle.instantAdd(logLine); } else { - this.battle.activityQueue.push(logLine); + this.battle.stepQueue.push(logLine); } } - this.battle.add('', Dex.prefs('noanim')); + this.battle.add(); + if (Dex.prefs('noanim')) this.battle.seekTurn(Infinity); this.updateControls(); }, toggleMessages: function (user) { @@ -248,18 +250,18 @@ * Battle stuff *********************************************************/ - updateControls: function (force) { + updateControls: function () { if (this.battle.scene.customControls) return; var controlsShown = this.controlsShown; this.controlsShown = false; - if (this.battle.playbackState === 5) { + if (this.battle.seeking !== null) { // battle is seeking this.$controls.html(''); return; - } else if (this.battle.playbackState === 2 || this.battle.playbackState === 3) { + } else if (!this.battle.atQueueEnd) { // battle is playing or paused if (!this.side || this.battleEnded) { @@ -296,7 +298,7 @@ // player this.controlsShown = true; - if (force || !controlsShown || this.choice === undefined || this.choice && this.choice.waiting) { + if (!controlsShown || this.choice === undefined || this.choice && this.choice.waiting) { // don't update controls (and, therefore, side) if `this.choice === null`: causes damage miscalculations this.updateControlsForPlayer(); } else { @@ -325,7 +327,6 @@ // since those early-return. app.topbar.updateTabbar(); }, - controlsShown: false, updateControlsForPlayer: function () { this.callbackWaiting = true; @@ -393,6 +394,7 @@ if (this.battle.mySide.pokemon && !this.battle.mySide.pokemon.length) { // too early, we can't determine `this.choice.count` yet // TODO: send teamPreviewCount in the request object + this.controlsShown = false; return; } if (!this.choice) { @@ -977,18 +979,15 @@ request.requestType = 'wait'; } - var choice = null; - if (choiceText) { - choice = {waiting: true}; - } - this.choice = choice; + this.choice = choiceText ? {waiting: true} : null; this.finalDecision = this.finalDecisionMove = this.finalDecisionSwitch = false; this.request = request; if (request.side) { this.updateSideLocation(request.side); } this.notifyRequest(); - this.updateControls(true); + this.controlsShown = false; + this.updateControls(); }, notifyRequest: function () { var oName = this.battle.farSide.name; @@ -1089,11 +1088,11 @@ }, rewindTurn: function () { if (this.battle.turn) { - this.battle.fastForwardTo(this.battle.turn - 1); + this.battle.seekTurn(this.battle.turn - 1); } }, goToEnd: function () { - this.battle.fastForwardTo(-1); + this.battle.seekTurn(Infinity); }, register: function (userid) { var registered = app.user.get('registered'); diff --git a/js/client-chat.js b/js/client-chat.js index 3c250961e..730451a12 100644 --- a/js/client-chat.js +++ b/js/client-chat.js @@ -1041,16 +1041,7 @@ for (var roomid in app.rooms) { var battle = app.rooms[roomid] && app.rooms[roomid].battle; if (!battle) continue; - var turn = battle.turn; - var oldState = battle.playbackState; - if (oldState === 4) turn = -1; - battle.reset(true); - battle.fastForwardTo(turn); - if (oldState !== 3) { - battle.play(); - } else { - battle.pause(); - } + battle.resetToCurrentTurn(); } return false; diff --git a/js/replay-embed.template.js b/js/replay-embed.template.js index cd74504d9..c63dfd2b0 100644 --- a/js/replay-embed.template.js +++ b/js/replay-embed.template.js @@ -36,13 +36,17 @@ requireScript('https://play.pokemonshowdown.com/js/battle-tooltips.js?a7'); requireScript('https://play.pokemonshowdown.com/js/battle.js?a7'); var Replays = { - init: function (log) { + battle: null, + muted: false, + init: function () { this.$el = $('.wrapper'); if (!this.$el.length) { $('body').append('' + BattleLog.escapeHTML(m[1]) + '). It contains errors and cannot be viewed.' + BattleLog.escapeHTML(m[1]) + '). It contains errors.' + BattleLog.escapeHTML(m[1]) + '). It contains errors and cannot be viewed.' + BattleLog.escapeHTML(m[1]) + '). It contains errors.{atEnd ? diff --git a/test/battle.test.js b/test/battle.test.js index 6b9daebda..d016e0a39 100644 --- a/test/battle.test.js +++ b/test/battle.test.js @@ -12,33 +12,32 @@ require('../js/battle.js'); describe('Battle', () => { it('should process a bunch of messages properly', () => { - let battle = new Battle(); - battle.debug = true; - - battle.setQueue([ - "|init|battle", - "|title|FOO vs. BAR", - "|j|FOO", - "|j|BAR", - "|request|", - "|player|p1|FOO|169", - "|player|p2|BAR|265", - "|teamsize|p1|6", - "|teamsize|p2|6", - "|gametype|singles", - "|gen|7", - "|tier|[Gen 7] Random Battle", - "|rated|", - "|seed|", - "|rule|Sleep Clause Mod: Limit one foe put to sleep", - "|rule|HP Percentage Mod: HP is shown in percentages", - "|", - "|start", - "|switch|p1a: Leafeon|Leafeon, L83, F|100/100", - "|switch|p2a: Gliscor|Gliscor, L77, F|242/242", - "|turn|1", - ]); - battle.fastForwardTo(-1); + let battle = new Battle({ + debug: true, + log: [ + "|init|battle", + "|title|FOO vs. BAR", + "|j|FOO", + "|j|BAR", + "|request|", + "|player|p1|FOO|169", + "|player|p2|BAR|265", + "|teamsize|p1|6", + "|teamsize|p2|6", + "|gametype|singles", + "|gen|7", + "|tier|[Gen 7] Random Battle", + "|rated|", + "|seed|", + "|rule|Sleep Clause Mod: Limit one foe put to sleep", + "|rule|HP Percentage Mod: HP is shown in percentages", + "|", + "|start", + "|switch|p1a: Leafeon|Leafeon, L83, F|100/100", + "|switch|p2a: Gliscor|Gliscor, L77, F|242/242", + "|turn|1", + ], + }); let p1 = battle.sides[0]; let p2 = battle.sides[1]; @@ -75,7 +74,6 @@ describe('Battle', () => { ]) { battle.add(line); } - battle.fastForwardTo(-1); assert(!p2gliscor.isActive()); let p2kyurem = p2.pokemon[1];