From b9137d5d37fd9f65cfe92758f555c0e79ad2a872 Mon Sep 17 00:00:00 2001 From: Ivo Julca Date: Fri, 13 Feb 2015 19:43:10 -0500 Subject: [PATCH 1/2] Implement BattleSide#resolveDecision It will be useful to support decision fallbacks for turn timeouts. --- battle-engine.js | 79 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/battle-engine.js b/battle-engine.js index c61a158267..017e669ea8 100644 --- a/battle-engine.js +++ b/battle-engine.js @@ -1416,6 +1416,81 @@ BattleSide = (function () { BattleSide.prototype.emitRequest = function (update) { this.battle.send('request', this.id + "\n" + this.battle.rqid + "\n" + JSON.stringify(update)); }; + BattleSide.prototype.resolveDecision = function () { + if (this.decision) return this.decision; + var decisions = []; + + switch (this.currentRequest) { + case 'move': + for (var i = 0; i < this.active.length; i++) { + var pokemon = this.active[i]; + if (!pokemon || pokemon.fainted) continue; + + var lockedMove = pokemon.getLockedMove(); + if (lockedMove) { + decisions.push({ + choice: 'move', + pokemon: pokemon, + targetLoc: this.battle.runEvent('LockMoveTarget', pokemon) || 0, + move: lockedMove + }); + continue; + } + + var moveid = 'struggle'; + var moves = pokemon.getMoves(); + for (var j = 0; j < moves.length; j++) { + if (moves[j].disabled) continue; + moveid = moves[j].id; + break; + } + decisions.push({ + choice: 'move', + pokemon: pokemon, + targetLoc: 0, + move: moveid + }); + } + break; + + case 'switch': + var canSwitchOut = []; + for (var i = 0; i < this.active.length; i++) { + if (this.active[i] && this.active[i].switchFlag) canSwitchOut.push(i); + } + + var canSwitchIn = []; + for (var i = this.active.length; i < this.pokemon.length; i++) { + if (this.pokemon[i] && !this.pokemon[i].fainted) canSwitchIn.push(i); + } + + var willPass = canSwitchOut.splice(Math.min(canSwitchOut.length, canSwitchIn.length)); + for (var i = 0; i < canSwitchOut.length; i++) { + decisions.push({ + choice: 'switch', + pokemon: this.active[canSwitchOut[i]], + priority: 101 + }); + } + for (var i = 0; i < willPass.length; i++) { + decisions.push({ + choice: 'pass', + pokemon: this.active[willPass[i]], + priority: 102 + }); + } + break; + + case 'teampreview': + decisions.push({ + choice: 'team', + side: this, + team: '123456'.slice(0, this.currentRequestDetails ? parseInt(this.currentRequestDetails, 10) : this.active.length) + }); + } + + return decisions; + }; BattleSide.prototype.destroy = function () { // deallocate ourself @@ -3619,10 +3694,10 @@ Battle = (function () { }; Battle.prototype.commitDecisions = function () { if (this.p1.decision !== true) { - this.addQueue(this.p1.decision, true, this.p1); + this.addQueue(this.p1.resolveDecision(), true, this.p1); } if (this.p2.decision !== true) { - this.addQueue(this.p2.decision, true, this.p2); + this.addQueue(this.p2.resolveDecision(), true, this.p2); } this.currentRequest = ''; From 1e6d387cf744445bf0a1ec7817520b1fca73d3db Mon Sep 17 00:00:00 2001 From: Ivo Julca Date: Fri, 13 Feb 2015 18:10:43 -0500 Subject: [PATCH 2/2] =?UTF-8?q?Choice=20parsing:=20'default'=20is=20now=20?= =?UTF-8?q?a=20valid=20choice=20for=20move=20requests=20-=20Its=20result?= =?UTF-8?q?=20is=20equivalent=20as=20timing=20out=20on=20own=20turn=20in-g?= =?UTF-8?q?ame:=20it=20forces=20the=20Pok=C3=A9mon,=20as=20well=20as=20any?= =?UTF-8?q?=20remaining=20active=20Pok=C3=A9mon=20to=20use=20their=20first?= =?UTF-8?q?=20available=20move,=20and=20target=20randomly.=20To=20maximize?= =?UTF-8?q?=20similarity,=20this=20decision=20is=20not=20be=20cancelable.?= =?UTF-8?q?=20-=20Reject=20move=20choices=20in=20Doubles/Triples=20that=20?= =?UTF-8?q?don't=20specify=20a=20target=20when=20required.=20-=20'default'?= =?UTF-8?q?=20is=20not=20implemented=20-but=20reserved-=20for=20switch=20r?= =?UTF-8?q?equests=20as=20it's=20currently=20no=20different=20from=20choos?= =?UTF-8?q?ing=20the=20next=20available=20Pok=C3=A9mon.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- battle-engine.js | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/battle-engine.js b/battle-engine.js index 017e669ea8..78bd9659a2 100644 --- a/battle-engine.js +++ b/battle-engine.js @@ -3742,12 +3742,16 @@ Battle = (function () { var len = choices.length; if (side.currentRequest !== 'teampreview') len = side.active.length; + var isDefault; + var choosableTargets = {normal:1, any:1, adjacentAlly:1, adjacentAllyOrSelf:1, adjacentFoe:1}; + var freeSwitchCount = {'switch':0, 'pass':0}; if (side.currentRequest === 'switch') { var canSwitch = side.active.filter(function (mon) {return mon && mon.switchFlag;}).length; freeSwitchCount['switch'] = Math.min(canSwitch, side.pokemon.slice(side.active.length).filter(function (mon) {return !mon.fainted;}).length); freeSwitchCount['pass'] = canSwitch - freeSwitchCount['switch']; } + for (var i = 0; i < len; i++) { var choice = (choices[i] || '').trim(); @@ -3782,6 +3786,23 @@ Battle = (function () { }); continue; } + if (isDefault || choice === 'default') { + isDefault = true; + var moves = pokemon.getMoves(); + var moveid = 'struggle'; + for (var j = 0; j < moves.length; j++) { + if (moves[j].disabled) continue; + moveid = moves[j].id; + break; + } + decisions.push({ + choice: 'move', + pokemon: pokemon, + targetLoc: 0, + move: moveid + }); + continue; + } if (choice !== 'move' && choice !== 'switch' && choice !== 'shift') { if (i === 0) return false; // fallback @@ -3917,13 +3938,27 @@ Battle = (function () { return false; } moveid = requestMoves[moveIndex].id; + if (!targetLoc && side.active.length > 1 && requestMoves[moveIndex].target in choosableTargets) { + this.debug("Can't use the move without a target"); + return false; + } } else { // parse a move name moveid = toId(data); if (moveid.substr(0, 11) === 'hiddenpower') { moveid = 'hiddenpower'; } - if (!requestMoves.map('id').any(moveid)) { + var isValidMove = false; + for (var j = 0; j < requestMoves.length; j++) { + if (requestMoves[j].id !== moveid) continue; + if (!targetLoc && side.active.length > 1 && requestMoves[j].target in choosableTargets) { + this.debug("Can't use the move without a target"); + return false; + } + isValidMove = true; + break; + } + if (!isValidMove) { this.debug("Can't use an unexpected move"); return false; } @@ -3974,7 +4009,7 @@ Battle = (function () { case 'pass': if (i > side.active.length || i > side.pokemon.length) continue; if (side.currentRequest !== 'switch') { - this.debug("No se pudo pasar el turno."); + this.debug("Can't pass the turn"); return false; } decisions.push({ @@ -3986,7 +4021,7 @@ Battle = (function () { } if (freeSwitchCount['switch'] !== 0 || freeSwitchCount['pass'] !== 0) return false; - if (!this.supportCancel) decisions.finalDecision = true; + if (!this.supportCancel || isDefault) decisions.finalDecision = true; return decisions; }; Battle.prototype.add = function () {