Merge pull request #3861 from pagefaultgames/fun-and-games
Fun And Games! Encounter
This commit is contained in:
commit
162a3b1d5b
Binary file not shown.
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "carnival_game.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 38,
|
||||
"h": 82
|
||||
},
|
||||
"scale": 1,
|
||||
"frames": [
|
||||
{
|
||||
"filename": "0001.png",
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 38,
|
||||
"h": 82
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 38,
|
||||
"h": 82
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 38,
|
||||
"h": 82
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:d40b6742392c2fe8ca0735b3f561e319:5dcda5410b12f0aa75eb0dd1fbcbe4f9:d171fb17d3017d1f655cd8dd14c252b7$"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 517 B |
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "carnival_man.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 50,
|
||||
"h": 77
|
||||
},
|
||||
"scale": 1,
|
||||
"frames": [
|
||||
{
|
||||
"filename": "0001.png",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 80,
|
||||
"h": 80
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 15,
|
||||
"y": 3,
|
||||
"w": 50,
|
||||
"h": 77
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 50,
|
||||
"h": 77
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:e80aa9a809a7cca6d05992cb82f6dbd9:ea9962edd1cdc1e503deecf2ce1863c1:55647352b6547cf03212506309f2abf5$"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 833 B |
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "carnival_wobbuffet.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 45,
|
||||
"h": 55
|
||||
},
|
||||
"scale": 1,
|
||||
"frames": [
|
||||
{
|
||||
"filename": "0001.png",
|
||||
"rotated": false,
|
||||
"trimmed": false,
|
||||
"sourceSize": {
|
||||
"w": 45,
|
||||
"h": 55
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 45,
|
||||
"h": 55
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 45,
|
||||
"h": 55
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:879de17da906ea52e5a71afacb88fcf6:90f64e8eaac4ff1e67373f60c3d98d36:a090cb3294ca1218a4f90ecb97df81d7$"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 772 B |
|
@ -254,7 +254,7 @@ export default class BattleScene extends SceneBase {
|
|||
public pokemonInfoContainer: PokemonInfoContainer;
|
||||
private party: PlayerPokemon[];
|
||||
public mysteryEncounterData: MysteryEncounterData = new MysteryEncounterData(null);
|
||||
public lastMysteryEncounter: MysteryEncounter;
|
||||
public lastMysteryEncounter?: MysteryEncounter;
|
||||
/** Combined Biome and Wave count text */
|
||||
private biomeWaveText: Phaser.GameObjects.Text;
|
||||
private moneyText: Phaser.GameObjects.Text;
|
||||
|
@ -1213,7 +1213,7 @@ export default class BattleScene extends SceneBase {
|
|||
const maxExpLevel = this.getMaxExpLevel();
|
||||
|
||||
this.lastEnemyTrainer = lastBattle?.trainer ?? null;
|
||||
this.lastMysteryEncounter = lastBattle?.mysteryEncounter ?? null;
|
||||
this.lastMysteryEncounter = lastBattle?.mysteryEncounter;
|
||||
|
||||
this.executeWithSeedOffset(() => {
|
||||
this.currentBattle = new Battle(this.gameMode, newWaveIndex, newBattleType, newTrainer, newDouble);
|
||||
|
|
|
@ -70,7 +70,7 @@ export default class Battle {
|
|||
public lastUsedPokeball: PokeballType | null;
|
||||
public playerFaints: number; // The amount of times pokemon on the players side have fainted
|
||||
public enemyFaints: number; // The amount of times pokemon on the enemies side have fainted
|
||||
public mysteryEncounter: MysteryEncounter;
|
||||
public mysteryEncounter?: MysteryEncounter;
|
||||
|
||||
private rngCounter: integer = 0;
|
||||
|
||||
|
|
|
@ -891,6 +891,8 @@ export abstract class BattleAnim {
|
|||
const isUser = frame.target === AnimFrameTarget.USER;
|
||||
if (isUser && target === user) {
|
||||
continue;
|
||||
} else if (this.playOnEmptyField && frame.target === AnimFrameTarget.TARGET) {
|
||||
continue;
|
||||
}
|
||||
const sprites = spriteCache[isUser ? AnimFrameTarget.USER : AnimFrameTarget.TARGET];
|
||||
const spriteSource = isUser ? userSprite : targetSprite;
|
||||
|
@ -1223,8 +1225,8 @@ export class CommonBattleAnim extends BattleAnim {
|
|||
export class MoveAnim extends BattleAnim {
|
||||
public move: Moves;
|
||||
|
||||
constructor(move: Moves, user: Pokemon, target: BattlerIndex) {
|
||||
super(user, user.scene.getField()[target]);
|
||||
constructor(move: Moves, user: Pokemon, target: BattlerIndex, playOnEmptyField: boolean = false) {
|
||||
super(user, user.scene.getField()[target], playOnEmptyField);
|
||||
|
||||
this.move = move;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ export const ATrainersTestEncounter: MysteryEncounter =
|
|||
])
|
||||
.withAutoHideIntroVisuals(false)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Randomly pick from 1 of the 5 stat trainers to spawn
|
||||
let trainerType: TrainerType;
|
||||
|
@ -135,7 +135,7 @@ export const ATrainersTestEncounter: MysteryEncounter =
|
|||
buttonTooltip: `${namespace}.option.1.tooltip`
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
// Spawn standard trainer battle with memory mushroom reward
|
||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
|
||||
|
||||
|
@ -160,7 +160,7 @@ export const ATrainersTestEncounter: MysteryEncounter =
|
|||
buttonTooltip: `${namespace}.option.2.tooltip`
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
// Full heal party
|
||||
scene.unshiftPhase(new PartyHealPhase(scene, true));
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
.withDescription(`${namespace}.description`)
|
||||
.withQuery(`${namespace}.query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
scene.loadSe("PRSFX- Bug Bite", "battle_anims");
|
||||
scene.loadSe("Follow Me", "battle_anims", "Follow Me.mp3");
|
||||
|
@ -242,7 +242,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Pick battle
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Provides 1x Reviver Seed to each party member at end of battle
|
||||
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED);
|
||||
|
@ -283,7 +283,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const berryMap = encounter.misc.berryItemsMap;
|
||||
|
||||
// Returns 2/5 of the berries stolen from each Pokemon
|
||||
|
@ -349,7 +349,7 @@ function doGreedentSpriteSteal(scene: BattleScene) {
|
|||
const shakeDelay = 50;
|
||||
const slideDelay = 500;
|
||||
|
||||
const greedentSprites = scene.currentBattle.mysteryEncounter.introVisuals?.getSpriteAtIndex(1);
|
||||
const greedentSprites = scene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(1);
|
||||
|
||||
scene.playSound("battle-anims/Follow Me");
|
||||
scene.tweens.chain({
|
||||
|
@ -423,7 +423,7 @@ function doGreedentSpriteSteal(scene: BattleScene) {
|
|||
}
|
||||
|
||||
function doGreedentEatBerries(scene: BattleScene) {
|
||||
const greedentSprites = scene.currentBattle.mysteryEncounter.introVisuals?.getSpriteAtIndex(1);
|
||||
const greedentSprites = scene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(1);
|
||||
let index = 1;
|
||||
scene.tweens.add({
|
||||
targets: greedentSprites,
|
||||
|
@ -455,7 +455,7 @@ function doBerrySpritePile(scene: BattleScene, isEat: boolean = false) {
|
|||
if (isEat) {
|
||||
animationOrder = animationOrder.reverse();
|
||||
}
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
animationOrder.forEach((berry, i) => {
|
||||
const introVisualsIndex = encounter.spriteConfigs.findIndex(config => config.spriteKey?.includes(berry));
|
||||
let sprite: Phaser.GameObjects.Sprite, tintSprite: Phaser.GameObjects.Sprite;
|
||||
|
|
|
@ -58,7 +58,7 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
|
|||
.withDescription(`${namespace}.description`)
|
||||
.withQuery(`${namespace}.query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const pokemon = getHighestStatTotalPlayerPokemon(scene, false);
|
||||
const price = scene.getWaveMoneyAmount(10);
|
||||
|
||||
|
@ -99,7 +99,7 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
// Update money and remove pokemon from party
|
||||
updatePlayerMoney(scene, encounter.misc.price);
|
||||
scene.removePokemonFromPlayerParty(encounter.misc.pokemon);
|
||||
|
@ -132,7 +132,7 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Extort the rich kid for money
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
// Update money and remove pokemon from party
|
||||
updatePlayerMoney(scene, encounter.misc.price);
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Calculate boss mon
|
||||
const level = (scene.currentBattle.enemyLevels?.[0] ?? scene.currentBattle.waveIndex) + Math.max(Math.round((scene.currentBattle.waveIndex / 10)), 0);
|
||||
|
@ -125,7 +125,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
},
|
||||
async (scene: BattleScene) => {
|
||||
// Pick battle
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const numBerries = encounter.misc.numBerries;
|
||||
|
||||
const doBerryRewards = async () => {
|
||||
|
@ -150,7 +150,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
}
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards);
|
||||
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]);
|
||||
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
|
||||
}
|
||||
)
|
||||
.withOption(
|
||||
|
@ -162,7 +162,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Pick race for berries
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const fastestPokemon = encounter.misc.fastestPokemon;
|
||||
const enemySpeed = encounter.misc.enemySpeed;
|
||||
const speedDiff = fastestPokemon.getStat(Stat.SPD) / (enemySpeed * 1.1);
|
||||
|
@ -191,7 +191,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
}
|
||||
};
|
||||
|
||||
const config = scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0];
|
||||
const config = scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0];
|
||||
config.pokemonConfigs![0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON];
|
||||
config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => {
|
||||
queueEncounterMessage(pokemon.scene, `${namespace}.option.2.boss_enraged`);
|
||||
|
|
|
@ -204,7 +204,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
// Calculates what trainers are available for battle in the encounter
|
||||
|
||||
// Bug type superfan trainer config
|
||||
|
@ -241,7 +241,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
},
|
||||
async (scene: BattleScene) => {
|
||||
// Select battle the bug trainer
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
|
||||
|
||||
// Init the moves available for tutor
|
||||
|
@ -272,7 +272,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
// Player shows off their bug types
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Player gets different rewards depending on the number of bug types they have
|
||||
const numBugTypes = scene.getParty().filter(p => p.isOfType(Type.BUG, true)).length;
|
||||
|
@ -360,7 +360,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
secondOptionPrompt: `${namespace}.option.3.select_prompt`,
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Get Pokemon held items and filter for valid ones
|
||||
const validItems = pokemon.getHeldItems().filter(item => {
|
||||
|
@ -403,7 +403,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
|||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const modifier = encounter.misc.chosenModifier;
|
||||
|
||||
// Remove the modifier if its stacks go to 0
|
||||
|
@ -583,7 +583,7 @@ function getRandomPartyMemberFunc(speciesPool: Species[], trainerSlot: TrainerSl
|
|||
|
||||
function doBugTypeMoveTutor(scene: BattleScene): Promise<void> {
|
||||
return new Promise<void>(async resolve => {
|
||||
const moveOptions = scene.currentBattle.mysteryEncounter.misc.moveTutorOptions;
|
||||
const moveOptions = scene.currentBattle.mysteryEncounter!.misc.moveTutorOptions;
|
||||
await showEncounterDialogue(scene, `${namespace}.battle_won`, `${namespace}.speaker`);
|
||||
|
||||
const overlayScale = 1;
|
||||
|
|
|
@ -102,7 +102,7 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const clownTrainerType = TrainerType.HARLEQUIN;
|
||||
const clownConfig = trainerConfigs[clownTrainerType].copy();
|
||||
|
@ -159,7 +159,7 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
// Spawn battle
|
||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
|
||||
|
||||
|
@ -236,7 +236,7 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||
// Swap player's items on pokemon with the most items
|
||||
// Item comparisons look at whichever Pokemon has the greatest number of TRANSFERABLE, non-berry items
|
||||
// So Vitamins, form change items, etc. are not included
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const party = scene.getParty();
|
||||
let mostHeldItemsPokemon = party[0];
|
||||
|
@ -418,8 +418,8 @@ function onYesAbilitySwap(scene: BattleScene, resolve) {
|
|||
if (!pokemon.mysteryEncounterData) {
|
||||
pokemon.mysteryEncounterData = new MysteryEncounterPokemonData(undefined, Abilities.AERILATE);
|
||||
}
|
||||
pokemon.mysteryEncounterData.ability = scene.currentBattle.mysteryEncounter.misc.ability;
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("chosenPokemon", pokemon.getNameToRender());
|
||||
pokemon.mysteryEncounterData.ability = scene.currentBattle.mysteryEncounter!.misc.ability;
|
||||
scene.currentBattle.mysteryEncounter!.setDialogueToken("chosenPokemon", pokemon.getNameToRender());
|
||||
scene.ui.setMode(Mode.MESSAGE).then(() => resolve(true));
|
||||
};
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
.withDescription(`${namespace}.description`)
|
||||
.withQuery(`${namespace}.query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const species = getPokemonSpecies(Species.ORICORIO);
|
||||
const enemyPokemon = scene.addEnemyPokemon(species, scene.currentBattle.enemyLevels![0], TrainerSlot.NONE, false);
|
||||
|
@ -170,7 +170,7 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Pick battle
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
transitionMysteryEncounterIntroVisuals(scene, true, true, 500);
|
||||
|
||||
|
@ -200,7 +200,7 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
// Learn its Dance
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
encounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
|
||||
|
@ -236,7 +236,7 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
// Open menu for selecting pokemon with a Dancing move
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Return the options for nature selection
|
||||
return pokemon.moveset
|
||||
|
@ -272,7 +272,7 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Show the Oricorio a dance, and recruit it
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const oricorio = encounter.misc.oricorioData.toPokemon(scene);
|
||||
oricorio.passive = true;
|
||||
|
||||
|
|
|
@ -127,14 +127,15 @@ export const DarkDealEncounter: MysteryEncounter =
|
|||
const removedPokemon = getRandomPlayerPokemon(scene, false, true);
|
||||
scene.removePokemonFromPlayerParty(removedPokemon);
|
||||
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("pokeName", removedPokemon.getNameToRender());
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
encounter.setDialogueToken("pokeName", removedPokemon.getNameToRender());
|
||||
|
||||
// Store removed pokemon types
|
||||
scene.currentBattle.mysteryEncounter.misc = [
|
||||
encounter.misc = [
|
||||
removedPokemon.species.type1,
|
||||
];
|
||||
if (removedPokemon.species.type2) {
|
||||
scene.currentBattle.mysteryEncounter.misc.push(removedPokemon.species.type2);
|
||||
encounter.misc.push(removedPokemon.species.type2);
|
||||
}
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
|
@ -142,7 +143,7 @@ export const DarkDealEncounter: MysteryEncounter =
|
|||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.ROGUE_BALL));
|
||||
|
||||
// Start encounter with random legendary (7-10 starter strength) that has level additive
|
||||
const bossTypes = scene.currentBattle.mysteryEncounter.misc as Type[];
|
||||
const bossTypes = scene.currentBattle.mysteryEncounter!.misc as Type[];
|
||||
// Starter egg tier, 35/50/10/5 %odds for tiers 6/7/8/9+
|
||||
const roll = randSeedInt(100);
|
||||
const starterTier: number | [number, number] =
|
||||
|
|
|
@ -102,7 +102,7 @@ export const DelibirdyEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
updatePlayerMoney(scene, -(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney, true, false);
|
||||
return true;
|
||||
})
|
||||
|
@ -140,7 +140,7 @@ export const DelibirdyEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Get Pokemon held items and filter for valid ones
|
||||
const validItems = pokemon.getHeldItems().filter((it) => {
|
||||
|
@ -178,7 +178,7 @@ export const DelibirdyEncounter: MysteryEncounter =
|
|||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const modifier = encounter.misc.chosenModifier;
|
||||
|
||||
// Give the player a Candy Jar if they gave a Berry, and a Healing Charm for Reviver Seed
|
||||
|
@ -235,7 +235,7 @@ export const DelibirdyEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Get Pokemon held items and filter for valid ones
|
||||
const validItems = pokemon.getHeldItems().filter((it) => {
|
||||
|
@ -273,7 +273,7 @@ export const DelibirdyEncounter: MysteryEncounter =
|
|||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const modifier = encounter.misc.chosenModifier;
|
||||
|
||||
// Check if the player has max stacks of Berry Pouch already
|
||||
|
|
|
@ -67,7 +67,7 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Return the options for Pokemon move valid for this option
|
||||
return pokemon.moveset.map((move: PokemonMove) => {
|
||||
|
@ -123,7 +123,7 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
return selectPokemonForOption(scene, onPokemonSelected);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
if (encounter.misc.correctMove) {
|
||||
const modifiers = [
|
||||
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.ATK])!,
|
||||
|
@ -153,7 +153,7 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Return the options for Pokemon move valid for this option
|
||||
return pokemon.moveset.map((move: PokemonMove) => {
|
||||
|
@ -215,7 +215,7 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
return selectPokemonForOption(scene, onPokemonSelected);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
if (encounter.misc.correctMove) {
|
||||
const modifiers = [
|
||||
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPATK])!,
|
||||
|
@ -245,7 +245,7 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Return the options for Pokemon move valid for this option
|
||||
return pokemon.moveset.map((move: PokemonMove) => {
|
||||
|
@ -301,7 +301,7 @@ export const FieldTripEncounter: MysteryEncounter =
|
|||
return selectPokemonForOption(scene, onPokemonSelected);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
if (encounter.misc.correctMove) {
|
||||
const modifiers = [
|
||||
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.ACC])!,
|
||||
|
|
|
@ -50,7 +50,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Calculate boss mons
|
||||
const volcaronaSpecies = getPokemonSpecies(Species.VOLCARONA);
|
||||
|
@ -132,7 +132,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
},
|
||||
async (scene: BattleScene) => {
|
||||
// Pick battle
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
setEncounterRewards(scene, { fillRemaining: true }, undefined, () => giveLeadPokemonCharcoal(scene));
|
||||
|
||||
encounter.startOfBattleEffects.push(
|
||||
|
@ -160,7 +160,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
move: new PokemonMove(Moves.QUIVER_DANCE),
|
||||
ignorePp: true
|
||||
});
|
||||
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]);
|
||||
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
|
||||
}
|
||||
)
|
||||
.withSimpleOption(
|
||||
|
@ -175,7 +175,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
},
|
||||
async (scene: BattleScene) => {
|
||||
// Damage non-fire types and burn 1 random non-fire type member
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const nonFireTypes = scene.getParty().filter((p) => p.isAllowedInBattle() && !p.getTypes().includes(Type.FIRE));
|
||||
|
||||
for (const pkm of nonFireTypes) {
|
||||
|
@ -220,7 +220,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Fire types help calm the Volcarona
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
transitionMysteryEncounterIntroVisuals(scene);
|
||||
setEncounterRewards(scene,
|
||||
{ fillRemaining: true },
|
||||
|
@ -245,7 +245,7 @@ function giveLeadPokemonCharcoal(scene: BattleScene) {
|
|||
if (leadPokemon) {
|
||||
const charcoal = generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.FIRE]) as AttackTypeBoosterModifierType;
|
||||
applyModifierTypeToPlayerPokemon(scene, leadPokemon, charcoal);
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("leadPokemon", leadPokemon.getNameToRender());
|
||||
scene.currentBattle.mysteryEncounter!.setDialogueToken("leadPokemon", leadPokemon.getNameToRender());
|
||||
queueEncounterMessage(scene, `${namespace}.found_charcoal`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ export const FightOrFlightEncounter: MysteryEncounter =
|
|||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Calculate boss mon
|
||||
const level = (scene.currentBattle.enemyLevels?.[0] ?? scene.currentBattle.waveIndex) + Math.max(Math.round((scene.currentBattle.waveIndex / 10)), 0);
|
||||
|
@ -122,10 +122,9 @@ export const FightOrFlightEncounter: MysteryEncounter =
|
|||
},
|
||||
async (scene: BattleScene) => {
|
||||
// Pick battle
|
||||
const item = scene.currentBattle.mysteryEncounter
|
||||
.misc as ModifierTypeOption;
|
||||
const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false });
|
||||
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]);
|
||||
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
|
||||
}
|
||||
)
|
||||
.withOption(
|
||||
|
@ -144,8 +143,8 @@ export const FightOrFlightEncounter: MysteryEncounter =
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Pick steal
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const item = scene.currentBattle.mysteryEncounter.misc as ModifierTypeOption;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false });
|
||||
|
||||
// Use primaryPokemon to execute the thievery
|
||||
|
|
|
@ -0,0 +1,422 @@
|
|||
import { leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterRewards, transitionMysteryEncounterIntroVisuals, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { TrainerSlot } from "#app/data/trainer-config";
|
||||
import Pokemon, { FieldPosition, PlayerPokemon } from "#app/field/pokemon";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||
import { getEncounterText, queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { Species } from "#enums/species";
|
||||
import i18next from "i18next";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { PlayerGender } from "#enums/player-gender";
|
||||
import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball";
|
||||
import { addPokeballOpenParticles } from "#app/field/anims";
|
||||
import { ShinySparklePhase } from "#app/phases/shiny-sparkle-phase";
|
||||
import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms";
|
||||
import { PostSummonPhase } from "#app/phases/post-summon-phase";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { Nature } from "#enums/nature";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounter:funAndGames";
|
||||
|
||||
/**
|
||||
* Fun and Games! encounter.
|
||||
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3819 | GitHub Issue #3819}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const FunAndGamesEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.FUN_AND_GAMES)
|
||||
.withEncounterTier(MysteryEncounterTier.GREAT)
|
||||
.withSceneWaveRangeRequirement(10, 180)
|
||||
.withSceneRequirement(new MoneyRequirement(0, 1.5)) // Cost equal to 1 Max Potion to play
|
||||
.withAutoHideIntroVisuals(false)
|
||||
// Allows using move without a visible enemy pokemon
|
||||
.withBattleAnimationsWithoutTargets(true)
|
||||
// The Wobbuffet won't use moves
|
||||
.withSkipEnemyBattleTurns(true)
|
||||
// Will skip COMMAND selection menu and go straight to FIGHT (move select) menu
|
||||
.withSkipToFightInput(true)
|
||||
.withIntroSpriteConfigs([
|
||||
{
|
||||
spriteKey: "carnival_game",
|
||||
fileRoot: "mystery-encounters",
|
||||
hasShadow: false,
|
||||
x: 0,
|
||||
y: 6,
|
||||
},
|
||||
{
|
||||
spriteKey: "carnival_wobbuffet",
|
||||
fileRoot: "mystery-encounters",
|
||||
hasShadow: true,
|
||||
x: -28,
|
||||
y: 6,
|
||||
yShadow: 6
|
||||
},
|
||||
{
|
||||
spriteKey: "carnival_man",
|
||||
fileRoot: "mystery-encounters",
|
||||
hasShadow: true,
|
||||
x: 40,
|
||||
y: 6,
|
||||
yShadow: 6
|
||||
},
|
||||
])
|
||||
.withIntroDialogue([
|
||||
{
|
||||
speaker: `${namespace}.speaker`,
|
||||
text: `${namespace}.intro_dialogue`,
|
||||
},
|
||||
])
|
||||
.withTitle(`${namespace}.title`)
|
||||
.withDescription(`${namespace}.description`)
|
||||
.withQuery(`${namespace}.query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
scene.loadBgm("mystery_encounter_fun_and_games", "mystery_encounter_fun_and_games.mp3");
|
||||
return true;
|
||||
})
|
||||
.withOnVisualsStart((scene: BattleScene) => {
|
||||
// Change the bgm
|
||||
scene.fadeOutBgm(2000, false);
|
||||
scene.time.delayedCall(2000, () => {
|
||||
scene.playBgm("mystery_encounter_fun_and_games");
|
||||
});
|
||||
|
||||
return true;
|
||||
})
|
||||
.withOption(MysteryEncounterOptionBuilder
|
||||
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withSceneRequirement(new MoneyRequirement(0, 1.5)) // Cost equal to 1 Max Potion
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}.option.1.label`,
|
||||
buttonTooltip: `${namespace}.option.1.tooltip`,
|
||||
selected: [
|
||||
{
|
||||
text: `${namespace}.option.1.selected`,
|
||||
},
|
||||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
// Select Pokemon for minigame
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
encounter.misc = {
|
||||
playerPokemon: pokemon,
|
||||
};
|
||||
};
|
||||
|
||||
// Only Pokemon that are not KOed/legal can be selected
|
||||
const selectableFilter = (pokemon: Pokemon) => {
|
||||
const meetsReqs = pokemon.isAllowedInBattle();
|
||||
if (!meetsReqs) {
|
||||
return getEncounterText(scene, `${namespace}.invalid_selection`) ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Start minigame
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
encounter.misc.turnsRemaining = 3;
|
||||
|
||||
// Update money
|
||||
const moneyCost = (encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney;
|
||||
updatePlayerMoney(scene, -moneyCost, true, false);
|
||||
await showEncounterText(scene, i18next.t("mysteryEncounterMessages:paid_money", { amount: moneyCost }));
|
||||
|
||||
// Handlers for battle events
|
||||
encounter.onTurnStart = handleNextTurn; // triggered during TurnInitPhase
|
||||
encounter.doContinueEncounter = handleLoseMinigame; // triggered during MysteryEncounterRewardsPhase, post VictoryPhase if the player KOs Wobbuffet
|
||||
|
||||
hideShowmanIntroSprite(scene);
|
||||
await summonPlayerPokemon(scene);
|
||||
await showWobbuffetHealthBar(scene);
|
||||
|
||||
return true;
|
||||
})
|
||||
.build()
|
||||
)
|
||||
.withSimpleOption(
|
||||
{
|
||||
buttonLabel: `${namespace}.option.2.label`,
|
||||
buttonTooltip: `${namespace}.option.2.tooltip`,
|
||||
selected: [
|
||||
{
|
||||
text: `${namespace}.option.2.selected`,
|
||||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
// Leave encounter with no rewards or exp
|
||||
transitionMysteryEncounterIntroVisuals(scene, true, true);
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
return true;
|
||||
}
|
||||
)
|
||||
.build();
|
||||
|
||||
async function summonPlayerPokemon(scene: BattleScene) {
|
||||
return new Promise<void>(async resolve => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const playerPokemon = encounter.misc.playerPokemon;
|
||||
// Swaps the chosen Pokemon and the first player's lead Pokemon in the party
|
||||
const party = scene.getParty();
|
||||
const chosenIndex = party.indexOf(playerPokemon);
|
||||
if (chosenIndex !== 0) {
|
||||
[party[chosenIndex], party[0]] = [party[chosenIndex], party[chosenIndex]];
|
||||
}
|
||||
|
||||
// Do trainer summon animation
|
||||
let playerAnimationPromise: Promise<void> | undefined;
|
||||
scene.ui.showText(i18next.t("battle:playerGo", { pokemonName: getPokemonNameWithAffix(playerPokemon) }));
|
||||
scene.pbTray.hide();
|
||||
scene.trainer.setTexture(`trainer_${scene.gameData.gender === PlayerGender.FEMALE ? "f" : "m"}_back_pb`);
|
||||
scene.time.delayedCall(562, () => {
|
||||
scene.trainer.setFrame("2");
|
||||
scene.time.delayedCall(64, () => {
|
||||
scene.trainer.setFrame("3");
|
||||
});
|
||||
});
|
||||
scene.tweens.add({
|
||||
targets: scene.trainer,
|
||||
x: -36,
|
||||
duration: 1000,
|
||||
onComplete: () => scene.trainer.setVisible(false)
|
||||
});
|
||||
scene.time.delayedCall(750, () => {
|
||||
playerAnimationPromise = summonPlayerPokemonAnimation(scene, playerPokemon);
|
||||
});
|
||||
|
||||
// Also loads Wobbuffet data
|
||||
const enemySpecies = getPokemonSpecies(Species.WOBBUFFET);
|
||||
scene.currentBattle.enemyParty = [];
|
||||
const wobbuffet = scene.addEnemyPokemon(enemySpecies, encounter.misc.playerPokemon.level, TrainerSlot.NONE, false);
|
||||
wobbuffet.ivs = [0, 0, 0, 0, 0, 0];
|
||||
wobbuffet.setNature(Nature.MILD);
|
||||
wobbuffet.setAlpha(0);
|
||||
wobbuffet.setVisible(false);
|
||||
wobbuffet.calculateStats();
|
||||
scene.currentBattle.enemyParty[0] = wobbuffet;
|
||||
scene.gameData.setPokemonSeen(wobbuffet, true);
|
||||
await wobbuffet.loadAssets();
|
||||
const id = setInterval(checkPlayerAnimationPromise, 500);
|
||||
async function checkPlayerAnimationPromise() {
|
||||
if (playerAnimationPromise) {
|
||||
clearInterval(id);
|
||||
await playerAnimationPromise;
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleLoseMinigame(scene: BattleScene) {
|
||||
return new Promise<void>(async resolve => {
|
||||
// Check Wobbuffet is still alive
|
||||
const wobbuffet = scene.getEnemyPokemon();
|
||||
if (!wobbuffet || wobbuffet.isFainted(true) || wobbuffet.hp === 0) {
|
||||
// Player loses
|
||||
// End the battle
|
||||
if (wobbuffet) {
|
||||
wobbuffet.hideInfo();
|
||||
scene.field.remove(wobbuffet);
|
||||
}
|
||||
transitionMysteryEncounterIntroVisuals(scene, true, true);
|
||||
scene.currentBattle.enemyParty = [];
|
||||
scene.currentBattle.mysteryEncounter!.doContinueEncounter = undefined;
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
await showEncounterText(scene, `${namespace}.ko`);
|
||||
const reviveCost = scene.getWaveMoneyAmount(1.5);
|
||||
updatePlayerMoney(scene, -reviveCost, true, false);
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function handleNextTurn(scene: BattleScene) {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const wobbuffet = scene.getEnemyPokemon();
|
||||
if (!wobbuffet) {
|
||||
// Should never be triggered, just handling the edge case
|
||||
handleLoseMinigame(scene);
|
||||
return true;
|
||||
}
|
||||
if (encounter.misc.turnsRemaining <= 0) {
|
||||
// Check Wobbuffet's health for the actual result
|
||||
const healthRatio = wobbuffet.hp / wobbuffet.getMaxHp();
|
||||
let resultMessageKey: string;
|
||||
let isHealPhase = false;
|
||||
if (healthRatio < 0.03) {
|
||||
// Grand prize
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.MULTI_LENS], fillRemaining: false });
|
||||
resultMessageKey = `${namespace}.best_result`;
|
||||
} else if (healthRatio < 0.15) {
|
||||
// 2nd prize
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.SCOPE_LENS], fillRemaining: false });
|
||||
resultMessageKey = `${namespace}.great_result`;
|
||||
} else if (healthRatio < 0.33) {
|
||||
// 3rd prize
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.WIDE_LENS], fillRemaining: false });
|
||||
resultMessageKey = `${namespace}.good_result`;
|
||||
} else {
|
||||
// No prize
|
||||
isHealPhase = true;
|
||||
resultMessageKey = `${namespace}.bad_result`;
|
||||
}
|
||||
|
||||
// End the battle
|
||||
wobbuffet.hideInfo();
|
||||
scene.field.remove(wobbuffet);
|
||||
scene.currentBattle.enemyParty = [];
|
||||
scene.currentBattle.mysteryEncounter!.doContinueEncounter = undefined;
|
||||
leaveEncounterWithoutBattle(scene, isHealPhase);
|
||||
// Must end the TurnInit phase prematurely so battle phases aren't added to queue
|
||||
queueEncounterMessage(scene, `${namespace}.end_game`);
|
||||
queueEncounterMessage(scene, resultMessageKey);
|
||||
|
||||
// Skip remainder of TurnInitPhase
|
||||
return true;
|
||||
} else {
|
||||
if (encounter.misc.turnsRemaining < 3) {
|
||||
// Display charging messages on turns that aren't the initial turn
|
||||
queueEncounterMessage(scene, `${namespace}.charging_continue`);
|
||||
}
|
||||
queueEncounterMessage(scene, `${namespace}.turn_remaining_${encounter.misc.turnsRemaining}`);
|
||||
encounter.misc.turnsRemaining--;
|
||||
}
|
||||
|
||||
// Don't skip remainder of TurnInitPhase
|
||||
return false;
|
||||
}
|
||||
|
||||
async function showWobbuffetHealthBar(scene: BattleScene) {
|
||||
const wobbuffet = scene.getEnemyPokemon()!;
|
||||
|
||||
scene.add.existing(wobbuffet);
|
||||
scene.field.add(wobbuffet);
|
||||
|
||||
const playerPokemon = scene.getPlayerPokemon() as Pokemon;
|
||||
if (playerPokemon?.visible) {
|
||||
scene.field.moveBelow(wobbuffet, playerPokemon);
|
||||
}
|
||||
// Show health bar and trigger cry
|
||||
wobbuffet.showInfo();
|
||||
scene.time.delayedCall(1000, () => {
|
||||
wobbuffet.cry();
|
||||
});
|
||||
wobbuffet.resetSummonData();
|
||||
|
||||
// Track the HP change across turns
|
||||
scene.currentBattle.mysteryEncounter!.misc.wobbuffetHealth = wobbuffet.hp;
|
||||
}
|
||||
|
||||
function summonPlayerPokemonAnimation(scene: BattleScene, pokemon: PlayerPokemon): Promise<void> {
|
||||
return new Promise<void>(resolve => {
|
||||
const pokeball = scene.addFieldSprite(36, 80, "pb", getPokeballAtlasKey(pokemon.pokeball));
|
||||
pokeball.setVisible(false);
|
||||
pokeball.setOrigin(0.5, 0.625);
|
||||
scene.field.add(pokeball);
|
||||
|
||||
pokemon.setFieldPosition(FieldPosition.CENTER, 0);
|
||||
|
||||
const fpOffset = pokemon.getFieldPositionOffset();
|
||||
|
||||
pokeball.setVisible(true);
|
||||
|
||||
scene.tweens.add({
|
||||
targets: pokeball,
|
||||
duration: 650,
|
||||
x: 100 + fpOffset[0]
|
||||
});
|
||||
|
||||
scene.tweens.add({
|
||||
targets: pokeball,
|
||||
duration: 150,
|
||||
ease: "Cubic.easeOut",
|
||||
y: 70 + fpOffset[1],
|
||||
onComplete: () => {
|
||||
scene.tweens.add({
|
||||
targets: pokeball,
|
||||
duration: 500,
|
||||
ease: "Cubic.easeIn",
|
||||
angle: 1440,
|
||||
y: 132 + fpOffset[1],
|
||||
onComplete: () => {
|
||||
scene.playSound("se/pb_rel");
|
||||
pokeball.destroy();
|
||||
scene.add.existing(pokemon);
|
||||
scene.field.add(pokemon);
|
||||
addPokeballOpenParticles(scene, pokemon.x, pokemon.y - 16, pokemon.pokeball);
|
||||
scene.updateModifiers(true);
|
||||
scene.updateFieldScale();
|
||||
pokemon.showInfo();
|
||||
pokemon.playAnim();
|
||||
pokemon.setVisible(true);
|
||||
pokemon.getSprite().setVisible(true);
|
||||
pokemon.setScale(0.5);
|
||||
pokemon.tint(getPokeballTintColor(pokemon.pokeball));
|
||||
pokemon.untint(250, "Sine.easeIn");
|
||||
scene.updateFieldScale();
|
||||
scene.tweens.add({
|
||||
targets: pokemon,
|
||||
duration: 250,
|
||||
ease: "Sine.easeIn",
|
||||
scale: pokemon.getSpriteScale(),
|
||||
onComplete: () => {
|
||||
pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 });
|
||||
pokemon.getSprite().clearTint();
|
||||
pokemon.resetSummonData();
|
||||
scene.time.delayedCall(1000, () => {
|
||||
if (pokemon.isShiny()) {
|
||||
scene.unshiftPhase(new ShinySparklePhase(scene, pokemon.getBattlerIndex()));
|
||||
}
|
||||
|
||||
pokemon.resetTurnData();
|
||||
|
||||
scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
|
||||
scene.pushPhase(new PostSummonPhase(scene, pokemon.getBattlerIndex()));
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function hideShowmanIntroSprite(scene: BattleScene) {
|
||||
const carnivalGame = scene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(0)[0];
|
||||
const wobbuffet = scene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(1)[0];
|
||||
const showMan = scene.currentBattle.mysteryEncounter!.introVisuals?.getSpriteAtIndex(2)[0];
|
||||
|
||||
// Hide the showman
|
||||
scene.tweens.add({
|
||||
targets: showMan,
|
||||
x: "+=16",
|
||||
y: "-=16",
|
||||
alpha: 0,
|
||||
ease: "Sine.easeInOut",
|
||||
duration: 750
|
||||
});
|
||||
|
||||
// Slide the Wobbuffet and Game over slightly
|
||||
scene.tweens.add({
|
||||
targets: [wobbuffet, carnivalGame],
|
||||
x: "+=16",
|
||||
ease: "Sine.easeInOut",
|
||||
duration: 750
|
||||
});
|
||||
}
|
|
@ -40,11 +40,11 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||
])
|
||||
.withIntroDialogue([{ text: `${namespace}.intro` }])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const { mysteryEncounter } = scene.currentBattle;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
mysteryEncounter.setDialogueToken("damagePercentage", String(DAMAGE_PERCENTAGE));
|
||||
mysteryEncounter.setDialogueToken("option1RequiredMove", Moves[OPTION_1_REQUIRED_MOVE]);
|
||||
mysteryEncounter.setDialogueToken("option2RequiredMove", Moves[OPTION_2_REQUIRED_MOVE]);
|
||||
encounter.setDialogueToken("damagePercentage", String(DAMAGE_PERCENTAGE));
|
||||
encounter.setDialogueToken("option1RequiredMove", Moves[OPTION_1_REQUIRED_MOVE]);
|
||||
encounter.setDialogueToken("option2RequiredMove", Moves[OPTION_2_REQUIRED_MOVE]);
|
||||
|
||||
return true;
|
||||
})
|
||||
|
@ -130,7 +130,7 @@ async function handlePokemonGuidingYouPhase(scene: BattleScene) {
|
|||
const laprasSpecies = getPokemonSpecies(Species.LAPRAS);
|
||||
const { mysteryEncounter } = scene.currentBattle;
|
||||
|
||||
if (mysteryEncounter.selectedOption?.primaryPokemon?.id) {
|
||||
if (mysteryEncounter?.selectedOption?.primaryPokemon?.id) {
|
||||
setEncounterExp(scene, mysteryEncounter.selectedOption.primaryPokemon.id, laprasSpecies.baseExp, true);
|
||||
} else {
|
||||
console.warn("Lost at sea: No guide pokemon found but pokemon guides player. huh!?");
|
||||
|
|
|
@ -37,7 +37,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
|
|||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
// Calculates what trainers are available for battle in the encounter
|
||||
|
||||
// Normal difficulty trainer is randomly pulled from biome
|
||||
|
@ -137,7 +137,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
|
|||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
// Spawn standard trainer battle with memory mushroom reward
|
||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
|
||||
|
||||
|
@ -162,7 +162,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
|
|||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
// Spawn hard fight with ULTRA/GREAT reward (can improve with luck)
|
||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1];
|
||||
|
||||
|
@ -187,7 +187,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
|
|||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
// Spawn brutal fight with ROGUE/ULTRA/GREAT reward (can improve with luck)
|
||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[2];
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
|||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
// Play animation
|
||||
const introVisuals =
|
||||
scene.currentBattle.mysteryEncounter.introVisuals!;
|
||||
scene.currentBattle.mysteryEncounter!.introVisuals!;
|
||||
introVisuals.spriteConfigs[0].disableAnimation = false;
|
||||
introVisuals.playAnim();
|
||||
})
|
||||
|
@ -113,7 +113,7 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
|||
);
|
||||
koPlayerPokemon(scene, highestLevelPokemon);
|
||||
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("pokeName", highestLevelPokemon.getNameToRender());
|
||||
scene.currentBattle.mysteryEncounter!.setDialogueToken("pokeName", highestLevelPokemon.getNameToRender());
|
||||
// Show which Pokemon was KOed, then leave encounter with no rewards
|
||||
// Does this synchronously so that game over doesn't happen over result message
|
||||
await showEncounterText(scene, `${namespace}.option.1.bad`);
|
||||
|
|
|
@ -82,7 +82,7 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
]
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
encounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
|
||||
|
@ -130,7 +130,7 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
// Bring visuals back in
|
||||
await transitionMysteryEncounterIntroVisuals(scene, false, false);
|
||||
|
||||
const moneyMultiplier = scene.currentBattle.mysteryEncounter.misc.moneyMultiplier;
|
||||
const moneyMultiplier = scene.currentBattle.mysteryEncounter!.misc.moneyMultiplier;
|
||||
|
||||
// Give money and do dialogue
|
||||
if (moneyMultiplier > 2.5) {
|
||||
|
@ -160,7 +160,7 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
]
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
encounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
|
||||
|
@ -211,7 +211,7 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
// Bring visuals back in
|
||||
await transitionMysteryEncounterIntroVisuals(scene, false, false);
|
||||
|
||||
const moneyMultiplier = scene.currentBattle.mysteryEncounter.misc.moneyMultiplier;
|
||||
const moneyMultiplier = scene.currentBattle.mysteryEncounter!.misc.moneyMultiplier;
|
||||
|
||||
// Give money and do dialogue
|
||||
if (moneyMultiplier > 2.5) {
|
||||
|
@ -244,7 +244,7 @@ export const PartTimerEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const selectedPokemon = encounter.selectedOption?.primaryPokemon!;
|
||||
encounter.setDialogueToken("selectedPokemon", selectedPokemon.getNameToRender());
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ export const SafariZoneEncounter: MysteryEncounter =
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Start safari encounter
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
encounter.continuousEncounter = true;
|
||||
encounter.misc = {
|
||||
safariPokemonRemaining: 3
|
||||
|
@ -130,7 +130,7 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Throw a ball option
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const pokemon = encounter.misc.pokemon;
|
||||
const catchResult = await throwPokeball(scene, pokemon);
|
||||
|
||||
|
@ -165,7 +165,7 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Throw bait option
|
||||
const pokemon = scene.currentBattle.mysteryEncounter.misc.pokemon;
|
||||
const pokemon = scene.currentBattle.mysteryEncounter!.misc.pokemon;
|
||||
await throwBait(scene, pokemon);
|
||||
|
||||
// 100% chance to increase catch stage +2
|
||||
|
@ -195,7 +195,7 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Throw mud option
|
||||
const pokemon = scene.currentBattle.mysteryEncounter.misc.pokemon;
|
||||
const pokemon = scene.currentBattle.mysteryEncounter!.misc.pokemon;
|
||||
await throwMud(scene, pokemon);
|
||||
// 100% chance to decrease flee stage -2
|
||||
tryChangeFleeStage(scene, -2);
|
||||
|
@ -219,7 +219,7 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Flee option
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const pokemon = encounter.misc.pokemon;
|
||||
await doPlayerFlee(scene, pokemon);
|
||||
// Check how many safari pokemon left
|
||||
|
@ -237,7 +237,7 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
|
|||
];
|
||||
|
||||
async function summonSafariPokemon(scene: BattleScene) {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
// Message pokemon remaining
|
||||
encounter.setDialogueToken("remainingCount", encounter.misc.safariPokemonRemaining);
|
||||
scene.queueMessage(getEncounterText(scene, `${namespace}.safari.remaining_count`) ?? "", null, true);
|
||||
|
@ -301,7 +301,7 @@ async function summonSafariPokemon(scene: BattleScene) {
|
|||
function throwPokeball(scene: BattleScene, pokemon: EnemyPokemon): Promise<boolean> {
|
||||
const baseCatchRate = pokemon.species.catchRate;
|
||||
// Catch stage ranges from -6 to +6 (like stat boost stages)
|
||||
const safariCatchStage = scene.currentBattle.mysteryEncounter.misc.catchStage;
|
||||
const safariCatchStage = scene.currentBattle.mysteryEncounter!.misc.catchStage;
|
||||
// Catch modifier ranges from 2/8 (-6 stage) to 8/2 (+6)
|
||||
const safariModifier = (2 + Math.min(Math.max(safariCatchStage, 0), 6)) / (2 - Math.max(Math.min(safariCatchStage, 0), -6));
|
||||
// Catch rate same as safari ball
|
||||
|
@ -464,8 +464,8 @@ function tryChangeFleeStage(scene: BattleScene, change: number, chance?: number)
|
|||
if (chance && randSeedInt(10) >= chance) {
|
||||
return false;
|
||||
}
|
||||
const currentFleeStage = scene.currentBattle.mysteryEncounter.misc.fleeStage ?? 0;
|
||||
scene.currentBattle.mysteryEncounter.misc.fleeStage = Math.min(Math.max(currentFleeStage + change, -6), 6);
|
||||
const currentFleeStage = scene.currentBattle.mysteryEncounter!.misc.fleeStage ?? 0;
|
||||
scene.currentBattle.mysteryEncounter!.misc.fleeStage = Math.min(Math.max(currentFleeStage + change, -6), 6);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -473,13 +473,13 @@ function tryChangeCatchStage(scene: BattleScene, change: number, chance?: number
|
|||
if (chance && randSeedInt(10) >= chance) {
|
||||
return false;
|
||||
}
|
||||
const currentCatchStage = scene.currentBattle.mysteryEncounter.misc.catchStage ?? 0;
|
||||
scene.currentBattle.mysteryEncounter.misc.catchStage = Math.min(Math.max(currentCatchStage + change, -6), 6);
|
||||
const currentCatchStage = scene.currentBattle.mysteryEncounter!.misc.catchStage ?? 0;
|
||||
scene.currentBattle.mysteryEncounter!.misc.catchStage = Math.min(Math.max(currentCatchStage + change, -6), 6);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function doEndTurn(scene: BattleScene, cursorIndex: number) {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const pokemon = encounter.misc.pokemon;
|
||||
const isFlee = isPokemonFlee(pokemon, encounter.misc.fleeStage);
|
||||
if (isFlee) {
|
||||
|
|
|
@ -73,7 +73,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Update money
|
||||
updatePlayerMoney(scene, -(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney);
|
||||
|
@ -105,7 +105,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Choose Cheap Option
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const chosenPokemon = encounter.misc.chosenPokemon;
|
||||
const modifiers = encounter.misc.modifiers;
|
||||
|
||||
|
@ -117,7 +117,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
|
|||
})
|
||||
.withPostOptionPhase(async (scene: BattleScene) => {
|
||||
// Damage and status applied after dealer leaves (to make thematic sense)
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const chosenPokemon = encounter.misc.chosenPokemon;
|
||||
|
||||
// Pokemon takes 1/3 max HP damage
|
||||
|
@ -156,7 +156,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Update money
|
||||
updatePlayerMoney(scene, -(encounter.options[1].requirements[0] as MoneyRequirement).requiredMoney);
|
||||
|
@ -188,7 +188,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Choose Expensive Option
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const chosenPokemon = encounter.misc.chosenPokemon;
|
||||
const modifiers = encounter.misc.modifiers;
|
||||
|
||||
|
@ -200,7 +200,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
|
|||
})
|
||||
.withPostOptionPhase(async (scene: BattleScene) => {
|
||||
// Status applied after dealer leaves (to make thematic sense)
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const chosenPokemon = encounter.misc.chosenPokemon;
|
||||
|
||||
// Roll for poison (20%)
|
||||
|
|
|
@ -48,7 +48,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
|
|||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
console.log(encounter);
|
||||
|
||||
// Calculate boss mon
|
||||
|
@ -85,7 +85,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
|
|||
},
|
||||
async (scene: BattleScene) => {
|
||||
// Pick battle
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: true});
|
||||
encounter.startOfBattleEffects.push(
|
||||
{
|
||||
|
@ -137,7 +137,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
|
|||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Steal the Snorlax's Leftovers
|
||||
const instance = scene.currentBattle.mysteryEncounter;
|
||||
const instance = scene.currentBattle.mysteryEncounter!;
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: false });
|
||||
// Snorlax exp to Pokemon that did the stealing
|
||||
setEncounterExp(scene, instance.primaryPokemon!.id, getPokemonSpecies(Species.SNORLAX).baseExp);
|
||||
|
|
|
@ -57,7 +57,7 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
|
|||
.withDescription(`${namespace}.description`)
|
||||
.withQuery(`${namespace}.query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const price = scene.getWaveMoneyAmount(MONEY_COST_MULTIPLIER);
|
||||
encounter.setDialogueToken("price", price.toString());
|
||||
encounter.misc = {
|
||||
|
@ -81,7 +81,7 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
|
|||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||
// Update money
|
||||
updatePlayerMoney(scene, -scene.currentBattle.mysteryEncounter.misc.price, true, false);
|
||||
updatePlayerMoney(scene, -scene.currentBattle.mysteryEncounter!.misc.price, true, false);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const config: EnemyPartyConfig = await doBiomeTransitionDialogueAndBattleInit(scene);
|
||||
|
@ -107,7 +107,7 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
|
|||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const config: EnemyPartyConfig = await doBiomeTransitionDialogueAndBattleInit(scene);
|
||||
setEncounterRewards(scene, { fillRemaining: true });
|
||||
setEncounterExp(scene, scene.currentBattle.mysteryEncounter.selectedOption!.primaryPokemon!.id, 100);
|
||||
setEncounterExp(scene, scene.currentBattle.mysteryEncounter!.selectedOption!.primaryPokemon!.id, 100);
|
||||
await initBattleWithEnemyConfig(scene, config);
|
||||
})
|
||||
.build()
|
||||
|
@ -124,7 +124,7 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
|
|||
},
|
||||
async (scene: BattleScene) => {
|
||||
// Inspect the Machine
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Init enemy
|
||||
const level = (scene.currentBattle.enemyLevels?.[0] ?? scene.currentBattle.waveIndex) + Math.max(Math.round((scene.currentBattle.waveIndex / 10)), 0);
|
||||
|
@ -150,7 +150,7 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
|
|||
.build();
|
||||
|
||||
async function doBiomeTransitionDialogueAndBattleInit(scene: BattleScene) {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Calculate new biome (cannot be current biome)
|
||||
const filteredBiomes = BIOME_CANDIDATES.filter(b => scene.arena.biomeType !== b);
|
||||
|
|
|
@ -51,7 +51,7 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
|
|||
.withDescription(`${namespace}.description`)
|
||||
.withQuery(`${namespace}.query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
let species = getPokemonSpecies(getRandomSpeciesByStarterTier([0, 5]));
|
||||
const tries = 0;
|
||||
|
@ -118,7 +118,7 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const price = encounter.misc.price;
|
||||
const purchasedPokemon = encounter.misc.pokemon as PlayerPokemon;
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ export const TheStrongStuffEncounter: MysteryEncounter =
|
|||
},
|
||||
])
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Calculate boss mon
|
||||
const config: EnemyPartyConfig = {
|
||||
|
@ -118,7 +118,7 @@ export const TheStrongStuffEncounter: MysteryEncounter =
|
|||
]
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
// Do blackout and hide intro visuals during blackout
|
||||
scene.time.delayedCall(750, () => {
|
||||
transitionMysteryEncounterIntroVisuals(scene, true, true, 50);
|
||||
|
@ -176,7 +176,7 @@ export const TheStrongStuffEncounter: MysteryEncounter =
|
|||
},
|
||||
async (scene: BattleScene) => {
|
||||
// Pick battle
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.SOUL_DEW], fillRemaining: true });
|
||||
encounter.startOfBattleEffects.push(
|
||||
{
|
||||
|
|
|
@ -80,7 +80,7 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter =
|
|||
])
|
||||
.withAutoHideIntroVisuals(false)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Loaded back to front for pop() operations
|
||||
encounter.enemyPartyConfigs.push(getVitoTrainerConfig(scene));
|
||||
|
@ -107,8 +107,7 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter =
|
|||
},
|
||||
async (scene: BattleScene) => {
|
||||
// Spawn 5 trainer battles back to back with Macho Brace in rewards
|
||||
// scene.currentBattle.mysteryEncounter.continuousEncounter = true;
|
||||
scene.currentBattle.mysteryEncounter.doContinueEncounter = (scene: BattleScene) => {
|
||||
scene.currentBattle.mysteryEncounter!.doContinueEncounter = (scene: BattleScene) => {
|
||||
return endTrainerBattleAndShowDialogue(scene);
|
||||
};
|
||||
await transitionMysteryEncounterIntroVisuals(scene, true, false);
|
||||
|
@ -136,7 +135,7 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter =
|
|||
.build();
|
||||
|
||||
async function spawnNextTrainerOrEndEncounter(scene: BattleScene) {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const nextConfig = encounter.enemyPartyConfigs.pop();
|
||||
if (!nextConfig) {
|
||||
await transitionMysteryEncounterIntroVisuals(scene, false, false);
|
||||
|
@ -151,7 +150,7 @@ async function spawnNextTrainerOrEndEncounter(scene: BattleScene) {
|
|||
|
||||
function endTrainerBattleAndShowDialogue(scene: BattleScene): Promise<void> {
|
||||
return new Promise(async resolve => {
|
||||
if (scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length === 0) {
|
||||
if (scene.currentBattle.mysteryEncounter!.enemyPartyConfigs.length === 0) {
|
||||
// Battle is over
|
||||
const trainer = scene.currentBattle.trainer;
|
||||
if (trainer) {
|
||||
|
|
|
@ -65,7 +65,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
|
|||
],
|
||||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
encounter.misc = {
|
||||
playerPokemon: pokemon,
|
||||
|
@ -85,7 +85,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
|
|||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const playerPokemon: PlayerPokemon = encounter.misc.playerPokemon;
|
||||
|
||||
// Spawn light training session with chosen pokemon
|
||||
|
@ -189,7 +189,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
|
|||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
// Open menu for selecting pokemon and Nature
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const natures = new Array(25).fill(null).map((val, i) => i as Nature);
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Return the options for nature selection
|
||||
|
@ -223,7 +223,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
|
|||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const playerPokemon: PlayerPokemon = encounter.misc.playerPokemon;
|
||||
|
||||
// Spawn medium training session with chosen pokemon
|
||||
|
@ -277,7 +277,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
|
|||
})
|
||||
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||
// Open menu for selecting pokemon and ability to learn
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||
// Return the options for ability selection
|
||||
const speciesForm = !!pokemon.getFusionSpeciesForm()
|
||||
|
@ -320,7 +320,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
|
|||
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const playerPokemon: PlayerPokemon = encounter.misc.playerPokemon;
|
||||
|
||||
// Spawn hard training session with chosen pokemon
|
||||
|
|
|
@ -54,7 +54,7 @@ export const TrashToTreasureEncounter: MysteryEncounter =
|
|||
.withDescription(`${namespace}.description`)
|
||||
.withQuery(`${namespace}.query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
// Calculate boss mon
|
||||
const bossSpecies = getPokemonSpecies(Species.GARBODOR);
|
||||
|
@ -124,7 +124,7 @@ export const TrashToTreasureEncounter: MysteryEncounter =
|
|||
await showEncounterText(scene, `${namespace}.option.2.selected_2`);
|
||||
transitionMysteryEncounterIntroVisuals(scene);
|
||||
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT], fillRemaining: true });
|
||||
encounter.startOfBattleEffects.push(
|
||||
|
|
|
@ -150,7 +150,7 @@ export const WeirdDreamEncounter: MysteryEncounter =
|
|||
// Calculate all the newly transformed Pokemon and begin asset load
|
||||
const teamTransformations = getTeamTransformations(scene);
|
||||
const loadAssets = teamTransformations.map(t => (t.newPokemon as PlayerPokemon).loadAssets());
|
||||
scene.currentBattle.mysteryEncounter.misc = {
|
||||
scene.currentBattle.mysteryEncounter!.misc = {
|
||||
teamTransformations,
|
||||
loadAssets
|
||||
};
|
||||
|
@ -161,8 +161,8 @@ export const WeirdDreamEncounter: MysteryEncounter =
|
|||
|
||||
// Change the entire player's party
|
||||
// Wait for all new Pokemon assets to be loaded before showing transformation animations
|
||||
await Promise.all(scene.currentBattle.mysteryEncounter.misc.loadAssets);
|
||||
const transformations = scene.currentBattle.mysteryEncounter.misc.teamTransformations;
|
||||
await Promise.all(scene.currentBattle.mysteryEncounter!.misc.loadAssets);
|
||||
const transformations = scene.currentBattle.mysteryEncounter!.misc.teamTransformations;
|
||||
|
||||
// If there are 1-3 transformations, do them centered back to back
|
||||
// Otherwise, the first 3 transformations are executed side-by-side, then any remaining 1-3 transformations occur in those same respective positions
|
||||
|
|
|
@ -42,6 +42,9 @@ export interface IMysteryEncounter {
|
|||
catchAllowed: boolean;
|
||||
continuousEncounter: boolean;
|
||||
maxAllowedEncounters: number;
|
||||
hasBattleAnimationsWithoutTargets: boolean;
|
||||
skipEnemyBattleTurns: boolean;
|
||||
skipToFightInput: boolean;
|
||||
|
||||
onInit?: (scene: BattleScene) => boolean;
|
||||
onVisualsStart?: (scene: BattleScene) => boolean;
|
||||
|
@ -113,7 +116,20 @@ export default class MysteryEncounter implements IMysteryEncounter {
|
|||
* Rogue tier encounters default to 1, others default to 3
|
||||
*/
|
||||
maxAllowedEncounters: number;
|
||||
|
||||
/**
|
||||
* If true, encounter will not animate the target Pokemon as part of battle animations
|
||||
* Used for encounters where it is not a "real" battle, but still uses battle animations and commands (see {@link FunAndGamesEncounter} for an example)
|
||||
*/
|
||||
hasBattleAnimationsWithoutTargets: boolean;
|
||||
/**
|
||||
* If true, will skip enemy pokemon turns during battle for the encounter
|
||||
* Used for encounters where it is not a "real" battle, but still uses battle animations and commands (see {@link FunAndGamesEncounter} for an example)
|
||||
*/
|
||||
skipEnemyBattleTurns: boolean;
|
||||
/**
|
||||
* If true, will skip COMMAND input and go straight to FIGHT (move select) input menu
|
||||
*/
|
||||
skipToFightInput: boolean;
|
||||
|
||||
/**
|
||||
* Event callback functions
|
||||
|
@ -122,6 +138,8 @@ export default class MysteryEncounter implements IMysteryEncounter {
|
|||
onInit?: (scene: BattleScene) => boolean;
|
||||
/** Event when battlefield visuals have finished sliding in and the encounter dialogue begins */
|
||||
onVisualsStart?: (scene: BattleScene) => boolean;
|
||||
/** Event triggered prior to {@link CommandPhase}, during {@link TurnInitPhase} */
|
||||
onTurnStart?: (scene: BattleScene) => boolean;
|
||||
/** Event prior to any rewards logic in {@link MysteryEncounterRewardsPhase} */
|
||||
onRewards?: (scene: BattleScene) => Promise<void>;
|
||||
/** Will provide the player party EXP before rewards are displayed for that wave */
|
||||
|
@ -471,6 +489,9 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||
catchAllowed: boolean = false;
|
||||
lockEncounterRewardTiers: boolean = false;
|
||||
startOfBattleEffectsComplete: boolean = false;
|
||||
hasBattleAnimationsWithoutTargets: boolean = false;
|
||||
skipEnemyBattleTurns: boolean = false;
|
||||
skipToFightInput: boolean = false;
|
||||
maxAllowedEncounters: number = 3;
|
||||
expMultiplier: number = 1;
|
||||
|
||||
|
@ -600,6 +621,35 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||
return Object.assign(this, { continuousEncounter: continuousEncounter });
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, encounter will not animate the target Pokemon as part of battle animations
|
||||
* Used for encounters where it is not a "real" battle, but still uses battle animations and commands (see {@link FunAndGamesEncounter} for an example)
|
||||
* Default false
|
||||
* @param hasBattleAnimationsWithoutTargets
|
||||
*/
|
||||
withBattleAnimationsWithoutTargets(hasBattleAnimationsWithoutTargets: boolean): this & Required<Pick<IMysteryEncounter, "hasBattleAnimationsWithoutTargets">> {
|
||||
return Object.assign(this, { hasBattleAnimationsWithoutTargets });
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, encounter will not animate the target Pokemon as part of battle animations
|
||||
* Used for encounters where it is not a "real" battle, but still uses battle animations and commands (see {@link FunAndGamesEncounter} for an example)
|
||||
* Default false
|
||||
* @param skipEnemyBattleTurns
|
||||
*/
|
||||
withSkipEnemyBattleTurns(skipEnemyBattleTurns: boolean): this & Required<Pick<IMysteryEncounter, "skipEnemyBattleTurns">> {
|
||||
return Object.assign(this, { skipEnemyBattleTurns });
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, will skip COMMAND input and go straight to FIGHT (move select) input menu
|
||||
* Default false
|
||||
* @param skipToFightInput
|
||||
*/
|
||||
withSkipToFightInput(skipToFightInput: boolean): this & Required<Pick<IMysteryEncounter, "skipToFightInput">> {
|
||||
return Object.assign(this, { skipToFightInput });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of times that an encounter can spawn in a given Classic run
|
||||
* @param maxAllowedEncounters
|
||||
|
|
|
@ -28,6 +28,7 @@ import { WeirdDreamEncounter } from "#app/data/mystery-encounters/encounters/wei
|
|||
import { TheWinstrateChallengeEncounter } from "#app/data/mystery-encounters/encounters/the-winstrate-challenge-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 { FunAndGamesEncounter } from "#app/data/mystery-encounters/encounters/fun-and-games-encounter";
|
||||
|
||||
// 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;
|
||||
|
@ -155,7 +156,8 @@ const humanTransitableBiomeEncounters: MysteryEncounterType[] = [
|
|||
|
||||
const civilizationBiomeEncounters: MysteryEncounterType[] = [
|
||||
MysteryEncounterType.DEPARTMENT_STORE_SALE,
|
||||
MysteryEncounterType.PART_TIMER
|
||||
MysteryEncounterType.PART_TIMER,
|
||||
MysteryEncounterType.FUN_AND_GAMES
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -279,6 +281,7 @@ export function initMysteryEncounters() {
|
|||
allMysteryEncounters[MysteryEncounterType.THE_WINSTRATE_CHALLENGE] = TheWinstrateChallengeEncounter;
|
||||
allMysteryEncounters[MysteryEncounterType.TELEPORTING_HIJINKS] = TeleportingHijinksEncounter;
|
||||
allMysteryEncounters[MysteryEncounterType.BUG_TYPE_SUPERFAN] = BugTypeSuperfanEncounter;
|
||||
allMysteryEncounters[MysteryEncounterType.FUN_AND_GAMES] = FunAndGamesEncounter;
|
||||
|
||||
// Add extreme encounters to biome map
|
||||
extremeBiomeEncounters.forEach(encounter => {
|
||||
|
|
|
@ -120,7 +120,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
|||
const partyTrainerConfig = partyConfig?.trainerConfig;
|
||||
let trainerConfig: TrainerConfig;
|
||||
if (!isNullOrUndefined(trainerType) || partyTrainerConfig) {
|
||||
scene.currentBattle.mysteryEncounter.encounterMode = MysteryEncounterMode.TRAINER_BATTLE;
|
||||
scene.currentBattle.mysteryEncounter!.encounterMode = MysteryEncounterMode.TRAINER_BATTLE;
|
||||
if (scene.currentBattle.trainer) {
|
||||
scene.currentBattle.trainer.setVisible(false);
|
||||
scene.currentBattle.trainer.destroy();
|
||||
|
@ -141,7 +141,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
|||
battle.enemyLevels = scene.currentBattle.trainer.getPartyLevels(scene.currentBattle.waveIndex);
|
||||
} else {
|
||||
// Wild
|
||||
scene.currentBattle.mysteryEncounter.encounterMode = MysteryEncounterMode.WILD_BATTLE;
|
||||
scene.currentBattle.mysteryEncounter!.encounterMode = MysteryEncounterMode.WILD_BATTLE;
|
||||
const numEnemies = partyConfig?.pokemonConfigs && partyConfig.pokemonConfigs.length > 0 ? partyConfig?.pokemonConfigs?.length : doubleBattle ? 2 : 1;
|
||||
battle.enemyLevels = new Array(numEnemies).fill(null).map(() => scene.currentBattle.getLevelForWave());
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
|||
enemySpecies = config.species;
|
||||
isBoss = config.isBoss;
|
||||
if (isBoss) {
|
||||
scene.currentBattle.mysteryEncounter.encounterMode = MysteryEncounterMode.BOSS_BATTLE;
|
||||
scene.currentBattle.mysteryEncounter!.encounterMode = MysteryEncounterMode.BOSS_BATTLE;
|
||||
}
|
||||
} else {
|
||||
enemySpecies = scene.randomSpecies(battle.waveIndex, level, true);
|
||||
|
@ -429,7 +429,7 @@ export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (p
|
|||
const pokemon = scene.getParty()[slotIndex];
|
||||
const secondaryOptions = onPokemonSelected(pokemon);
|
||||
if (!secondaryOptions) {
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
|
||||
scene.currentBattle.mysteryEncounter!.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
|
||||
resolve(true);
|
||||
return;
|
||||
}
|
||||
|
@ -443,7 +443,7 @@ export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (p
|
|||
const onSelect = option.handler;
|
||||
option.handler = () => {
|
||||
onSelect();
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
|
||||
scene.currentBattle.mysteryEncounter!.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
|
||||
resolve(true);
|
||||
return true;
|
||||
};
|
||||
|
@ -595,7 +595,7 @@ export function selectOptionThenPokemon(scene: BattleScene, options: OptionSelec
|
|||
* @param preRewardsCallback - can execute an arbitrary callback before the new phases if necessary (useful for updating items/party/injecting new phases before MysteryEncounterRewardsPhase)
|
||||
*/
|
||||
export function setEncounterRewards(scene: BattleScene, customShopRewards?: CustomModifierSettings, eggRewards?: IEggOptions[], preRewardsCallback?: Function) {
|
||||
scene.currentBattle.mysteryEncounter.doEncounterRewards = (scene: BattleScene) => {
|
||||
scene.currentBattle.mysteryEncounter!.doEncounterRewards = (scene: BattleScene) => {
|
||||
if (preRewardsCallback) {
|
||||
preRewardsCallback();
|
||||
}
|
||||
|
@ -638,7 +638,7 @@ export function setEncounterRewards(scene: BattleScene, customShopRewards?: Cust
|
|||
export function setEncounterExp(scene: BattleScene, participantId: integer | integer[], baseExpValue: number, useWaveIndex: boolean = true) {
|
||||
const participantIds = Array.isArray(participantId) ? participantId : [participantId];
|
||||
|
||||
scene.currentBattle.mysteryEncounter.doEncounterExp = (scene: BattleScene) => {
|
||||
scene.currentBattle.mysteryEncounter!.doEncounterExp = (scene: BattleScene) => {
|
||||
const party = scene.getParty();
|
||||
const expShareModifier = scene.findModifier(m => m instanceof ExpShareModifier) as ExpShareModifier;
|
||||
const expBalanceModifier = scene.findModifier(m => m instanceof ExpBalanceModifier) as ExpBalanceModifier;
|
||||
|
@ -650,7 +650,7 @@ export function setEncounterExp(scene: BattleScene, participantId: integer | int
|
|||
let expValue = Math.floor(baseExpValue * (useWaveIndex ? scene.currentBattle.waveIndex : 1) / 5 + 1);
|
||||
|
||||
if (participantIds?.length > 0) {
|
||||
if (scene.currentBattle.mysteryEncounter.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
||||
if (scene.currentBattle.mysteryEncounter!.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
||||
expValue = Math.floor(expValue * 1.5);
|
||||
}
|
||||
for (const partyMember of nonFaintedPartyMembers) {
|
||||
|
@ -752,7 +752,7 @@ export function initSubsequentOptionSelect(scene: BattleScene, optionSelectSetti
|
|||
* @param encounterMode - Can set custom encounter mode if necessary (may be required for forcing Pokemon to return before next phase)
|
||||
*/
|
||||
export function leaveEncounterWithoutBattle(scene: BattleScene, addHealPhase: boolean = false, encounterMode: MysteryEncounterMode = MysteryEncounterMode.NO_BATTLE) {
|
||||
scene.currentBattle.mysteryEncounter.encounterMode = encounterMode;
|
||||
scene.currentBattle.mysteryEncounter!.encounterMode = encounterMode;
|
||||
scene.clearPhaseQueue();
|
||||
scene.clearPhaseQueueSplice();
|
||||
handleMysteryEncounterVictory(scene, addHealPhase);
|
||||
|
@ -775,7 +775,7 @@ export function handleMysteryEncounterVictory(scene: BattleScene, addHealPhase:
|
|||
|
||||
// If in repeated encounter variant, do nothing
|
||||
// Variant must eventually be swapped in order to handle "true" end of the encounter
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
if (encounter.continuousEncounter || doNotContinue) {
|
||||
return;
|
||||
} else if (encounter.encounterMode === MysteryEncounterMode.NO_BATTLE) {
|
||||
|
@ -805,7 +805,7 @@ export function handleMysteryEncounterVictory(scene: BattleScene, addHealPhase:
|
|||
*/
|
||||
export function transitionMysteryEncounterIntroVisuals(scene: BattleScene, hide: boolean = true, destroy: boolean = true, duration: number = 750): Promise<boolean> {
|
||||
return new Promise(resolve => {
|
||||
const introVisuals = scene.currentBattle.mysteryEncounter.introVisuals;
|
||||
const introVisuals = scene.currentBattle.mysteryEncounter!.introVisuals;
|
||||
const enemyPokemon = scene.getEnemyField();
|
||||
if (enemyPokemon) {
|
||||
scene.currentBattle.enemyParty = [];
|
||||
|
@ -835,7 +835,7 @@ export function transitionMysteryEncounterIntroVisuals(scene: BattleScene, hide:
|
|||
scene.field.remove(pokemon, true);
|
||||
});
|
||||
|
||||
scene.currentBattle.mysteryEncounter.introVisuals = undefined;
|
||||
scene.currentBattle.mysteryEncounter!.introVisuals = undefined;
|
||||
}
|
||||
resolve(true);
|
||||
}
|
||||
|
@ -852,8 +852,8 @@ export function transitionMysteryEncounterIntroVisuals(scene: BattleScene, hide:
|
|||
* @param scene
|
||||
*/
|
||||
export function handleMysteryEncounterBattleStartEffects(scene: BattleScene) {
|
||||
const encounter = scene.currentBattle?.mysteryEncounter;
|
||||
if (scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && encounter.encounterMode !== MysteryEncounterMode.NO_BATTLE && !encounter.startOfBattleEffectsComplete) {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
if (scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && encounter && encounter.encounterMode !== MysteryEncounterMode.NO_BATTLE && !encounter.startOfBattleEffectsComplete) {
|
||||
const effects = encounter.startOfBattleEffects;
|
||||
effects.forEach(effect => {
|
||||
let source;
|
||||
|
@ -884,6 +884,21 @@ export function handleMysteryEncounterBattleStartEffects(scene: BattleScene) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can queue extra phases or logic during {@link TurnInitPhase}
|
||||
* Mostly useful for allowing MysteryEncounter enemies to "cheat" and use moves before the first turn
|
||||
* @param scene
|
||||
* @return boolean - if true, will skip the remainder of the {@link TurnInitPhase}
|
||||
*/
|
||||
export function handleMysteryEncounterTurnStartEffects(scene: BattleScene): boolean {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
if (scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && encounter && encounter.onTurnStart) {
|
||||
return encounter.onTurnStart(scene);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: remove once encounter spawn rate is finalized
|
||||
* Just a helper function to calculate aggregate stats for MEs in a Classic run
|
||||
|
|
|
@ -25,5 +25,6 @@ export enum MysteryEncounterType {
|
|||
WEIRD_DREAM,
|
||||
THE_WINSTRATE_CHALLENGE,
|
||||
TELEPORTING_HIJINKS,
|
||||
BUG_TYPE_SUPERFAN
|
||||
BUG_TYPE_SUPERFAN,
|
||||
FUN_AND_GAMES
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import weirdDreamDialogue from "#app/locales/en/mystery-encounters/weird-dream-d
|
|||
import theWinstrateChallengeDialogue from "#app/locales/en/mystery-encounters/the-winstrate-challenge-dialogue.json";
|
||||
import teleportingHijinksDialogue from "#app/locales/en/mystery-encounters/teleporting-hijinks-dialogue.json";
|
||||
import bugTypeSuperfanDialogue from "#app/locales/en/mystery-encounters/bug-type-superfan-dialogue.json";
|
||||
import funAndGamesDialogue from "#app/locales/en/mystery-encounters/fun-and-games-dialogue.json";
|
||||
|
||||
/**
|
||||
* Injection patterns that can be used:
|
||||
|
@ -71,5 +72,6 @@ export const mysteryEncounter = {
|
|||
weirdDream: weirdDreamDialogue,
|
||||
theWinstrateChallenge: theWinstrateChallengeDialogue,
|
||||
teleportingHijinks: teleportingHijinksDialogue,
|
||||
bugTypeSuperfan: bugTypeSuperfanDialogue
|
||||
bugTypeSuperfan: bugTypeSuperfanDialogue,
|
||||
funAndGames: funAndGamesDialogue
|
||||
} as const;
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"intro_dialogue": "Step right up, folks! Try your luck\non the brand new Wobbuffet Whack-o-matic!",
|
||||
"speaker": "Showman",
|
||||
"title": "Fun And Games!",
|
||||
"description": "You've encountered a traveling show with a prize game! You will have @[TOOLTIP_TITLE]{3 turns} to bring the Wobbuffet as close to @[TOOLTIP_TITLE]{1 HP} as possible @[TOOLTIP_TITLE]{without KOing it} so it can wind up a huge Counter on the bell-ringing machine.\nBut be careful! If you KO the Wobbuffet, you'll have to pay for the cost of reviving it!",
|
||||
"query": "Would you like to play?",
|
||||
"option": {
|
||||
"1": {
|
||||
"label": "Play the Game",
|
||||
"tooltip": "(-) Pay {{option1Money, money}}\n(+) Play Wobbuffet Whack-o-matic",
|
||||
"selected": "Time to test your luck!"
|
||||
},
|
||||
"2": {
|
||||
"label": "Leave",
|
||||
"tooltip": "(-) No Rewards",
|
||||
"selected": "You hurry along your way,\nwith a slight feeling of regret."
|
||||
}
|
||||
},
|
||||
"ko": "Oh no! The Wobbuffet fainted!$You lose the game and\nhave to pay for the revive cost...",
|
||||
"charging_continue": "The Wubboffet keeps charging its counter-swing!",
|
||||
"turn_remaining_3": "Three turns remaining!",
|
||||
"turn_remaining_2": "Two turns remaining!",
|
||||
"turn_remaining_1": "One turn remaining!",
|
||||
"end_game": "Time's up!$The Wobbuffet winds up to counter-swing and@d{16}.@d{16}.@d{16}.",
|
||||
"best_result": "The Wobbuffet smacks the button so hard\nthe bell breaks off the top!$You win the grand prize!",
|
||||
"great_result": "The Wobbuffet smacks the button, nearly hitting the bell!$So close!\nYou earn the second tier prize!",
|
||||
"good_result": "The Wobbuffet hits the button hard enough to go midway up the scale!$You earn the third tier prize!",
|
||||
"bad_result": "The Wobbuffet barely taps the button and nothing happens...$Oh no!\nYou don't win anything!",
|
||||
"outro": "That was a fun little game!"
|
||||
}
|
|
@ -72,7 +72,12 @@ export class CommandPhase extends FieldPhase {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
|
||||
if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && this.scene.currentBattle.mysteryEncounter?.skipToFightInput) {
|
||||
this.scene.ui.clearText();
|
||||
this.scene.ui.setMode(Mode.FIGHT, this.fieldIndex);
|
||||
} else {
|
||||
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,7 +143,7 @@ export class CommandPhase extends FieldPhase {
|
|||
this.scene.ui.showText("", 0);
|
||||
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
|
||||
}, null, true);
|
||||
} else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && !this.scene.currentBattle.mysteryEncounter.catchAllowed) {
|
||||
} else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && !this.scene.currentBattle.mysteryEncounter!.catchAllowed) {
|
||||
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
|
||||
this.scene.ui.setMode(Mode.MESSAGE);
|
||||
this.scene.ui.showText(i18next.t("battle:noPokeballMysteryEncounter"), null, () => {
|
||||
|
|
|
@ -150,7 +150,7 @@ export class EncounterPhase extends BattlePhase {
|
|||
const newEncounter = this.scene.getMysteryEncounter(mysteryEncounter);
|
||||
battle.mysteryEncounter = newEncounter;
|
||||
}
|
||||
loadEnemyAssets.push(battle.mysteryEncounter.introVisuals!.loadAssets().then(() => battle.mysteryEncounter.introVisuals!.initSprite()));
|
||||
loadEnemyAssets.push(battle.mysteryEncounter.introVisuals!.loadAssets().then(() => battle.mysteryEncounter!.introVisuals!.initSprite()));
|
||||
// Load Mystery Encounter Exclamation bubble and sfx
|
||||
loadEnemyAssets.push(new Promise<void>(resolve => {
|
||||
this.scene.loadSe("GEN8- Exclaim", "battle_anims", "GEN8- Exclaim.wav");
|
||||
|
@ -349,12 +349,13 @@ export class EncounterPhase extends BattlePhase {
|
|||
showDialogueAndSummon();
|
||||
}
|
||||
}
|
||||
} else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER) {
|
||||
const introVisuals = this.scene.currentBattle.mysteryEncounter.introVisuals!;
|
||||
} else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && this.scene.currentBattle.mysteryEncounter) {
|
||||
const encounter = this.scene.currentBattle.mysteryEncounter;
|
||||
const introVisuals = encounter.introVisuals!;
|
||||
introVisuals.playAnim();
|
||||
|
||||
if (this.scene.currentBattle.mysteryEncounter.onVisualsStart) {
|
||||
this.scene.currentBattle.mysteryEncounter.onVisualsStart(this.scene);
|
||||
if (encounter.onVisualsStart) {
|
||||
encounter.onVisualsStart(this.scene);
|
||||
}
|
||||
|
||||
const doEncounter = () => {
|
||||
|
@ -367,7 +368,7 @@ export class EncounterPhase extends BattlePhase {
|
|||
};
|
||||
|
||||
if (showEncounterMessage) {
|
||||
const introDialogue = this.scene.currentBattle.mysteryEncounter.dialogue.intro;
|
||||
const introDialogue = encounter.dialogue.intro;
|
||||
if (!introDialogue) {
|
||||
doShowEncounterOptions();
|
||||
} else {
|
||||
|
|
|
@ -17,11 +17,15 @@ import { FieldPhase } from "./field-phase";
|
|||
*/
|
||||
export class EnemyCommandPhase extends FieldPhase {
|
||||
protected fieldIndex: integer;
|
||||
protected skipTurn: boolean = false;
|
||||
|
||||
constructor(scene: BattleScene, fieldIndex: integer) {
|
||||
super(scene);
|
||||
|
||||
this.fieldIndex = fieldIndex;
|
||||
if (this.scene.currentBattle.mysteryEncounter?.skipEnemyBattleTurns) {
|
||||
this.skipTurn = true;
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
|
@ -63,7 +67,7 @@ export class EnemyCommandPhase extends FieldPhase {
|
|||
const index = trainer.getNextSummonIndex(enemyPokemon.trainerSlot, partyMemberScores);
|
||||
|
||||
battle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] =
|
||||
{ command: Command.POKEMON, cursor: index, args: [false] };
|
||||
{ command: Command.POKEMON, cursor: index, args: [false], skip: this.skipTurn };
|
||||
|
||||
battle.enemySwitchCounter++;
|
||||
|
||||
|
@ -77,7 +81,7 @@ export class EnemyCommandPhase extends FieldPhase {
|
|||
const nextMove = enemyPokemon.getNextMove();
|
||||
|
||||
this.scene.currentBattle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] =
|
||||
{ command: Command.FIGHT, move: nextMove };
|
||||
{ command: Command.FIGHT, move: nextMove, skip: this.skipTurn };
|
||||
|
||||
this.scene.currentBattle.enemySwitchCounter = Math.max(this.scene.currentBattle.enemySwitchCounter - 1, 0);
|
||||
|
||||
|
|
|
@ -119,8 +119,9 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||
/** All move effect attributes are chained together in this array to be applied asynchronously. */
|
||||
const applyAttrs: Promise<void>[] = [];
|
||||
|
||||
const playOnEmptyField = this.scene.currentBattle?.mysteryEncounter?.hasBattleAnimationsWithoutTargets ?? false;
|
||||
// Move animation only needs one target
|
||||
new MoveAnim(move.id as Moves, user, this.getTarget()?.getBattlerIndex()!).play(this.scene, () => { // TODO: is the bang correct here?
|
||||
new MoveAnim(move.id as Moves, user, this.getTarget()?.getBattlerIndex()!, playOnEmptyField).play(this.scene, () => { // TODO: is the bang correct here?
|
||||
/** Has the move successfully hit a target (for damage) yet? */
|
||||
let hasHit: boolean = false;
|
||||
for (const target of targets) {
|
||||
|
|
|
@ -54,12 +54,13 @@ export class MysteryEncounterPhase extends Phase {
|
|||
this.scene.clearPhaseQueue();
|
||||
this.scene.clearPhaseQueueSplice();
|
||||
|
||||
this.scene.currentBattle.mysteryEncounter.updateSeedOffset(this.scene);
|
||||
const encounter = this.scene.currentBattle.mysteryEncounter!;
|
||||
encounter.updateSeedOffset(this.scene);
|
||||
|
||||
if (!this.optionSelectSettings) {
|
||||
// Sets flag that ME was encountered, only if this is not a followup option select phase
|
||||
// Can be used in later MEs to check for requirements to spawn, etc.
|
||||
this.scene.mysteryEncounterData.encounteredEvents.push([this.scene.currentBattle.mysteryEncounter.encounterType, this.scene.currentBattle.mysteryEncounter.encounterTier]);
|
||||
this.scene.mysteryEncounterData.encounteredEvents.push([encounter.encounterType, encounter.encounterTier]);
|
||||
}
|
||||
|
||||
// Initiates encounter dialogue window and option select
|
||||
|
@ -68,14 +69,14 @@ export class MysteryEncounterPhase extends Phase {
|
|||
|
||||
handleOptionSelect(option: MysteryEncounterOption, index: number): boolean {
|
||||
// Set option selected flag
|
||||
this.scene.currentBattle.mysteryEncounter.selectedOption = option;
|
||||
this.scene.currentBattle.mysteryEncounter!.selectedOption = option;
|
||||
|
||||
if (!option.onOptionPhase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Populate dialogue tokens for option requirements
|
||||
this.scene.currentBattle.mysteryEncounter.populateDialogueTokensFromRequirements(this.scene);
|
||||
this.scene.currentBattle.mysteryEncounter!.populateDialogueTokensFromRequirements(this.scene);
|
||||
|
||||
if (option.onPreOptionPhase) {
|
||||
this.scene.executeWithSeedOffset(async () => {
|
||||
|
@ -85,7 +86,7 @@ export class MysteryEncounterPhase extends Phase {
|
|||
this.continueEncounter();
|
||||
}
|
||||
});
|
||||
}, this.scene.currentBattle.mysteryEncounter.getSeedOffset());
|
||||
}, this.scene.currentBattle.mysteryEncounter?.getSeedOffset());
|
||||
} else {
|
||||
this.continueEncounter();
|
||||
}
|
||||
|
@ -149,25 +150,25 @@ export class MysteryEncounterOptionSelectedPhase extends Phase {
|
|||
|
||||
constructor(scene: BattleScene) {
|
||||
super(scene);
|
||||
this.onOptionSelect = this.scene.currentBattle.mysteryEncounter.selectedOption!.onOptionPhase;
|
||||
this.onOptionSelect = this.scene.currentBattle.mysteryEncounter!.selectedOption!.onOptionPhase;
|
||||
}
|
||||
|
||||
start() {
|
||||
super.start();
|
||||
if (this.scene.currentBattle.mysteryEncounter.autoHideIntroVisuals) {
|
||||
if (this.scene.currentBattle.mysteryEncounter?.autoHideIntroVisuals) {
|
||||
transitionMysteryEncounterIntroVisuals(this.scene).then(() => {
|
||||
this.scene.executeWithSeedOffset(() => {
|
||||
this.onOptionSelect(this.scene).finally(() => {
|
||||
this.end();
|
||||
});
|
||||
}, this.scene.currentBattle.mysteryEncounter.getSeedOffset());
|
||||
}, this.scene.currentBattle.mysteryEncounter?.getSeedOffset());
|
||||
});
|
||||
} else {
|
||||
this.scene.executeWithSeedOffset(() => {
|
||||
this.onOptionSelect(this.scene).finally(() => {
|
||||
this.end();
|
||||
});
|
||||
}, this.scene.currentBattle.mysteryEncounter.getSeedOffset());
|
||||
}, this.scene.currentBattle.mysteryEncounter?.getSeedOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -222,7 +223,7 @@ export class MysteryEncounterBattlePhase extends Phase {
|
|||
|
||||
getBattleMessage(scene: BattleScene): string {
|
||||
const enemyField = scene.getEnemyField();
|
||||
const encounterMode = scene.currentBattle.mysteryEncounter.encounterMode;
|
||||
const encounterMode = scene.currentBattle.mysteryEncounter!.encounterMode;
|
||||
|
||||
if (scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
|
||||
return i18next.t("battle:bossAppeared", { bossName: enemyField[0].name });
|
||||
|
@ -243,7 +244,7 @@ export class MysteryEncounterBattlePhase extends Phase {
|
|||
}
|
||||
|
||||
doMysteryEncounterBattle(scene: BattleScene) {
|
||||
const encounterMode = scene.currentBattle.mysteryEncounter.encounterMode;
|
||||
const encounterMode = scene.currentBattle.mysteryEncounter!.encounterMode;
|
||||
if (encounterMode === MysteryEncounterMode.WILD_BATTLE || encounterMode === MysteryEncounterMode.BOSS_BATTLE) {
|
||||
// Summons the wild/boss Pokemon
|
||||
if (encounterMode === MysteryEncounterMode.BOSS_BATTLE) {
|
||||
|
@ -255,7 +256,7 @@ export class MysteryEncounterBattlePhase extends Phase {
|
|||
scene.unshiftPhase(new SummonPhase(scene, 1, false));
|
||||
}
|
||||
|
||||
if (!scene.currentBattle.mysteryEncounter.hideBattleIntroMessage) {
|
||||
if (!scene.currentBattle.mysteryEncounter?.hideBattleIntroMessage) {
|
||||
scene.ui.showText(this.getBattleMessage(scene), null, () => this.endBattleSetup(scene), 0);
|
||||
} else {
|
||||
this.endBattleSetup(scene);
|
||||
|
@ -276,7 +277,7 @@ export class MysteryEncounterBattlePhase extends Phase {
|
|||
}
|
||||
this.endBattleSetup(scene);
|
||||
};
|
||||
if (!scene.currentBattle.mysteryEncounter.hideBattleIntroMessage) {
|
||||
if (!scene.currentBattle.mysteryEncounter?.hideBattleIntroMessage) {
|
||||
scene.ui.showText(this.getBattleMessage(scene), null, doTrainerSummon, 1000, true);
|
||||
} else {
|
||||
doTrainerSummon();
|
||||
|
@ -290,7 +291,7 @@ export class MysteryEncounterBattlePhase extends Phase {
|
|||
} else {
|
||||
const trainer = this.scene.currentBattle.trainer;
|
||||
let message: string;
|
||||
scene.executeWithSeedOffset(() => message = Utils.randSeedItem(encounterMessages), this.scene.currentBattle.mysteryEncounter.getSeedOffset());
|
||||
scene.executeWithSeedOffset(() => message = Utils.randSeedItem(encounterMessages), this.scene.currentBattle.mysteryEncounter?.getSeedOffset());
|
||||
message = message!; // tell TS compiler it's defined now
|
||||
const showDialogueAndSummon = () => {
|
||||
scene.ui.showDialogue(message, trainer?.getName(TrainerSlot.NONE, true), null, () => {
|
||||
|
@ -308,7 +309,7 @@ export class MysteryEncounterBattlePhase extends Phase {
|
|||
|
||||
endBattleSetup(scene: BattleScene) {
|
||||
const enemyField = scene.getEnemyField();
|
||||
const encounterMode = scene.currentBattle.mysteryEncounter.encounterMode;
|
||||
const encounterMode = scene.currentBattle.mysteryEncounter!.encounterMode;
|
||||
|
||||
// PostSummon and ShinySparkle phases are handled by SummonPhase
|
||||
|
||||
|
@ -410,7 +411,7 @@ export class MysteryEncounterRewardsPhase extends Phase {
|
|||
|
||||
start() {
|
||||
super.start();
|
||||
const encounter = this.scene.currentBattle.mysteryEncounter;
|
||||
const encounter = this.scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
if (encounter.doContinueEncounter) {
|
||||
encounter.doContinueEncounter(this.scene).then(() => {
|
||||
|
@ -431,7 +432,7 @@ export class MysteryEncounterRewardsPhase extends Phase {
|
|||
}
|
||||
|
||||
doEncounterRewardsAndContinue() {
|
||||
const encounter = this.scene.currentBattle.mysteryEncounter;
|
||||
const encounter = this.scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
if (encounter.doEncounterExp) {
|
||||
encounter.doEncounterExp(this.scene);
|
||||
|
@ -462,7 +463,7 @@ export class PostMysteryEncounterPhase extends Phase {
|
|||
|
||||
constructor(scene: BattleScene) {
|
||||
super(scene);
|
||||
this.onPostOptionSelect = this.scene.currentBattle.mysteryEncounter.selectedOption?.onPostOptionPhase;
|
||||
this.onPostOptionSelect = this.scene.currentBattle.mysteryEncounter?.selectedOption?.onPostOptionPhase;
|
||||
}
|
||||
|
||||
start() {
|
||||
|
@ -476,7 +477,7 @@ export class PostMysteryEncounterPhase extends Phase {
|
|||
this.continueEncounter();
|
||||
}
|
||||
});
|
||||
}, this.scene.currentBattle.mysteryEncounter.getSeedOffset());
|
||||
}, this.scene.currentBattle.mysteryEncounter?.getSeedOffset());
|
||||
} else {
|
||||
this.continueEncounter();
|
||||
}
|
||||
|
|
|
@ -24,11 +24,11 @@ export class NextEncounterPhase extends EncounterPhase {
|
|||
|
||||
const enemyField = this.scene.getEnemyField();
|
||||
const moveTargets: any[] = [this.scene.arenaEnemy, this.scene.arenaNextEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.lastEnemyTrainer];
|
||||
const lastEncounterVisuals = this.scene?.lastMysteryEncounter?.introVisuals;
|
||||
const lastEncounterVisuals = this.scene.lastMysteryEncounter?.introVisuals;
|
||||
if (lastEncounterVisuals) {
|
||||
moveTargets.push(lastEncounterVisuals);
|
||||
}
|
||||
const nextEncounterVisuals = this.scene.currentBattle?.mysteryEncounter?.introVisuals;
|
||||
const nextEncounterVisuals = this.scene.currentBattle.mysteryEncounter?.introVisuals;
|
||||
if (nextEncounterVisuals) {
|
||||
const enterFromRight = nextEncounterVisuals.enterFromRight;
|
||||
if (enterFromRight) {
|
||||
|
@ -58,7 +58,7 @@ export class NextEncounterPhase extends EncounterPhase {
|
|||
}
|
||||
if (lastEncounterVisuals) {
|
||||
this.scene.field.remove(lastEncounterVisuals, true);
|
||||
this.scene.lastMysteryEncounter.introVisuals = undefined;
|
||||
this.scene.lastMysteryEncounter!.introVisuals = undefined;
|
||||
}
|
||||
|
||||
if (!this.tryOverrideForBattleSpec()) {
|
||||
|
|
|
@ -9,7 +9,7 @@ import { CommandPhase } from "./command-phase";
|
|||
import { EnemyCommandPhase } from "./enemy-command-phase";
|
||||
import { GameOverPhase } from "./game-over-phase";
|
||||
import { TurnStartPhase } from "./turn-start-phase";
|
||||
import { handleMysteryEncounterBattleStartEffects } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { handleMysteryEncounterBattleStartEffects, handleMysteryEncounterTurnStartEffects } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
|
||||
export class TurnInitPhase extends FieldPhase {
|
||||
constructor(scene: BattleScene) {
|
||||
|
@ -49,6 +49,12 @@ export class TurnInitPhase extends FieldPhase {
|
|||
|
||||
handleMysteryEncounterBattleStartEffects(this.scene);
|
||||
|
||||
// If true, will skip remainder of current phase (and not queue CommandPhases etc.)
|
||||
if (handleMysteryEncounterTurnStartEffects(this.scene)) {
|
||||
this.end();
|
||||
return;
|
||||
}
|
||||
|
||||
this.scene.getField().forEach((pokemon, i) => {
|
||||
if (pokemon?.isActive()) {
|
||||
if (pokemon.isPlayer()) {
|
||||
|
|
|
@ -46,7 +46,7 @@ export class VictoryPhase extends PokemonPhase {
|
|||
let expValue = this.getPokemon().getExpValue();
|
||||
if (this.scene.currentBattle.battleType === BattleType.TRAINER) {
|
||||
expValue = Math.floor(expValue * 1.5);
|
||||
} else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER) {
|
||||
} else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && this.scene.currentBattle.mysteryEncounter) {
|
||||
expValue = Math.floor(expValue * this.scene.currentBattle.mysteryEncounter.expMultiplier);
|
||||
}
|
||||
for (const partyMember of nonFaintedPartyMembers) {
|
||||
|
|
|
@ -140,7 +140,7 @@ describe("An Offer You Can't Refuse - Mystery Encounter", () => {
|
|||
await game.runToMysteryEncounter(MysteryEncounterType.AN_OFFER_YOU_CANT_REFUSE, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
const price = scene.currentBattle.mysteryEncounter.misc.price;
|
||||
const price = scene.currentBattle.mysteryEncounter!.misc.price;
|
||||
|
||||
expect(updateMoneySpy).toHaveBeenCalledWith(scene, price);
|
||||
expect(scene.money).toBe(initialMoney + price);
|
||||
|
@ -160,7 +160,7 @@ describe("An Offer You Can't Refuse - Mystery Encounter", () => {
|
|||
await game.runToMysteryEncounter(MysteryEncounterType.AN_OFFER_YOU_CANT_REFUSE, defaultParty);
|
||||
|
||||
const initialPartySize = scene.getParty().length;
|
||||
const pokemonName = scene.currentBattle.mysteryEncounter.misc.pokemon.name;
|
||||
const pokemonName = scene.currentBattle.mysteryEncounter!.misc.pokemon.name;
|
||||
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
|
@ -227,7 +227,7 @@ describe("An Offer You Can't Refuse - Mystery Encounter", () => {
|
|||
await game.runToMysteryEncounter(MysteryEncounterType.AN_OFFER_YOU_CANT_REFUSE, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
const price = scene.currentBattle.mysteryEncounter.misc.price;
|
||||
const price = scene.currentBattle.mysteryEncounter!.misc.price;
|
||||
|
||||
expect(updateMoneySpy).toHaveBeenCalledWith(scene, price);
|
||||
expect(scene.money).toBe(initialMoney + price);
|
||||
|
|
|
@ -119,7 +119,7 @@ describe("Berries Abound - Mystery Encounter", () => {
|
|||
it("should start a fight against the boss", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty);
|
||||
|
||||
const config = game.scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0];
|
||||
const config = game.scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0];
|
||||
const speciesToSpawn = config.pokemonConfigs?.[0].species.speciesId;
|
||||
|
||||
await runMysteryEncounterToEnd(game, 1, undefined, true);
|
||||
|
@ -133,7 +133,7 @@ describe("Berries Abound - Mystery Encounter", () => {
|
|||
it("should reward the player with X berries based on wave", { retry: 5 }, async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty);
|
||||
|
||||
const numBerries = game.scene.currentBattle.mysteryEncounter.misc.numBerries;
|
||||
const numBerries = game.scene.currentBattle.mysteryEncounter!.misc.numBerries;
|
||||
scene.modifiers = [];
|
||||
|
||||
await runMysteryEncounterToEnd(game, 1, undefined, true);
|
||||
|
@ -179,7 +179,7 @@ describe("Berries Abound - Mystery Encounter", () => {
|
|||
const encounterTextSpy = vi.spyOn(EncounterDialogueUtils, "showEncounterText");
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty);
|
||||
|
||||
const config = game.scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0];
|
||||
const config = game.scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0];
|
||||
const speciesToSpawn = config.pokemonConfigs?.[0].species.speciesId;
|
||||
// Setting enemy's level arbitrarily high to outspeed
|
||||
config.pokemonConfigs![0].dataSource!.level = 1000;
|
||||
|
|
|
@ -199,7 +199,7 @@ describe("Clowning Around - Mystery Encounter", () => {
|
|||
await game.phaseInterceptor.to(SelectModifierPhase, false);
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name);
|
||||
await game.phaseInterceptor.run(SelectModifierPhase);
|
||||
const abilityToTrain = scene.currentBattle.mysteryEncounter.misc.ability;
|
||||
const abilityToTrain = scene.currentBattle.mysteryEncounter?.misc.ability;
|
||||
|
||||
game.onNextPrompt("PostMysteryEncounterPhase", Mode.MESSAGE, () => {
|
||||
game.scene.ui.getHandler().processInput(Button.ACTION);
|
||||
|
|
|
@ -114,7 +114,7 @@ describe("Delibird-y - Mystery Encounter", () => {
|
|||
await game.runToMysteryEncounter(MysteryEncounterType.DELIBIRDY, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
const price = (scene.currentBattle.mysteryEncounter.options[0].requirements[0] as MoneyRequirement).requiredMoney;
|
||||
const price = (scene.currentBattle.mysteryEncounter?.options[0].requirements[0] as MoneyRequirement).requiredMoney;
|
||||
|
||||
expect(updateMoneySpy).toHaveBeenCalledWith(scene, -price, true, false);
|
||||
expect(scene.money).toBe(initialMoney - price);
|
||||
|
|
|
@ -213,7 +213,7 @@ describe("Fiery Fallout - Mystery Encounter", () => {
|
|||
|
||||
const burnablePokemon = party.filter((pkm) => pkm.isAllowedInBattle() && !pkm.getTypes().includes(Type.FIRE));
|
||||
const notBurnablePokemon = party.filter((pkm) => !pkm.isAllowedInBattle() || pkm.getTypes().includes(Type.FIRE));
|
||||
expect(scene.currentBattle.mysteryEncounter.dialogueTokens["burnedPokemon"]).toBe("Gengar");
|
||||
expect(scene.currentBattle.mysteryEncounter?.dialogueTokens["burnedPokemon"]).toBe("Gengar");
|
||||
burnablePokemon.forEach((pkm) => {
|
||||
expect(pkm.hp, `${pkm.name} should have received 20% damage: ${pkm.hp} / ${pkm.getMaxHp()} HP`).toBe(pkm.getMaxHp() - Math.floor(pkm.getMaxHp() * 0.2));
|
||||
});
|
||||
|
|
|
@ -120,7 +120,7 @@ describe("Fight or Flight - Mystery Encounter", () => {
|
|||
it("should start a fight against the boss", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FIGHT_OR_FLIGHT, defaultParty);
|
||||
|
||||
const config = game.scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0];
|
||||
const config = game.scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0];
|
||||
const speciesToSpawn = config.pokemonConfigs?.[0].species.speciesId;
|
||||
|
||||
await runMysteryEncounterToEnd(game, 1, undefined, true);
|
||||
|
@ -134,7 +134,7 @@ describe("Fight or Flight - Mystery Encounter", () => {
|
|||
it("should reward the player with the item based on wave", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FIGHT_OR_FLIGHT, defaultParty);
|
||||
|
||||
const item = game.scene.currentBattle.mysteryEncounter.misc;
|
||||
const item = game.scene.currentBattle.mysteryEncounter?.misc;
|
||||
|
||||
await runMysteryEncounterToEnd(game, 1, undefined, true);
|
||||
await skipBattleRunMysteryEncounterRewardsPhase(game);
|
||||
|
@ -193,7 +193,7 @@ describe("Fight or Flight - Mystery Encounter", () => {
|
|||
|
||||
// Mock moveset
|
||||
scene.getParty()[0].moveset = [new PokemonMove(Moves.KNOCK_OFF)];
|
||||
const item = game.scene.currentBattle.mysteryEncounter.misc;
|
||||
const item = game.scene.currentBattle.mysteryEncounter!.misc;
|
||||
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
await game.phaseInterceptor.to(SelectModifierPhase, false);
|
||||
|
|
|
@ -0,0 +1,304 @@
|
|||
import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters";
|
||||
import { HUMAN_TRANSITABLE_BIOMES } 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 BattleScene from "#app/battle-scene";
|
||||
import { Mode } from "#app/ui/ui";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils";
|
||||
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
|
||||
import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { Nature } from "#enums/nature";
|
||||
import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases";
|
||||
import { CommandPhase } from "#app/phases/command-phase";
|
||||
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
|
||||
import { FunAndGamesEncounter } from "#app/data/mystery-encounters/encounters/fun-and-games-encounter";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Command } from "#app/ui/command-ui-handler";
|
||||
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
|
||||
const namespace = "mysteryEncounter:funAndGames";
|
||||
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA];
|
||||
const defaultBiome = Biome.CAVE;
|
||||
const defaultWave = 45;
|
||||
|
||||
describe("Fun And Games! - 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();
|
||||
|
||||
const biomeMap = new Map<Biome, MysteryEncounterType[]>([
|
||||
[Biome.VOLCANO, [MysteryEncounterType.FIGHT_OR_FLIGHT]],
|
||||
]);
|
||||
HUMAN_TRANSITABLE_BIOMES.forEach(biome => {
|
||||
biomeMap.set(biome, [MysteryEncounterType.FUN_AND_GAMES]);
|
||||
});
|
||||
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(biomeMap);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
vi.clearAllMocks();
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it("should have the correct properties", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FUN_AND_GAMES, defaultParty);
|
||||
|
||||
expect(FunAndGamesEncounter.encounterType).toBe(MysteryEncounterType.FUN_AND_GAMES);
|
||||
expect(FunAndGamesEncounter.encounterTier).toBe(MysteryEncounterTier.GREAT);
|
||||
expect(FunAndGamesEncounter.dialogue).toBeDefined();
|
||||
expect(FunAndGamesEncounter.dialogue.intro).toStrictEqual([
|
||||
{
|
||||
speaker: `${namespace}.speaker`,
|
||||
text: `${namespace}.intro_dialogue`,
|
||||
}
|
||||
]);
|
||||
expect(FunAndGamesEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`);
|
||||
expect(FunAndGamesEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`);
|
||||
expect(FunAndGamesEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`);
|
||||
expect(FunAndGamesEncounter.options.length).toBe(2);
|
||||
});
|
||||
|
||||
it("should not spawn outside of CIVILIZATIONN biomes", async () => {
|
||||
game.override.mysteryEncounterTier(MysteryEncounterTier.GREAT);
|
||||
game.override.startingBiome(Biome.VOLCANO);
|
||||
await game.runToMysteryEncounter();
|
||||
|
||||
expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.FUN_AND_GAMES);
|
||||
});
|
||||
|
||||
it("should not run below wave 10", async () => {
|
||||
game.override.startingWave(9);
|
||||
|
||||
await game.runToMysteryEncounter();
|
||||
|
||||
expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.FUN_AND_GAMES);
|
||||
});
|
||||
|
||||
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 = new MysteryEncounter(FunAndGamesEncounter);
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
scene.currentBattle.waveIndex = defaultWave;
|
||||
|
||||
const { onInit } = encounter;
|
||||
|
||||
expect(encounter.onInit).toBeDefined();
|
||||
|
||||
const onInitResult = onInit!(scene);
|
||||
expect(onInitResult).toBe(true);
|
||||
});
|
||||
|
||||
describe("Option 1 - Play the Wobbuffet game", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option = FunAndGamesEncounter.options[0];
|
||||
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DISABLED_OR_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 NOT be selectable if the player doesn't have enough money", async () => {
|
||||
game.scene.money = 0;
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FUN_AND_GAMES, 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, 1);
|
||||
|
||||
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 get 3 turns to attack the Wobbuffet for a reward", async () => {
|
||||
scene.money = 20000;
|
||||
game.override.moveset([Moves.TACKLE]);
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FUN_AND_GAMES, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 1, { pokemonNo: 1 }, true);
|
||||
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
|
||||
expect(scene.getEnemyPokemon()?.species.speciesId).toBe(Species.WOBBUFFET);
|
||||
expect(scene.getEnemyPokemon()?.ivs).toEqual([0, 0, 0, 0, 0, 0]);
|
||||
expect(scene.getEnemyPokemon()?.nature).toBe(Nature.MILD);
|
||||
|
||||
game.onNextPrompt("MessagePhase", Mode.MESSAGE, () => {
|
||||
game.endPhase();
|
||||
});
|
||||
|
||||
// Turn 1
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, false);
|
||||
await game.phaseInterceptor.to(CommandPhase);
|
||||
|
||||
// Turn 2
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, false);
|
||||
await game.phaseInterceptor.to(CommandPhase);
|
||||
|
||||
// Turn 3
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, false);
|
||||
await game.phaseInterceptor.to(SelectModifierPhase, false);
|
||||
|
||||
// Rewards
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name);
|
||||
});
|
||||
|
||||
it("should have no items in rewards if Wubboffet doesn't take enough damage", async () => {
|
||||
scene.money = 20000;
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FUN_AND_GAMES, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 1, { pokemonNo: 1 }, true);
|
||||
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
|
||||
game.onNextPrompt("MessagePhase", Mode.MESSAGE, () => {
|
||||
game.endPhase();
|
||||
});
|
||||
|
||||
// Skip minigame
|
||||
scene.currentBattle.mysteryEncounter!.misc.turnsRemaining = 0;
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, false);
|
||||
await game.phaseInterceptor.to(SelectModifierPhase, false);
|
||||
|
||||
// Rewards
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name);
|
||||
await game.phaseInterceptor.run(SelectModifierPhase);
|
||||
|
||||
expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
|
||||
const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
|
||||
expect(modifierSelectHandler.options.length).toEqual(0);
|
||||
});
|
||||
|
||||
it("should have Wide Lens item in rewards if Wubboffet is at 15-33% HP remaining", async () => {
|
||||
scene.money = 20000;
|
||||
game.override.moveset([Moves.SPLASH]);
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FUN_AND_GAMES, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 1, { pokemonNo: 1 }, true);
|
||||
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
|
||||
game.onNextPrompt("MessagePhase", Mode.MESSAGE, () => {
|
||||
game.endPhase();
|
||||
});
|
||||
|
||||
// Skip minigame
|
||||
const wobbuffet = scene.getEnemyPokemon()!;
|
||||
wobbuffet.hp = Math.floor(0.2 * wobbuffet.getMaxHp());
|
||||
scene.currentBattle.mysteryEncounter!.misc.turnsRemaining = 0;
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, false);
|
||||
await game.phaseInterceptor.to(SelectModifierPhase, false);
|
||||
|
||||
// Rewards
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name);
|
||||
await game.phaseInterceptor.run(SelectModifierPhase);
|
||||
|
||||
expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
|
||||
const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
|
||||
expect(modifierSelectHandler.options.length).toEqual(1);
|
||||
expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("WIDE_LENS");
|
||||
});
|
||||
|
||||
it("should have Scope Lens item in rewards if Wubboffet is at 3-15% HP remaining", async () => {
|
||||
scene.money = 20000;
|
||||
game.override.moveset([Moves.SPLASH]);
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FUN_AND_GAMES, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 1, { pokemonNo: 1 }, true);
|
||||
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
|
||||
game.onNextPrompt("MessagePhase", Mode.MESSAGE, () => {
|
||||
game.endPhase();
|
||||
});
|
||||
|
||||
// Skip minigame
|
||||
const wobbuffet = scene.getEnemyPokemon()!;
|
||||
wobbuffet.hp = Math.floor(0.1 * wobbuffet.getMaxHp());
|
||||
scene.currentBattle.mysteryEncounter!.misc.turnsRemaining = 0;
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, false);
|
||||
await game.phaseInterceptor.to(SelectModifierPhase, false);
|
||||
|
||||
// Rewards
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name);
|
||||
await game.phaseInterceptor.run(SelectModifierPhase);
|
||||
|
||||
expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
|
||||
const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
|
||||
expect(modifierSelectHandler.options.length).toEqual(1);
|
||||
expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("SCOPE_LENS");
|
||||
});
|
||||
|
||||
it("should have Multi Lens item in rewards if Wubboffet is at <3% HP remaining", async () => {
|
||||
scene.money = 20000;
|
||||
game.override.moveset([Moves.SPLASH]);
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FUN_AND_GAMES, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 1, { pokemonNo: 1 }, true);
|
||||
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
|
||||
game.onNextPrompt("MessagePhase", Mode.MESSAGE, () => {
|
||||
game.endPhase();
|
||||
});
|
||||
|
||||
// Skip minigame
|
||||
const wobbuffet = scene.getEnemyPokemon()!;
|
||||
wobbuffet.hp = 1;
|
||||
scene.currentBattle.mysteryEncounter!.misc.turnsRemaining = 0;
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, false);
|
||||
await game.phaseInterceptor.to(SelectModifierPhase, false);
|
||||
|
||||
// Rewards
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name);
|
||||
await game.phaseInterceptor.run(SelectModifierPhase);
|
||||
|
||||
expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
|
||||
const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
|
||||
expect(modifierSelectHandler.options.length).toEqual(1);
|
||||
expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("MULTI_LENS");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Option 2 - Leave", () => {
|
||||
it("should leave encounter without battle", async () => {
|
||||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FUN_AND_GAMES, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -70,7 +70,7 @@ describe("Lost at Sea - Mystery Encounter", () => {
|
|||
game.override.startingBiome(Biome.MOUNTAIN);
|
||||
await game.runToMysteryEncounter();
|
||||
|
||||
expect(game.scene.currentBattle.mysteryEncounter.encounterType).not.toBe(MysteryEncounterType.LOST_AT_SEA);
|
||||
expect(game.scene.currentBattle.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.LOST_AT_SEA);
|
||||
});
|
||||
|
||||
it("should not run below wave 11", async () => {
|
||||
|
|
|
@ -98,7 +98,7 @@ describe("Mysterious Challengers - Mystery Encounter", () => {
|
|||
it("should initialize fully", async () => {
|
||||
initSceneWithoutEncounterPhase(scene, defaultParty);
|
||||
scene.currentBattle.mysteryEncounter = new MysteryEncounter(MysteriousChallengersEncounter);
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
scene.currentBattle.waveIndex = defaultWave;
|
||||
|
||||
const { onInit } = encounter;
|
||||
|
@ -162,7 +162,7 @@ describe("Mysterious Challengers - Mystery Encounter", () => {
|
|||
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
|
||||
expect(scene.currentBattle.trainer).toBeDefined();
|
||||
expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
expect(scene.currentBattle.mysteryEncounter?.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
});
|
||||
|
||||
it("should have normal trainer rewards after battle", async () => {
|
||||
|
@ -204,7 +204,7 @@ describe("Mysterious Challengers - Mystery Encounter", () => {
|
|||
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
|
||||
expect(scene.currentBattle.trainer).toBeDefined();
|
||||
expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
expect(scene.currentBattle.mysteryEncounter?.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
});
|
||||
|
||||
it("should have hard trainer rewards after battle", async () => {
|
||||
|
@ -247,7 +247,7 @@ describe("Mysterious Challengers - Mystery Encounter", () => {
|
|||
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
|
||||
expect(scene.currentBattle.trainer).toBeDefined();
|
||||
expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
expect(scene.currentBattle.mysteryEncounter?.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
});
|
||||
|
||||
it("should have brutal trainer rewards after battle", async () => {
|
||||
|
|
|
@ -142,7 +142,7 @@ describe("The Pokemon Salesman - Mystery Encounter", () => {
|
|||
await game.runToMysteryEncounter(MysteryEncounterType.THE_POKEMON_SALESMAN, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
const price = scene.currentBattle.mysteryEncounter.misc.price;
|
||||
const price = scene.currentBattle.mysteryEncounter!.misc.price;
|
||||
|
||||
expect(updateMoneySpy).toHaveBeenCalledWith(scene, -price, true, false);
|
||||
expect(scene.money).toBe(initialMoney - price);
|
||||
|
@ -153,7 +153,7 @@ describe("The Pokemon Salesman - Mystery Encounter", () => {
|
|||
await game.runToMysteryEncounter(MysteryEncounterType.THE_POKEMON_SALESMAN, defaultParty);
|
||||
|
||||
const initialPartySize = scene.getParty().length;
|
||||
const pokemonName = scene.currentBattle.mysteryEncounter.misc.pokemon.name;
|
||||
const pokemonName = scene.currentBattle.mysteryEncounter!.misc.pokemon.name;
|
||||
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ describe("The Winstrate Challenge - Mystery Encounter", () => {
|
|||
it("should initialize fully", async () => {
|
||||
initSceneWithoutEncounterPhase(scene, defaultParty);
|
||||
scene.currentBattle.mysteryEncounter = new MysteryEncounter(TheWinstrateChallengeEncounter);
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
scene.currentBattle.waveIndex = defaultWave;
|
||||
|
||||
const { onInit } = encounter;
|
||||
|
@ -281,32 +281,32 @@ describe("The Winstrate Challenge - Mystery Encounter", () => {
|
|||
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
|
||||
expect(scene.currentBattle.trainer).toBeDefined();
|
||||
expect(scene.currentBattle.trainer!.config.trainerType).toBe(TrainerType.VICTOR);
|
||||
expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(4);
|
||||
expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
expect(scene.currentBattle.mysteryEncounter?.enemyPartyConfigs.length).toBe(4);
|
||||
expect(scene.currentBattle.mysteryEncounter?.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
|
||||
await skipBattleToNextBattle(game);
|
||||
expect(scene.currentBattle.trainer).toBeDefined();
|
||||
expect(scene.currentBattle.trainer!.config.trainerType).toBe(TrainerType.VICTORIA);
|
||||
expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(3);
|
||||
expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
expect(scene.currentBattle.mysteryEncounter?.enemyPartyConfigs.length).toBe(3);
|
||||
expect(scene.currentBattle.mysteryEncounter?.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
|
||||
await skipBattleToNextBattle(game);
|
||||
expect(scene.currentBattle.trainer).toBeDefined();
|
||||
expect(scene.currentBattle.trainer!.config.trainerType).toBe(TrainerType.VIVI);
|
||||
expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(2);
|
||||
expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
expect(scene.currentBattle.mysteryEncounter?.enemyPartyConfigs.length).toBe(2);
|
||||
expect(scene.currentBattle.mysteryEncounter?.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
|
||||
await skipBattleToNextBattle(game);
|
||||
expect(scene.currentBattle.trainer).toBeDefined();
|
||||
expect(scene.currentBattle.trainer!.config.trainerType).toBe(TrainerType.VICKY);
|
||||
expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(1);
|
||||
expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
expect(scene.currentBattle.mysteryEncounter?.enemyPartyConfigs.length).toBe(1);
|
||||
expect(scene.currentBattle.mysteryEncounter?.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
|
||||
await skipBattleToNextBattle(game);
|
||||
expect(scene.currentBattle.trainer).toBeDefined();
|
||||
expect(scene.currentBattle.trainer!.config.trainerType).toBe(TrainerType.VITO);
|
||||
expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(0);
|
||||
expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
expect(scene.currentBattle.mysteryEncounter?.enemyPartyConfigs.length).toBe(0);
|
||||
expect(scene.currentBattle.mysteryEncounter?.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
|
||||
// Should have Macho Brace in the rewards
|
||||
await skipBattleToNextBattle(game, true);
|
||||
|
|
|
@ -286,7 +286,7 @@ describe("Mystery Encounter Utils", () => {
|
|||
scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value");
|
||||
const spy = vi.spyOn(game.scene.ui, "showText");
|
||||
|
||||
showEncounterText(scene, "mysteryEncounter:unit_test_dialogue");
|
||||
await showEncounterText(scene, "mysteryEncounter:unit_test_dialogue");
|
||||
expect(spy).toHaveBeenCalledWith("valuevalue {{testvalue}} {{test1}} {{test}} {{test\\}} {{test\\}} {test}}", null, expect.any(Function), 0, true);
|
||||
});
|
||||
});
|
||||
|
@ -297,7 +297,7 @@ describe("Mystery Encounter Utils", () => {
|
|||
scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value");
|
||||
const spy = vi.spyOn(game.scene.ui, "showDialogue");
|
||||
|
||||
showEncounterDialogue(scene, "mysteryEncounter:unit_test_dialogue", "mysteryEncounter:unit_test_dialogue");
|
||||
await showEncounterDialogue(scene, "mysteryEncounter:unit_test_dialogue", "mysteryEncounter:unit_test_dialogue");
|
||||
expect(spy).toHaveBeenCalledWith("valuevalue {{testvalue}} {{test1}} {{test}} {{test\\}} {{test\\}} {test}}", "valuevalue {{testvalue}} {{test1}} {{test}} {{test\\}} {{test\\}} {test}}", null, expect.any(Function), 0);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ import i18next from "i18next";
|
|||
import {Button} from "#enums/buttons";
|
||||
import Pokemon, { PokemonMove } from "#app/field/pokemon.js";
|
||||
import { CommandPhase } from "#app/phases/command-phase.js";
|
||||
import { BattleType } from "#app/battle";
|
||||
|
||||
export default class FightUiHandler extends UiHandler {
|
||||
public static readonly MOVES_CONTAINER_NAME = "moves";
|
||||
|
@ -116,8 +117,11 @@ export default class FightUiHandler extends UiHandler {
|
|||
ui.playError();
|
||||
}
|
||||
} else {
|
||||
ui.setMode(Mode.COMMAND, this.fieldIndex);
|
||||
success = true;
|
||||
// Cannot back out of fight menu if skipToFightInput is enabled
|
||||
if (this.scene.currentBattle.battleType !== BattleType.MYSTERY_ENCOUNTER || !this.scene.currentBattle.mysteryEncounter?.skipToFightInput) {
|
||||
ui.setMode(Mode.COMMAND, this.fieldIndex);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (button) {
|
||||
|
|
|
@ -326,7 +326,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
|||
|
||||
displayEncounterOptions(slideInDescription: boolean = true): void {
|
||||
this.getUi().clearText();
|
||||
const mysteryEncounter = this.scene.currentBattle.mysteryEncounter;
|
||||
const mysteryEncounter = this.scene.currentBattle.mysteryEncounter!;
|
||||
this.encounterOptions = this.overrideSettings?.overrideOptions ?? mysteryEncounter.options;
|
||||
this.optionsMeetsReqs = [];
|
||||
|
||||
|
|
Loading…
Reference in New Issue