Adds Uncommon Breed ME and misc. ME bug fixes
This commit is contained in:
parent
e77c6adb4f
commit
b6e90931ac
|
@ -1107,12 +1107,13 @@ export abstract class BattleAnim {
|
||||||
let r = anim!.frames.length;
|
let r = anim!.frames.length;
|
||||||
let f = 0;
|
let f = 0;
|
||||||
|
|
||||||
const existingFieldSprites = [...scene.field.getAll()];
|
let existingFieldSprites = scene.field.getAll().slice(0);
|
||||||
|
|
||||||
scene.tweens.addCounter({
|
scene.tweens.addCounter({
|
||||||
duration: Utils.getFrameMs(3) * frameTimeMult,
|
duration: Utils.getFrameMs(3) * frameTimeMult,
|
||||||
repeat: anim!.frames.length,
|
repeat: anim!.frames.length,
|
||||||
onRepeat: () => {
|
onRepeat: () => {
|
||||||
|
existingFieldSprites = scene.field.getAll().slice(0);
|
||||||
const spriteFrames = anim!.frames[f];
|
const spriteFrames = anim!.frames[f];
|
||||||
const frameData = this.getGraphicFrameDataWithoutTarget(anim!.frames[f], targetInitialX, targetInitialY);
|
const frameData = this.getGraphicFrameDataWithoutTarget(anim!.frames[f], targetInitialX, targetInitialY);
|
||||||
const u = 0;
|
const u = 0;
|
||||||
|
@ -1139,7 +1140,8 @@ export abstract class BattleAnim {
|
||||||
const setSpritePriority = (priority: integer) => {
|
const setSpritePriority = (priority: integer) => {
|
||||||
if (existingFieldSprites.length > priority) {
|
if (existingFieldSprites.length > priority) {
|
||||||
// Move to specified priority index
|
// Move to specified priority index
|
||||||
scene.field.moveTo(moveSprite, scene.field.getIndex(existingFieldSprites[priority]));
|
const index = scene.field.getIndex(existingFieldSprites[priority]);
|
||||||
|
scene.field.moveTo(moveSprite, index);
|
||||||
} else {
|
} else {
|
||||||
// Move to top of scene
|
// Move to top of scene
|
||||||
scene.field.moveTo(moveSprite, scene.field.getAll().length - 1);
|
scene.field.moveTo(moveSprite, scene.field.getAll().length - 1);
|
||||||
|
|
|
@ -175,7 +175,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
||||||
.withOnInit((scene: BattleScene) => {
|
.withOnInit((scene: BattleScene) => {
|
||||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||||
|
|
||||||
scene.loadSe("PRSFX- Bug Bite", "battle_anims");
|
scene.loadSe("PRSFX- Bug Bite", "battle_anims", "PRSFX- Bug Bite.wav");
|
||||||
scene.loadSe("Follow Me", "battle_anims", "Follow Me.mp3");
|
scene.loadSe("Follow Me", "battle_anims", "Follow Me.mp3");
|
||||||
|
|
||||||
// Get all player berry items, remove from party, and store reference
|
// Get all player berry items, remove from party, and store reference
|
||||||
|
@ -351,7 +351,7 @@ function doGreedentSpriteSteal(scene: BattleScene) {
|
||||||
|
|
||||||
const greedentSprites = scene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(1);
|
const greedentSprites = scene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(1);
|
||||||
|
|
||||||
scene.playSound("battle-anims/Follow Me");
|
scene.playSound("battle_anims/Follow Me");
|
||||||
scene.tweens.chain({
|
scene.tweens.chain({
|
||||||
targets: greedentSprites,
|
targets: greedentSprites,
|
||||||
tweens: [
|
tweens: [
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import Pokemon, { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene";
|
||||||
|
@ -88,7 +88,7 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
||||||
.withAutoHideIntroVisuals(false)
|
.withAutoHideIntroVisuals(false)
|
||||||
.withCatchAllowed(true)
|
.withCatchAllowed(true)
|
||||||
.withOnVisualsStart((scene: BattleScene) => {
|
.withOnVisualsStart((scene: BattleScene) => {
|
||||||
const danceAnim = new EncounterBattleAnim(EncounterAnim.DANCE, scene.getEnemyPokemon()!, scene.getPlayerPokemon());
|
const danceAnim = new EncounterBattleAnim(EncounterAnim.DANCE, scene.getEnemyPokemon()!, scene.getParty()[0]);
|
||||||
danceAnim.play(scene);
|
danceAnim.play(scene);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -105,7 +105,8 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
||||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||||
|
|
||||||
const species = getPokemonSpecies(Species.ORICORIO);
|
const species = getPokemonSpecies(Species.ORICORIO);
|
||||||
const enemyPokemon = scene.addEnemyPokemon(species, scene.currentBattle.enemyLevels![0], TrainerSlot.NONE, false);
|
const level = (scene.currentBattle.enemyLevels?.[0] ?? scene.currentBattle.waveIndex) + Math.max(Math.round((scene.currentBattle.waveIndex / 10)), 0);
|
||||||
|
const enemyPokemon = new EnemyPokemon(scene, species, level, TrainerSlot.NONE, false);
|
||||||
if (!enemyPokemon.moveset.some(m => m && m.getMove().id === Moves.REVELATION_DANCE)) {
|
if (!enemyPokemon.moveset.some(m => m && m.getMove().id === Moves.REVELATION_DANCE)) {
|
||||||
if (enemyPokemon.moveset.length < 4) {
|
if (enemyPokemon.moveset.length < 4) {
|
||||||
enemyPokemon.moveset.push(new PokemonMove(Moves.REVELATION_DANCE));
|
enemyPokemon.moveset.push(new PokemonMove(Moves.REVELATION_DANCE));
|
||||||
|
@ -130,10 +131,11 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
||||||
}
|
}
|
||||||
|
|
||||||
const oricorioData = new PokemonData(enemyPokemon);
|
const oricorioData = new PokemonData(enemyPokemon);
|
||||||
|
const oricorio = scene.addEnemyPokemon(species, scene.currentBattle.enemyLevels![0], TrainerSlot.NONE, false, oricorioData);
|
||||||
|
|
||||||
// Adds a real Pokemon sprite to the field (required for the animation)
|
// Adds a real Pokemon sprite to the field (required for the animation)
|
||||||
scene.currentBattle.enemyParty[0] = enemyPokemon;
|
scene.currentBattle.enemyParty[0] = oricorio;
|
||||||
scene.field.add(enemyPokemon);
|
scene.field.add(oricorio);
|
||||||
|
|
||||||
const config: EnemyPartyConfig = {
|
const config: EnemyPartyConfig = {
|
||||||
levelAdditiveMultiplier: 1,
|
levelAdditiveMultiplier: 1,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
setEncounterRewards
|
setEncounterRewards
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import { STEALING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
import { STEALING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
||||||
import { EnemyPokemon } from "#app/field/pokemon";
|
import Pokemon, { EnemyPokemon } from "#app/field/pokemon";
|
||||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||||
import {
|
import {
|
||||||
getPartyLuckValue,
|
getPartyLuckValue,
|
||||||
|
@ -24,6 +24,10 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode
|
||||||
import { TrainerSlot } from "#app/data/trainer-config";
|
import { TrainerSlot } from "#app/data/trainer-config";
|
||||||
import { getSpriteKeysFromPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
import { getSpriteKeysFromPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import PokemonData from "#app/system/pokemon-data";
|
import PokemonData from "#app/system/pokemon-data";
|
||||||
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
|
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
|
import { StatChangePhase } from "#app/phases/stat-change-phase";
|
||||||
|
import { randSeedInt } from "#app/utils";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounter:fightOrFlight";
|
const namespace = "mysteryEncounter:fightOrFlight";
|
||||||
|
@ -58,7 +62,13 @@ export const FightOrFlightEncounter: MysteryEncounter =
|
||||||
level: level,
|
level: level,
|
||||||
species: bossSpecies,
|
species: bossSpecies,
|
||||||
dataSource: new PokemonData(bossPokemon),
|
dataSource: new PokemonData(bossPokemon),
|
||||||
isBoss: true
|
isBoss: true,
|
||||||
|
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
|
||||||
|
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
||||||
|
queueEncounterMessage(pokemon.scene, `${namespace}.option.1.stat_boost`);
|
||||||
|
// Randomly boost 1 stat 2 stages
|
||||||
|
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [randSeedInt(8)], 2));
|
||||||
|
}
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
encounter.enemyPartyConfigs = [config];
|
encounter.enemyPartyConfigs = [config];
|
||||||
|
@ -122,6 +132,7 @@ export const FightOrFlightEncounter: MysteryEncounter =
|
||||||
},
|
},
|
||||||
async (scene: BattleScene) => {
|
async (scene: BattleScene) => {
|
||||||
// Pick battle
|
// Pick battle
|
||||||
|
// Pokemon will randomly boost 1 stat by 2 stages
|
||||||
const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
|
const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
|
||||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false });
|
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false });
|
||||||
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
|
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
|
||||||
|
|
|
@ -74,9 +74,9 @@ export const SafariZoneEncounter: MysteryEncounter =
|
||||||
};
|
};
|
||||||
updatePlayerMoney(scene, -(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney);
|
updatePlayerMoney(scene, -(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney);
|
||||||
// Load bait/mud assets
|
// Load bait/mud assets
|
||||||
scene.loadSe("PRSFX- Bug Bite", "battle_anims");
|
scene.loadSe("PRSFX- Bug Bite", "battle_anims", "PRSFX- Bug Bite.wav");
|
||||||
scene.loadSe("PRSFX- Sludge Bomb2", "battle_anims");
|
scene.loadSe("PRSFX- Sludge Bomb2", "battle_anims", "PRSFX- Sludge Bomb2.wav");
|
||||||
scene.loadSe("PRSFX- Taunt2", "battle_anims");
|
scene.loadSe("PRSFX- Taunt2", "battle_anims", "PRSFX- Taunt2.wav");
|
||||||
scene.loadAtlas("bait", "mystery-encounters");
|
scene.loadAtlas("bait", "mystery-encounters");
|
||||||
scene.loadAtlas("mud", "mystery-encounters");
|
scene.loadAtlas("mud", "mystery-encounters");
|
||||||
await summonSafariPokemon(scene);
|
await summonSafariPokemon(scene);
|
||||||
|
@ -353,12 +353,12 @@ async function throwBait(scene: BattleScene, pokemon: EnemyPokemon): Promise<boo
|
||||||
y: originalY - 5,
|
y: originalY - 5,
|
||||||
loop: 6,
|
loop: 6,
|
||||||
onStart: () => {
|
onStart: () => {
|
||||||
scene.playSound("battle-anims/PRSFX- Bug Bite");
|
scene.playSound("battle_anims/PRSFX- Bug Bite");
|
||||||
bait.setFrame("0002.png");
|
bait.setFrame("0002.png");
|
||||||
},
|
},
|
||||||
onLoop: () => {
|
onLoop: () => {
|
||||||
if (index % 2 === 0) {
|
if (index % 2 === 0) {
|
||||||
scene.playSound("battle-anims/PRSFX- Bug Bite");
|
scene.playSound("battle_anims/PRSFX- Bug Bite");
|
||||||
}
|
}
|
||||||
if (index === 4) {
|
if (index === 4) {
|
||||||
bait.setFrame("0003.png");
|
bait.setFrame("0003.png");
|
||||||
|
@ -409,7 +409,7 @@ async function throwMud(scene: BattleScene, pokemon: EnemyPokemon): Promise<bool
|
||||||
duration: 500,
|
duration: 500,
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
// Mud frame 2
|
// Mud frame 2
|
||||||
scene.playSound("battle-anims/PRSFX- Sludge Bomb2");
|
scene.playSound("battle_anims/PRSFX- Sludge Bomb2");
|
||||||
mud.setFrame("0002.png");
|
mud.setFrame("0002.png");
|
||||||
// Mud splat
|
// Mud splat
|
||||||
scene.time.delayedCall(200, () => {
|
scene.time.delayedCall(200, () => {
|
||||||
|
@ -435,10 +435,10 @@ async function throwMud(scene: BattleScene, pokemon: EnemyPokemon): Promise<bool
|
||||||
y: originalY - 20,
|
y: originalY - 20,
|
||||||
loop: 1,
|
loop: 1,
|
||||||
onStart: () => {
|
onStart: () => {
|
||||||
scene.playSound("battle-anims/PRSFX- Taunt2");
|
scene.playSound("battle_anims/PRSFX- Taunt2");
|
||||||
},
|
},
|
||||||
onLoop: () => {
|
onLoop: () => {
|
||||||
scene.playSound("battle-anims/PRSFX- Taunt2");
|
scene.playSound("battle_anims/PRSFX- Taunt2");
|
||||||
},
|
},
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
resolve(true);
|
resolve(true);
|
||||||
|
|
|
@ -209,12 +209,12 @@ async function tryApplyDigRewardItems(scene: BattleScene) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doGarbageDig(scene: BattleScene) {
|
async function doGarbageDig(scene: BattleScene) {
|
||||||
scene.playSound("battle-anims/PRSFX- Dig2");
|
scene.playSound("battle_anims/PRSFX- Dig2");
|
||||||
scene.time.delayedCall(SOUND_EFFECT_WAIT_TIME, () => {
|
scene.time.delayedCall(SOUND_EFFECT_WAIT_TIME, () => {
|
||||||
scene.playSound("battle-anims/PRSFX- Dig2");
|
scene.playSound("battle_anims/PRSFX- Dig2");
|
||||||
scene.playSound("battle-anims/PRSFX- Venom Drench", { volume: 2 });
|
scene.playSound("battle_anims/PRSFX- Venom Drench", { volume: 2 });
|
||||||
});
|
});
|
||||||
scene.time.delayedCall(SOUND_EFFECT_WAIT_TIME * 2, () => {
|
scene.time.delayedCall(SOUND_EFFECT_WAIT_TIME * 2, () => {
|
||||||
scene.playSound("battle-anims/PRSFX- Dig2");
|
scene.playSound("battle_anims/PRSFX- Dig2");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,265 @@
|
||||||
|
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
|
import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
|
import { CHARMING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
||||||
|
import Pokemon, { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
||||||
|
import { getPartyLuckValue } from "#app/modifier/modifier-type";
|
||||||
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
|
import BattleScene from "#app/battle-scene";
|
||||||
|
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||||
|
import { MoveRequirement, PersistentModifierRequirement } from "../mystery-encounter-requirements";
|
||||||
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
|
import { TrainerSlot } from "#app/data/trainer-config";
|
||||||
|
import { catchPokemon, getHighestLevelPlayerPokemon, getSpriteKeysFromPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
|
import PokemonData from "#app/system/pokemon-data";
|
||||||
|
import { speciesEggMoves } from "#app/data/egg-moves";
|
||||||
|
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { SelfStatusMove } from "#app/data/move";
|
||||||
|
import { PokeballType } from "#enums/pokeball";
|
||||||
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
|
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
|
import { StatChangePhase } from "#app/phases/stat-change-phase";
|
||||||
|
import { BattleStat } from "#app/data/battle-stat";
|
||||||
|
import { BerryModifier } from "#app/modifier/modifier";
|
||||||
|
|
||||||
|
/** the i18n namespace for the encounter */
|
||||||
|
const namespace = "mysteryEncounter:uncommonBreed";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uncommon Breed encounter.
|
||||||
|
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3811 | GitHub Issue #3811}
|
||||||
|
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||||
|
*/
|
||||||
|
export const UncommonBreedEncounter: MysteryEncounter =
|
||||||
|
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.UNCOMMON_BREED)
|
||||||
|
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||||
|
.withSceneWaveRangeRequirement(10, 180) // waves 10 to 180
|
||||||
|
.withCatchAllowed(true)
|
||||||
|
.withHideWildIntroMessage(true)
|
||||||
|
.withIntroSpriteConfigs([]) // Set in onInit()
|
||||||
|
.withIntroDialogue([
|
||||||
|
{
|
||||||
|
text: `${namespace}.intro`,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.withOnInit((scene: BattleScene) => {
|
||||||
|
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||||
|
|
||||||
|
// Calculate boss mon
|
||||||
|
// Level equal to 2 below highest party member
|
||||||
|
const level = getHighestLevelPlayerPokemon(scene).level - 2;
|
||||||
|
const species = scene.arena.randomSpecies(scene.currentBattle.waveIndex, level, 0, getPartyLuckValue(scene.getParty()), true);
|
||||||
|
const pokemon = new EnemyPokemon(scene, species, level, TrainerSlot.NONE, true);
|
||||||
|
const speciesRootForm = pokemon.species.getRootSpeciesId();
|
||||||
|
encounter.misc = {
|
||||||
|
pokemon
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pokemon will always have one of its egg moves in its moveset
|
||||||
|
if (speciesEggMoves.hasOwnProperty(speciesRootForm)) {
|
||||||
|
const eggMoves: Moves[] = speciesEggMoves[speciesRootForm];
|
||||||
|
const eggMoveIndex = randSeedInt(4);
|
||||||
|
const randomEggMove: Moves = eggMoves[eggMoveIndex];
|
||||||
|
encounter.misc.eggMove = randomEggMove;
|
||||||
|
if (pokemon.moveset.length < 4) {
|
||||||
|
pokemon.moveset.push(new PokemonMove(randomEggMove));
|
||||||
|
} else {
|
||||||
|
pokemon.moveset[0] = new PokemonMove(randomEggMove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const config: EnemyPartyConfig = {
|
||||||
|
pokemonConfigs: [{
|
||||||
|
level: level,
|
||||||
|
species: species,
|
||||||
|
dataSource: new PokemonData(pokemon),
|
||||||
|
isBoss: false,
|
||||||
|
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
|
||||||
|
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
||||||
|
queueEncounterMessage(pokemon.scene, `${namespace}.option.1.stat_boost`);
|
||||||
|
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD], 1));
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
encounter.enemyPartyConfigs = [config];
|
||||||
|
|
||||||
|
const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(pokemon);
|
||||||
|
encounter.spriteConfigs = [
|
||||||
|
{
|
||||||
|
spriteKey: spriteKey,
|
||||||
|
fileRoot: fileRoot,
|
||||||
|
hasShadow: true,
|
||||||
|
x: -5,
|
||||||
|
repeat: true,
|
||||||
|
isPokemon: true
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
encounter.setDialogueToken("enemyPokemon", pokemon.getNameToRender());
|
||||||
|
scene.loadSe("PRSFX- Spotlight2", "battle_anims", "PRSFX- Spotlight2.wav");
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.withOnVisualsStart((scene: BattleScene) => {
|
||||||
|
// Animate the pokemon
|
||||||
|
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||||
|
const pokemonSprite = encounter.introVisuals!.getSprites();
|
||||||
|
|
||||||
|
scene.tweens.add({ // Bounce at the end
|
||||||
|
targets: pokemonSprite,
|
||||||
|
duration: 300,
|
||||||
|
ease: "Cubic.easeOut",
|
||||||
|
yoyo: true,
|
||||||
|
y: "-=20",
|
||||||
|
loop: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
scene.time.delayedCall(500, () => scene.playSound("battle_anims/PRSFX- Spotlight2"));
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.withTitle(`${namespace}.title`)
|
||||||
|
.withDescription(`${namespace}.description`)
|
||||||
|
.withQuery(`${namespace}.query`)
|
||||||
|
.withSimpleOption(
|
||||||
|
{
|
||||||
|
buttonLabel: `${namespace}.option.1.label`,
|
||||||
|
buttonTooltip: `${namespace}.option.1.tooltip`,
|
||||||
|
selected: [
|
||||||
|
{
|
||||||
|
text: `${namespace}.option.1.selected`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
async (scene: BattleScene) => {
|
||||||
|
// Pick battle
|
||||||
|
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||||
|
|
||||||
|
const eggMove = encounter.misc.eggMove;
|
||||||
|
if (!isNullOrUndefined(eggMove)) {
|
||||||
|
// Check what type of move the egg move is to determine target
|
||||||
|
const pokemonMove = new PokemonMove(eggMove);
|
||||||
|
const move = pokemonMove.getMove();
|
||||||
|
const target = move instanceof SelfStatusMove ? BattlerIndex.ENEMY : BattlerIndex.PLAYER;
|
||||||
|
|
||||||
|
encounter.startOfBattleEffects.push(
|
||||||
|
{
|
||||||
|
sourceBattlerIndex: BattlerIndex.ENEMY,
|
||||||
|
targets: [target],
|
||||||
|
move: pokemonMove,
|
||||||
|
ignorePp: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setEncounterRewards(scene, { fillRemaining: true });
|
||||||
|
await initBattleWithEnemyConfig(scene, encounter.enemyPartyConfigs[0]);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.withOption(
|
||||||
|
MysteryEncounterOptionBuilder
|
||||||
|
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
|
||||||
|
.withSceneRequirement(new PersistentModifierRequirement("BerryModifier", 4)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically
|
||||||
|
.withDialogue({
|
||||||
|
buttonLabel: `${namespace}.option.2.label`,
|
||||||
|
buttonTooltip: `${namespace}.option.2.tooltip`,
|
||||||
|
disabledButtonTooltip: `${namespace}.option.2.disabled_tooltip`,
|
||||||
|
selected: [
|
||||||
|
{
|
||||||
|
text: `${namespace}.option.2.selected`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.withOptionPhase(async (scene: BattleScene) => {
|
||||||
|
// Give it some food
|
||||||
|
|
||||||
|
// Remove 4 random berries from player's party
|
||||||
|
// Get all player berry items, remove from party, and store reference
|
||||||
|
let berryItems: BerryModifier[] = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
berryItems = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
|
||||||
|
const randBerry = berryItems[randSeedInt(berryItems.length)];
|
||||||
|
randBerry.stackCount--;
|
||||||
|
if (randBerry.stackCount === 0) {
|
||||||
|
scene.removeModifier(randBerry);
|
||||||
|
}
|
||||||
|
scene.updateModifiers(true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pokemon joins the team, with 2 egg moves
|
||||||
|
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||||
|
const pokemon = encounter.misc.pokemon;
|
||||||
|
|
||||||
|
// Give 1 additional egg move
|
||||||
|
const previousEggMove = encounter.misc.eggMove;
|
||||||
|
const speciesRootForm = pokemon.species.getRootSpeciesId();
|
||||||
|
if (speciesEggMoves.hasOwnProperty(speciesRootForm)) {
|
||||||
|
const eggMoves: Moves[] = speciesEggMoves[speciesRootForm];
|
||||||
|
let randomEggMove: Moves = eggMoves[randSeedInt(4)];
|
||||||
|
while (randomEggMove === previousEggMove) {
|
||||||
|
randomEggMove = eggMoves[randSeedInt(4)];
|
||||||
|
}
|
||||||
|
if (pokemon.moveset.length < 4) {
|
||||||
|
pokemon.moveset.push(new PokemonMove(randomEggMove));
|
||||||
|
} else {
|
||||||
|
pokemon.moveset[1] = new PokemonMove(randomEggMove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await catchPokemon(scene, pokemon, null, PokeballType.POKEBALL, false);
|
||||||
|
setEncounterRewards(scene, { fillRemaining: true });
|
||||||
|
leaveEncounterWithoutBattle(scene);
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.withOption(
|
||||||
|
MysteryEncounterOptionBuilder
|
||||||
|
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
|
||||||
|
.withPrimaryPokemonRequirement(new MoveRequirement(CHARMING_MOVES)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically
|
||||||
|
.withDialogue({
|
||||||
|
buttonLabel: `${namespace}.option.3.label`,
|
||||||
|
buttonTooltip: `${namespace}.option.3.tooltip`,
|
||||||
|
disabledButtonTooltip: `${namespace}.option.3.disabled_tooltip`,
|
||||||
|
selected: [
|
||||||
|
{
|
||||||
|
text: `${namespace}.option.3.selected`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.withOptionPhase(async (scene: BattleScene) => {
|
||||||
|
// Attract the pokemon with a move
|
||||||
|
// Pokemon joins the team, with 2 egg moves and IVs rolled an additional time
|
||||||
|
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||||
|
const pokemon = encounter.misc.pokemon;
|
||||||
|
|
||||||
|
// Give 1 additional egg move
|
||||||
|
const previousEggMove = encounter.misc.eggMove;
|
||||||
|
const speciesRootForm = pokemon.species.getRootSpeciesId();
|
||||||
|
if (speciesEggMoves.hasOwnProperty(speciesRootForm)) {
|
||||||
|
const eggMoves: Moves[] = speciesEggMoves[speciesRootForm];
|
||||||
|
let randomEggMove: Moves = eggMoves[randSeedInt(4)];
|
||||||
|
while (randomEggMove === previousEggMove) {
|
||||||
|
randomEggMove = eggMoves[randSeedInt(4)];
|
||||||
|
}
|
||||||
|
if (pokemon.moveset.length < 4) {
|
||||||
|
pokemon.moveset.push(new PokemonMove(randomEggMove));
|
||||||
|
} else {
|
||||||
|
pokemon.moveset[1] = new PokemonMove(randomEggMove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Roll IVs a second time
|
||||||
|
pokemon.ivs = pokemon.ivs.map(iv => {
|
||||||
|
const newValue = randSeedInt(31);
|
||||||
|
return newValue > iv ? newValue : iv;
|
||||||
|
});
|
||||||
|
|
||||||
|
await catchPokemon(scene, pokemon, null, PokeballType.POKEBALL, false);
|
||||||
|
if (encounter.selectedOption?.primaryPokemon?.id) {
|
||||||
|
setEncounterExp(scene, encounter.selectedOption.primaryPokemon.id, pokemon.getExpValue(), false);
|
||||||
|
}
|
||||||
|
setEncounterRewards(scene, { fillRemaining: true });
|
||||||
|
leaveEncounterWithoutBattle(scene);
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build();
|
|
@ -29,6 +29,7 @@ import { TheWinstrateChallengeEncounter } from "#app/data/mystery-encounters/enc
|
||||||
import { TeleportingHijinksEncounter } from "#app/data/mystery-encounters/encounters/teleporting-hijinks-encounter";
|
import { TeleportingHijinksEncounter } from "#app/data/mystery-encounters/encounters/teleporting-hijinks-encounter";
|
||||||
import { BugTypeSuperfanEncounter } from "#app/data/mystery-encounters/encounters/bug-type-superfan-encounter";
|
import { BugTypeSuperfanEncounter } from "#app/data/mystery-encounters/encounters/bug-type-superfan-encounter";
|
||||||
import { FunAndGamesEncounter } from "#app/data/mystery-encounters/encounters/fun-and-games-encounter";
|
import { FunAndGamesEncounter } from "#app/data/mystery-encounters/encounters/fun-and-games-encounter";
|
||||||
|
import { UncommonBreedEncounter } from "#app/data/mystery-encounters/encounters/uncommon-breed-encounter";
|
||||||
|
|
||||||
// Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * <number of missed spawns>) / 256
|
// Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * <number of missed spawns>) / 256
|
||||||
export const BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT = 1;
|
export const BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT = 1;
|
||||||
|
@ -175,7 +176,8 @@ const anyBiomeEncounters: MysteryEncounterType[] = [
|
||||||
MysteryEncounterType.CLOWNING_AROUND,
|
MysteryEncounterType.CLOWNING_AROUND,
|
||||||
MysteryEncounterType.WEIRD_DREAM,
|
MysteryEncounterType.WEIRD_DREAM,
|
||||||
MysteryEncounterType.TELEPORTING_HIJINKS,
|
MysteryEncounterType.TELEPORTING_HIJINKS,
|
||||||
MysteryEncounterType.BUG_TYPE_SUPERFAN
|
MysteryEncounterType.BUG_TYPE_SUPERFAN,
|
||||||
|
MysteryEncounterType.UNCOMMON_BREED
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -282,6 +284,7 @@ export function initMysteryEncounters() {
|
||||||
allMysteryEncounters[MysteryEncounterType.TELEPORTING_HIJINKS] = TeleportingHijinksEncounter;
|
allMysteryEncounters[MysteryEncounterType.TELEPORTING_HIJINKS] = TeleportingHijinksEncounter;
|
||||||
allMysteryEncounters[MysteryEncounterType.BUG_TYPE_SUPERFAN] = BugTypeSuperfanEncounter;
|
allMysteryEncounters[MysteryEncounterType.BUG_TYPE_SUPERFAN] = BugTypeSuperfanEncounter;
|
||||||
allMysteryEncounters[MysteryEncounterType.FUN_AND_GAMES] = FunAndGamesEncounter;
|
allMysteryEncounters[MysteryEncounterType.FUN_AND_GAMES] = FunAndGamesEncounter;
|
||||||
|
allMysteryEncounters[MysteryEncounterType.UNCOMMON_BREED] = UncommonBreedEncounter;
|
||||||
|
|
||||||
// Add extreme encounters to biome map
|
// Add extreme encounters to biome map
|
||||||
extremeBiomeEncounters.forEach(encounter => {
|
extremeBiomeEncounters.forEach(encounter => {
|
||||||
|
|
|
@ -886,7 +886,7 @@ export function handleMysteryEncounterBattleStartEffects(scene: BattleScene) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can queue extra phases or logic during {@link TurnInitPhase}
|
* Can queue extra phases or logic during {@link TurnInitPhase}
|
||||||
* Mostly useful for allowing MysteryEncounter enemies to "cheat" and use moves before the first turn
|
* Should mostly just be used for injecting custom phases into the battle system on turn start
|
||||||
* @param scene
|
* @param scene
|
||||||
* @return boolean - if true, will skip the remainder of the {@link TurnInitPhase}
|
* @return boolean - if true, will skip the remainder of the {@link TurnInitPhase}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -26,5 +26,6 @@ export enum MysteryEncounterType {
|
||||||
THE_WINSTRATE_CHALLENGE,
|
THE_WINSTRATE_CHALLENGE,
|
||||||
TELEPORTING_HIJINKS,
|
TELEPORTING_HIJINKS,
|
||||||
BUG_TYPE_SUPERFAN,
|
BUG_TYPE_SUPERFAN,
|
||||||
FUN_AND_GAMES
|
FUN_AND_GAMES,
|
||||||
|
UNCOMMON_BREED
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,32 @@
|
||||||
import lostAtSeaDialogue from "./mystery-encounters/lost-at-sea-dialogue.json";
|
import lostAtSea from "./mystery-encounters/lost-at-sea-dialogue.json";
|
||||||
import mysteriousChestDialogue from "#app/locales/en/mystery-encounters/mysterious-chest-dialogue.json";
|
import mysteriousChest from "#app/locales/en/mystery-encounters/mysterious-chest-dialogue.json";
|
||||||
import mysteriousChallengersDialogue from "#app/locales/en/mystery-encounters/mysterious-challengers-dialogue.json";
|
import mysteriousChallengers from "#app/locales/en/mystery-encounters/mysterious-challengers-dialogue.json";
|
||||||
import darkDealDialogue from "#app/locales/en/mystery-encounters/dark-deal-dialogue.json";
|
import darkDeal from "#app/locales/en/mystery-encounters/dark-deal-dialogue.json";
|
||||||
import departmentStoreSaleDialogue from "#app/locales/en/mystery-encounters/department-store-sale-dialogue.json";
|
import departmentStoreSale from "#app/locales/en/mystery-encounters/department-store-sale-dialogue.json";
|
||||||
import fieldTripDialogue from "#app/locales/en/mystery-encounters/field-trip-dialogue.json";
|
import fieldTrip from "#app/locales/en/mystery-encounters/field-trip-dialogue.json";
|
||||||
import fieryFalloutDialogue from "#app/locales/en/mystery-encounters/fiery-fallout-dialogue.json";
|
import fieryFallout from "#app/locales/en/mystery-encounters/fiery-fallout-dialogue.json";
|
||||||
import fightOrFlightDialogue from "#app/locales/en/mystery-encounters/fight-or-flight-dialogue.json";
|
import fightOrFlight from "#app/locales/en/mystery-encounters/fight-or-flight-dialogue.json";
|
||||||
import safariZoneDialogue from "#app/locales/en/mystery-encounters/safari-zone-dialogue.json";
|
import safariZone from "#app/locales/en/mystery-encounters/safari-zone-dialogue.json";
|
||||||
import shadyVitaminDealerDialogue from "#app/locales/en/mystery-encounters/shady-vitamin-dealer-dialogue.json";
|
import shadyVitaminDealer from "#app/locales/en/mystery-encounters/shady-vitamin-dealer-dialogue.json";
|
||||||
import slumberingSnorlaxDialogue from "#app/locales/en/mystery-encounters/slumbering-snorlax-dialogue.json";
|
import slumberingSnorlax from "#app/locales/en/mystery-encounters/slumbering-snorlax-dialogue.json";
|
||||||
import trainingSessionDialogue from "#app/locales/en/mystery-encounters/training-session-dialogue.json";
|
import trainingSession from "#app/locales/en/mystery-encounters/training-session-dialogue.json";
|
||||||
import theStrongStuffDialogue from "#app/locales/en/mystery-encounters/the-strong-stuff-dialogue.json";
|
import theStrongStuff from "#app/locales/en/mystery-encounters/the-strong-stuff-dialogue.json";
|
||||||
import thePokemonSalesmanDialogue from "#app/locales/en/mystery-encounters/the-pokemon-salesman-dialogue.json";
|
import pokemonSalesman from "#app/locales/en/mystery-encounters/the-pokemon-salesman-dialogue.json";
|
||||||
import anOfferYouCantRefuseDialogue from "#app/locales/en/mystery-encounters/an-offer-you-cant-refuse-dialogue.json";
|
import offerYouCantRefuse from "#app/locales/en/mystery-encounters/an-offer-you-cant-refuse-dialogue.json";
|
||||||
import delibirdyDialogue from "#app/locales/en/mystery-encounters/delibirdy-dialogue.json";
|
import delibirdy from "#app/locales/en/mystery-encounters/delibirdy-dialogue.json";
|
||||||
import absoluteAvariceDialogue from "#app/locales/en/mystery-encounters/absolute-avarice-dialogue.json";
|
import absoluteAvarice from "#app/locales/en/mystery-encounters/absolute-avarice-dialogue.json";
|
||||||
import aTrainersTestDialogue from "#app/locales/en/mystery-encounters/a-trainers-test-dialogue.json";
|
import aTrainersTest from "#app/locales/en/mystery-encounters/a-trainers-test-dialogue.json";
|
||||||
import trashToTreasureDialogue from "#app/locales/en/mystery-encounters/trash-to-treasure-dialogue.json";
|
import trashToTreasure from "#app/locales/en/mystery-encounters/trash-to-treasure-dialogue.json";
|
||||||
import berriesAboundDialogue from "#app/locales/en/mystery-encounters/berries-abound-dialogue.json";
|
import berriesAbound from "#app/locales/en/mystery-encounters/berries-abound-dialogue.json";
|
||||||
import clowningAroundDialogue from "#app/locales/en/mystery-encounters/clowning-around-dialogue.json";
|
import clowningAround from "#app/locales/en/mystery-encounters/clowning-around-dialogue.json";
|
||||||
import partTimerDialogue from "#app/locales/en/mystery-encounters/part-timer-dialogue.json";
|
import partTimer from "#app/locales/en/mystery-encounters/part-timer-dialogue.json";
|
||||||
import dancingLessonsDialogue from "#app/locales/en/mystery-encounters/dancing-lessons-dialogue.json";
|
import dancingLessons from "#app/locales/en/mystery-encounters/dancing-lessons-dialogue.json";
|
||||||
import weirdDreamDialogue from "#app/locales/en/mystery-encounters/weird-dream-dialogue.json";
|
import weirdDream from "#app/locales/en/mystery-encounters/weird-dream-dialogue.json";
|
||||||
import theWinstrateChallengeDialogue from "#app/locales/en/mystery-encounters/the-winstrate-challenge-dialogue.json";
|
import theWinstrateChallenge from "#app/locales/en/mystery-encounters/the-winstrate-challenge-dialogue.json";
|
||||||
import teleportingHijinksDialogue from "#app/locales/en/mystery-encounters/teleporting-hijinks-dialogue.json";
|
import teleportingHijinks from "#app/locales/en/mystery-encounters/teleporting-hijinks-dialogue.json";
|
||||||
import bugTypeSuperfanDialogue from "#app/locales/en/mystery-encounters/bug-type-superfan-dialogue.json";
|
import bugTypeSuperfan from "#app/locales/en/mystery-encounters/bug-type-superfan-dialogue.json";
|
||||||
import funAndGamesDialogue from "#app/locales/en/mystery-encounters/fun-and-games-dialogue.json";
|
import funAndGames from "#app/locales/en/mystery-encounters/fun-and-games-dialogue.json";
|
||||||
|
import uncommonBreed from "#app/locales/en/mystery-encounters/uncommon-breed-dialogue.json";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection patterns that can be used:
|
* Injection patterns that can be used:
|
||||||
|
@ -46,32 +47,33 @@ export const mysteryEncounter = {
|
||||||
// DO NOT REMOVE
|
// DO NOT REMOVE
|
||||||
"unit_test_dialogue": "{{test}}{{test}} {{test{{test}}}} {{test1}} {{test\}} {{test\\}} {{test\\\}} {test}}",
|
"unit_test_dialogue": "{{test}}{{test}} {{test{{test}}}} {{test1}} {{test\}} {{test\\}} {{test\\\}} {test}}",
|
||||||
|
|
||||||
mysteriousChallengers: mysteriousChallengersDialogue,
|
mysteriousChallengers,
|
||||||
mysteriousChest: mysteriousChestDialogue,
|
mysteriousChest,
|
||||||
darkDeal: darkDealDialogue,
|
darkDeal,
|
||||||
fightOrFlight: fightOrFlightDialogue,
|
fightOrFlight,
|
||||||
slumberingSnorlax: slumberingSnorlaxDialogue,
|
slumberingSnorlax,
|
||||||
trainingSession: trainingSessionDialogue,
|
trainingSession,
|
||||||
departmentStoreSale: departmentStoreSaleDialogue,
|
departmentStoreSale,
|
||||||
shadyVitaminDealer: shadyVitaminDealerDialogue,
|
shadyVitaminDealer,
|
||||||
fieldTrip: fieldTripDialogue,
|
fieldTrip,
|
||||||
safariZone: safariZoneDialogue,
|
safariZone,
|
||||||
lostAtSea: lostAtSeaDialogue,
|
lostAtSea,
|
||||||
fieryFallout: fieryFalloutDialogue,
|
fieryFallout,
|
||||||
theStrongStuff: theStrongStuffDialogue,
|
theStrongStuff,
|
||||||
pokemonSalesman: thePokemonSalesmanDialogue,
|
pokemonSalesman,
|
||||||
offerYouCantRefuse: anOfferYouCantRefuseDialogue,
|
offerYouCantRefuse,
|
||||||
delibirdy: delibirdyDialogue,
|
delibirdy,
|
||||||
absoluteAvarice: absoluteAvariceDialogue,
|
absoluteAvarice,
|
||||||
aTrainersTest: aTrainersTestDialogue,
|
aTrainersTest,
|
||||||
trashToTreasure: trashToTreasureDialogue,
|
trashToTreasure,
|
||||||
berriesAbound: berriesAboundDialogue,
|
berriesAbound,
|
||||||
clowningAround: clowningAroundDialogue,
|
clowningAround,
|
||||||
partTimer: partTimerDialogue,
|
partTimer,
|
||||||
dancingLessons: dancingLessonsDialogue,
|
dancingLessons,
|
||||||
weirdDream: weirdDreamDialogue,
|
weirdDream,
|
||||||
theWinstrateChallenge: theWinstrateChallengeDialogue,
|
theWinstrateChallenge,
|
||||||
teleportingHijinks: teleportingHijinksDialogue,
|
teleportingHijinks,
|
||||||
bugTypeSuperfan: bugTypeSuperfanDialogue,
|
bugTypeSuperfan,
|
||||||
funAndGames: funAndGamesDialogue
|
funAndGames,
|
||||||
|
uncommonBreed,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
"1": {
|
"1": {
|
||||||
"label": "Battle the Pokémon",
|
"label": "Battle the Pokémon",
|
||||||
"tooltip": "(-) Hard Battle\n(+) New Item",
|
"tooltip": "(-) Hard Battle\n(+) New Item",
|
||||||
"selected": "You approach the\nPokémon without fear."
|
"selected": "You approach the\nPokémon without fear.",
|
||||||
|
"stat_boost": "The {{enemyPokemon}} latent strength boosted one of its stats!"
|
||||||
},
|
},
|
||||||
"2": {
|
"2": {
|
||||||
"label": "Steal the Item",
|
"label": "Steal the Item",
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"intro": "That isn't just an ordinary Pokémon!",
|
||||||
|
"title": "Uncommon Breed",
|
||||||
|
"description": "That {{enemyPokemon}} looks special compared to others of its kind. @[TOOLTIP_TITLE]{Perhaps it knows a special move?} You could battle and catch it outright, but there might also be a way to befriend it.",
|
||||||
|
"query": "What will you do?",
|
||||||
|
"option": {
|
||||||
|
"1": {
|
||||||
|
"label": "Battle the Pokémon",
|
||||||
|
"tooltip": "(-) Tricky Battle\n(+) Strong Catchable Foe",
|
||||||
|
"selected": "You approach the\n{{enemyPokemon}} without fear.",
|
||||||
|
"stat_boost": "The {{enemyPokemon}} heightened abilities boost its stats!"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"label": "Give It Food",
|
||||||
|
"disabled_tooltip": "You need 4 berry items to choose this",
|
||||||
|
"tooltip": "(-) Give 4 Berries\n(+) The {{enemyPokemon}} Likes You",
|
||||||
|
"selected": "You toss the berries at the {{enemyPokemon}}!$It eats them happily!$The {{enemyPokemon}} wants to join your party!"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"label": "Befriend It",
|
||||||
|
"disabled_tooltip": "Your Pokémon need to know certain moves to choose this",
|
||||||
|
"tooltip": "(+) {{option3PrimaryName}} uses {{option3PrimaryMove}}\n(+) The {{enemyPokemon}} Likes You",
|
||||||
|
"selected": "Your {{option3PrimaryName}} uses {{option3PrimaryMove}} to charm the {{enemyPokemon}}!$The {{enemyPokemon}} wants to join your party!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -133,9 +133,9 @@ class DefaultOverrides {
|
||||||
// -------------------------
|
// -------------------------
|
||||||
|
|
||||||
/** 1 to 256, set to null to ignore */
|
/** 1 to 256, set to null to ignore */
|
||||||
readonly MYSTERY_ENCOUNTER_RATE_OVERRIDE: number | null = 256;
|
readonly MYSTERY_ENCOUNTER_RATE_OVERRIDE: number | null = null;
|
||||||
readonly MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier | null = null;
|
readonly MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier | null = null;
|
||||||
readonly MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType | null = MysteryEncounterType.MYSTERIOUS_CHEST;
|
readonly MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType | null = null;
|
||||||
|
|
||||||
// -------------------------
|
// -------------------------
|
||||||
// MODIFIER / ITEM OVERRIDES
|
// MODIFIER / ITEM OVERRIDES
|
||||||
|
|
|
@ -22,6 +22,8 @@ import { ReturnPhase } from "#app/phases/return-phase";
|
||||||
import { CheckSwitchPhase } from "#app/phases/check-switch-phase";
|
import { CheckSwitchPhase } from "#app/phases/check-switch-phase";
|
||||||
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
|
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
|
||||||
import { NewBattlePhase } from "#app/phases/new-battle-phase";
|
import { NewBattlePhase } from "#app/phases/new-battle-phase";
|
||||||
|
import { GameOverPhase } from "#app/phases/game-over-phase";
|
||||||
|
import { SwitchPhase } from "#app/phases/switch-phase";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will handle (in order):
|
* Will handle (in order):
|
||||||
|
@ -161,21 +163,22 @@ export class MysteryEncounterOptionSelectedPhase extends Phase {
|
||||||
this.onOptionSelect(this.scene).finally(() => {
|
this.onOptionSelect(this.scene).finally(() => {
|
||||||
this.end();
|
this.end();
|
||||||
});
|
});
|
||||||
}, this.scene.currentBattle.mysteryEncounter?.getSeedOffset());
|
}, this.scene.currentBattle.mysteryEncounter?.getSeedOffset() * 500);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.scene.executeWithSeedOffset(() => {
|
this.scene.executeWithSeedOffset(() => {
|
||||||
this.onOptionSelect(this.scene).finally(() => {
|
this.onOptionSelect(this.scene).finally(() => {
|
||||||
this.end();
|
this.end();
|
||||||
});
|
});
|
||||||
}, this.scene.currentBattle.mysteryEncounter?.getSeedOffset());
|
}, this.scene.currentBattle.mysteryEncounter?.getSeedOffset() * 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs at the beginning of an Encounter's battle
|
* Runs at the beginning of an Encounter's battle
|
||||||
* Will cleanup any residual flinches, Endure, etc. that are left over from startOfBattleEffects
|
* Will clean up any residual flinches, Endure, etc. that are left over from startOfBattleEffects
|
||||||
|
* Will also handle Game Overs, switches, etc. that could happen from handleMysteryEncounterBattleStartEffects
|
||||||
* See [TurnEndPhase](../phases.ts) for more details
|
* See [TurnEndPhase](../phases.ts) for more details
|
||||||
*/
|
*/
|
||||||
export class MysteryEncounterBattleStartCleanupPhase extends Phase {
|
export class MysteryEncounterBattleStartCleanupPhase extends Phase {
|
||||||
|
@ -196,6 +199,28 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
|
||||||
this.scene.tryRemovePhase(p => p instanceof PostTurnStatusEffectPhase);
|
this.scene.tryRemovePhase(p => p instanceof PostTurnStatusEffectPhase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The total number of Pokemon in the player's party that can legally fight
|
||||||
|
const legalPlayerPokemon = this.scene.getParty().filter(p => p.isAllowedInBattle());
|
||||||
|
// The total number of legal player Pokemon that aren't currently on the field
|
||||||
|
const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true));
|
||||||
|
if (!legalPlayerPokemon.length) {
|
||||||
|
this.scene.unshiftPhase(new GameOverPhase(this.scene));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for any KOd player mons and switch
|
||||||
|
// For each fainted mon on the field, if there is a legal replacement, summon it
|
||||||
|
const playerField = this.scene.getPlayerField();
|
||||||
|
playerField.forEach((pokemon, i) => {
|
||||||
|
if (!pokemon.isAllowedInBattle() && legalPlayerPartyPokemon.length > i) {
|
||||||
|
this.scene.unshiftPhase(new SwitchPhase(this.scene, i, true, false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// THEN, if is a double battle, and player only has 1 summoned pokemon, center pokemon on field
|
||||||
|
if (this.scene.currentBattle.double && legalPlayerPokemon.length === 1 && legalPlayerPartyPokemon.length === 0) {
|
||||||
|
this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true));
|
||||||
|
}
|
||||||
|
|
||||||
super.end();
|
super.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -477,7 +502,7 @@ export class PostMysteryEncounterPhase extends Phase {
|
||||||
this.continueEncounter();
|
this.continueEncounter();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, this.scene.currentBattle.mysteryEncounter?.getSeedOffset());
|
}, this.scene.currentBattle.mysteryEncounter?.getSeedOffset() * 2000);
|
||||||
} else {
|
} else {
|
||||||
this.continueEncounter();
|
this.continueEncounter();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,240 @@
|
||||||
|
import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters";
|
||||||
|
import { Biome } from "#app/enums/biome";
|
||||||
|
import { MysteryEncounterType } from "#app/enums/mystery-encounter-type";
|
||||||
|
import { Species } from "#app/enums/species";
|
||||||
|
import GameManager from "#app/test/utils/gameManager";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption } from "#test/mystery-encounter/encounter-test-utils";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import BattleScene from "#app/battle-scene";
|
||||||
|
import { PokemonMove } from "#app/field/pokemon";
|
||||||
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
|
import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils";
|
||||||
|
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
|
import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases";
|
||||||
|
import { CommandPhase } from "#app/phases/command-phase";
|
||||||
|
import { UncommonBreedEncounter } from "#app/data/mystery-encounters/encounters/uncommon-breed-encounter";
|
||||||
|
import { MovePhase } from "#app/phases/move-phase";
|
||||||
|
import { speciesEggMoves } from "#app/data/egg-moves";
|
||||||
|
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||||
|
import { BerryType } from "#enums/berry-type";
|
||||||
|
|
||||||
|
const namespace = "mysteryEncounter:uncommonBreed";
|
||||||
|
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA];
|
||||||
|
const defaultBiome = Biome.CAVE;
|
||||||
|
const defaultWave = 45;
|
||||||
|
|
||||||
|
describe("Uncommon Breed - Mystery Encounter", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
let scene: BattleScene;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({ type: Phaser.HEADLESS });
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
scene = game.scene;
|
||||||
|
game.override.mysteryEncounterChance(100);
|
||||||
|
game.override.startingWave(defaultWave);
|
||||||
|
game.override.startingBiome(defaultBiome);
|
||||||
|
game.override.disableTrainerWaves();
|
||||||
|
|
||||||
|
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(
|
||||||
|
new Map<Biome, MysteryEncounterType[]>([
|
||||||
|
[Biome.CAVE, [MysteryEncounterType.UNCOMMON_BREED]],
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
vi.clearAllMocks();
|
||||||
|
vi.resetAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should have the correct properties", async () => {
|
||||||
|
await game.runToMysteryEncounter(MysteryEncounterType.UNCOMMON_BREED, defaultParty);
|
||||||
|
|
||||||
|
expect(UncommonBreedEncounter.encounterType).toBe(MysteryEncounterType.UNCOMMON_BREED);
|
||||||
|
expect(UncommonBreedEncounter.encounterTier).toBe(MysteryEncounterTier.COMMON);
|
||||||
|
expect(UncommonBreedEncounter.dialogue).toBeDefined();
|
||||||
|
expect(UncommonBreedEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}.intro` }]);
|
||||||
|
expect(UncommonBreedEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`);
|
||||||
|
expect(UncommonBreedEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`);
|
||||||
|
expect(UncommonBreedEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`);
|
||||||
|
expect(UncommonBreedEncounter.options.length).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not run below wave 10", async () => {
|
||||||
|
game.override.startingWave(9);
|
||||||
|
|
||||||
|
await game.runToMysteryEncounter();
|
||||||
|
|
||||||
|
expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.UNCOMMON_BREED);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not run above wave 179", async () => {
|
||||||
|
game.override.startingWave(181);
|
||||||
|
|
||||||
|
await game.runToMysteryEncounter();
|
||||||
|
|
||||||
|
expect(scene.currentBattle.mysteryEncounter).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should initialize fully", async () => {
|
||||||
|
initSceneWithoutEncounterPhase(scene, defaultParty);
|
||||||
|
scene.currentBattle.mysteryEncounter = UncommonBreedEncounter;
|
||||||
|
|
||||||
|
const { onInit } = UncommonBreedEncounter;
|
||||||
|
|
||||||
|
expect(UncommonBreedEncounter.onInit).toBeDefined();
|
||||||
|
|
||||||
|
UncommonBreedEncounter.populateDialogueTokensFromRequirements(scene);
|
||||||
|
const onInitResult = onInit!(scene);
|
||||||
|
|
||||||
|
const config = UncommonBreedEncounter.enemyPartyConfigs[0];
|
||||||
|
expect(config).toBeDefined();
|
||||||
|
expect(config.pokemonConfigs?.[0].isBoss).toBe(false);
|
||||||
|
expect(onInitResult).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Option 1 - Fight", () => {
|
||||||
|
it("should have the correct properties", () => {
|
||||||
|
const option = UncommonBreedEncounter.options[0];
|
||||||
|
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||||
|
expect(option.dialogue).toBeDefined();
|
||||||
|
expect(option.dialogue).toStrictEqual({
|
||||||
|
buttonLabel: `${namespace}.option.1.label`,
|
||||||
|
buttonTooltip: `${namespace}.option.1.tooltip`,
|
||||||
|
selected: [
|
||||||
|
{
|
||||||
|
text: `${namespace}.option.1.selected`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should start a fight against the boss", async () => {
|
||||||
|
const phaseSpy = vi.spyOn(scene, "pushPhase");
|
||||||
|
await game.runToMysteryEncounter(MysteryEncounterType.UNCOMMON_BREED, defaultParty);
|
||||||
|
|
||||||
|
const config = game.scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0];
|
||||||
|
const speciesToSpawn = config.pokemonConfigs?.[0].species.speciesId;
|
||||||
|
|
||||||
|
await runMysteryEncounterToEnd(game, 1, undefined, true);
|
||||||
|
|
||||||
|
const enemyField = scene.getEnemyField();
|
||||||
|
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
|
||||||
|
expect(enemyField.length).toBe(1);
|
||||||
|
expect(enemyField[0].species.speciesId).toBe(speciesToSpawn);
|
||||||
|
expect(enemyField[0].summonData.battleStats).toEqual([1, 1, 1, 1, 1, 0, 0]);
|
||||||
|
|
||||||
|
// Should have used its egg move pre-battle
|
||||||
|
const movePhases = phaseSpy.mock.calls.filter(p => p[0] instanceof MovePhase).map(p => p[0]);
|
||||||
|
expect(movePhases.length).toBe(1);
|
||||||
|
const eggMoves: Moves[] = speciesEggMoves[getPokemonSpecies(speciesToSpawn).getRootSpeciesId()];
|
||||||
|
const usedMove = (movePhases[0] as MovePhase).move.moveId;
|
||||||
|
expect(eggMoves.includes(usedMove)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Option 2 - Give it Food", () => {
|
||||||
|
it("should have the correct properties", () => {
|
||||||
|
const option = UncommonBreedEncounter.options[1];
|
||||||
|
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL);
|
||||||
|
expect(option.dialogue).toBeDefined();
|
||||||
|
expect(option.dialogue).toStrictEqual({
|
||||||
|
buttonLabel: `${namespace}.option.2.label`,
|
||||||
|
buttonTooltip: `${namespace}.option.2.tooltip`,
|
||||||
|
disabledButtonTooltip: `${namespace}.option.2.disabled_tooltip`,
|
||||||
|
selected: [
|
||||||
|
{
|
||||||
|
text: `${namespace}.option.2.selected`,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should NOT be selectable if the player doesn't have enough berries", async () => {
|
||||||
|
game.override.startingHeldItems([{name: "BERRY", count: 2, type: BerryType.SITRUS}]);
|
||||||
|
await game.runToMysteryEncounter(MysteryEncounterType.UNCOMMON_BREED, defaultParty);
|
||||||
|
await game.phaseInterceptor.to(MysteryEncounterPhase, false);
|
||||||
|
|
||||||
|
const encounterPhase = scene.getCurrentPhase();
|
||||||
|
expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name);
|
||||||
|
const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase;
|
||||||
|
vi.spyOn(mysteryEncounterPhase, "continueEncounter");
|
||||||
|
vi.spyOn(mysteryEncounterPhase, "handleOptionSelect");
|
||||||
|
vi.spyOn(scene.ui, "playError");
|
||||||
|
|
||||||
|
await runSelectMysteryEncounterOption(game, 2);
|
||||||
|
|
||||||
|
expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name);
|
||||||
|
expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled
|
||||||
|
expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled();
|
||||||
|
expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should skip fight when player meets requirements", async () => {
|
||||||
|
game.override.startingHeldItems([{name: "BERRY", count: 2, type: BerryType.SITRUS}, {name: "BERRY", count: 3, type: BerryType.GANLON}]);
|
||||||
|
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||||
|
|
||||||
|
await game.runToMysteryEncounter(MysteryEncounterType.UNCOMMON_BREED, defaultParty);
|
||||||
|
|
||||||
|
await runMysteryEncounterToEnd(game, 2);
|
||||||
|
|
||||||
|
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Option 3 - Use an Attracting Move", () => {
|
||||||
|
it("should have the correct properties", () => {
|
||||||
|
const option = UncommonBreedEncounter.options[2];
|
||||||
|
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL);
|
||||||
|
expect(option.dialogue).toBeDefined();
|
||||||
|
expect(option.dialogue).toStrictEqual({
|
||||||
|
buttonLabel: `${namespace}.option.3.label`,
|
||||||
|
buttonTooltip: `${namespace}.option.3.tooltip`,
|
||||||
|
disabledButtonTooltip: `${namespace}.option.3.disabled_tooltip`,
|
||||||
|
selected: [
|
||||||
|
{
|
||||||
|
text: `${namespace}.option.3.selected`,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should NOT be selectable if the player doesn't have an Attracting move", async () => {
|
||||||
|
await game.runToMysteryEncounter(MysteryEncounterType.UNCOMMON_BREED, defaultParty);
|
||||||
|
scene.getParty().forEach(p => p.moveset = []);
|
||||||
|
await game.phaseInterceptor.to(MysteryEncounterPhase, false);
|
||||||
|
|
||||||
|
const encounterPhase = scene.getCurrentPhase();
|
||||||
|
expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name);
|
||||||
|
const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase;
|
||||||
|
vi.spyOn(mysteryEncounterPhase, "continueEncounter");
|
||||||
|
vi.spyOn(mysteryEncounterPhase, "handleOptionSelect");
|
||||||
|
vi.spyOn(scene.ui, "playError");
|
||||||
|
|
||||||
|
await runSelectMysteryEncounterOption(game, 3);
|
||||||
|
|
||||||
|
expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name);
|
||||||
|
expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled
|
||||||
|
expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled();
|
||||||
|
expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should skip fight when player meets requirements", async () => {
|
||||||
|
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||||
|
await game.runToMysteryEncounter(MysteryEncounterType.UNCOMMON_BREED, defaultParty);
|
||||||
|
// Mock moveset
|
||||||
|
scene.getParty()[0].moveset = [new PokemonMove(Moves.CHARM)];
|
||||||
|
await runMysteryEncounterToEnd(game, 3);
|
||||||
|
|
||||||
|
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue