Add more logic for trainers (WiP) and various changes

Add WiP logic for trainer Pokemon pools and biome trainer pools; add more music tracks; fix issue with implementation of Mimic move
This commit is contained in:
Flashfyre 2023-10-09 20:20:02 -04:00
parent 5d5c8318fd
commit 6d73d71608
66 changed files with 4313 additions and 191 deletions

2
.gitignore vendored
View File

@ -22,3 +22,5 @@ dist-ssr
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
public/images/trainer/convert/*

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/audio/bgm/heal.mp3 Normal file

Binary file not shown.

View File

@ -1,7 +1,7 @@
{ {
"textures": [ "textures": [
{ {
"image": "battle_girl.png", "image": "black_belt_f.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": { "size": {
"w": 211, "w": 211,

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -1,7 +1,7 @@
{ {
"textures": [ "textures": [
{ {
"image": "blackbelt.png", "image": "black_belt_m.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": { "size": {
"w": 280, "w": 280,

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -1,7 +1,7 @@
{ {
"textures": [ "textures": [
{ {
"image": "socialite.png", "image": "rich_f.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": { "size": {
"w": 216, "w": 216,

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -1,7 +1,7 @@
{ {
"textures": [ "textures": [
{ {
"image": "lady.png", "image": "rich_kid_f.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": { "size": {
"w": 299, "w": 299,

View File

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -1,7 +1,7 @@
{ {
"textures": [ "textures": [
{ {
"image": "rich_boy.png", "image": "rich_kid_m.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": { "size": {
"w": 152, "w": 152,

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,7 +1,7 @@
{ {
"textures": [ "textures": [
{ {
"image": "gentleman.png", "image": "rich_m.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": { "size": {
"w": 308, "w": 308,

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -1,7 +1,7 @@
{ {
"textures": [ "textures": [
{ {
"image": "lass.png", "image": "youngster_f.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": { "size": {
"w": 218, "w": 218,

View File

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -1,7 +1,7 @@
{ {
"textures": [ "textures": [
{ {
"image": "youngster.png", "image": "youngster_m.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": { "size": {
"w": 125, "w": 125,

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,6 +1,6 @@
import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
import BattleScene from "./battle-scene"; import BattleScene from "./battle-scene";
import { Biome, BiomePoolTier, BiomeTierPools, biomePools } from "./data/biome"; import { Biome, BiomePoolTier, BiomeTierPokemonPools, biomePokemonPools } from "./data/biome";
import * as Utils from "./utils"; import * as Utils from "./utils";
import PokemonSpecies, { getPokemonSpecies } from "./data/pokemon-species"; import PokemonSpecies, { getPokemonSpecies } from "./data/pokemon-species";
import { Species } from "./data/species"; import { Species } from "./data/species";
@ -17,16 +17,16 @@ export class Arena {
public biomeType: Biome; public biomeType: Biome;
public weather: Weather; public weather: Weather;
public tags: ArenaTag[]; public tags: ArenaTag[];
private bgm: string; public bgm: string;
private pokemonPool: BiomeTierPools; private pokemonPool: BiomeTierPokemonPools;
constructor(scene: BattleScene, biome: Biome, bgm: string) { constructor(scene: BattleScene, biome: Biome, bgm: string) {
this.scene = scene; this.scene = scene;
this.biomeType = biome; this.biomeType = biome;
this.tags = []; this.tags = [];
this.bgm = bgm; this.bgm = bgm;
this.pokemonPool = biomePools[biome]; this.pokemonPool = biomePokemonPools[biome];
} }
randomSpecies(waveIndex: integer, level: integer, attempt?: integer): PokemonSpecies { randomSpecies(waveIndex: integer, level: integer, attempt?: integer): PokemonSpecies {
@ -238,20 +238,6 @@ export class Arena {
this.scene.loadBgm(this.bgm); this.scene.loadBgm(this.bgm);
} }
playBgm(): void {
this.scene.loadBgm(this.bgm);
this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => this.scene.playBgm(this.bgm, this.getBgmLoopPoint()));
if (!this.scene.load.isLoading())
this.scene.load.start();
}
fadeOutBgm(duration: integer, destroy?: boolean): void {
if (destroy === undefined)
destroy = true;
const bgm = this.scene.sound.get(this.bgm);
SoundFade.fadeOut(this.scene, bgm, duration, destroy);
}
getBgmLoopPoint(): number { getBgmLoopPoint(): number {
switch (this.biomeType) { switch (this.biomeType) {
case Biome.TOWN: case Biome.TOWN:

View File

@ -1,7 +1,7 @@
import BattleScene, { startingLevel, startingWave } from "./battle-scene"; import BattleScene, { startingLevel, startingWave } from "./battle-scene";
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult } from "./pokemon"; import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult } from "./pokemon";
import * as Utils from './utils'; import * as Utils from './utils';
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveCategory, MoveEffectAttr, MoveFlags, Moves, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger } from "./data/move"; import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveCategory, MoveEffectAttr, MoveFlags, Moves, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr } from "./data/move";
import { Mode } from './ui/ui'; import { Mode } from './ui/ui';
import { Command } from "./ui/command-ui-handler"; import { Command } from "./ui/command-ui-handler";
import { Stat } from "./data/pokemon-stat"; import { Stat } from "./data/pokemon-stat";
@ -72,7 +72,7 @@ export class CheckLoadPhase extends BattlePhase {
this.scene.arena.preloadBgm(); this.scene.arena.preloadBgm();
this.scene.pushPhase(new SelectStarterPhase(this.scene)); this.scene.pushPhase(new SelectStarterPhase(this.scene));
} else } else
this.scene.arena.playBgm(); this.scene.playBgm();
const availablePartyMembers = this.scene.getParty().filter(p => !p.isFainted()).length; const availablePartyMembers = this.scene.getParty().filter(p => !p.isFainted()).length;
@ -116,7 +116,7 @@ export class SelectStarterPhase extends BattlePhase {
this.scene.ui.clearText(); this.scene.ui.clearText();
this.scene.ui.setMode(Mode.MESSAGE).then(() => { this.scene.ui.setMode(Mode.MESSAGE).then(() => {
SoundFade.fadeOut(this.scene.sound.get('menu'), 500, true); SoundFade.fadeOut(this.scene.sound.get('menu'), 500, true);
this.scene.time.delayedCall(500, () => this.scene.arena.playBgm()); this.scene.time.delayedCall(500, () => this.scene.playBgm());
this.end(); this.end();
}); });
}); });
@ -237,7 +237,9 @@ export class EncounterPhase extends BattlePhase {
const battle = this.scene.currentBattle; const battle = this.scene.currentBattle;
battle.enemyLevels.forEach((level, e) => { battle.enemyLevels.forEach((level, e) => {
const enemySpecies = this.scene.randomSpecies(battle.waveIndex, level, true); const enemySpecies = battle.battleType === BattleType.TRAINER
? this.scene.currentBattle.trainer.genPartyMemberSpecies(level)
: this.scene.randomSpecies(battle.waveIndex, level, null, true);
if (!this.loaded) if (!this.loaded)
battle.enemyParty[e] = new EnemyPokemon(this.scene, enemySpecies, level); battle.enemyParty[e] = new EnemyPokemon(this.scene, enemySpecies, level);
const enemyPokemon = this.scene.getEnemyParty()[e]; const enemyPokemon = this.scene.getEnemyParty()[e];
@ -287,6 +289,8 @@ export class EncounterPhase extends BattlePhase {
} }
doEncounter() { doEncounter() {
this.scene.playBgm(undefined, true);
if (startingWave > 10) { if (startingWave > 10) {
for (let m = 0; m < Math.min(Math.floor(startingWave / 10), 99); m++) for (let m = 0; m < Math.min(Math.floor(startingWave / 10), 99); m++)
this.scene.addModifier(getPlayerModifierTypeOptionsForWave((m + 1) * 10, 1, this.scene.getParty())[0].type.newModifier()); this.scene.addModifier(getPlayerModifierTypeOptionsForWave((m + 1) * 10, 1, this.scene.getParty())[0].type.newModifier());
@ -360,6 +364,8 @@ export class NextEncounterPhase extends EncounterPhase {
} }
doEncounter(): void { doEncounter(): void {
this.scene.playBgm(undefined, true);
const enemyField = this.scene.getEnemyField(); const enemyField = this.scene.getEnemyField();
this.scene.tweens.add({ this.scene.tweens.add({
targets: [ this.scene.arenaEnemy, this.scene.arenaNextEnemy, this.scene.currentBattle.trainer, enemyField ].flat(), targets: [ this.scene.arenaEnemy, this.scene.arenaNextEnemy, this.scene.currentBattle.trainer, enemyField ].flat(),
@ -419,7 +425,7 @@ export class SelectBiomePhase extends BattlePhase {
start() { start() {
super.start(); super.start();
this.scene.arena.fadeOutBgm(2000, true); this.scene.fadeOutBgm(2000, true);
const currentBiome = this.scene.arena.biomeType; const currentBiome = this.scene.arena.biomeType;
@ -481,7 +487,7 @@ export class SwitchBiomePhase extends BattlePhase {
this.scene.arenaPlayerTransition.setAlpha(0); this.scene.arenaPlayerTransition.setAlpha(0);
this.scene.arenaPlayerTransition.setVisible(true); this.scene.arenaPlayerTransition.setVisible(true);
this.scene.time.delayedCall(1000, () => this.scene.arena.playBgm()); this.scene.time.delayedCall(1000, () => this.scene.playBgm());
this.scene.tweens.add({ this.scene.tweens.add({
targets: [ this.scene.arenaPlayer, this.scene.arenaBgTransition, this.scene.arenaPlayerTransition ], targets: [ this.scene.arenaPlayer, this.scene.arenaBgTransition, this.scene.arenaPlayerTransition ],
@ -1271,6 +1277,9 @@ export class MovePhase extends BattlePhase {
if (!moveQueue.length || !moveQueue.shift().ignorePP) if (!moveQueue.length || !moveQueue.shift().ignorePP)
this.move.ppUsed++; this.move.ppUsed++;
if (!allMoves[this.move.moveId].getAttrs(CopyMoveAttr).length)
this.scene.currentBattle.lastMove = this.move.moveId;
// Assume conditions affecting targets only apply to moves with a single target // Assume conditions affecting targets only apply to moves with a single target
let success = this.move.getMove().applyConditions(this.pokemon, targets[0], this.move.getMove()); let success = this.move.getMove().applyConditions(this.pokemon, targets[0], this.move.getMove());
if (success && this.scene.arena.isMoveWeatherCancelled(this.move.getMove())) if (success && this.scene.arena.isMoveWeatherCancelled(this.move.getMove()))
@ -1400,12 +1409,12 @@ class MoveEffectPhase extends PokemonPhase {
const isProtected = !this.move.getMove().hasFlag(MoveFlags.IGNORE_PROTECT) && target.lapseTag(BattlerTagType.PROTECTED); const isProtected = !this.move.getMove().hasFlag(MoveFlags.IGNORE_PROTECT) && target.lapseTag(BattlerTagType.PROTECTED);
moveHistoryEntry.result = MoveResult.SUCCESS; moveHistoryEntry.result = MoveResult.SUCCESS;
const hitResult = !isProtected ? target.apply(user, this.move) : HitResult.NO_EFFECT;
applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.PRE_APPLY, applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.PRE_APPLY,
user, target, this.move.getMove()); user, target, this.move.getMove());
const hitResult = !isProtected ? target.apply(user, this.move) : HitResult.NO_EFFECT;
if (hitResult !== HitResult.FAIL) { if (hitResult !== HitResult.FAIL) {
const chargeEffect = !!this.move.getMove().getAttrs(ChargeAttr).find(ca => (ca as ChargeAttr).chargeEffect); const chargeEffect = !!this.move.getMove().getAttrs(ChargeAttr).find(ca => (ca as ChargeAttr).chargeEffect);
// Charge attribute with charge effect takes all effect attributes and applies them to charge stage, so ignore them if this is present // Charge attribute with charge effect takes all effect attributes and applies them to charge stage, so ignore them if this is present

View File

@ -3,7 +3,7 @@ import { Biome } from './data/biome';
import UI from './ui/ui'; import UI from './ui/ui';
import { EncounterPhase, SummonPhase, NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, CheckLoadPhase, TurnInitPhase, ReturnPhase, ToggleDoublePositionPhase, CheckSwitchPhase, LevelCapPhase } from './battle-phases'; import { EncounterPhase, SummonPhase, NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, CheckLoadPhase, TurnInitPhase, ReturnPhase, ToggleDoublePositionPhase, CheckSwitchPhase, LevelCapPhase } from './battle-phases';
import Pokemon, { PlayerPokemon, EnemyPokemon } from './pokemon'; import Pokemon, { PlayerPokemon, EnemyPokemon } from './pokemon';
import PokemonSpecies, { allSpecies, getPokemonSpecies, initSpecies } from './data/pokemon-species'; import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies, initSpecies } from './data/pokemon-species';
import * as Utils from './utils'; import * as Utils from './utils';
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier } from './modifier/modifier'; import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier } from './modifier/modifier';
import { PokeballType } from './data/pokeball'; import { PokeballType } from './data/pokeball';
@ -26,6 +26,8 @@ import PartyExpBar from './ui/party-exp-bar';
import { TrainerType, trainerConfigs } from './data/trainer-type'; import { TrainerType, trainerConfigs } from './data/trainer-type';
import Trainer from './trainer'; import Trainer from './trainer';
import TrainerData from './system/trainer-data'; import TrainerData from './system/trainer-data';
import SoundFade from 'phaser3-rex-plugins/plugins/soundfade';
import { pokemonPrevolutions } from './data/pokemon-evolutions';
const enableAuto = true; const enableAuto = true;
const quickStart = false; const quickStart = false;
@ -289,9 +291,10 @@ export default class BattleScene extends Phaser.Scene {
this.loadSe('pb_lock'); this.loadSe('pb_lock');
this.loadBgm('menu'); this.loadBgm('menu');
this.loadBgm('level_up_fanfare');
this.loadBgm('evolution'); this.loadBgm('level_up_fanfare', 'bw/level_up_fanfare.mp3');
this.loadBgm('evolution_fanfare'); this.loadBgm('evolution', 'bw/evolution.mp3');
this.loadBgm('evolution_fanfare', 'bw/evolution_fanfare.mp3');
populateAnims(); populateAnims();
} }
@ -403,7 +406,7 @@ export default class BattleScene extends Phaser.Scene {
if (this.quickStart) { if (this.quickStart) {
for (let s = 0; s < 3; s++) { for (let s = 0; s < 3; s++) {
const playerSpecies = this.randomSpecies(startingWave, startingLevel, false); const playerSpecies = this.randomSpecies(startingWave, startingLevel, null, false);
const playerPokemon = new PlayerPokemon(this, playerSpecies, startingLevel, 0, 0); const playerPokemon = new PlayerPokemon(this, playerSpecies, startingLevel, 0, 0);
playerPokemon.setVisible(false); playerPokemon.setVisible(false);
this.party.push(playerPokemon); this.party.push(playerPokemon);
@ -554,10 +557,8 @@ export default class BattleScene extends Phaser.Scene {
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance); this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
this.getPlayerField().forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance)); this.getPlayerField().forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance));
newDouble = !Utils.randInt(doubleChance.value); newDouble = !Utils.randInt(doubleChance.value);
} else if (newBattleType === BattleType.TRAINER) { } else if (newBattleType === BattleType.TRAINER)
console.log(newTrainer, newTrainer.config);
newDouble = newTrainer.config.isDouble; newDouble = newTrainer.config.isDouble;
}
} else } else
newDouble = !!double; newDouble = !!double;
@ -585,14 +586,11 @@ export default class BattleScene extends Phaser.Scene {
if (!this.quickStart) if (!this.quickStart)
this.pushPhase(new CheckLoadPhase(this)); this.pushPhase(new CheckLoadPhase(this));
else { else {
this.arena.playBgm();
this.pushPhase(new EncounterPhase(this)); this.pushPhase(new EncounterPhase(this));
this.pushPhase(new SummonPhase(this, 0)); this.pushPhase(new SummonPhase(this, 0));
} }
} }
console.log(lastBattle, newDouble)
if ((lastBattle?.double || false) !== newDouble) { if ((lastBattle?.double || false) !== newDouble) {
const availablePartyMemberCount = this.getParty().filter(p => !p.isFainted()).length; const availablePartyMemberCount = this.getParty().filter(p => !p.isFainted()).length;
if (newDouble) { if (newDouble) {
@ -653,10 +651,15 @@ export default class BattleScene extends Phaser.Scene {
return Math.min(Math.ceil(baseLevel / 2) * 2 + 2, 10000); return Math.min(Math.ceil(baseLevel / 2) * 2 + 2, 10000);
} }
randomSpecies(waveIndex: integer, level: integer, fromArenaPool?: boolean): PokemonSpecies { randomSpecies(waveIndex: integer, level: integer, speciesFilter?: PokemonSpeciesFilter, fromArenaPool?: boolean): PokemonSpecies {
return fromArenaPool if (fromArenaPool)
? this.arena.randomSpecies(waveIndex, level) return this.arena.randomSpecies(waveIndex, level);
: getPokemonSpecies(allSpecies[(Utils.randInt(allSpecies.length)) - 1].getSpeciesForLevel(level)); const filteredSpecies = speciesFilter ? [...new Set(allSpecies.slice(0, -1).filter(speciesFilter).map(s => {
while (pokemonPrevolutions.hasOwnProperty(s.speciesId))
s = getPokemonSpecies(pokemonPrevolutions[s.speciesId]);
return s;
}))] : allSpecies.slice(0, -1);
return getPokemonSpecies(filteredSpecies[Utils.randInt(filteredSpecies.length)].getSpeciesForLevel(level, true));
} }
checkInput(): boolean { checkInput(): boolean {
@ -718,19 +721,53 @@ export default class BattleScene extends Phaser.Scene {
return this.buttonKeys[button].filter(k => k.isDown).length >= 1; return this.buttonKeys[button].filter(k => k.isDown).length >= 1;
} }
playBgm(bgmName?: string, loopPoint?: number): void { playBgm(bgmName?: string, fadeOut?: boolean): void {
if (!bgmName && this.bgm && !this.bgm.pendingRemove) { if (bgmName === undefined)
this.bgm.play({ bgmName = this.currentBattle.getBgmOverride() || this.arena.bgm;
volume: 1 if (this.bgm && bgmName === this.bgm.key) {
}); if (!this.bgm.isPlaying || this.bgm.pendingRemove) {
this.bgm.play({
volume: 1
});
}
return; return;
} }
if (this.bgm && !this.bgm.pendingRemove && this.bgm.isPlaying) if (fadeOut && !this.bgm)
this.bgm.stop(); fadeOut = false;
this.bgm = this.sound.add(bgmName, { loop: true }); this.loadBgm(bgmName);
this.bgm.play(); let loopPoint = 0;
if (loopPoint) loopPoint = bgmName === this.arena.bgm
this.bgm.on('looped', () => this.bgm.play({ seek: loopPoint })); ? this.arena.getBgmLoopPoint()
: this.getBgmLoopPoint(bgmName);
let loaded = false;
const playNewBgm = () => {
if (bgmName === null && this.bgm && !this.bgm.pendingRemove) {
this.bgm.play({
volume: 1
});
return;
}
if (this.bgm && !this.bgm.pendingRemove && this.bgm.isPlaying)
this.bgm.stop();
this.bgm = this.sound.add(bgmName, { loop: true });
this.bgm.play();
if (loopPoint)
this.bgm.on('looped', () => this.bgm.play({ seek: loopPoint }));
};
this.load.once(Phaser.Loader.Events.COMPLETE, () => {
loaded = true;
if (!fadeOut || !this.bgm.isPlaying)
playNewBgm();
});
if (fadeOut) {
this.fadeOutBgm(500, true);
this.time.delayedCall(750, () => {
if (loaded && (!this.bgm.isPlaying || this.bgm.pendingRemove))
playNewBgm();
});
}
if (!this.load.isLoading())
this.load.start();
} }
pauseBgm(): void { pauseBgm(): void {
@ -744,7 +781,14 @@ export default class BattleScene extends Phaser.Scene {
} }
fadeOutBgm(duration?: integer, destroy?: boolean): void { fadeOutBgm(duration?: integer, destroy?: boolean): void {
this.arena.fadeOutBgm(duration || 500, destroy); if (!this.bgm)
return;
if (!duration)
duration = 500;
if (destroy === undefined)
destroy = true;
const bgm = this.sound.get(this.bgm.key);
SoundFade.fadeOut(this, bgm, duration, destroy);
} }
playSoundWithoutBgm(soundName: string, pauseDuration?: integer): void { playSoundWithoutBgm(soundName: string, pauseDuration?: integer): void {
@ -759,6 +803,39 @@ export default class BattleScene extends Phaser.Scene {
}); });
} }
getBgmLoopPoint(bgmName: string): number {
switch (bgmName) {
case 'battle_cynthia':
return 12.235;
case 'battle_elite':
return 17.730;
case 'battle_final':
return 16.453;
case 'battle_gym':
return 19.145;
case 'battle_legendary':
return 13.855;
case 'battle_legendary_k':
return 18.314;
case 'battle_legendary_rz':
return 18.329;
case 'battle_rival':
return 13.689;
case 'battle_rival_2':
return 17.714;
case 'battle_rival_3':
return 17.586;
case 'battle_trainer':
return 13.686;
case 'battle_wild':
return 12.703;
case 'battle_wild_strong':
return 13.940;
}
return 0;
}
getCurrentPhase(): BattlePhase { getCurrentPhase(): BattlePhase {
return this.currentPhase; return this.currentPhase;
} }

View File

@ -3,6 +3,9 @@ import { EnemyPokemon, PlayerPokemon, QueuedMove } from "./pokemon";
import { Command } from "./ui/command-ui-handler"; import { Command } from "./ui/command-ui-handler";
import * as Utils from "./utils"; import * as Utils from "./utils";
import Trainer from "./trainer"; import Trainer from "./trainer";
import { Species } from "./data/species";
import { Moves } from "./data/move";
import { TrainerType } from "./data/trainer-type";
export enum BattleType { export enum BattleType {
WILD, WILD,
@ -40,6 +43,7 @@ export default class Battle {
public turnPokeballCounts: PokeballCounts; public turnPokeballCounts: PokeballCounts;
public playerParticipantIds: Set<integer> = new Set<integer>(); public playerParticipantIds: Set<integer> = new Set<integer>();
public escapeAttempts: integer = 0; public escapeAttempts: integer = 0;
public lastMove: Moves;
constructor(waveIndex: integer, battleType: BattleType, trainer: Trainer, double: boolean) { constructor(waveIndex: integer, battleType: BattleType, trainer: Trainer, double: boolean) {
this.waveIndex = waveIndex; this.waveIndex = waveIndex;
@ -82,4 +86,26 @@ export default class Battle {
removeFaintedParticipant(playerPokemon: PlayerPokemon): void { removeFaintedParticipant(playerPokemon: PlayerPokemon): void {
this.playerParticipantIds.delete(playerPokemon.id); this.playerParticipantIds.delete(playerPokemon.id);
} }
getBgmOverride(): string {
const battlers = this.enemyParty.slice(0, this.getBattlerCount());
for (let pokemon of battlers) {
if (this.battleType === BattleType.TRAINER) {
if (this.trainer.config.trainerType === TrainerType.RIVAL)
return 'battle_rival';
return 'battle_trainer';
}
if (pokemon.species.speciesId === Species.ETERNATUS)
return 'battle_final';
if (pokemon.species.legendary) {
if (pokemon.species.speciesId === Species.RESHIRAM || pokemon.species.speciesId === Species.ZEKROM)
return 'battle_legendary_rz';
if (pokemon.species.speciesId === Species.KYUREM)
return 'battle_legendary_z';
return 'battle_legendary';
}
}
return null;
}
} }

View File

@ -4,6 +4,7 @@ import { Type } from './type';
import * as Utils from '../utils'; import * as Utils from '../utils';
import beautify from 'json-beautify'; import beautify from 'json-beautify';
import { TrainerType } from "./trainer-type";
export enum Biome { export enum Biome {
TOWN, TOWN,
@ -101,15 +102,23 @@ export interface SpeciesTree {
[key: integer]: Species[] [key: integer]: Species[]
} }
export interface BiomeTierPools { export interface BiomeTierPokemonPools {
[key: integer]: Array<Species | SpeciesTree> [key: integer]: Array<Species | SpeciesTree>
} }
export interface BiomePools { export interface BiomePokemonPools {
[key: integer]: BiomeTierPools [key: integer]: BiomeTierPokemonPools
} }
export const biomePools: BiomePools = { export interface BiomeTierTrainerPools {
[key: integer]: TrainerType[]
}
export interface BiomeTrainerPools {
[key: integer]: BiomeTierTrainerPools
}
export const biomePokemonPools: BiomePokemonPools = {
[Biome.TOWN]: { [Biome.TOWN]: {
[BiomePoolTier.COMMON]: [ [BiomePoolTier.COMMON]: [
{ 1: [ Species.CATERPIE ], 7: [ Species.METAPOD ] }, { 1: [ Species.CATERPIE ], 7: [ Species.METAPOD ] },
@ -357,11 +366,10 @@ export const biomePools: BiomePools = {
{ 1: [ Species.STARYU ], 20: [ Species.STARMIE ] }, { 1: [ Species.STARYU ], 20: [ Species.STARMIE ] },
{ 1: [ Species.MAGIKARP ], 20: [ Species.GYARADOS ] }, { 1: [ Species.MAGIKARP ], 20: [ Species.GYARADOS ] },
{ 1: [ Species.WAILMER ], 40: [ Species.WAILORD ] }, { 1: [ Species.WAILMER ], 40: [ Species.WAILORD ] },
{ 1: [ Species.PANPOUR ], 20: [ Species.SIMIPOUR ] }, { 1: [ Species.PANPOUR ], 20: [ Species.SIMIPOUR ] }
{ 1: [ Species.TIRTOUGA ], 37: [ Species.CARRACOSTA ] }
], ],
[BiomePoolTier.RARE]: [ Species.LAPRAS, { 1: [ Species.PIPLUP ], 16: [ Species.PRINPLUP ], 36: [ Species.EMPOLEON ] } ], [BiomePoolTier.RARE]: [ Species.LAPRAS, { 1: [ Species.PIPLUP ], 16: [ Species.PRINPLUP ], 36: [ Species.EMPOLEON ] } ],
[BiomePoolTier.SUPER_RARE]: [ Species.KINGDRA ], [BiomePoolTier.SUPER_RARE]: [ Species.KINGDRA, { 1: [ Species.TIRTOUGA ], 37: [ Species.CARRACOSTA ] } ],
[BiomePoolTier.ULTRA_RARE]: [], [BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ Species.TENTACRUEL, Species.PELIPPER, Species.SHARPEDO, Species.FLOATZEL, Species.LUMINEON, Species.SIMIPOUR ], [BiomePoolTier.BOSS]: [ Species.TENTACRUEL, Species.PELIPPER, Species.SHARPEDO, Species.FLOATZEL, Species.LUMINEON, Species.SIMIPOUR ],
[BiomePoolTier.BOSS_RARE]: [ Species.KINGDRA, Species.EMPOLEON ], [BiomePoolTier.BOSS_RARE]: [ Species.KINGDRA, Species.EMPOLEON ],
@ -399,15 +407,14 @@ export const biomePools: BiomePools = {
{ 1: [ Species.KRABBY ], 28: [ Species.KINGLER ] }, { 1: [ Species.KRABBY ], 28: [ Species.KINGLER ] },
{ 1: [ Species.STARYU ], 20: [ Species.STARMIE ] }, { 1: [ Species.STARYU ], 20: [ Species.STARMIE ] },
{ 1: [ Species.CORPHISH ], 30: [ Species.CRAWDAUNT ] }, { 1: [ Species.CORPHISH ], 30: [ Species.CRAWDAUNT ] },
{ 1: [ Species.DWEBBLE ], 34: [ Species.CRUSTLE ] }, { 1: [ Species.DWEBBLE ], 34: [ Species.CRUSTLE ] }
{ 1: [ Species.TIRTOUGA ], 37: [ Species.CARRACOSTA ] }
], ],
[BiomePoolTier.UNCOMMON]: [ { 1: [ Species.BURMY ], 20: [ Species.WORMADAM ] } ], [BiomePoolTier.UNCOMMON]: [ { 1: [ Species.BURMY ], 20: [ Species.WORMADAM ] } ],
[BiomePoolTier.RARE]: [], [BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [], [BiomePoolTier.SUPER_RARE]: [ { 1: [ Species.TIRTOUGA ], 37: [ Species.CARRACOSTA ] } ],
[BiomePoolTier.ULTRA_RARE]: [ Species.KELDEO ], [BiomePoolTier.ULTRA_RARE]: [ Species.KELDEO ],
[BiomePoolTier.BOSS]: [ Species.CLOYSTER, Species.KINGLER, Species.STARMIE, Species.CRAWDAUNT, Species.WORMADAM, Species.CRUSTLE, Species.CARRACOSTA ], [BiomePoolTier.BOSS]: [ Species.CLOYSTER, Species.KINGLER, Species.STARMIE, Species.CRAWDAUNT, Species.WORMADAM, Species.CRUSTLE ],
[BiomePoolTier.BOSS_RARE]: [], [BiomePoolTier.BOSS_RARE]: [ Species.CARRACOSTA ],
[BiomePoolTier.BOSS_SUPER_RARE]: [ Species.KELDEO ], [BiomePoolTier.BOSS_SUPER_RARE]: [ Species.KELDEO ],
[BiomePoolTier.BOSS_ULTRA_RARE]: [] [BiomePoolTier.BOSS_ULTRA_RARE]: []
}, },
@ -467,6 +474,7 @@ export const biomePools: BiomePools = {
{ 1: [ Species.CRANIDOS ], 30: [ Species.RAMPARDOS ] }, { 1: [ Species.CRANIDOS ], 30: [ Species.RAMPARDOS ] },
{ 1: [ Species.SHIELDON ], 30: [ Species.BASTIODON ] }, { 1: [ Species.SHIELDON ], 30: [ Species.BASTIODON ] },
{ 1: [ Species.GIBLE ], 24: [ Species.GABITE ], 48: [ Species.GARCHOMP ] }, { 1: [ Species.GIBLE ], 24: [ Species.GABITE ], 48: [ Species.GARCHOMP ] },
Species.ARCHEOPS,
{ 1: [ Species.AXEW ], 38: [ Species.FRAXURE ] } { 1: [ Species.AXEW ], 38: [ Species.FRAXURE ] }
], ],
[BiomePoolTier.ULTRA_RARE]: [ Species.TORNADUS ], [BiomePoolTier.ULTRA_RARE]: [ Species.TORNADUS ],
@ -731,6 +739,306 @@ export const biomePools: BiomePools = {
} }
}; };
export const biomeTrainerPools: BiomeTrainerPools = {
[Biome.TOWN]: {
[BiomePoolTier.COMMON]: [ TrainerType.YOUNGSTER ],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.PLAINS]: {
[BiomePoolTier.COMMON]: [ TrainerType.BREEDER, TrainerType.TWINS ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.CYCLIST ],
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.GRASS]: {
[BiomePoolTier.COMMON]: [ TrainerType.BREEDER ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ],
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.TALL_GRASS]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BREEDER, TrainerType.RANGER ],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.CITY]: {
[BiomePoolTier.COMMON]: [ TrainerType.BAKER, TrainerType.OFFICER ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.BREEDER ],
[BiomePoolTier.RARE]: [ TrainerType.ARTIST ],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.FOREST]: {
[BiomePoolTier.COMMON]: [ TrainerType.RANGER ],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.SEA]: {
[BiomePoolTier.COMMON]: [ TrainerType.SWIMMER ],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.SWAMP]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ],
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.BEACH]: {
[BiomePoolTier.COMMON]: [ TrainerType.FISHERMAN, TrainerType.PARASOL_LADY ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BREEDER ],
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.LAKE]: {
[BiomePoolTier.COMMON]: [ TrainerType.BREEDER, TrainerType.FISHERMAN ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ],
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.SEABED]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.MOUNTAIN]: {
[BiomePoolTier.COMMON]: [ TrainerType.BACKPACKER, TrainerType.BLACK_BELT, TrainerType.HIKER ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.BADLANDS]: {
[BiomePoolTier.COMMON]: [ TrainerType.BACKPACKER, TrainerType.HIKER ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.CAVE]: {
[BiomePoolTier.COMMON]: [ TrainerType.BACKPACKER, TrainerType.HIKER ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BLACK_BELT ],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.DESERT]: {
[BiomePoolTier.COMMON]: [ TrainerType.SCIENTIST ],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.ICE_CAVE]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.MEADOW]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BREEDER ],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.POWER_PLANT]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.VOLCANO]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.GRAVEYARD]: {
[BiomePoolTier.COMMON]: [ TrainerType.PSYCHIC ],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.DOJO]: {
[BiomePoolTier.COMMON]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.FACTORY]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.RUINS]: {
[BiomePoolTier.COMMON]: [ TrainerType.PSYCHIC, TrainerType.SCIENTIST ],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BLACK_BELT ],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.WASTELAND]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.ABYSS]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.SPACE]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
},
[Biome.END]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
}
};
{ {
const pokemonBiomes = [ const pokemonBiomes = [
[ Species.BULBASAUR, Type.GRASS, Type.POISON, [ [ Species.BULBASAUR, Type.GRASS, Type.POISON, [
@ -3422,14 +3730,14 @@ export const biomePools: BiomePools = {
] ]
], ],
[ Species.TIRTOUGA, Type.WATER, Type.ROCK, [ [ Species.TIRTOUGA, Type.WATER, Type.ROCK, [
[ Biome.BEACH, BiomePoolTier.COMMON ], [ Biome.SEA, BiomePoolTier.SUPER_RARE ],
[ Biome.SEA, BiomePoolTier.UNCOMMON ] [ Biome.BEACH, BiomePoolTier.SUPER_RARE ]
] ]
], ],
[ Species.CARRACOSTA, Type.WATER, Type.ROCK, [ [ Species.CARRACOSTA, Type.WATER, Type.ROCK, [
[ Biome.BEACH, BiomePoolTier.COMMON ], [ Biome.SEA, BiomePoolTier.SUPER_RARE ],
[ Biome.BEACH, BiomePoolTier.BOSS ], [ Biome.BEACH, BiomePoolTier.SUPER_RARE ],
[ Biome.SEA, BiomePoolTier.UNCOMMON ] [ Biome.BEACH, BiomePoolTier.BOSS_RARE ]
] ]
], ],
[ Species.ARCHEN, Type.ROCK, Type.FLYING, [ [ Species.ARCHEN, Type.ROCK, Type.FLYING, [
@ -3437,6 +3745,7 @@ export const biomePools: BiomePools = {
] ]
], ],
[ Species.ARCHEOPS, Type.ROCK, Type.FLYING, [ [ Species.ARCHEOPS, Type.ROCK, Type.FLYING, [
[ Biome.MOUNTAIN, BiomePoolTier.SUPER_RARE ],
[ Biome.RUINS, BiomePoolTier.SUPER_RARE ], [ Biome.RUINS, BiomePoolTier.SUPER_RARE ],
[ Biome.RUINS, BiomePoolTier.BOSS_RARE ] [ Biome.RUINS, BiomePoolTier.BOSS_RARE ]
] ]
@ -3827,11 +4136,154 @@ export const biomePools: BiomePools = {
] ]
]; ];
for (let biome of Utils.getEnumValues(Biome)) { const trainerBiomes = [
biomePools[biome] = {}; [ TrainerType.ACE_TRAINER, [
[ Biome.PLAINS, BiomePoolTier.UNCOMMON ],
[ Biome.GRASS, BiomePoolTier.UNCOMMON ],
[ Biome.TALL_GRASS, BiomePoolTier.UNCOMMON ],
[ Biome.SWAMP, BiomePoolTier.UNCOMMON ],
[ Biome.BEACH, BiomePoolTier.UNCOMMON ],
[ Biome.LAKE, BiomePoolTier.UNCOMMON ],
[ Biome.MOUNTAIN, BiomePoolTier.UNCOMMON ],
[ Biome.BADLANDS, BiomePoolTier.UNCOMMON ],
[ Biome.CAVE, BiomePoolTier.UNCOMMON ],
[ Biome.MEADOW, BiomePoolTier.UNCOMMON ],
[ Biome.RUINS, BiomePoolTier.UNCOMMON ],
[ Biome.ABYSS, BiomePoolTier.UNCOMMON ]
]
],
[ TrainerType.ARTIST, [
[ Biome.CITY, BiomePoolTier.RARE ]
]
],
[ TrainerType.BACKERS, [] ],
[ TrainerType.BACKPACKER, [
[ Biome.MOUNTAIN, BiomePoolTier.COMMON ],
[ Biome.CAVE, BiomePoolTier.COMMON ],
[ Biome.BADLANDS, BiomePoolTier.COMMON ]
]
],
[ TrainerType.BAKER, [
[ Biome.CITY, BiomePoolTier.COMMON ]
]
],
[ TrainerType.BEAUTY, [] ],
[ TrainerType.BIKER, [] ],
[ TrainerType.BLACK_BELT, [
[ Biome.DOJO, BiomePoolTier.COMMON ],
[ Biome.PLAINS, BiomePoolTier.RARE ],
[ Biome.GRASS, BiomePoolTier.RARE ],
[ Biome.SWAMP, BiomePoolTier.RARE ],
[ Biome.BEACH, BiomePoolTier.RARE ],
[ Biome.LAKE, BiomePoolTier.RARE ],
[ Biome.MOUNTAIN, BiomePoolTier.COMMON ],
[ Biome.CAVE, BiomePoolTier.UNCOMMON ],
[ Biome.RUINS, BiomePoolTier.UNCOMMON ]
]
],
[ TrainerType.BREEDER, [
[ Biome.PLAINS, BiomePoolTier.COMMON ],
[ Biome.GRASS, BiomePoolTier.COMMON ],
[ Biome.TALL_GRASS, BiomePoolTier.UNCOMMON ],
[ Biome.CITY, BiomePoolTier.UNCOMMON ],
[ Biome.BEACH, BiomePoolTier.UNCOMMON ],
[ Biome.LAKE, BiomePoolTier.COMMON ],
[ Biome.MEADOW, BiomePoolTier.UNCOMMON ]
]
],
[ TrainerType.CLERK, [] ],
[ TrainerType.CYCLIST, [
[ Biome.PLAINS, BiomePoolTier.UNCOMMON ]
]
],
[ TrainerType.DANCER, [] ],
[ TrainerType.DEPOT_AGENT, [] ],
[ TrainerType.DOCTOR, [] ],
[ TrainerType.FISHERMAN, [
[ Biome.LAKE, BiomePoolTier.COMMON ],
[ Biome.BEACH, BiomePoolTier.COMMON ]
]
],
[ TrainerType.RICH, [] ],
[ TrainerType.GUITARIST, [] ],
[ TrainerType.HARLEQUIN, [] ],
[ TrainerType.HIKER, [
[ Biome.MOUNTAIN, BiomePoolTier.COMMON ],
[ Biome.CAVE, BiomePoolTier.COMMON ],
[ Biome.BADLANDS, BiomePoolTier.COMMON ]
]
],
[ TrainerType.HOOLIGANS, [] ],
[ TrainerType.HOOPSTER, [] ],
[ TrainerType.INFIELDER, [] ],
[ TrainerType.JANITOR, [] ],
[ TrainerType.LINEBACKER, [] ],
[ TrainerType.MAID, [] ],
[ TrainerType.MUSICIAN, [] ],
[ TrainerType.NURSE, [] ],
[ TrainerType.NURSERY_AIDE, [] ],
[ TrainerType.OFFICER, [
[ Biome.CITY, BiomePoolTier.COMMON ]
]
],
[ TrainerType.PARASOL_LADY, [
[ Biome.BEACH, BiomePoolTier.COMMON ]
]
],
[ TrainerType.PILOT, [] ],
[ TrainerType.POKEFAN, [] ],
[ TrainerType.PRESCHOOLER, [] ],
[ TrainerType.PSYCHIC, [
[ Biome.GRAVEYARD, BiomePoolTier.COMMON ],
[ Biome.RUINS, BiomePoolTier.COMMON ]
]
],
[ TrainerType.RANGER, [
[ Biome.TALL_GRASS, BiomePoolTier.UNCOMMON ],
[ Biome.FOREST, BiomePoolTier.COMMON ]
]
],
[ TrainerType.RICH_KID, [] ],
[ TrainerType.ROUGHNECK, [] ],
[ TrainerType.SCIENTIST, [
[ Biome.DESERT, BiomePoolTier.COMMON ],
[ Biome.RUINS, BiomePoolTier.COMMON ]
]
],
[ TrainerType.SMASHER, [] ],
[ TrainerType.SNOW_WORKER, [
[ Biome.ICE_CAVE ]
]
],
[ TrainerType.STRIKER, [] ],
[ TrainerType.STUDENT, [] ],
[ TrainerType.SWIMMER, [
[ Biome.SEA, BiomePoolTier.COMMON ]
]
],
[ TrainerType.TWINS, [
[ Biome.PLAINS, BiomePoolTier.COMMON ]
]
],
[ TrainerType.VETERAN, [] ],
[ TrainerType.WAITER, [] ],
[ TrainerType.WORKER, [] ],
[ TrainerType.YOUNGSTER, [
[ Biome.TOWN, BiomePoolTier.COMMON ]
]
],
[ TrainerType.RIVAL, [] ],
[ TrainerType.CYNTHIA, [] ]
]
for (let tier of Utils.getEnumValues(BiomePoolTier)) for (let biome of Utils.getEnumValues(Biome)) {
biomePools[biome][tier] = []; biomePokemonPools[biome] = {};
biomeTrainerPools[biome] = {};
for (let tier of Utils.getEnumValues(BiomePoolTier)) {
biomePokemonPools[biome][tier] = [];
biomeTrainerPools[biome][tier] = [];
}
} }
for (let pb of pokemonBiomes) { for (let pb of pokemonBiomes) {
@ -3846,10 +4298,10 @@ export const biomePools: BiomePools = {
const biome = b[0]; const biome = b[0];
const tier = b[1]; const tier = b[1];
if (!biomePools.hasOwnProperty(biome) || !biomePools[biome].hasOwnProperty(tier)) if (!biomePokemonPools.hasOwnProperty(biome) || !biomePokemonPools[biome].hasOwnProperty(tier))
continue; continue;
const biomeTierPool = biomePools[biome][tier]; const biomeTierPool = biomePokemonPools[biome][tier];
let treeIndex = -1; let treeIndex = -1;
let arrayIndex = 0; let arrayIndex = 0;
@ -3881,10 +4333,10 @@ export const biomePools: BiomePools = {
} }
} }
for (let b of Object.keys(biomePools)) { for (let b of Object.keys(biomePokemonPools)) {
for (let t of Object.keys(biomePools[b])) { for (let t of Object.keys(biomePokemonPools[b])) {
const tier = parseInt(t) as BiomePoolTier; const tier = parseInt(t) as BiomePoolTier;
const biomeTierPool = biomePools[b][t]; const biomeTierPool = biomePokemonPools[b][t];
for (let e = 0; e < biomeTierPool.length; e++) { for (let e = 0; e < biomeTierPool.length; e++) {
const entry = biomeTierPool[e]; const entry = biomeTierPool[e];
if (entry.length === 1) if (entry.length === 1)
@ -3908,20 +4360,39 @@ export const biomePools: BiomePools = {
} }
} }
function outputPools() { for (let tb of trainerBiomes) {
const output = {}; const trainerType = tb[0] as TrainerType;
const biomeEntries = tb[1] as BiomePoolTier[][];
for (let b of Object.keys(biomePools)) { for (let b of biomeEntries) {
const biome = b[0];
const tier = b[1];
if (!biomeTrainerPools.hasOwnProperty(biome) || !biomeTrainerPools[biome].hasOwnProperty(tier))
continue;
const biomeTierPool = biomeTrainerPools[biome][tier];
biomeTierPool.push(trainerType);
}
}
function outputPools() {
const pokemonOutput = {};
const trainerOutput = {};
for (let b of Object.keys(biomePokemonPools)) {
const biome = Biome[b]; const biome = Biome[b];
output[biome] = {}; pokemonOutput[biome] = {};
for (let t of Object.keys(biomePools[b])) { trainerOutput[biome] = {};
for (let t of Object.keys(biomePokemonPools[b])) {
const tier = BiomePoolTier[t]; const tier = BiomePoolTier[t];
output[biome][tier] = []; pokemonOutput[biome][tier] = [];
for (let f of biomePools[b][t]) { for (let f of biomePokemonPools[b][t]) {
if (typeof f === 'number') if (typeof f === 'number')
output[biome][tier].push(Species[f]); pokemonOutput[biome][tier].push(Species[f]);
else { else {
const tree = {}; const tree = {};
@ -3929,13 +4400,23 @@ export const biomePools: BiomePools = {
tree[l] = f[l].map(s => Species[s]); tree[l] = f[l].map(s => Species[s]);
} }
output[biome][tier].push(tree); pokemonOutput[biome][tier].push(tree);
} }
} }
} }
for (let t of Object.keys(biomeTrainerPools[b])) {
const tier = BiomePoolTier[t];
trainerOutput[biome][tier] = [];
for (let f of biomeTrainerPools[b][t])
trainerOutput[biome][tier].push(TrainerType[f]);
}
} }
console.log(beautify(output, null, 2, 180).replace(/( | (?:\{ "\d+": \[ )?| "(?:.*?)": \[ |, (?:(?:\{ )?"\d+": \[ )?)"(.*?)"/g, '$1Species.$2').replace(/"(\d+)": /g, '$1: ').replace(/( )"(.*?)"/g, '$1[BiomePoolTier.$2]').replace(/( )"(.*?)"/g, '$1[Biome.$2]')); console.log(beautify(pokemonOutput, null, 2, 180).replace(/( | (?:\{ "\d+": \[ )?| "(?:.*?)": \[ |, (?:(?:\{ )?"\d+": \[ )?)"(.*?)"/g, '$1Species.$2').replace(/"(\d+)": /g, '$1: ').replace(/( )"(.*?)"/g, '$1[BiomePoolTier.$2]').replace(/( )"(.*?)"/g, '$1[Biome.$2]'));
console.log(beautify(trainerOutput, null, 2, 120).replace(/( | (?:\{ "\d+": \[ )?| "(?:.*?)": \[ |, (?:(?:\{ )?"\d+": \[ )?)"(.*?)"/g, '$1TrainerType.$2').replace(/"(\d+)": /g, '$1: ').replace(/( )"(.*?)"/g, '$1[BiomePoolTier.$2]').replace(/( )"(.*?)"/g, '$1[Biome.$2]'));
} }
outputPools(); outputPools();

View File

@ -1990,6 +1990,46 @@ export class RandomMoveAttr extends OverrideMoveEffectAttr {
} }
} }
const lastMoveCopiableCondition = (user: Pokemon, target: Pokemon, move: Move) => {
const copiableMove = user.scene.currentBattle.lastMove;
if (!copiableMove)
return false;
if (allMoves[copiableMove].getAttrs(ChargeAttr).length)
return false;
// TODO: Add last turn of Bide
return true;
};
export class CopyMoveAttr extends OverrideMoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const lastMove = user.scene.currentBattle.lastMove;
const moveTargets = getMoveTargets(user, lastMove);
if (!moveTargets.targets.length)
return false;
const targets = moveTargets.multiple || moveTargets.targets.length === 1
? moveTargets.targets
: moveTargets.targets.indexOf(target.getBattlerIndex()) > -1
? [ target.getBattlerIndex() ]
: [ moveTargets.targets[Utils.randInt(moveTargets.targets.length)] ];
user.getMoveQueue().push({ move: lastMove, targets: targets, ignorePP: true });
user.scene.unshiftPhase(new MovePhase(user.scene, user as PlayerPokemon, targets, new PokemonMove(lastMove, 0, 0, true), true));
return true;
}
getCondition(): MoveCondition {
return lastMoveCopiableCondition;
}
}
// TODO: Review this
const targetMoveCopiableCondition = (user: Pokemon, target: Pokemon, move: Move) => { const targetMoveCopiableCondition = (user: Pokemon, target: Pokemon, move: Move) => {
const targetMoves = target.getMoveHistory().filter(m => !m.virtual); const targetMoves = target.getMoveHistory().filter(m => !m.virtual);
if (!targetMoves.length) if (!targetMoves.length)
@ -2000,7 +2040,7 @@ const targetMoveCopiableCondition = (user: Pokemon, target: Pokemon, move: Move)
if (!copiableMove.move) if (!copiableMove.move)
return false; return false;
if (allMoves[copiableMove.move].getAttrs(ChargeAttr) && copiableMove.result === MoveResult.OTHER) if (allMoves[copiableMove.move].getAttrs(ChargeAttr).length && copiableMove.result === MoveResult.OTHER)
return false; return false;
// TODO: Add last turn of Bide // TODO: Add last turn of Bide
@ -2008,35 +2048,6 @@ const targetMoveCopiableCondition = (user: Pokemon, target: Pokemon, move: Move)
return true; return true;
}; };
export class CopyMoveAttr extends OverrideMoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const targetMoves = target.getMoveHistory().filter(m => !m.virtual);
if (!targetMoves.length)
return false;
const copiedMove = targetMoves[0];
const moveTargets = getMoveTargets(user, copiedMove.move);
if (!moveTargets.targets.length)
return false;
const targets = moveTargets.multiple || moveTargets.targets.length === 1
? moveTargets.targets
: moveTargets.targets.indexOf(target.getBattlerIndex()) > -1
? [ target.getBattlerIndex() ]
: [ moveTargets.targets[Utils.randInt(moveTargets.targets.length)] ];
user.getMoveQueue().push({ move: copiedMove.move, targets: targets, ignorePP: true });
user.scene.unshiftPhase(new MovePhase(user.scene, user as PlayerPokemon, targets, new PokemonMove(copiedMove.move, 0, 0, true), true));
return true;
}
getCondition(): MoveCondition {
return targetMoveCopiableCondition;
}
}
export class MovesetCopyMoveAttr extends OverrideMoveEffectAttr { export class MovesetCopyMoveAttr extends OverrideMoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const targetMoves = target.getMoveHistory().filter(m => !m.virtual); const targetMoves = target.getMoveHistory().filter(m => !m.virtual);

View File

@ -5,6 +5,7 @@ import { SpeciesWildEvolutionDelay, pokemonEvolutions, pokemonPrevolutions } fro
import { Species } from './species'; import { Species } from './species';
import { Type } from './type'; import { Type } from './type';
import * as Utils from '../utils'; import * as Utils from '../utils';
import { TrainerType, trainerConfigs } from './trainer-type';
export function getPokemonSpecies(species: Species): PokemonSpecies { export function getPokemonSpecies(species: Species): PokemonSpecies {
if (species >= Species.XERNEAS) if (species >= Species.XERNEAS)
@ -12,6 +13,8 @@ export function getPokemonSpecies(species: Species): PokemonSpecies {
return allSpecies[species - 1]; return allSpecies[species - 1];
} }
export type PokemonSpeciesFilter = (species: PokemonSpecies) => boolean;
export abstract class PokemonSpeciesForm { export abstract class PokemonSpeciesForm {
public speciesId: Species; public speciesId: Species;
public formIndex: integer; public formIndex: integer;
@ -272,7 +275,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm {
for (let weight of evolutionPool.keys()) { for (let weight of evolutionPool.keys()) {
if (randValue < weight) if (randValue < weight)
return evolutionPool.get(weight); return getPokemonSpecies(evolutionPool.get(weight)).getSpeciesForLevel(level, true);
} }
return this.speciesId; return this.speciesId;
@ -344,7 +347,7 @@ class PokemonForm extends PokemonSpeciesForm {
} }
} }
export const allSpecies = []; export const allSpecies: PokemonSpecies[] = [];
export function initSpecies() { export function initSpecies() {
allSpecies.push( allSpecies.push(
@ -1102,4 +1105,17 @@ export function initSpecies() {
new PokemonSpecies(Species.YVELTAL, "Yveltal", 6, false, true, false, "Destruction Pokémon", Type.DARK, Type.FLYING, 5.8, 203, Abilities.DARK_AURA, Abilities.NONE, Abilities.NONE, 680, 126, 131, 95, 131, 98, 99, 45, 0, 306, GrowthRate.SLOW, "Undiscovered", null, null, 120, false), new PokemonSpecies(Species.YVELTAL, "Yveltal", 6, false, true, false, "Destruction Pokémon", Type.DARK, Type.FLYING, 5.8, 203, Abilities.DARK_AURA, Abilities.NONE, Abilities.NONE, 680, 126, 131, 95, 131, 98, 99, 45, 0, 306, GrowthRate.SLOW, "Undiscovered", null, null, 120, false),
new PokemonSpecies(Species.ETERNATUS, 'Eternatus', 8, false, true, false, 'Gigantic Pokemon', Type.POISON, Type.DRAGON, 20, 950, Abilities.PRESSURE, Abilities.NONE, Abilities.NONE, 690, 140, 85, 95, 145, 95, 130, 255, 0, 345, GrowthRate.SLOW, "Undiscovered", null, null, 120, false, false) new PokemonSpecies(Species.ETERNATUS, 'Eternatus', 8, false, true, false, 'Gigantic Pokemon', Type.POISON, Type.DRAGON, 20, 950, Abilities.PRESSURE, Abilities.NONE, Abilities.NONE, 690, 140, 85, 95, 145, 95, 130, 255, 0, 345, GrowthRate.SLOW, "Undiscovered", null, null, 120, false, false)
); );
} }
// TODO: Remove
/*{
setTimeout(() => {
for (let tc of Object.keys(trainerConfigs)) {
console.log(TrainerType[tc], !trainerConfigs[tc].speciesFilter ? 'all' : [...new Set(allSpecies.slice(0, -1).filter(trainerConfigs[tc].speciesFilter).map(s => {
while (pokemonPrevolutions.hasOwnProperty(s.speciesId))
s = getPokemonSpecies(pokemonPrevolutions[s.speciesId]);
return s;
}))].map(s => s.name));
}
}, 1000);
}*/

View File

@ -1,5 +1,11 @@
import BattleScene from "../battle-scene"; import BattleScene from "../battle-scene";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { Moves } from "./move";
import { pokemonLevelMoves } from "./pokemon-level-moves";
import { PokemonSpeciesFilter } from "./pokemon-species";
import { Species } from "./species";
import { tmSpecies } from "./tms";
import { Type } from "./type";
export enum TrainerType { export enum TrainerType {
ACE_TRAINER = 1, ACE_TRAINER = 1,
@ -7,10 +13,9 @@ export enum TrainerType {
BACKERS, BACKERS,
BACKPACKER, BACKPACKER,
BAKER, BAKER,
BATTLE_GIRL,
BEAUTY, BEAUTY,
BIKER, BIKER,
BLACKBELT, BLACK_BELT,
BREEDER, BREEDER,
CLERK, CLERK,
CYCLIST, CYCLIST,
@ -18,7 +23,6 @@ export enum TrainerType {
DEPOT_AGENT, DEPOT_AGENT,
DOCTOR, DOCTOR,
FISHERMAN, FISHERMAN,
GENTLEMAN,
GUITARIST, GUITARIST,
HARLEQUIN, HARLEQUIN,
HIKER, HIKER,
@ -26,8 +30,6 @@ export enum TrainerType {
HOOPSTER, HOOPSTER,
INFIELDER, INFIELDER,
JANITOR, JANITOR,
LADY,
LASS,
LINEBACKER, LINEBACKER,
MAID, MAID,
MUSICIAN, MUSICIAN,
@ -40,12 +42,12 @@ export enum TrainerType {
PRESCHOOLER, PRESCHOOLER,
PSYCHIC, PSYCHIC,
RANGER, RANGER,
RICH_BOY, RICH,
RICH_KID,
ROUGHNECK, ROUGHNECK,
SCIENTIST, SCIENTIST,
SMASHER, SMASHER,
SNOW_WORKER, SNOW_WORKER,
SOCIALITE,
STRIKER, STRIKER,
STUDENT, STUDENT,
SWIMMER, SWIMMER,
@ -54,16 +56,45 @@ export enum TrainerType {
WAITER, WAITER,
WORKER, WORKER,
YOUNGSTER, YOUNGSTER,
RIVAL,
CYNTHIA CYNTHIA
} }
export enum TrainerPartyType {
DEFAULT,
BALANCED,
REPEATED
}
export enum TrainerPoolTier {
COMMON,
UNCOMMON,
RARE,
SUPER_RARE,
ULTRA_RARE
};
export interface TrainerTierPools {
[key: integer]: Species[]
}
export class TrainerConfig { export class TrainerConfig {
public trainerType: TrainerType; public trainerType: TrainerType;
public name: string;
public nameFemale: string;
public hasGenders: boolean = false; public hasGenders: boolean = false;
public isDouble: boolean = false; public isDouble: boolean = false;
public partyType: TrainerPartyType = TrainerPartyType.DEFAULT;
public encounterBgm: string;
public femaleEncounterBgm: string;
public speciesPools: TrainerTierPools;
public speciesFilter: PokemonSpeciesFilter;
constructor(trainerType: TrainerType) { constructor(trainerType: TrainerType, allowLegendaries?: boolean) {
this.trainerType = trainerType; this.trainerType = trainerType;
this.name = Utils.toPokemonUpperCase(TrainerType[this.trainerType].toString().replace(/\_/g, ' '));
this.encounterBgm = this.name.toLowerCase();
this.speciesFilter = species => allowLegendaries || (!species.legendary && !species.pseudoLegendary && !species.mythical);
} }
public getKey(female?: boolean): string { public getKey(female?: boolean): string {
@ -73,8 +104,16 @@ export class TrainerConfig {
return ret; return ret;
} }
public setHasGenders(): TrainerConfig { public setName(name: string): TrainerConfig {
this.name = name;
return this;
}
public setHasGenders(nameFemale?: string, femaleEncounterBgm?: TrainerType | string): TrainerConfig {
this.hasGenders = true; this.hasGenders = true;
this.nameFemale = nameFemale;
if (femaleEncounterBgm)
this.femaleEncounterBgm = typeof femaleEncounterBgm === 'number' ? TrainerType[femaleEncounterBgm].toString().replace(/\_/g, ' ').toLowerCase() : femaleEncounterBgm;
return this; return this;
} }
@ -83,8 +122,39 @@ export class TrainerConfig {
return this; return this;
} }
public getName(): string { public setEncounterBgm(encounterBgm: TrainerType | string): TrainerConfig {
return Utils.toPokemonUpperCase(TrainerType[this.trainerType].toString().replace(/\_/g, ' ')); this.encounterBgm = typeof encounterBgm === 'number' ? TrainerType[encounterBgm].toString().replace(/\_/g, ' ').toLowerCase() : encounterBgm;
return this;
}
public setPartyType(partyType: TrainerPartyType): TrainerConfig {
this.partyType = partyType;
return this;
}
public setSpeciesPools(speciesPools: TrainerTierPools | Species[]): TrainerConfig {
this.speciesPools = (Array.isArray(speciesPools) ? speciesPools : { [TrainerPoolTier.COMMON]: speciesPools }) as unknown as TrainerTierPools;
return this;
}
public setSpeciesFilter(speciesFilter: PokemonSpeciesFilter, allowLegendaries?: boolean): TrainerConfig {
const baseFilter = this.speciesFilter;
this.speciesFilter = allowLegendaries ? speciesFilter : species => speciesFilter(species) && baseFilter(species);
return this;
}
public getName(female?: boolean): string {
let ret = this.name;
if (this.hasGenders) {
if (this.nameFemale) {
if (female)
return this.nameFemale;
} else
ret += !female ? '♂' : '♀';
}
return ret;
} }
public genPartySize(): integer { public genPartySize(): integer {
@ -122,58 +192,65 @@ interface TrainerConfigs {
[key: integer]: TrainerConfig [key: integer]: TrainerConfig
} }
export const trainerConfigs: TrainerConfigs = { export const trainerConfigs: TrainerConfigs = {
[TrainerType.ACE_TRAINER]: new TrainerConfig(++t).setHasGenders(), [TrainerType.ACE_TRAINER]: new TrainerConfig(++t).setHasGenders().setPartyType(TrainerPartyType.BALANCED),
[TrainerType.ARTIST]: new TrainerConfig(++t), [TrainerType.ARTIST]: new TrainerConfig(++t).setEncounterBgm(TrainerType.RICH).setSpeciesPools([ Species.SMEARGLE ]),
[TrainerType.BACKERS]: new TrainerConfig(++t).setHasGenders().setDouble(), [TrainerType.BACKERS]: new TrainerConfig(++t).setHasGenders().setEncounterBgm(TrainerType.CYCLIST).setDouble(),
[TrainerType.BACKPACKER]: new TrainerConfig(++t).setHasGenders(), [TrainerType.BACKPACKER]: new TrainerConfig(++t).setHasGenders().setSpeciesFilter(s => s.isOfType(Type.FLYING) || s.isOfType(Type.ROCK)),
[TrainerType.BAKER]: new TrainerConfig(++t), [TrainerType.BAKER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => s.isOfType(Type.GRASS) || s.isOfType(Type.FIRE)),
[TrainerType.BATTLE_GIRL]: new TrainerConfig(++t), [TrainerType.BEAUTY]: new TrainerConfig(++t).setEncounterBgm(TrainerType.PARASOL_LADY),
[TrainerType.BEAUTY]: new TrainerConfig(++t), [TrainerType.BIKER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => s.isOfType(Type.POISON)),
[TrainerType.BIKER]: new TrainerConfig(++t), [TrainerType.BLACK_BELT]: new TrainerConfig(++t).setHasGenders('Battle Girl', TrainerType.PSYCHIC).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => s.isOfType(Type.FIGHTING)),
[TrainerType.BLACKBELT]: new TrainerConfig(++t), [TrainerType.BREEDER]: new TrainerConfig(++t).setHasGenders().setDouble().setEncounterBgm(TrainerType.POKEFAN),
[TrainerType.BREEDER]: new TrainerConfig(++t).setHasGenders().setDouble(),
[TrainerType.CLERK]: new TrainerConfig(++t).setHasGenders(), [TrainerType.CLERK]: new TrainerConfig(++t).setHasGenders(),
[TrainerType.CYCLIST]: new TrainerConfig(++t).setHasGenders(), [TrainerType.CYCLIST]: new TrainerConfig(++t).setHasGenders().setSpeciesFilter(s => !!pokemonLevelMoves[s.speciesId].find(plm => plm[1] === Moves.QUICK_ATTACK)),
[TrainerType.DANCER]: new TrainerConfig(++t), [TrainerType.DANCER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.DEPOT_AGENT]: new TrainerConfig(++t), [TrainerType.DEPOT_AGENT]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK),
[TrainerType.DOCTOR]: new TrainerConfig(++t), [TrainerType.DOCTOR]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK),
[TrainerType.FISHERMAN]: new TrainerConfig(++t), [TrainerType.FISHERMAN]: new TrainerConfig(++t).setEncounterBgm(TrainerType.BACKPACKER).setSpeciesPools({
[TrainerType.GENTLEMAN]: new TrainerConfig(++t), [TrainerPoolTier.COMMON]: [ Species.TENTACOOL, Species.MAGIKARP, Species.GOLDEEN, Species.STARYU, Species.REMORAID ],
[TrainerType.GUITARIST]: new TrainerConfig(++t), [TrainerPoolTier.UNCOMMON]: [ Species.POLIWAG, Species.SHELLDER, Species.KRABBY, Species.HORSEA, Species.CARVANHA, Species.BARBOACH, Species.CORPHISH, Species.FINNEON, Species.TYMPOLE, Species.BASCULIN, Species.FRILLISH ],
[TrainerType.HARLEQUIN]: new TrainerConfig(++t), [TrainerPoolTier.RARE]: [ Species.CHINCHOU, Species.CORSOLA, Species.WAILMER, Species.CLAMPERL, Species.LUVDISC, Species.MANTYKE, Species.ALOMOMOLA ],
[TrainerType.HIKER]: new TrainerConfig(++t), [TrainerPoolTier.SUPER_RARE]: [ Species.LAPRAS, Species.FEEBAS, Species.RELICANTH ]
[TrainerType.HOOLIGANS]: new TrainerConfig(++t).setDouble(), }),
[TrainerType.HOOPSTER]: new TrainerConfig(++t), [TrainerType.GUITARIST]: new TrainerConfig(++t).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => s.isOfType(Type.ELECTRIC)),
[TrainerType.INFIELDER]: new TrainerConfig(++t), [TrainerType.HARLEQUIN]: new TrainerConfig(++t).setEncounterBgm(TrainerType.PSYCHIC).setSpeciesFilter(s => tmSpecies[Moves.TRICK_ROOM].indexOf(s.speciesId) > -1),
[TrainerType.JANITOR]: new TrainerConfig(++t), [TrainerType.HIKER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.BACKPACKER).setSpeciesFilter(s => s.isOfType(Type.GROUND) || s.isOfType(Type.ROCK)),
[TrainerType.LADY]: new TrainerConfig(++t), [TrainerType.HOOLIGANS]: new TrainerConfig(++t).setDouble().setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => s.isOfType(Type.POISON) || s.isOfType(Type.DARK)),
[TrainerType.LASS]: new TrainerConfig(++t), [TrainerType.HOOPSTER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.LINEBACKER]: new TrainerConfig(++t), [TrainerType.INFIELDER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.MAID]: new TrainerConfig(++t), [TrainerType.JANITOR]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK),
[TrainerType.MUSICIAN]: new TrainerConfig(++t), [TrainerType.LINEBACKER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.NURSE]: new TrainerConfig(++t), [TrainerType.MAID]: new TrainerConfig(++t).setEncounterBgm(TrainerType.RICH).setSpeciesFilter(s => s.eggType1 === 'Field' || s.eggType2 === 'Field'),
[TrainerType.NURSERY_AIDE]: new TrainerConfig(++t), [TrainerType.MUSICIAN]: new TrainerConfig(++t).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => !!pokemonLevelMoves[s.speciesId].find(plm => plm[1] === Moves.SING)),
[TrainerType.OFFICER]: new TrainerConfig(++t), [TrainerType.NURSE]: new TrainerConfig(++t).setEncounterBgm('lass').setSpeciesFilter(s => !!pokemonLevelMoves[s.speciesId].find(plm => plm[1] === Moves.CHARM) || !!pokemonLevelMoves[s.speciesId].find(plm => plm[1] === Moves.HEAL_PULSE)),
[TrainerType.PARASOL_LADY]: new TrainerConfig(++t), [TrainerType.NURSERY_AIDE]: new TrainerConfig(++t).setEncounterBgm('lass'),
[TrainerType.PILOT]: new TrainerConfig(++t), [TrainerType.OFFICER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK).setSpeciesPools([ Species.VULPIX, Species.GROWLITHE, Species.SNUBBULL, Species.HOUNDOUR, Species.POOCHYENA, Species.ELECTRIKE, Species.LILLIPUP ]),
[TrainerType.PARASOL_LADY]: new TrainerConfig(++t).setSpeciesFilter(s => s.isOfType(Type.WATER)),
[TrainerType.PILOT]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => tmSpecies[Moves.FLY].indexOf(s.speciesId) > -1),
[TrainerType.POKEFAN]: new TrainerConfig(++t).setHasGenders(), [TrainerType.POKEFAN]: new TrainerConfig(++t).setHasGenders(),
[TrainerType.PRESCHOOLER]: new TrainerConfig(++t).setHasGenders(), [TrainerType.PRESCHOOLER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders(undefined, 'lass'),
[TrainerType.PSYCHIC]: new TrainerConfig(++t).setHasGenders(), [TrainerType.PSYCHIC]: new TrainerConfig(++t).setHasGenders(),
[TrainerType.RANGER]: new TrainerConfig(++t).setHasGenders(), [TrainerType.RANGER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.BACKPACKER).setHasGenders(),
[TrainerType.RICH_BOY]: new TrainerConfig(++t), [TrainerType.RICH]: new TrainerConfig(++t).setName('Gentleman').setHasGenders().setSpeciesFilter(s => s.eggType1 === 'Field' || s.eggType2 === 'Field'),
[TrainerType.ROUGHNECK]: new TrainerConfig(++t), [TrainerType.RICH_KID]: new TrainerConfig(++t).setName('Rich Boy').setHasGenders('Lady').setEncounterBgm(TrainerType.RICH),
[TrainerType.SCIENTIST]: new TrainerConfig(++t).setHasGenders(), [TrainerType.ROUGHNECK]: new TrainerConfig(++t).setSpeciesFilter(s => s.isOfType(Type.DARK)),
[TrainerType.SMASHER]: new TrainerConfig(++t), [TrainerType.SCIENTIST]: new TrainerConfig(++t).setHasGenders().setSpeciesPools({
[TrainerType.SNOW_WORKER]: new TrainerConfig(++t), [TrainerPoolTier.COMMON]: [ Species.MAGNEMITE, Species.GRIMER, Species.DROWZEE, Species.VOLTORB, Species.KOFFING ],
[TrainerType.SOCIALITE]: new TrainerConfig(++t), [TrainerPoolTier.UNCOMMON]: [ Species.KLINK ],
[TrainerType.STRIKER]: new TrainerConfig(++t), [TrainerPoolTier.RARE ]: [ Species.ABRA, Species.PORYGON ],
[TrainerPoolTier.SUPER_RARE ]: [ Species.OMANYTE, Species.KABUTO, Species.AERODACTYL, Species.LILEEP, Species.ANORITH, Species.CRANIDOS, Species.SHIELDON, Species.TIRTOUGA, Species.ARCHEN ]
}),
[TrainerType.SMASHER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.SNOW_WORKER]: new TrainerConfig(++t).setName('Worker').setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => s.isOfType(Type.ICE) || s.isOfType(Type.STEEL)),
[TrainerType.STRIKER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.STUDENT]: new TrainerConfig(++t).setHasGenders(), [TrainerType.STUDENT]: new TrainerConfig(++t).setHasGenders(),
[TrainerType.SWIMMER]: new TrainerConfig(++t).setHasGenders(), [TrainerType.SWIMMER]: new TrainerConfig(++t).setHasGenders().setEncounterBgm(TrainerType.PARASOL_LADY).setSpeciesFilter(s => s.isOfType(Type.WATER)),
[TrainerType.TWINS]: new TrainerConfig(++t).setDouble(), [TrainerType.TWINS]: new TrainerConfig(++t).setDouble(),
[TrainerType.VETERAN]: new TrainerConfig(++t).setHasGenders(), [TrainerType.VETERAN]: new TrainerConfig(++t).setHasGenders().setEncounterBgm(TrainerType.RICH),
[TrainerType.WAITER]: new TrainerConfig(++t).setHasGenders(), [TrainerType.WAITER]: new TrainerConfig(++t).setHasGenders().setEncounterBgm(TrainerType.CLERK),
[TrainerType.WORKER]: new TrainerConfig(++t), [TrainerType.WORKER]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => s.isOfType(Type.ROCK) || s.isOfType(Type.STEEL)),
[TrainerType.YOUNGSTER]: new TrainerConfig(++t), [TrainerType.YOUNGSTER]: new TrainerConfig(++t).setHasGenders('Lass', 'lass').setEncounterBgm(TrainerType.YOUNGSTER),
[TrainerType.RIVAL]: new TrainerConfig(++t).setHasGenders(),
[TrainerType.CYNTHIA]: new TrainerConfig(++t), [TrainerType.CYNTHIA]: new TrainerConfig(++t),
} }

View File

@ -1,5 +1,6 @@
import BattleScene from "./battle-scene"; import BattleScene from "./battle-scene";
import { TrainerConfig, TrainerType, trainerConfigs } from "./data/trainer-type"; import PokemonSpecies, { getPokemonSpecies } from "./data/pokemon-species";
import { TrainerConfig, TrainerPartyType, TrainerType, trainerConfigs } from "./data/trainer-type";
import * as Utils from "./utils"; import * as Utils from "./utils";
export default class Trainer extends Phaser.GameObjects.Container { export default class Trainer extends Phaser.GameObjects.Container {
@ -32,7 +33,22 @@ export default class Trainer extends Phaser.GameObjects.Container {
} }
getName(): string { getName(): string {
return this.config.getName(); return this.config.getName(this.female);
}
genPartyMemberSpecies(level: integer, attempt?: integer): PokemonSpecies {
const battle = this.scene.currentBattle;
if (this.config.partyType === TrainerPartyType.REPEATED && battle.enemyParty.length)
return getPokemonSpecies(battle.enemyParty[0].species.getSpeciesForLevel(level));
const ret = getPokemonSpecies(this.scene.randomSpecies(battle.waveIndex, level, this.config.speciesFilter, true).getSpeciesForLevel(level));
if (this.config.partyType === TrainerPartyType.BALANCED) {
const partyTypes = this.scene.getEnemyParty().map(p => p.getTypes()).flat();
if ((attempt || 0) < 10 && (partyTypes.indexOf(ret.type1) > -1 || (ret.type2 !== null && partyTypes.indexOf(ret.type2) > -1)))
return this.genPartyMemberSpecies(level, (attempt || 0) + 1);
}
return ret;
} }
getNextSummonIndex(): integer { getNextSummonIndex(): integer {