"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var battle_queue_exports = {}; __export(battle_queue_exports, { BattleQueue: () => BattleQueue, default: () => battle_queue_default }); module.exports = __toCommonJS(battle_queue_exports); /** * Simulator Battle Action Queue * Pokemon Showdown - http://pokemonshowdown.com/ * * The action queue is the core of the battle simulation. A rough overview of * the core battle loop: * * - chosen moves/switches are added to the action queue * - the action queue is sorted in speed/priority order * - we go through the action queue * - repeat * * @license MIT */ class BattleQueue { constructor(battle) { this.battle = battle; this.list = []; const queueScripts = battle.format.queue || battle.dex.data.Scripts.queue; if (queueScripts) Object.assign(this, queueScripts); } shift() { return this.list.shift(); } peek(end) { return this.list[end ? this.list.length - 1 : 0]; } push(action) { return this.list.push(action); } unshift(action) { return this.list.unshift(action); } [Symbol.iterator]() { return this.list[Symbol.iterator](); } entries() { return this.list.entries(); } /** * Takes an ActionChoice, and fills it out into a full Action object. * * Returns an array of Actions because some ActionChoices (like mega moves) * resolve to two Actions (mega evolution + use move) */ resolveAction(action, midTurn = false) { if (!action) throw new Error(`Action not passed to resolveAction`); if (action.choice === "pass") return []; const actions = [action]; if (!action.side && action.pokemon) action.side = action.pokemon.side; if (!action.move && action.moveid) action.move = this.battle.dex.getActiveMove(action.moveid); if (!action.order) { const orders = { team: 1, start: 2, instaswitch: 3, beforeTurn: 4, beforeTurnMove: 5, revivalblessing: 6, runSwitch: 101, switch: 103, megaEvo: 104, megaEvoX: 104, megaEvoY: 104, runDynamax: 105, terastallize: 106, priorityChargeMove: 107, shift: 200, // default is 200 (for moves) residual: 300 }; if (action.choice in orders) { action.order = orders[action.choice]; } else { action.order = 200; if (!["move", "event"].includes(action.choice)) { throw new Error(`Unexpected orderless action ${action.choice}`); } } } if (!midTurn) { if (action.choice === "move") { if (!action.maxMove && !action.zmove && action.move.beforeTurnCallback) { actions.unshift(...this.resolveAction({ choice: "beforeTurnMove", pokemon: action.pokemon, move: action.move, targetLoc: action.targetLoc })); } if (action.mega && !action.pokemon.isSkyDropped()) { actions.unshift(...this.resolveAction({ choice: "megaEvo", pokemon: action.pokemon })); } if (action.megax && !action.pokemon.isSkyDropped()) { actions.unshift(...this.resolveAction({ choice: "megaEvoX", pokemon: action.pokemon })); } if (action.megay && !action.pokemon.isSkyDropped()) { actions.unshift(...this.resolveAction({ choice: "megaEvoY", pokemon: action.pokemon })); } if (action.terastallize && !action.pokemon.terastallized) { actions.unshift(...this.resolveAction({ choice: "terastallize", pokemon: action.pokemon })); } if (action.maxMove && !action.pokemon.volatiles["dynamax"]) { actions.unshift(...this.resolveAction({ choice: "runDynamax", pokemon: action.pokemon })); } if (!action.maxMove && !action.zmove && action.move.priorityChargeCallback) { actions.unshift(...this.resolveAction({ choice: "priorityChargeMove", pokemon: action.pokemon, move: action.move })); } action.fractionalPriority = this.battle.runEvent("FractionalPriority", action.pokemon, null, action.move, 0); } else if (["switch", "instaswitch"].includes(action.choice)) { if (typeof action.pokemon.switchFlag === "string") { action.sourceEffect = this.battle.dex.moves.get(action.pokemon.switchFlag); } action.pokemon.switchFlag = false; } } const deferPriority = this.battle.gen === 7 && action.mega && action.mega !== "done"; if (action.move) { let target = null; action.move = this.battle.dex.getActiveMove(action.move); if (!action.targetLoc) { target = this.battle.getRandomTarget(action.pokemon, action.move); if (target) action.targetLoc = action.pokemon.getLocOf(target); } action.originalTarget = action.pokemon.getAtLoc(action.targetLoc); } if (!deferPriority) this.battle.getActionSpeed(action); return actions; } /** * Makes the passed action happen next (skipping speed order). */ prioritizeAction(action, sourceEffect) { for (const [i, curAction] of this.list.entries()) { if (curAction === action) { this.list.splice(i, 1); break; } } action.sourceEffect = sourceEffect; action.order = 3; this.list.unshift(action); } /** * Changes a pokemon's action, and inserts its new action * in priority order. * * You'd normally want the OverrideAction event (which doesn't * change priority order). */ changeAction(pokemon, action) { this.cancelAction(pokemon); if (!action.pokemon) action.pokemon = pokemon; this.insertChoice(action); } addChoice(choices) { if (!Array.isArray(choices)) choices = [choices]; for (const choice of choices) { const resolvedChoices = this.resolveAction(choice); this.list.push(...resolvedChoices); for (const resolvedChoice of resolvedChoices) { if (resolvedChoice && resolvedChoice.choice === "move" && resolvedChoice.move.id !== "recharge") { resolvedChoice.pokemon.side.lastSelectedMove = resolvedChoice.move.id; } } } } willAct() { for (const action of this.list) { if (["move", "switch", "instaswitch", "shift"].includes(action.choice)) { return action; } } return null; } willMove(pokemon) { if (pokemon.fainted) return null; for (const action of this.list) { if (action.choice === "move" && action.pokemon === pokemon) { return action; } } return null; } cancelAction(pokemon) { const oldLength = this.list.length; for (let i = 0; i < this.list.length; i++) { if (this.list[i].pokemon === pokemon) { this.list.splice(i, 1); i--; } } return this.list.length !== oldLength; } cancelMove(pokemon) { for (const [i, action] of this.list.entries()) { if (action.choice === "move" && action.pokemon === pokemon) { this.list.splice(i, 1); return true; } } return false; } willSwitch(pokemon) { for (const action of this.list) { if (["switch", "instaswitch"].includes(action.choice) && action.pokemon === pokemon) { return action; } } return null; } /** * Inserts the passed action into the action queue when it normally * would have happened (sorting by priority/speed), without * re-sorting the existing actions. */ insertChoice(choices, midTurn = false) { if (Array.isArray(choices)) { for (const choice2 of choices) { this.insertChoice(choice2); } return; } const choice = choices; if (choice.pokemon) { choice.pokemon.updateSpeed(); } const actions = this.resolveAction(choice, midTurn); let firstIndex = null; let lastIndex = null; for (const [i, curAction] of this.list.entries()) { const compared = this.battle.comparePriority(actions[0], curAction); if (compared <= 0 && firstIndex === null) { firstIndex = i; } if (compared < 0) { lastIndex = i; break; } } if (firstIndex === null) { this.list.push(...actions); } else { if (lastIndex === null) lastIndex = this.list.length; const index = firstIndex === lastIndex ? firstIndex : this.battle.random(firstIndex, lastIndex + 1); this.list.splice(index, 0, ...actions); } } clear() { this.list = []; } debug(action) { if (action) { return `${action.order || ""}:${action.priority || ""}:${action.speed || ""}:${action.subOrder || ""} - ${action.choice}${action.pokemon ? " " + action.pokemon : ""}${action.move ? " " + action.move : ""}`; } return this.list.map( (queueAction) => this.debug(queueAction) ).join("\n") + "\n"; } sort() { this.battle.speedSort(this.list); return this; } } var battle_queue_default = BattleQueue; //# sourceMappingURL=battle-queue.js.map