Add auto mode and various changes

This commit is contained in:
Flashfyre 2023-03-29 00:31:25 -04:00
parent 2f17903d30
commit a739a1666f
14 changed files with 806 additions and 502 deletions

View File

@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es6",
"target": "ES2019",
"moduleResolution": "node",
"checkJs": true,
"esModuleInterop": true

268
src/auto-play.ts Normal file
View File

@ -0,0 +1,268 @@
import { SelectModifierPhase } from "./battle-phase";
import BattleScene from "./battle-scene";
import { ModifierTier, ModifierType, PokemonBaseStatBoosterModifierType, PokemonHpRestoreModifierType, PokemonReviveModifierType } from "./modifier";
import Pokemon, { AiType, EnemyPokemon, PlayerPokemon, PokemonMove } from "./pokemon";
import { Species } from "./species";
import { getTypeDamageMultiplier } from "./type";
import BattleMessageUiHandler from "./ui/battle-message-ui-handler";
import CommandUiHandler from "./ui/command-ui-handler";
import FightUiHandler from "./ui/fight-ui-handler";
import MessageUiHandler from "./ui/message-ui-handler";
import ModifierSelectUiHandler from "./ui/modifier-select-ui-handler";
import PartyUiHandler from "./ui/party-ui-handler";
import SwitchCheckUiHandler from "./ui/switch-check-ui-handler";
import { Mode } from "./ui/ui";
export function initAutoPlay(speed: number) {
const thisArg = this as BattleScene;
const originalDelayedCall = this.time.delayedCall;
this.time.delayedCall = function (delay: number, callback: Function, args?: any[], callbackScope?: any) {
delay /= speed;
originalDelayedCall.apply(this, [ delay, callback, args, callbackScope ]);
};
const originalAddEvent = this.time.addEvent;
this.time.addEvent = function (config: Phaser.Time.TimerEvent | Phaser.Types.Time.TimerEventConfig) {
if (config.delay)
config.delay = Math.ceil(config.delay / speed);
if (config.startAt)
config.startAt = Math.ceil(config.startAt / speed);
return originalAddEvent.apply(this, [ config ]);
};
const originalTweensAdd = this.tweens.add;
this.tweens.add = function (config: Phaser.Types.Tweens.TweenBuilderConfig | object) {
if (config.duration)
config.duration = Math.ceil(config.duration / speed);
if (config.delay)
config.delay = Math.ceil(config.delay / speed);
return originalTweensAdd.apply(this, [ config ]);
};
const originalAddCounter = this.tweens.addCounter;
this.tweens.addCounter = function (config: Phaser.Types.Tweens.NumberTweenBuilderConfig) {
if (config.duration)
config.duration = Math.ceil(config.duration / speed);
if (config.delay)
config.delay = Math.ceil(config.delay / speed);
return originalAddCounter.apply(this, [ config ]);
};
const keyCodes = Phaser.Input.Keyboard.KeyCodes;
PlayerPokemon.prototype.getNextMove = EnemyPokemon.prototype.getNextMove;
const playerPokemon = this.getParty()[0] as PlayerPokemon;
const messageUiHandler = this.ui.handlers[Mode.MESSAGE] as BattleMessageUiHandler;
const commandUiHandler = this.ui.handlers[Mode.COMMAND] as CommandUiHandler;
const fightUiHandler = this.ui.handlers[Mode.FIGHT] as FightUiHandler;
const partyUiHandler = this.ui.handlers[Mode.PARTY] as PartyUiHandler;
const switchCheckUiHandler = this.ui.handlers[Mode.SWITCH_CHECK] as SwitchCheckUiHandler;
const modifierSelectUiHandler = this.ui.handlers[Mode.MODIFIER_SELECT] as ModifierSelectUiHandler;
const getBestPartyMemberIndex = () => {
const enemyPokemon = thisArg.getEnemyPokemon();
const party = thisArg.getParty();
let bestPartyMemberIndex = -1;
let bestPartyMemberEffectiveness = 0.5;
for (let p = 0; p < party.length; p++) {
const pokemon = party[p];
if ((pokemon.hp / pokemon.getMaxHp()) <= 0.4)
continue;
const effectiveness = getMaxMoveEffectiveness(pokemon, enemyPokemon) / getMaxMoveEffectiveness(enemyPokemon, pokemon);
if (effectiveness > bestPartyMemberEffectiveness) {
bestPartyMemberIndex = p;
bestPartyMemberEffectiveness = effectiveness;
}
console.log(p, Species[pokemon.species.speciesId], '->', Species[enemyPokemon.species.speciesId], effectiveness);
}
if (bestPartyMemberIndex === -1) {
let highestHpValue = 0;
for (let p = 0; p < party.length; p++) {
const pokemon = party[p];
if (pokemon.hp > highestHpValue) {
highestHpValue = pokemon.hp;
bestPartyMemberIndex = p;
}
}
}
return bestPartyMemberIndex;
};
const getMaxMoveEffectiveness = (attacker: Pokemon, defender: Pokemon) => {
let maxEffectiveness = 0.5;
for (let m of attacker.moveset) {
const moveType = m.getMove().type;
let effectiveness = getTypeDamageMultiplier(moveType, defender.species.type1);
if (defender.species.type2 > -1)
effectiveness *= getTypeDamageMultiplier(moveType, defender.species.type2);
if (effectiveness > maxEffectiveness)
maxEffectiveness = effectiveness;
}
return maxEffectiveness;
};
let nextPartyMemberIndex = -1;
const originalMessageUiHandlerShowText = MessageUiHandler.prototype.showText;
MessageUiHandler.prototype.showText = function (text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean) {
delay = 0;
callbackDelay = 0;
originalMessageUiHandlerShowText.apply(this, [ text, delay, callback, callbackDelay, prompt ]);
};
const originalMessageUiHandlerShowPrompt = MessageUiHandler.prototype.showPrompt;
MessageUiHandler.prototype.showPrompt = function (callback: Function, callbackDelay: integer) {
callbackDelay = 0;
originalMessageUiHandlerShowPrompt.apply(this, [ callback, callbackDelay ]);
thisArg.time.delayedCall(20, () => this.processInput(keyCodes.Z));
};
const originalMessageUiHandlerPromptLevelUpStats = messageUiHandler.promptLevelUpStats;
messageUiHandler.promptLevelUpStats = function (prevStats: integer[], showTotals: boolean, callback?: Function) {
originalMessageUiHandlerPromptLevelUpStats.apply(this, [ prevStats, showTotals, callback ]);
this.processInput(keyCodes.Z);
};
const originalCommandUiHandlerShow = commandUiHandler.show;
commandUiHandler.show = function (args: any[]) {
originalCommandUiHandlerShow.apply(this, [ args ]);
const bestPartyMemberIndex = getBestPartyMemberIndex();
if (bestPartyMemberIndex) {
console.log(bestPartyMemberIndex, thisArg.getParty())
console.log('Switching to ', Species[thisArg.getParty()[bestPartyMemberIndex].species.speciesId]);
nextPartyMemberIndex = bestPartyMemberIndex;
commandUiHandler.setCursor(2);
this.processInput(keyCodes.Z);
} else {
commandUiHandler.setCursor(0);
this.processInput(keyCodes.Z);
}
};
const originalFightUiHandlerShow = fightUiHandler.show;
fightUiHandler.show = function (args: any[]) {
originalFightUiHandlerShow.apply(this, [ args ]);
if (!playerPokemon.aiType)
playerPokemon.aiType = AiType.SMART;
thisArg.time.delayedCall(20, () => {
const nextMove = playerPokemon.getNextMove() as PokemonMove;
fightUiHandler.setCursor(playerPokemon.moveset.indexOf(nextMove));
this.processInput(keyCodes.Z);
});
};
const originalPartyUiHandlerShow = partyUiHandler.show;
partyUiHandler.show = function (args: any[]) {
originalPartyUiHandlerShow.apply(this, [ args ]);
thisArg.time.delayedCall(20, () => {
if (nextPartyMemberIndex === -1)
nextPartyMemberIndex = getBestPartyMemberIndex();
partyUiHandler.setCursor(nextPartyMemberIndex);
nextPartyMemberIndex = -1;
this.processInput(keyCodes.Z);
});
};
const originalSwitchCheckUiHandlerShow = switchCheckUiHandler.show;
switchCheckUiHandler.show = function (args: any[]) {
originalSwitchCheckUiHandlerShow.apply(this, [ args ]);
const bestPartyMemberIndex = getBestPartyMemberIndex();
thisArg.time.delayedCall(20, () => {
if (bestPartyMemberIndex)
nextPartyMemberIndex = bestPartyMemberIndex;
switchCheckUiHandler.setCursor(bestPartyMemberIndex ? 1 : 0);
this.processInput(keyCodes.Z);
});
}
const tryGetBestModifier = (modifierTypes: Array<ModifierType>, predicate: Function) => {
for (let mt = 0; mt < modifierTypes.length; mt++) {
const modifierType = modifierTypes[mt];
if (predicate(modifierType)) {
return mt;
}
}
return -1;
};
const originalModifierSelectUiHandlerShow = modifierSelectUiHandler.show;
modifierSelectUiHandler.show = function (args: any[]) {
if (modifierSelectUiHandler.active)
return;
originalModifierSelectUiHandlerShow.apply(this, [ args ]);
const party = thisArg.getParty();
const modifierTypes = modifierSelectUiHandler.options.map(o => o.modifierType);
const faintedPartyMemberIndex = party.findIndex(p => !p.hp);
const lowHpPartyMemberIndex = party.findIndex(p => (p.hp / p.getMaxHp()) <= 0.5);
const criticalHpPartyMemberIndex = party.findIndex(p => (p.hp / p.getMaxHp()) <= 0.25);
let optionIndex = tryGetBestModifier(modifierTypes, (modifierType: ModifierType) => {
if (modifierType instanceof PokemonHpRestoreModifierType) {
if (modifierType instanceof PokemonReviveModifierType) {
if (faintedPartyMemberIndex > -1) {
nextPartyMemberIndex = faintedPartyMemberIndex;
return true;
}
} else if (criticalHpPartyMemberIndex > -1){
nextPartyMemberIndex = faintedPartyMemberIndex;
return true;
}
}
});
if (optionIndex === -1) {
optionIndex = tryGetBestModifier(modifierTypes, (modifierType: ModifierType) => {
if (modifierType.tier >= ModifierTier.ULTRA) {
nextPartyMemberIndex = 0;
return true;
}
});
}
if (optionIndex === -1) {
optionIndex = tryGetBestModifier(modifierTypes, (modifierType: ModifierType) => {
if (modifierType instanceof PokemonBaseStatBoosterModifierType) {
nextPartyMemberIndex = 0;
return true;
}
});
}
if (optionIndex === -1) {
optionIndex = tryGetBestModifier(modifierTypes, (modifierType: ModifierType) => {
if (lowHpPartyMemberIndex && modifierType instanceof PokemonHpRestoreModifierType && !(ModifierType instanceof PokemonReviveModifierType)) {
nextPartyMemberIndex = lowHpPartyMemberIndex;
return true;
}
});
}
if (optionIndex === -1)
optionIndex = 0;
const trySelectModifier = () => {
modifierSelectUiHandler.setCursor(optionIndex);
thisArg.time.delayedCall(20, () => {
modifierSelectUiHandler.processInput(keyCodes.Z);
thisArg.time.delayedCall(100, () => {
console.log(modifierTypes[optionIndex]?.name);
if (thisArg.getCurrentPhase() instanceof SelectModifierPhase) {
if (optionIndex < modifierSelectUiHandler.options.length - 1) {
optionIndex++;
trySelectModifier();
} else
modifierSelectUiHandler.processInput(keyCodes.X);
}
});
});
};
thisArg.time.delayedCall(4000, () => trySelectModifier());
}
}

View File

@ -74,23 +74,26 @@ export class NextEncounterPhase extends BattlePhase {
this.scene.getEnemyPokemon().destroy();
const newEnemyPokemon = new EnemyPokemon(this.scene, this.scene.randomSpecies(true), this.scene.getLevelForWave());
this.scene.setEnemyPokemon(newEnemyPokemon);
this.scene.field.add(newEnemyPokemon);
this.scene.field.moveBelow(newEnemyPokemon, this.scene.getPlayerPokemon());
newEnemyPokemon.tint(0, 0.5);
this.scene.tweens.add({
targets: [ this.scene.arenaEnemy, this.scene.arenaEnemy2, newEnemyPokemon ],
x: '+=300',
duration: 2000,
onComplete: () => {
this.scene.arenaEnemy.setX(this.scene.arenaEnemy2.x);
this.scene.arenaEnemy2.setX(this.scene.arenaEnemy2.x - 300);
newEnemyPokemon.untint(100, 'Sine.easeOut');
newEnemyPokemon.cry();
newEnemyPokemon.showInfo();
this.scene.ui.showText(`A wild ${newEnemyPokemon.name} appeared!`, null, () => this.end(), 1500);
}
});
newEnemyPokemon.loadAssets().then(() => {
this.scene.setEnemyPokemon(newEnemyPokemon);
this.scene.field.add(newEnemyPokemon);
this.scene.field.moveBelow(newEnemyPokemon, this.scene.getPlayerPokemon());
newEnemyPokemon.tint(0, 0.5);
this.scene.tweens.add({
targets: [ this.scene.arenaEnemy, this.scene.arenaEnemy2, newEnemyPokemon ],
x: '+=300',
duration: 2000,
onComplete: () => {
this.scene.arenaEnemy.setX(this.scene.arenaEnemy2.x);
this.scene.arenaEnemy2.setX(this.scene.arenaEnemy2.x - 300);
newEnemyPokemon.untint(100, 'Sine.easeOut');
newEnemyPokemon.cry();
newEnemyPokemon.showInfo();
this.scene.ui.showText(`A wild ${newEnemyPokemon.name} appeared!`, null, () => this.end(), 1500);
}
});
});
this.scene.load.start();
}
end() {
@ -241,7 +244,7 @@ export class CheckSwitchPhase extends BattlePhase {
start() {
super.start();
this.scene.ui.showText('Will you switch\nPokémon?', null, () => {
this.scene.ui.showText('Will you switch\nPOKéMON?', null, () => {
this.scene.ui.setMode(Mode.SWITCH_CHECK, () => this.end());
});
}
@ -340,6 +343,8 @@ abstract class MovePhase extends BattlePhase {
this.end();
return;
}
if (!this.move)
console.log(this.pokemon.moveset);
this.scene.ui.showText(`${this.pokemon.name} used\n${this.move.getName()}!`, null, () => this.end(), 500);
if (this.move.getMove().category !== MOVE_CATEGORY.STATUS)
this.scene.unshiftPhase(this.getDamagePhase());

View File

@ -3,13 +3,17 @@ import { ArenaType, Arena } from './arena';
import UI from './ui/ui';
import { BattlePhase, EncounterPhase, SummonPhase, CommandPhase } from './battle-phase';
import { PlayerPokemon, EnemyPokemon } from './pokemon';
import PokemonSpecies, { default as Pokemon, allSpecies } from './pokemon-species';
import PokemonSpecies, { allSpecies, getPokemonSpecies } from './pokemon-species';
import * as Utils from './utils';
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonModifierType, PokemonModifier } from './modifier';
import { Stat } from './pokemon-stat';
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonModifier } from './modifier';
import { PokeballType } from './pokeball';
import { Species } from './species';
import { initAutoPlay } from './auto-play';
export default class BattleScene extends Phaser.Scene {
private auto: boolean;
private autoSpeed: integer = 10;
private phaseQueue: Array<BattlePhase>;
private phaseQueuePrepend: Array<BattlePhase>;
private currentPhase: BattlePhase;
@ -190,7 +194,7 @@ export default class BattleScene extends Phaser.Scene {
new Arena(this, ArenaType.ARENA_PINK, 'elite_4'),
new Arena(this, ArenaType.ARENA_ORANGE, 'elite_5')
];
const arena = arenas[Utils.randInt(15)];
const arena = arenas[0];//arenas[Utils.randInt(15)];
this.arena = arena;
@ -218,17 +222,20 @@ export default class BattleScene extends Phaser.Scene {
this.modifiers = [];
this.modifierBar = new ModifierBar(this);
this.add.existing(this.modifierBar);
uiContainer.add(this.modifierBar);
this.add.existing(this.modifierBar);
uiContainer.add(this.modifierBar);
this.waveIndex = 1;
this.party = [];
let loadPokemonAssets = [];
for (let s = 0; s < 3; s++) {
const playerSpecies = this.randomSpecies();
const playerSpecies = getPokemonSpecies(s === 0 ? Species.TORCHIC : s === 1 ? Species.TREECKO : Species.MUDKIP); //this.randomSpecies();
const playerPokemon = new PlayerPokemon(this, playerSpecies, 5);
playerPokemon.setVisible(false);
loadPokemonAssets.push(playerPokemon.loadAssets());
this.party.push(playerPokemon);
}
@ -236,6 +243,7 @@ export default class BattleScene extends Phaser.Scene {
const enemySpecies = arena.randomSpecies(1);
console.log(enemySpecies.name);
const enemyPokemon = new EnemyPokemon(this, enemySpecies, this.getLevelForWave());
loadPokemonAssets.push(enemyPokemon.loadAssets());
this.add.existing(enemyPokemon);
this.enemyPokemon = enemyPokemon;
@ -274,16 +282,22 @@ export default class BattleScene extends Phaser.Scene {
ui.setup();
this.phaseQueue.push(new EncounterPhase(this), new SummonPhase(this));
this.shiftPhase();
this.upKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.UP);
this.downKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.DOWN);
this.leftKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.LEFT);
this.rightKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.RIGHT);
this.actionKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Z);
this.cancelKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.X);
Promise.all(loadPokemonAssets).then(() => {
if (this.auto)
initAutoPlay.apply(this, [ this.autoSpeed ]);
this.phaseQueue.push(new EncounterPhase(this), new SummonPhase(this));
this.shiftPhase();
});
this.load.start();
}
update() {
@ -313,16 +327,14 @@ export default class BattleScene extends Phaser.Scene {
}
getLevelForWave() {
if (this.waveIndex === 1)
return 5;
let averageLevel = 5 + this.waveIndex * 0.5;
let averageLevel = 1 + this.waveIndex * 0.25;
if (this.waveIndex % 10 === 0)
return averageLevel + 5;
return Math.floor(averageLevel * 1.25);
const deviation = 10 / this.waveIndex;
return averageLevel + Math.round(Utils.randGauss(deviation));
return Math.max(Math.round(averageLevel + Utils.randGauss(deviation)), 1);
}
checkInput(): boolean {

View File

@ -334,7 +334,7 @@ export abstract class PokemonModifierType extends ModifierType {
}
}
class PokemonHpRestoreModifierType extends PokemonModifierType {
export class PokemonHpRestoreModifierType extends PokemonModifierType {
protected restorePercent: integer;
constructor(name: string, restorePercent: integer, iconImage?: string) {
@ -349,7 +349,7 @@ class PokemonHpRestoreModifierType extends PokemonModifierType {
}
}
class PokemonReviveModifierType extends PokemonHpRestoreModifierType {
export class PokemonReviveModifierType extends PokemonHpRestoreModifierType {
constructor(name: string, restorePercent: integer, iconImage?: string) {
super(name, restorePercent, iconImage);
@ -362,7 +362,7 @@ class PokemonReviveModifierType extends PokemonHpRestoreModifierType {
}
}
class PokemonBaseStatBoosterModifierType extends PokemonModifierType {
export class PokemonBaseStatBoosterModifierType extends PokemonModifierType {
private stat: Stat;
constructor(name: string, stat: Stat, _iconImage?: string) {

View File

@ -219,7 +219,7 @@ export enum Moves {
PROTECT,
MACH_PUNCH,
SCARY_FACE,
FAINT_ATTACK,
FEINT_ATTACK,
SWEET_KISS,
BELLY_DRUM,
SLUDGE_BOMB,
@ -781,7 +781,7 @@ export const allMoves = [
[ Moves.PROTECT, "Protect", Type.NORMAL, MOVE_CATEGORY.STATUS, -1, -1, 10, "TM07", "Protects the user, but may fail if used consecutively.", -1, 2 ],
[ Moves.MACH_PUNCH, "Mach Punch", Type.FIGHTING, MOVE_CATEGORY.PHYSICAL, 40, 100, 30, "", "User attacks first.", -1, 2 ],
[ Moves.SCARY_FACE, "Scary Face", Type.NORMAL, MOVE_CATEGORY.STATUS, -1, 100, 10, "TM06", "Sharply lowers opponent's Speed.", -1, 2 ],
[ Moves.FAINT_ATTACK, "Faint Attack", Type.DARK, MOVE_CATEGORY.PHYSICAL, 60, 999, 20, "", "Ignores Accuracy and Evasiveness.", -1, 2 ],
[ Moves.FEINT_ATTACK, "Feint Attack", Type.DARK, MOVE_CATEGORY.PHYSICAL, 60, 999, 20, "", "Ignores Accuracy and Evasiveness.", -1, 2 ],
[ Moves.SWEET_KISS, "Sweet Kiss", Type.FAIRY, MOVE_CATEGORY.STATUS, -1, 75, 10, "", "Confuses opponent.", -1, 2 ],
[ Moves.BELLY_DRUM, "Belly Drum", Type.NORMAL, MOVE_CATEGORY.STATUS, -1, -1, 10, "", "User loses 50% of its max HP, but Attack raises to maximum.", -1, 2 ],
[ Moves.SLUDGE_BOMB, "Sludge Bomb", Type.POISON, MOVE_CATEGORY.SPECIAL, 90, 100, 10, "TM148", "May poison opponent.", 30, 2 ],

File diff suppressed because it is too large Load Diff

View File

@ -550,7 +550,7 @@ export const pokemonLevelMoves = {
[ 12, Moves.FIRE_SPIN ],
[ 15, Moves.CONFUSE_RAY ],
[ 18, Moves.IMPRISON ],
[ 20, Moves.FAINT_ATTACK ],
[ 20, Moves.FEINT_ATTACK ],
[ 23, Moves.FLAME_BURST ],
[ 26, Moves.WILL_O_WISP ],
[ 28, Moves.HEX ],
@ -775,7 +775,7 @@ export const pokemonLevelMoves = {
[ 9, Moves.FAKE_OUT ],
[ 14, Moves.FURY_SWIPES ],
[ 17, Moves.SCREECH ],
[ 22, Moves.FAINT_ATTACK ],
[ 22, Moves.FEINT_ATTACK ],
[ 25, Moves.TAUNT ],
[ 30, Moves.PAY_DAY ],
[ 33, Moves.SLASH ],
@ -795,7 +795,7 @@ export const pokemonLevelMoves = {
[ 9, Moves.FAKE_OUT ],
[ 14, Moves.FURY_SWIPES ],
[ 17, Moves.SCREECH ],
[ 22, Moves.FAINT_ATTACK ],
[ 22, Moves.FEINT_ATTACK ],
[ 25, Moves.TAUNT ],
[ 28, Moves.SWIFT ],
[ 32, Moves.POWER_GEM ],
@ -2078,7 +2078,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.SMOG ],
[ 5, Moves.EMBER ],
[ 8, Moves.SMOKESCREEN ],
[ 12, Moves.FAINT_ATTACK ],
[ 12, Moves.FEINT_ATTACK ],
[ 15, Moves.FIRE_SPIN ],
[ 19, Moves.CLEAR_SMOG ],
[ 22, Moves.FLAME_BURST ],
@ -3066,7 +3066,7 @@ export const pokemonLevelMoves = {
[ 12, Moves.ROCK_THROW ],
[ 15, Moves.MIMIC ],
[ 15, Moves.SLAM ],
[ 19, Moves.FAINT_ATTACK ],
[ 19, Moves.FEINT_ATTACK ],
[ 22, Moves.ROCK_TOMB ],
[ 26, Moves.BLOCK ],
[ 29, Moves.ROCK_SLIDE ],
@ -3277,7 +3277,7 @@ export const pokemonLevelMoves = {
[ 9, Moves.PURSUIT ],
[ 13, Moves.QUICK_ATTACK ],
[ 17, Moves.CONFUSE_RAY ],
[ 21, Moves.FAINT_ATTACK ],
[ 21, Moves.FEINT_ATTACK ],
[ 25, Moves.ASSURANCE ],
[ 29, Moves.SCREECH ],
[ 33, Moves.MOONLIGHT ],
@ -3294,7 +3294,7 @@ export const pokemonLevelMoves = {
[ 21, Moves.NIGHT_SHADE ],
[ 25, Moves.ASSURANCE ],
[ 31, Moves.TAUNT ],
[ 35, Moves.FAINT_ATTACK ],
[ 35, Moves.FEINT_ATTACK ],
[ 41, Moves.MEAN_LOOK ],
[ 45, Moves.FOUL_PLAY ],
[ 51, Moves.TAILWIND ],
@ -3432,7 +3432,7 @@ export const pokemonLevelMoves = {
[ 10, Moves.KNOCK_OFF ],
[ 13, Moves.QUICK_ATTACK ],
[ 16, Moves.FURY_CUTTER ],
[ 19, Moves.FAINT_ATTACK ],
[ 19, Moves.FEINT_ATTACK ],
[ 22, Moves.ACROBATICS ],
[ 27, Moves.SLASH ],
[ 30, Moves.U_TURN ],
@ -3585,7 +3585,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.TAUNT ],
[ 1, Moves.SCRATCH ],
[ 8, Moves.QUICK_ATTACK ],
[ 10, Moves.FAINT_ATTACK ],
[ 10, Moves.FEINT_ATTACK ],
[ 14, Moves.ICY_WIND ],
[ 16, Moves.FURY_SWIPES ],
[ 20, Moves.AGILITY ],
@ -3605,7 +3605,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.LICK ],
[ 1, Moves.COVET ],
[ 8, Moves.FURY_SWIPES ],
[ 15, Moves.FAINT_ATTACK ],
[ 15, Moves.FEINT_ATTACK ],
[ 22, Moves.SWEET_SCENT ],
[ 29, Moves.SLASH ],
[ 36, Moves.CHARM ],
@ -3621,7 +3621,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.LICK ],
[ 1, Moves.COVET ],
[ 8, Moves.FURY_SWIPES ],
[ 15, Moves.FAINT_ATTACK ],
[ 15, Moves.FEINT_ATTACK ],
[ 22, Moves.SWEET_SCENT ],
[ 29, Moves.SLASH ],
[ 38, Moves.SCARY_FACE ],
@ -3810,7 +3810,7 @@ export const pokemonLevelMoves = {
[ 20, Moves.ODOR_SLEUTH ],
[ 25, Moves.BEAT_UP ],
[ 28, Moves.FIRE_FANG ],
[ 32, Moves.FAINT_ATTACK ],
[ 32, Moves.FEINT_ATTACK ],
[ 37, Moves.EMBARGO ],
[ 40, Moves.FOUL_PLAY ],
[ 44, Moves.FLAMETHROWER ],
@ -3831,7 +3831,7 @@ export const pokemonLevelMoves = {
[ 20, Moves.ODOR_SLEUTH ],
[ 26, Moves.BEAT_UP ],
[ 30, Moves.FIRE_FANG ],
[ 35, Moves.FAINT_ATTACK ],
[ 35, Moves.FEINT_ATTACK ],
[ 41, Moves.EMBARGO ],
[ 45, Moves.FOUL_PLAY ],
[ 50, Moves.FLAMETHROWER ],
@ -3999,7 +3999,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.SMOG ],
[ 5, Moves.EMBER ],
[ 8, Moves.SMOKESCREEN ],
[ 12, Moves.FAINT_ATTACK ],
[ 12, Moves.FEINT_ATTACK ],
[ 15, Moves.FIRE_SPIN ],
[ 19, Moves.CLEAR_SMOG ],
[ 22, Moves.FLAME_BURST ],
@ -4509,7 +4509,7 @@ export const pokemonLevelMoves = {
[ 13, Moves.NATURE_POWER ],
[ 19, Moves.FAKE_OUT ],
[ 25, Moves.TORMENT ],
[ 31, Moves.FAINT_ATTACK ],
[ 31, Moves.FEINT_ATTACK ],
[ 37, Moves.RAZOR_WIND ],
[ 43, Moves.SWAGGER ],
[ 49, Moves.EXTRASENSORY ]
@ -4518,7 +4518,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.WHIRLWIND ],
[ 1, Moves.NASTY_PLOT ],
[ 1, Moves.RAZOR_LEAF ],
[ 1, Moves.FAINT_ATTACK ],
[ 1, Moves.FEINT_ATTACK ],
[ 19, Moves.LEAF_TORNADO ],
[ 49, Moves.LEAF_STORM ]
],
@ -4711,7 +4711,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.SCRATCH ],
[ 7, Moves.ENCORE ],
[ 13, Moves.SLACK_OFF ],
[ 19, Moves.FAINT_ATTACK ],
[ 19, Moves.FEINT_ATTACK ],
[ 25, Moves.AMNESIA ],
[ 31, Moves.COVET ],
[ 37, Moves.CHIP_AWAY ],
@ -4740,7 +4740,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.SCRATCH ],
[ 7, Moves.ENCORE ],
[ 13, Moves.SLACK_OFF ],
[ 19, Moves.FAINT_ATTACK ],
[ 19, Moves.FEINT_ATTACK ],
[ 25, Moves.AMNESIA ],
[ 31, Moves.COVET ],
[ 36, Moves.SWAGGER ],
@ -4934,7 +4934,7 @@ export const pokemonLevelMoves = {
[ 18, Moves.COPYCAT ],
[ 22, Moves.ASSIST ],
[ 25, Moves.CHARM ],
[ 29, Moves.FAINT_ATTACK ],
[ 29, Moves.FEINT_ATTACK ],
[ 32, Moves.WAKE_UP_SLAP ],
[ 36, Moves.COVET ],
[ 39, Moves.HEAL_BELL ],
@ -4958,7 +4958,7 @@ export const pokemonLevelMoves = {
[ 22, Moves.DETECT ],
[ 25, Moves.SHADOW_SNEAK ],
[ 29, Moves.KNOCK_OFF ],
[ 32, Moves.FAINT_ATTACK ],
[ 32, Moves.FEINT_ATTACK ],
[ 36, Moves.PUNISHMENT ],
[ 39, Moves.SHADOW_CLAW ],
[ 43, Moves.POWER_GEM ],
@ -4974,7 +4974,7 @@ export const pokemonLevelMoves = {
[ 11, Moves.BITE ],
[ 16, Moves.SWEET_SCENT ],
[ 21, Moves.VISE_GRIP ],
[ 26, Moves.FAINT_ATTACK ],
[ 26, Moves.FEINT_ATTACK ],
[ 31, Moves.BATON_PASS ],
[ 36, Moves.CRUNCH ],
[ 41, Moves.IRON_DEFENSE ],
@ -5415,7 +5415,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.TACKLE ],
[ 5, Moves.UPROAR ],
[ 10, Moves.COPYCAT ],
[ 14, Moves.FAINT_ATTACK ],
[ 14, Moves.FEINT_ATTACK ],
[ 19, Moves.PSYBEAM ],
[ 23, Moves.HYPNOSIS ],
[ 28, Moves.DIZZY_PUNCH ],
@ -5429,7 +5429,7 @@ export const pokemonLevelMoves = {
[Species.TRAPINCH]: [
[ 1, Moves.BITE ],
[ 4, Moves.SAND_ATTACK ],
[ 7, Moves.FAINT_ATTACK ],
[ 7, Moves.FEINT_ATTACK ],
[ 10, Moves.SAND_TOMB ],
[ 13, Moves.MUD_SLAP ],
[ 17, Moves.BIDE ],
@ -5448,10 +5448,10 @@ export const pokemonLevelMoves = {
[Species.VIBRAVA]: [
[ 1, Moves.SAND_ATTACK ],
[ 1, Moves.SAND_TOMB ],
[ 1, Moves.FAINT_ATTACK ],
[ 1, Moves.FEINT_ATTACK ],
[ 1, Moves.SONIC_BOOM ],
[ 4, Moves.SAND_ATTACK ],
[ 7, Moves.FAINT_ATTACK ],
[ 7, Moves.FEINT_ATTACK ],
[ 10, Moves.SAND_TOMB ],
[ 13, Moves.MUD_SLAP ],
[ 17, Moves.BIDE ],
@ -5467,10 +5467,10 @@ export const pokemonLevelMoves = {
[Species.FLYGON]: [
[ 1, Moves.SAND_ATTACK ],
[ 1, Moves.SAND_TOMB ],
[ 1, Moves.FAINT_ATTACK ],
[ 1, Moves.FEINT_ATTACK ],
[ 1, Moves.SONIC_BOOM ],
[ 4, Moves.SAND_ATTACK ],
[ 7, Moves.FAINT_ATTACK ],
[ 7, Moves.FEINT_ATTACK ],
[ 10, Moves.SAND_TOMB ],
[ 13, Moves.MUD_SLAP ],
[ 17, Moves.BIDE ],
@ -5494,7 +5494,7 @@ export const pokemonLevelMoves = {
[ 17, Moves.SAND_ATTACK ],
[ 21, Moves.PIN_MISSILE ],
[ 25, Moves.INGRAIN ],
[ 29, Moves.FAINT_ATTACK ],
[ 29, Moves.FEINT_ATTACK ],
[ 33, Moves.SPIKES ],
[ 37, Moves.SUCKER_PUNCH ],
[ 41, Moves.PAYBACK ],
@ -5515,7 +5515,7 @@ export const pokemonLevelMoves = {
[ 17, Moves.SAND_ATTACK ],
[ 21, Moves.PIN_MISSILE ],
[ 25, Moves.INGRAIN ],
[ 29, Moves.FAINT_ATTACK ],
[ 29, Moves.FEINT_ATTACK ],
[ 35, Moves.SPIKES ],
[ 41, Moves.SUCKER_PUNCH ],
[ 47, Moves.PAYBACK ],
@ -5849,7 +5849,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.ASTONISH ],
[ 1, Moves.THIEF ],
[ 4, Moves.BIND ],
[ 7, Moves.FAINT_ATTACK ],
[ 7, Moves.FEINT_ATTACK ],
[ 10, Moves.FURY_SWIPES ],
[ 14, Moves.FEINT ],
[ 18, Moves.PSYBEAM ],
@ -5870,7 +5870,7 @@ export const pokemonLevelMoves = {
[ 13, Moves.WILL_O_WISP ],
[ 16, Moves.SHADOW_SNEAK ],
[ 19, Moves.CURSE ],
[ 22, Moves.FAINT_ATTACK ],
[ 22, Moves.FEINT_ATTACK ],
[ 26, Moves.HEX ],
[ 30, Moves.SHADOW_BALL ],
[ 34, Moves.SUCKER_PUNCH ],
@ -5890,7 +5890,7 @@ export const pokemonLevelMoves = {
[ 13, Moves.WILL_O_WISP ],
[ 16, Moves.SHADOW_SNEAK ],
[ 19, Moves.CURSE ],
[ 22, Moves.FAINT_ATTACK ],
[ 22, Moves.FEINT_ATTACK ],
[ 26, Moves.HEX ],
[ 30, Moves.SHADOW_BALL ],
[ 34, Moves.SUCKER_PUNCH ],
@ -7061,7 +7061,7 @@ export const pokemonLevelMoves = {
[ 5, Moves.SCRATCH ],
[ 8, Moves.GROWL ],
[ 13, Moves.HYPNOSIS ],
[ 17, Moves.FAINT_ATTACK ],
[ 17, Moves.FEINT_ATTACK ],
[ 20, Moves.FURY_SWIPES ],
[ 25, Moves.CHARM ],
[ 29, Moves.ASSIST ],
@ -7078,7 +7078,7 @@ export const pokemonLevelMoves = {
[ 5, Moves.SCRATCH ],
[ 8, Moves.GROWL ],
[ 13, Moves.HYPNOSIS ],
[ 17, Moves.FAINT_ATTACK ],
[ 17, Moves.FEINT_ATTACK ],
[ 20, Moves.FURY_SWIPES ],
[ 25, Moves.CHARM ],
[ 29, Moves.ASSIST ],
@ -7138,7 +7138,7 @@ export const pokemonLevelMoves = {
[ 11, Moves.CONFUSE_RAY ],
[ 15, Moves.PSYWAVE ],
[ 19, Moves.IRON_DEFENSE ],
[ 21, Moves.FAINT_ATTACK ],
[ 21, Moves.FEINT_ATTACK ],
[ 25, Moves.SAFEGUARD ],
[ 29, Moves.FUTURE_SIGHT ],
[ 31, Moves.METAL_SOUND ],
@ -7160,7 +7160,7 @@ export const pokemonLevelMoves = {
[ 11, Moves.CONFUSE_RAY ],
[ 15, Moves.PSYWAVE ],
[ 19, Moves.IRON_DEFENSE ],
[ 21, Moves.FAINT_ATTACK ],
[ 21, Moves.FEINT_ATTACK ],
[ 25, Moves.SAFEGUARD ],
[ 29, Moves.FUTURE_SIGHT ],
[ 31, Moves.METAL_SOUND ],
@ -7178,7 +7178,7 @@ export const pokemonLevelMoves = {
[ 8, Moves.LOW_KICK ],
[ 12, Moves.ROCK_THROW ],
[ 15, Moves.SLAM ],
[ 19, Moves.FAINT_ATTACK ],
[ 19, Moves.FEINT_ATTACK ],
[ 22, Moves.ROCK_TOMB ],
[ 26, Moves.BLOCK ],
[ 29, Moves.ROCK_SLIDE ],
@ -7236,7 +7236,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.CURSE ],
[ 1, Moves.SHADOW_SNEAK ],
[ 1, Moves.PURSUIT ],
[ 7, Moves.FAINT_ATTACK ],
[ 7, Moves.FEINT_ATTACK ],
[ 13, Moves.HYPNOSIS ],
[ 19, Moves.DREAM_EATER ],
[ 25, Moves.OMINOUS_WIND ],
@ -7419,7 +7419,7 @@ export const pokemonLevelMoves = {
[ 8, Moves.POISON_STING ],
[ 10, Moves.TAUNT ],
[ 15, Moves.PURSUIT ],
[ 17, Moves.FAINT_ATTACK ],
[ 17, Moves.FEINT_ATTACK ],
[ 22, Moves.REVENGE ],
[ 24, Moves.SWAGGER ],
[ 29, Moves.MUD_BOMB ],
@ -7438,7 +7438,7 @@ export const pokemonLevelMoves = {
[ 8, Moves.POISON_STING ],
[ 10, Moves.TAUNT ],
[ 15, Moves.PURSUIT ],
[ 17, Moves.FAINT_ATTACK ],
[ 17, Moves.FEINT_ATTACK ],
[ 22, Moves.REVENGE ],
[ 24, Moves.SWAGGER ],
[ 29, Moves.MUD_BOMB ],
@ -7456,7 +7456,7 @@ export const pokemonLevelMoves = {
[ 11, Moves.VINE_WHIP ],
[ 17, Moves.SWEET_SCENT ],
[ 21, Moves.INGRAIN ],
[ 27, Moves.FAINT_ATTACK ],
[ 27, Moves.FEINT_ATTACK ],
[ 31, Moves.LEAF_TORNADO ],
[ 37, Moves.STOCKPILE ],
[ 37, Moves.SWALLOW ],
@ -7556,7 +7556,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.ASSURANCE ],
[ 1, Moves.SCRATCH ],
[ 8, Moves.QUICK_ATTACK ],
[ 10, Moves.FAINT_ATTACK ],
[ 10, Moves.FEINT_ATTACK ],
[ 14, Moves.ICY_WIND ],
[ 16, Moves.FURY_SWIPES ],
[ 20, Moves.NASTY_PLOT ],
@ -7680,7 +7680,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.SMOG ],
[ 5, Moves.EMBER ],
[ 8, Moves.SMOKESCREEN ],
[ 12, Moves.FAINT_ATTACK ],
[ 12, Moves.FEINT_ATTACK ],
[ 15, Moves.FIRE_SPIN ],
[ 19, Moves.CLEAR_SMOG ],
[ 22, Moves.FLAME_BURST ],
@ -7765,7 +7765,7 @@ export const pokemonLevelMoves = {
[ 10, Moves.KNOCK_OFF ],
[ 13, Moves.QUICK_ATTACK ],
[ 16, Moves.FURY_CUTTER ],
[ 19, Moves.FAINT_ATTACK ],
[ 19, Moves.FEINT_ATTACK ],
[ 22, Moves.ACROBATICS ],
[ 27, Moves.NIGHT_SLASH ],
[ 30, Moves.U_TURN ],
@ -8081,7 +8081,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.OMINOUS_WIND ],
[ 11, Moves.QUICK_ATTACK ],
[ 20, Moves.HYPNOSIS ],
[ 29, Moves.FAINT_ATTACK ],
[ 29, Moves.FEINT_ATTACK ],
[ 38, Moves.NIGHTMARE ],
[ 47, Moves.DOUBLE_TEAM ],
[ 57, Moves.HAZE ],
@ -9203,7 +9203,7 @@ export const pokemonLevelMoves = {
[ 5, Moves.ROCK_BLAST ],
[ 7, Moves.WITHDRAW ],
[ 11, Moves.SAND_ATTACK ],
[ 13, Moves.FAINT_ATTACK ],
[ 13, Moves.FEINT_ATTACK ],
[ 17, Moves.SMACK_DOWN ],
[ 19, Moves.ROCK_POLISH ],
[ 23, Moves.BUG_BITE ],
@ -9223,7 +9223,7 @@ export const pokemonLevelMoves = {
[ 5, Moves.ROCK_BLAST ],
[ 7, Moves.WITHDRAW ],
[ 11, Moves.SAND_ATTACK ],
[ 13, Moves.FAINT_ATTACK ],
[ 13, Moves.FEINT_ATTACK ],
[ 17, Moves.SMACK_DOWN ],
[ 19, Moves.ROCK_POLISH ],
[ 23, Moves.BUG_BITE ],
@ -9239,7 +9239,7 @@ export const pokemonLevelMoves = {
[ 1, Moves.LEER ],
[ 1, Moves.LOW_KICK ],
[ 5, Moves.SAND_ATTACK ],
[ 9, Moves.FAINT_ATTACK ],
[ 9, Moves.FEINT_ATTACK ],
[ 12, Moves.HEADBUTT ],
[ 16, Moves.SWAGGER ],
[ 20, Moves.BRICK_BREAK ],
@ -9257,9 +9257,9 @@ export const pokemonLevelMoves = {
[ 1, Moves.SAND_ATTACK ],
[ 1, Moves.LEER ],
[ 1, Moves.LOW_KICK ],
[ 1, Moves.FAINT_ATTACK ],
[ 1, Moves.FEINT_ATTACK ],
[ 5, Moves.SAND_ATTACK ],
[ 9, Moves.FAINT_ATTACK ],
[ 9, Moves.FEINT_ATTACK ],
[ 12, Moves.HEADBUTT ],
[ 16, Moves.SWAGGER ],
[ 20, Moves.BRICK_BREAK ],
@ -9455,7 +9455,7 @@ export const pokemonLevelMoves = {
[ 5, Moves.PURSUIT ],
[ 9, Moves.FAKE_TEARS ],
[ 13, Moves.FURY_SWIPES ],
[ 17, Moves.FAINT_ATTACK ],
[ 17, Moves.FEINT_ATTACK ],
[ 21, Moves.SCARY_FACE ],
[ 25, Moves.TAUNT ],
[ 29, Moves.FOUL_PLAY ],
@ -9476,7 +9476,7 @@ export const pokemonLevelMoves = {
[ 5, Moves.PURSUIT ],
[ 9, Moves.HONE_CLAWS ],
[ 13, Moves.FURY_SWIPES ],
[ 17, Moves.FAINT_ATTACK ],
[ 17, Moves.FEINT_ATTACK ],
[ 21, Moves.SCARY_FACE ],
[ 25, Moves.TAUNT ],
[ 29, Moves.FOUL_PLAY ],
@ -9524,7 +9524,7 @@ export const pokemonLevelMoves = {
[ 14, Moves.DOUBLE_SLAP ],
[ 16, Moves.PSYBEAM ],
[ 19, Moves.EMBARGO ],
[ 24, Moves.FAINT_ATTACK ],
[ 24, Moves.FEINT_ATTACK ],
[ 25, Moves.PSYSHOCK ],
[ 28, Moves.FLATTER ],
[ 31, Moves.FUTURE_SIGHT ],
@ -9545,7 +9545,7 @@ export const pokemonLevelMoves = {
[ 14, Moves.DOUBLE_SLAP ],
[ 16, Moves.PSYBEAM ],
[ 19, Moves.EMBARGO ],
[ 24, Moves.FAINT_ATTACK ],
[ 24, Moves.FEINT_ATTACK ],
[ 25, Moves.PSYSHOCK ],
[ 28, Moves.FLATTER ],
[ 31, Moves.FUTURE_SIGHT ],
@ -9566,7 +9566,7 @@ export const pokemonLevelMoves = {
[ 14, Moves.DOUBLE_SLAP ],
[ 16, Moves.PSYBEAM ],
[ 19, Moves.EMBARGO ],
[ 24, Moves.FAINT_ATTACK ],
[ 24, Moves.FEINT_ATTACK ],
[ 25, Moves.PSYSHOCK ],
[ 28, Moves.FLATTER ],
[ 31, Moves.FUTURE_SIGHT ],
@ -9739,7 +9739,7 @@ export const pokemonLevelMoves = {
[ 7, Moves.SAND_ATTACK ],
[ 10, Moves.DOUBLE_KICK ],
[ 13, Moves.LEECH_SEED ],
[ 16, Moves.FAINT_ATTACK ],
[ 16, Moves.FEINT_ATTACK ],
[ 20, Moves.TAKE_DOWN ],
[ 24, Moves.JUMP_KICK ],
[ 28, Moves.AROMATHERAPY ],
@ -9759,7 +9759,7 @@ export const pokemonLevelMoves = {
[ 7, Moves.SAND_ATTACK ],
[ 10, Moves.DOUBLE_KICK ],
[ 13, Moves.LEECH_SEED ],
[ 16, Moves.FAINT_ATTACK ],
[ 16, Moves.FEINT_ATTACK ],
[ 20, Moves.TAKE_DOWN ],
[ 24, Moves.JUMP_KICK ],
[ 28, Moves.AROMATHERAPY ],
@ -9831,7 +9831,7 @@ export const pokemonLevelMoves = {
[ 12, Moves.BIDE ],
[ 15, Moves.MEGA_DRAIN ],
[ 18, Moves.INGRAIN ],
[ 20, Moves.FAINT_ATTACK ],
[ 20, Moves.FEINT_ATTACK ],
[ 24, Moves.SWEET_SCENT ],
[ 28, Moves.GIGA_DRAIN ],
[ 32, Moves.TOXIC ],
@ -9851,7 +9851,7 @@ export const pokemonLevelMoves = {
[ 12, Moves.BIDE ],
[ 15, Moves.MEGA_DRAIN ],
[ 18, Moves.INGRAIN ],
[ 20, Moves.FAINT_ATTACK ],
[ 20, Moves.FEINT_ATTACK ],
[ 24, Moves.SWEET_SCENT ],
[ 28, Moves.GIGA_DRAIN ],
[ 32, Moves.TOXIC ],
@ -10437,7 +10437,7 @@ export const pokemonLevelMoves = {
[ 6, Moves.LEER ],
[ 9, Moves.FURY_CUTTER ],
[ 14, Moves.TORMENT ],
[ 17, Moves.FAINT_ATTACK ],
[ 17, Moves.FEINT_ATTACK ],
[ 22, Moves.SCARY_FACE ],
[ 25, Moves.METAL_CLAW ],
[ 30, Moves.SLASH ],
@ -10459,7 +10459,7 @@ export const pokemonLevelMoves = {
[ 6, Moves.LEER ],
[ 9, Moves.FURY_CUTTER ],
[ 14, Moves.TORMENT ],
[ 17, Moves.FAINT_ATTACK ],
[ 17, Moves.FEINT_ATTACK ],
[ 22, Moves.SCARY_FACE ],
[ 25, Moves.METAL_CLAW ],
[ 30, Moves.SLASH ],
@ -10534,7 +10534,7 @@ export const pokemonLevelMoves = {
[ 10, Moves.PLUCK ],
[ 14, Moves.NASTY_PLOT ],
[ 19, Moves.FLATTER ],
[ 23, Moves.FAINT_ATTACK ],
[ 23, Moves.FEINT_ATTACK ],
[ 28, Moves.PUNISHMENT ],
[ 32, Moves.DEFOG ],
[ 37, Moves.TAILWIND ],
@ -10554,7 +10554,7 @@ export const pokemonLevelMoves = {
[ 10, Moves.PLUCK ],
[ 14, Moves.NASTY_PLOT ],
[ 19, Moves.FLATTER ],
[ 23, Moves.FAINT_ATTACK ],
[ 23, Moves.FEINT_ATTACK ],
[ 28, Moves.PUNISHMENT ],
[ 32, Moves.DEFOG ],
[ 37, Moves.TAILWIND ],

View File

@ -1,5 +1,5 @@
import { GrowthRate } from './exp';
import { PokemonSpeciesEvolutionCondition, pokemonEvolutions } from './pokemon-evolutions';
import { pokemonEvolutions } from './pokemon-evolutions';
import { Species } from './species';
import { Type } from './type';
import * as Utils from './utils';
@ -69,7 +69,7 @@ export default class PokemonSpecies {
return this.type1 === type || (this.type2 > -1 && this.type2 === type);
}
getSpeciesForLevel(level: integer): Species {
getSpeciesForLevel(level: integer, allowEvolving?: boolean): Species {
const prevolutionLevels = this.getPrevolutionLevels();
if (prevolutionLevels.length) {
@ -80,6 +80,9 @@ export default class PokemonSpecies {
}
}
if (!allowEvolving)
return this.speciesId;
const evolutionLevels = this.getEvolutionLevels();
let speciesIds = [];

View File

@ -114,25 +114,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
tintSprite.setVisible(false);
(this.scene as BattleScene).loadAtlas(this.getSpriteKey(), 'pokemon', this.getAtlasPath());
this.scene.load.audio(this.species.speciesId.toString(), `audio/cry/${this.species.speciesId}.mp3`);
this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => {
const originalWarn = console.warn;
// Ignore warnings for missing frames, because there will be a lot
console.warn = () => {};
const frameNames = this.scene.anims.generateFrameNames(this.getSpriteKey(), { zeroPad: 4, suffix: ".png", start: 1, end: 256 });
console.warn = originalWarn;
this.scene.anims.create({
key: this.getSpriteKey(),
frames: frameNames,
frameRate: 12,
repeat: -1
});
sprite.play(this.getSpriteKey());
tintSprite.play(this.getSpriteKey());
});
this.scene.load.start()
this.add(sprite);
this.add(tintSprite);
@ -156,35 +137,58 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
abstract isPlayer(): boolean;
getAtlasPath() {
loadAssets(): Promise<void> {
return new Promise(resolve => {
(this.scene as BattleScene).loadAtlas(this.getSpriteKey(), 'pokemon', this.getAtlasPath());
this.scene.load.audio(this.species.speciesId.toString(), `audio/cry/${this.species.speciesId}.mp3`);
this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => {
const originalWarn = console.warn;
// Ignore warnings for missing frames, because there will be a lot
console.warn = () => {};
const frameNames = this.scene.anims.generateFrameNames(this.getSpriteKey(), { zeroPad: 4, suffix: ".png", start: 1, end: 256 });
console.warn = originalWarn;
this.scene.anims.create({
key: this.getSpriteKey(),
frames: frameNames,
frameRate: 12,
repeat: -1
});
this.getSprite().play(this.getSpriteKey());
this.getTintSprite().play(this.getSpriteKey());
resolve();
});
});
}
getAtlasPath(): string {
return this.getSpriteId().replace(/\_{2}/g, '/');
}
getSpriteId() {
getSpriteId(): string {
return `${this.isPlayer() ? 'back__' : ''}${this.shiny ? 'shiny__' : ''}${this.species.genderDiffs && !this.gender ? 'female__' : ''}${this.species.speciesId}`;
}
getSpriteKey() {
getSpriteKey(): string {
return `pkmn__${this.getSpriteId()}`;
}
getIconAtlasKey() {
getIconAtlasKey(): string {
return `pokemon_icons_${this.species.generation}`;
}
getIconId() {
getIconId(): string {
return `${Utils.padInt(this.species.speciesId, 3)}`;
}
getIconKey() {
getIconKey(): string {
return `pkmn_icon__${this.getIconId()}`;
}
getSprite() {
getSprite(): Phaser.GameObjects.Sprite {
return this.getAt(0) as Phaser.GameObjects.Sprite;
}
getTintSprite() {
getTintSprite(): Phaser.GameObjects.Sprite {
return this.getAt(1) as Phaser.GameObjects.Sprite;
}
@ -303,7 +307,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
apply(source: Pokemon, battlerMove: PokemonMove, callback?: Function) {
const battleScene = this.scene as BattleScene;
let result: integer;
let sound: Phaser.Sound.BaseSound;
let success = false;
const move = battlerMove.getMove();
const moveCategory = move.category;
@ -390,7 +393,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.scene.sound.play(this.species.speciesId.toString());
}
faintCry(callback) {
faintCry(callback: Function) {
const key = this.species.speciesId.toString();
let i = 0;
let rate = 0.85;
@ -519,7 +522,7 @@ export class EnemyPokemon extends Pokemon {
constructor(scene: BattleScene, species: PokemonSpecies, level: integer) {
super(scene, -63, 86, species, level);
this.aiType = AiType.SMART;
this.aiType = AiType.SMART_RANDOM;
}
getNextMove(): PokemonMove {
@ -530,6 +533,7 @@ export class EnemyPokemon extends Pokemon {
switch (this.aiType) {
case AiType.RANDOM:
return movePool[Utils.randInt(movePool.length)];
case AiType.SMART_RANDOM:
case AiType.SMART:
const target = (this.scene as BattleScene).getPlayerPokemon();
const moveScores = movePool.map(() => 0);
@ -567,19 +571,23 @@ export class EnemyPokemon extends Pokemon {
moveScores[m] = score;
}
}
console.log(moveScores);
const sortedMovePool = movePool.slice(0);
sortedMovePool.sort((a, b) => {
const scoreA = moveScores[movePool.indexOf(a)];
const scoreB = moveScores[movePool.indexOf(b)];
console.log(a, b, scoreA, scoreB)
return scoreA < scoreB ? 1 : scoreA > scoreB ? -1 : 0;
});
let randomBool: integer;
let randInt: integer;
let r = 0;
while (r < sortedMovePool.length - 1 && (randomBool = Utils.randInt(2)))
r++;
if (this.aiType === AiType.SMART_RANDOM) {
while (r < sortedMovePool.length - 1 && (randInt = Utils.randInt(8)) >= 5)
r++;
}
console.log(movePool.map(m => m.getName()), moveScores, r, sortedMovePool.map(m => m.getName()));
return sortedMovePool[r]
return sortedMovePool[r];
}
}
return new PokemonMove(Moves.STRUGGLE, 0, 0);
@ -598,8 +606,9 @@ export class EnemyPokemon extends Pokemon {
}
}
enum AiType {
export enum AiType {
RANDOM,
SMART_RANDOM,
SMART
};

View File

@ -26,41 +26,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
};
if (prompt) {
const originalCallback = callback;
callback = () => {
const wrappedTextLines = this.message.runWordWrap(this.message.text).split(/\n/g);
const textLinesCount = wrappedTextLines.length;
const lastTextLine = wrappedTextLines[wrappedTextLines.length - 1];
const lastLineTest = this.scene.add.text(0, 0, lastTextLine, { font: '96px emerald' });
lastLineTest.setScale(this.message.scale);
const lastLineWidth = lastLineTest.displayWidth;
lastLineTest.destroy();
if (prompt) {
if (this.prompt) {
this.prompt.setPosition(lastLineWidth + 2, (textLinesCount - 1) * 18 + 2);
this.prompt.play('prompt');
}
this.pendingPrompt = false;
}
this.awaitingActionInput = true;
this.onActionInput = () => {
if (this.prompt) {
this.prompt.anims.stop();
this.prompt.setVisible(false);
}
if (originalCallback) {
if (callbackDelay) {
this.textCallbackTimer = this.scene.time.delayedCall(callbackDelay, () => {
if (this.textCallbackTimer) {
this.textCallbackTimer.destroy();
this.textCallbackTimer = null;
}
originalCallback();
});
} else
originalCallback();
}
};
};
callback = () => this.showPrompt(originalCallback, callbackDelay);
}
if (delay) {
this.clearText();
@ -94,6 +60,40 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
}
}
showPrompt(callback: Function, callbackDelay: integer) {
const wrappedTextLines = this.message.runWordWrap(this.message.text).split(/\n/g);
const textLinesCount = wrappedTextLines.length;
const lastTextLine = wrappedTextLines[wrappedTextLines.length - 1];
const lastLineTest = this.scene.add.text(0, 0, lastTextLine, { font: '96px emerald' });
lastLineTest.setScale(this.message.scale);
const lastLineWidth = lastLineTest.displayWidth;
lastLineTest.destroy();
if (this.prompt) {
this.prompt.setPosition(lastLineWidth + 2, (textLinesCount - 1) * 18 + 2);
this.prompt.play('prompt');
}
this.pendingPrompt = false;
this.awaitingActionInput = true;
this.onActionInput = () => {
if (this.prompt) {
this.prompt.anims.stop();
this.prompt.setVisible(false);
}
if (callback) {
if (callbackDelay) {
this.textCallbackTimer = this.scene.time.delayedCall(callbackDelay, () => {
if (this.textCallbackTimer) {
this.textCallbackTimer.destroy();
this.textCallbackTimer = null;
}
callback();
});
} else
callback();
}
};
}
clearText() {
this.message.setText('');
this.pendingPrompt = false;

View File

@ -9,7 +9,7 @@ import { Mode } from "./ui";
export default class ModifierSelectUiHandler extends AwaitableUiHandler {
private overlayBg: Phaser.GameObjects.Rectangle;
private modifierContainer: Phaser.GameObjects.Container;
private options: ModifierOption[];
public options: ModifierOption[];
private cursorObj: Phaser.GameObjects.Image;
@ -66,8 +66,10 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
onUpdate: t => {
const value = t.getValue();
const index = Math.floor(value * types.length);
if (index > i && index <= types.length)
this.options[i++].show(Math.floor((1 - value) * 1250) * 0.325);
if (index > i && index <= types.length) {
const option = this.options[i++];
option?.show(Math.floor((1 - value) * 1250) * 0.325);
}
}
});
@ -225,6 +227,8 @@ class ModifierOption extends Phaser.GameObjects.Container {
duration: 1250,
ease: 'Bounce.Out',
onUpdate: t => {
if (!this.scene)
return;
const value = t.getValue();
if (!bounce && value > lastValue) {
this.scene.sound.play('pb_bounce_1', { volume: 1 / ++bounceCount });
@ -236,6 +240,9 @@ class ModifierOption extends Phaser.GameObjects.Container {
});
this.scene.time.delayedCall(remainingDuration + 2000, () => {
if (!this.scene)
return;
this.pb.setTexture('pb', `${this.getPbAtlasKey()}_open`);
this.scene.sound.play('pb_rel');

View File

@ -63,7 +63,6 @@ export default class PartyUiHandler extends MessageUiHandler {
this.partyMessageBox = partyMessageBox;
const partyMessageText = addTextObject(this.scene, 8, 10, defaultMessage, TextStyle.WINDOW, { maxLines: 2 });
partyMessageText.setPositionRelative
partyMessageText.setOrigin(0, 0);
partyMessageBoxContainer.add(partyMessageText);

View File

@ -5,7 +5,7 @@ export default abstract class UiHandler {
protected scene: BattleScene;
protected mode: integer;
protected cursor: integer = 0;
protected active: boolean = false;
public active: boolean = false;
constructor(scene: BattleScene, mode: Mode) {
this.scene = scene;