Merge pull request #3850 from pagefaultgames/bug-type-superfan

Bug-Type Superfan Mystery Encounter
This commit is contained in:
ImperialSympathizer 2024-08-27 12:52:57 -04:00 committed by GitHub
commit b27e093252
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
105 changed files with 7789 additions and 4732 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -13,7 +13,17 @@ import { Arena, ArenaBase } from "./field/arena";
import { GameData } from "./system/game-data";
import { addTextObject, getTextColor, TextStyle } from "./ui/text";
import { allMoves } from "./data/move";
import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getModifierType, getPartyLuckValue, modifierTypes } from "./modifier/modifier-type";
import {
ModifierPoolType,
getDefaultModifierTypeForTier,
getEnemyModifierTypesForWave,
getLuckString,
getLuckTextTint,
getModifierPoolForType,
getModifierType,
getPartyLuckValue,
modifierTypes
} from "./modifier/modifier-type";
import AbilityBar from "./ui/ability-bar";
import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, ChangeMovePriorityAbAttr, PostBattleInitAbAttr, applyAbAttrs, applyPostBattleInitAbAttrs } from "./data/ability";
import { allAbilities } from "./data/ability";

View File

@ -19,7 +19,7 @@ const namespace = "mysteryEncounter:aTrainersTest";
/**
* A Trainer's Test encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/115 | GitHub Issue #115}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3816 | GitHub Issue #3816}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const ATrainersTestEncounter: MysteryEncounter =

View File

@ -29,7 +29,7 @@ const namespace = "mysteryEncounter:absoluteAvarice";
/**
* Absolute Avarice encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/58 | GitHub Issue #58}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3805 | GitHub Issue #3805}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const AbsoluteAvariceEncounter: MysteryEncounter =
@ -249,8 +249,10 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
const givePartyPokemonReviverSeeds = () => {
const party = scene.getParty();
party.forEach(p => {
if (revSeed) {
const seedModifier = revSeed.newModifier(p);
scene.addModifier(seedModifier, false, false, false, true);
}
});
queueEncounterMessage(scene, `${namespace}.option.1.food_stash`);
};
@ -349,7 +351,7 @@ function doGreedentSpriteSteal(scene: BattleScene) {
const greedentSprites = scene.currentBattle.mysteryEncounter.introVisuals?.getSpriteAtIndex(1);
scene.playSound("Follow Me");
scene.playSound("battle-anims/Follow Me");
scene.tweens.chain({
targets: greedentSprites,
tweens: [
@ -431,11 +433,11 @@ function doGreedentEatBerries(scene: BattleScene) {
y: "-=8",
loop: 5,
onStart: () => {
scene.playSound("PRSFX- Bug Bite");
scene.playSound("battle_anims/PRSFX- Bug Bite");
},
onLoop: () => {
if (index % 2 === 0) {
scene.playSound("PRSFX- Bug Bite");
scene.playSound("battle_anims/PRSFX- Bug Bite");
}
index++;
}

View File

@ -18,7 +18,7 @@ const namespace = "mysteryEncounter:offerYouCantRefuse";
/**
* An Offer You Can't Refuse encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/72 | GitHub Issue #72}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3808 | GitHub Issue #3808}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const AnOfferYouCantRefuseEncounter: MysteryEncounter =

View File

@ -37,7 +37,7 @@ const namespace = "mysteryEncounter:berriesAbound";
/**
* Berries Abound encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/24 | GitHub Issue #24}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3810 | GitHub Issue #3810}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const BerriesAboundEncounter: MysteryEncounter =
@ -131,7 +131,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
const doBerryRewards = async () => {
const berryText = numBerries + " " + i18next.t(`${namespace}.berries`);
scene.playSound("item_fanfare");
scene.playSound("bgm/item_fanfare");
queueEncounterMessage(scene, i18next.t("battle:rewardGain", { modifierName: berryText }));
// Generate a random berry and give it to the first Pokemon with room for it
@ -143,7 +143,10 @@ export const BerriesAboundEncounter: MysteryEncounter =
const shopOptions: ModifierTypeOption[] = [];
for (let i = 0; i < 5; i++) {
// Generate shop berries
shopOptions.push(generateModifierTypeOption(scene, modifierTypes.BERRY));
const mod = generateModifierTypeOption(scene, modifierTypes.BERRY);
if (mod) {
shopOptions.push(mod);
}
}
setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards);
@ -168,7 +171,10 @@ export const BerriesAboundEncounter: MysteryEncounter =
const shopOptions: ModifierTypeOption[] = [];
for (let i = 0; i < 5; i++) {
// Generate shop berries
shopOptions.push(generateModifierTypeOption(scene, modifierTypes.BERRY));
const mod = generateModifierTypeOption(scene, modifierTypes.BERRY);
if (mod) {
shopOptions.push(mod);
}
}
if (speedDiff < 1) {
@ -176,7 +182,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
const doBerryRewards = async () => {
const berryText = numBerries + " " + i18next.t(`${namespace}.berries`);
scene.playSound("item_fanfare");
scene.playSound("bgm/item_fanfare");
queueEncounterMessage(scene, i18next.t("battle:rewardGain", { modifierName: berryText }));
// Generate a random berry and give it to the first Pokemon with room for it
@ -202,7 +208,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
const doFasterBerryRewards = async () => {
const berryText = numBerriesGrabbed + " " + i18next.t(`${namespace}.berries`);
scene.playSound("item_fanfare");
scene.playSound("bgm/item_fanfare");
queueEncounterMessage(scene, i18next.t("battle:rewardGain", { modifierName: berryText }));
// Generate a random berry and give it to the first Pokemon with room for it (trying to give to fastest first)

View File

@ -0,0 +1,659 @@
import {
EnemyPartyConfig,
generateModifierTypeOption,
initBattleWithEnemyConfig,
leaveEncounterWithoutBattle,
selectOptionThenPokemon,
selectPokemonForOption,
setEncounterRewards,
transitionMysteryEncounterIntroVisuals,
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import {
trainerConfigs,
TrainerPartyCompoundTemplate,
TrainerPartyTemplate,
TrainerSlot,
} from "#app/data/trainer-config";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { PartyMemberStrength } from "#enums/party-member-strength";
import BattleScene from "#app/battle-scene";
import * as Utils from "#app/utils";
import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils";
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { TrainerType } from "#enums/trainer-type";
import { Species } from "#enums/species";
import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon";
import { getPokemonSpecies } from "#app/data/pokemon-species";
import { getEncounterText, showEncounterDialogue } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { LearnMovePhase } from "#app/phases/learn-move-phase";
import { Moves } from "#enums/moves";
import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import {
AttackTypeBoosterHeldItemTypeRequirement,
CombinationPokemonRequirement,
HeldItemRequirement,
TypeRequirement
} from "#app/data/mystery-encounters/mystery-encounter-requirements";
import { Type } from "#app/data/type";
import { AttackTypeBoosterModifierType, ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type";
import {
AttackTypeBoosterModifier,
BypassSpeedChanceModifier,
ContactHeldItemTransferChanceModifier,
PokemonHeldItemModifier
} from "#app/modifier/modifier";
import i18next from "i18next";
import MoveInfoOverlay from "#app/ui/move-info-overlay";
import { allMoves } from "#app/data/move";
import { ModifierTier } from "#app/modifier/modifier-tier";
/** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:bugTypeSuperfan";
const POOL_1_POKEMON = [
Species.PARASECT,
Species.VENOMOTH,
Species.LEDIAN,
Species.ARIADOS,
Species.YANMA,
Species.BEAUTIFLY,
Species.DUSTOX,
Species.MASQUERAIN,
Species.NINJASK,
Species.VOLBEAT,
Species.ILLUMISE,
Species.ANORITH,
Species.KRICKETUNE,
Species.WORMADAM,
Species.MOTHIM,
Species.SKORUPI,
Species.JOLTIK,
Species.LARVESTA,
Species.VIVILLON,
Species.CHARJABUG,
Species.RIBOMBEE,
Species.SPIDOPS,
Species.LOKIX
];
const POOL_2_POKEMON = [
Species.SCYTHER,
Species.PINSIR,
Species.HERACROSS,
Species.FORRETRESS,
Species.SCIZOR,
Species.SHUCKLE,
Species.SHEDINJA,
Species.ARMALDO,
Species.VESPIQUEN,
Species.DRAPION,
Species.YANMEGA,
Species.LEAVANNY,
Species.SCOLIPEDE,
Species.CRUSTLE,
Species.ESCAVALIER,
Species.ACCELGOR,
Species.GALVANTULA,
Species.VIKAVOLT,
Species.ARAQUANID,
Species.ORBEETLE,
Species.CENTISKORCH,
Species.FROSMOTH,
Species.KLEAVOR,
];
const POOL_3_POKEMON: { species: Species, formIndex?: number }[] = [
{
species: Species.PINSIR,
formIndex: 1
},
{
species: Species.SCIZOR,
formIndex: 1
},
{
species: Species.HERACROSS,
formIndex: 1
},
{
species: Species.ORBEETLE,
formIndex: 1
},
{
species: Species.CENTISKORCH,
formIndex: 1
},
{
species: Species.DURANT,
},
{
species: Species.VOLCARONA,
},
{
species: Species.GOLISOPOD,
},
];
const POOL_4_POKEMON = [
Species.GENESECT,
Species.SLITHER_WING,
Species.BUZZWOLE,
Species.PHEROMOSA
];
const PHYSICAL_TUTOR_MOVES = [
Moves.MEGAHORN,
Moves.X_SCISSOR,
Moves.ATTACK_ORDER,
Moves.PIN_MISSILE,
Moves.FIRST_IMPRESSION
];
const SPECIAL_TUTOR_MOVES = [
Moves.SILVER_WIND,
Moves.BUG_BUZZ,
Moves.SIGNAL_BEAM,
Moves.POLLEN_PUFF
];
const STATUS_TUTOR_MOVES = [
Moves.STRING_SHOT,
Moves.STICKY_WEB,
Moves.SILK_TRAP,
Moves.RAGE_POWDER,
Moves.HEAL_ORDER
];
const MISC_TUTOR_MOVES = [
Moves.BUG_BITE,
Moves.LEECH_LIFE,
Moves.DEFEND_ORDER,
Moves.QUIVER_DANCE,
Moves.TAIL_GLOW,
Moves.INFESTATION,
Moves.U_TURN
];
/**
* Bug Type Superfan encounter.
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3810 | GitHub Issue #3810}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const BugTypeSuperfanEncounter: MysteryEncounter =
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.BUG_TYPE_SUPERFAN)
.withEncounterTier(MysteryEncounterTier.GREAT)
.withPrimaryPokemonRequirement(new CombinationPokemonRequirement(
// Must have at least 1 Bug type on team, OR have a bug item somewhere on the team
new HeldItemRequirement(["BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier"], 1),
new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1),
new TypeRequirement(Type.BUG, false, 1)
))
.withSceneWaveRangeRequirement(10, 180) // waves 10 to 180
.withIntroSpriteConfigs([]) // These are set in onInit()
.withAutoHideIntroVisuals(false)
.withIntroDialogue([
{
text: `${namespace}.intro`,
},
{
speaker: `${namespace}.speaker`,
text: `${namespace}.intro_dialogue`,
},
])
.withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter;
// Calculates what trainers are available for battle in the encounter
// Bug type superfan trainer config
const config = getTrainerConfigForWave(scene.currentBattle.waveIndex);
const spriteKey = config.getSpriteKey();
encounter.enemyPartyConfigs.push({
trainerConfig: config,
female: true,
});
encounter.spriteConfigs = [
{
spriteKey: spriteKey,
fileRoot: "trainer",
hasShadow: true,
},
];
return true;
})
.withTitle(`${namespace}.title`)
.withDescription(`${namespace}.description`)
.withQuery(`${namespace}.query`)
.withSimpleOption(
{
buttonLabel: `${namespace}.option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`,
selected: [
{
speaker: `${namespace}.speaker`,
text: `${namespace}.option.1.selected`,
},
],
},
async (scene: BattleScene) => {
// Select battle the bug trainer
const encounter = scene.currentBattle.mysteryEncounter;
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
// Init the moves available for tutor
const moveTutorOptions: PokemonMove[] = [];
moveTutorOptions.push(new PokemonMove(PHYSICAL_TUTOR_MOVES[randSeedInt(PHYSICAL_TUTOR_MOVES.length)]));
moveTutorOptions.push(new PokemonMove(SPECIAL_TUTOR_MOVES[randSeedInt(SPECIAL_TUTOR_MOVES.length)]));
moveTutorOptions.push(new PokemonMove(STATUS_TUTOR_MOVES[randSeedInt(STATUS_TUTOR_MOVES.length)]));
moveTutorOptions.push(new PokemonMove(MISC_TUTOR_MOVES[randSeedInt(MISC_TUTOR_MOVES.length)]));
encounter.misc = {
moveTutorOptions
};
// Assigns callback that teaches move before continuing to rewards
encounter.onRewards = doBugTypeMoveTutor;
setEncounterRewards(scene, { fillRemaining: true });
await transitionMysteryEncounterIntroVisuals(scene, true, true);
await initBattleWithEnemyConfig(scene, config);
}
)
.withOption(MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withPrimaryPokemonRequirement(new TypeRequirement(Type.BUG, false, 1)) // Must have 1 Bug type on team
.withDialogue({
buttonLabel: `${namespace}.option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`,
disabledButtonTooltip: `${namespace}.option.2.disabled_tooltip`
})
.withPreOptionPhase(async (scene: BattleScene) => {
// Player shows off their bug types
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;
encounter.setDialogueToken("numBugTypes", numBugTypes.toString());
if (numBugTypes < 2) {
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.SUPER_LURE, modifierTypes.GREAT_BALL], fillRemaining: false });
encounter.selectedOption!.dialogue!.selected = [
{
speaker: `${namespace}.speaker`,
text: `${namespace}.option.2.selected_0_to_1`,
},
];
} else if (numBugTypes < 4) {
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.QUICK_CLAW, modifierTypes.MAX_LURE, modifierTypes.ULTRA_BALL], fillRemaining: false });
encounter.selectedOption!.dialogue!.selected = [
{
speaker: `${namespace}.speaker`,
text: `${namespace}.option.2.selected_2_to_3`,
},
];
} else if (numBugTypes < 6) {
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.GRIP_CLAW, modifierTypes.MAX_LURE, modifierTypes.ROGUE_BALL], fillRemaining: false });
encounter.selectedOption!.dialogue!.selected = [
{
speaker: `${namespace}.speaker`,
text: `${namespace}.option.2.selected_4_to_5`,
},
];
} else {
// If player has any evolution/form change items that are valid for their party, will spawn one of those items in addition to a Master Ball
const modifierOptions: ModifierTypeOption[] = [generateModifierTypeOption(scene, modifierTypes.MASTER_BALL)!, generateModifierTypeOption(scene, modifierTypes.MAX_LURE)!];
const specialOptions: ModifierTypeOption[] = [];
const nonRareEvolutionModifier = generateModifierTypeOption(scene, modifierTypes.EVOLUTION_ITEM);
if (nonRareEvolutionModifier) {
specialOptions.push(nonRareEvolutionModifier);
}
const rareEvolutionModifier = generateModifierTypeOption(scene, modifierTypes.RARE_EVOLUTION_ITEM);
if (rareEvolutionModifier) {
specialOptions.push(rareEvolutionModifier);
}
const formChangeModifier = generateModifierTypeOption(scene, modifierTypes.FORM_CHANGE_ITEM);
if (formChangeModifier) {
specialOptions.push(formChangeModifier);
}
if (specialOptions.length > 0) {
modifierOptions.push(specialOptions[randSeedInt(specialOptions.length)]);
}
setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifierOptions, fillRemaining: false });
encounter.selectedOption!.dialogue!.selected = [
{
speaker: `${namespace}.speaker`,
text: `${namespace}.option.2.selected_6`,
},
];
}
})
.withOptionPhase(async (scene: BattleScene) => {
// Player shows off their bug types
leaveEncounterWithoutBattle(scene);
})
.build())
.withOption(MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withPrimaryPokemonRequirement(new CombinationPokemonRequirement(
// Meets one or both of the below reqs
new HeldItemRequirement(["BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier"], 1),
new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1)
))
.withDialogue({
buttonLabel: `${namespace}.option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`,
disabledButtonTooltip: `${namespace}.option.3.disabled_tooltip`,
selected: [
{
text: `${namespace}.option.3.selected`,
},
{
speaker: `${namespace}.speaker`,
text: `${namespace}.option.3.selected_dialogue`,
},
],
secondOptionPrompt: `${namespace}.option.3.select_prompt`,
})
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
const encounter = scene.currentBattle.mysteryEncounter;
const onPokemonSelected = (pokemon: PlayerPokemon) => {
// Get Pokemon held items and filter for valid ones
const validItems = pokemon.getHeldItems().filter(item => {
return item instanceof BypassSpeedChanceModifier ||
item instanceof ContactHeldItemTransferChanceModifier ||
(item instanceof AttackTypeBoosterModifier && (item.type as AttackTypeBoosterModifierType).moveType === Type.BUG);
});
return validItems.map((modifier: PokemonHeldItemModifier) => {
const option: OptionSelectItem = {
label: modifier.type.name,
handler: () => {
// Pokemon and item selected
encounter.setDialogueToken("selectedItem", modifier.type.name);
encounter.misc = {
chosenPokemon: pokemon,
chosenModifier: modifier,
};
return true;
},
};
return option;
});
};
const selectableFilter = (pokemon: Pokemon) => {
// If pokemon has valid item, it can be selected
const hasValidItem = pokemon.getHeldItems().some(item => {
return item instanceof BypassSpeedChanceModifier ||
item instanceof ContactHeldItemTransferChanceModifier ||
(item instanceof AttackTypeBoosterModifier && (item.type as AttackTypeBoosterModifierType).moveType === Type.BUG);
});
if (!hasValidItem) {
return getEncounterText(scene, `${namespace}.option.3.invalid_selection`) ?? null;
}
return null;
};
return selectPokemonForOption(scene, onPokemonSelected, undefined, selectableFilter);
})
.withOptionPhase(async (scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter;
const modifier = encounter.misc.chosenModifier;
// Remove the modifier if its stacks go to 0
modifier.stackCount -= 1;
if (modifier.stackCount === 0) {
scene.removeModifier(modifier);
}
scene.updateModifiers(true, true);
const bugNet = generateModifierTypeOption(scene, modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!;
bugNet.type.tier = ModifierTier.MASTER;
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [bugNet], guaranteedModifierTypeFuncs: [modifierTypes.REVIVER_SEED], fillRemaining: false });
leaveEncounterWithoutBattle(scene, true);
})
.build())
.withOutroDialogue([
{
text: `${namespace}.outro`,
},
])
.build();
function getTrainerConfigForWave(waveIndex: number) {
// Bug type superfan trainer config
const config = trainerConfigs[TrainerType.BUG_TYPE_SUPERFAN].copy();
config.name = i18next.t("trainerNames:bug_type_superfan");
const pool3Copy = POOL_3_POKEMON.slice(0);
randSeedShuffle(pool3Copy);
const pool3Mon = pool3Copy.pop()!;
if (waveIndex < 30) {
// Use default template (2 AVG)
config
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true));
} else if (waveIndex < 50) {
config
.setPartyTemplates(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE))
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true))
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_1_POKEMON, TrainerSlot.TRAINER, true));
} else if (waveIndex < 70) {
config
.setPartyTemplates(new TrainerPartyTemplate(4, PartyMemberStrength.AVERAGE))
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true))
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_1_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(3, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true));
} else if (waveIndex < 100) {
config
.setPartyTemplates(new TrainerPartyTemplate(5, PartyMemberStrength.AVERAGE))
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true))
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_1_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(3, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(4, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true));
} else if (waveIndex < 120) {
config
.setPartyTemplates(new TrainerPartyTemplate(5, PartyMemberStrength.AVERAGE))
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1;
p.generateAndPopulateMoveset();
p.generateName();
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1;
p.generateAndPopulateMoveset();
p.generateName();
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(3, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon.formIndex)) {
p.formIndex = pool3Mon.formIndex!;
p.generateAndPopulateMoveset();
p.generateName();
}
}));
} else if (waveIndex < 140) {
randSeedShuffle(pool3Copy);
const pool3Mon2 = pool3Copy.pop()!;
config
.setPartyTemplates(new TrainerPartyTemplate(5, PartyMemberStrength.AVERAGE))
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1;
p.generateAndPopulateMoveset();
p.generateName();
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1;
p.generateAndPopulateMoveset();
p.generateName();
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon.formIndex)) {
p.formIndex = pool3Mon.formIndex!;
p.generateAndPopulateMoveset();
p.generateName();
}
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([pool3Mon2.species], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon2.formIndex)) {
p.formIndex = pool3Mon2.formIndex!;
p.generateAndPopulateMoveset();
p.generateName();
}
}));
} else if (waveIndex < 160) {
config
.setPartyTemplates(new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(4, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)))
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1;
p.generateAndPopulateMoveset();
p.generateName();
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true, p => {
p.formIndex = 1;
p.generateAndPopulateMoveset();
p.generateName();
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon.formIndex)) {
p.formIndex = pool3Mon.formIndex!;
p.generateAndPopulateMoveset();
p.generateName();
}
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc(POOL_4_POKEMON, TrainerSlot.TRAINER, true));
} else {
config
.setPartyTemplates(new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(4, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)))
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.formIndex = 1;
p.generateAndPopulateMoveset();
p.generateName();
}))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.formIndex = 1;
p.generateAndPopulateMoveset();
p.generateName();
}))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon.formIndex)) {
p.formIndex = pool3Mon.formIndex!;
p.generateAndPopulateMoveset();
p.generateName();
}
}))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon.formIndex)) {
p.formIndex = pool3Mon.formIndex!;
p.generateAndPopulateMoveset();
p.generateName();
}
}))
.setPartyMemberFunc(4, getRandomPartyMemberFunc(POOL_4_POKEMON, TrainerSlot.TRAINER, true));
}
return config;
}
function getRandomPartyMemberFunc(speciesPool: Species[], trainerSlot: TrainerSlot = TrainerSlot.TRAINER, ignoreEvolution: boolean = false, postProcess?: (enemyPokemon: EnemyPokemon) => void) {
return (scene: BattleScene, level: integer, strength: PartyMemberStrength) => {
let species = Utils.randSeedItem(speciesPool);
if (!ignoreEvolution) {
species = getPokemonSpecies(species).getTrainerSpeciesForLevel(level, true, strength);
}
return scene.addEnemyPokemon(getPokemonSpecies(species), level, trainerSlot, undefined, undefined, postProcess);
};
}
function doBugTypeMoveTutor(scene: BattleScene): Promise<void> {
return new Promise<void>(async resolve => {
const moveOptions = scene.currentBattle.mysteryEncounter.misc.moveTutorOptions;
await showEncounterDialogue(scene, `${namespace}.battle_won`, `${namespace}.speaker`);
const overlayScale = 1;
const moveInfoOverlay = new MoveInfoOverlay(scene, {
delayVisibility: false,
scale: overlayScale,
onSide: true,
right: true,
x: 1,
y: -MoveInfoOverlay.getHeight(overlayScale, true) - 1,
width: (scene.game.canvas.width / 6) - 2,
});
scene.ui.add(moveInfoOverlay);
const optionSelectItems = moveOptions.map((move: PokemonMove) => {
const option: OptionSelectItem = {
label: move.getName(),
handler: () => {
moveInfoOverlay.active = false;
moveInfoOverlay.setVisible(false);
return true;
},
onHover: () => {
moveInfoOverlay.active = true;
moveInfoOverlay.show(allMoves[move.moveId]);
},
};
return option;
});
const onHoverOverCancel = () => {
moveInfoOverlay.active = false;
moveInfoOverlay.setVisible(false);
};
const result = await selectOptionThenPokemon(scene, optionSelectItems, `${namespace}.teach_move_prompt`, undefined, onHoverOverCancel);
// let forceExit = !!result;
if (!result) {
moveInfoOverlay.active = false;
moveInfoOverlay.setVisible(false);
}
// TODO: add menu to confirm player doesn't want to teach a move
// while (!result && !forceExit) {
// // Didn't teach a move, ask the player to confirm they don't want to teach a move
// await showEncounterDialogue(scene, `${namespace}.confirm_no_teach`, `${namespace}.speaker`);
// const confirm = await new Promise<boolean>(confirmResolve => {
// scene.ui.setMode(Mode.CONFIRM, () => confirmResolve(true), () => confirmResolve(false));
// });
// scene.ui.clearText();
// await scene.ui.setMode(Mode.MESSAGE);
// if (confirm) {
// // No teach, break out of loop
// forceExit = true;
// } else {
// // Re-show learn menu
// result = await selectOptionThenPokemon(scene, optionSelectItems, `${namespace}.teach_move_prompt`, undefined, onHoverOverCancel);
// if (!result) {
// moveInfoOverlay.active = false;
// moveInfoOverlay.setVisible(false);
// }
// }
// }
// Option select complete, handle if they are learning a move
if (result && result.selectedOptionIndex < moveOptions.length) {
scene.unshiftPhase(new LearnMovePhase(scene, result.selectedPokemonIndex, moveOptions[result.selectedOptionIndex].moveId));
}
// Complete battle and go to rewards
resolve();
});
}

View File

@ -53,7 +53,7 @@ const RANDOM_ABILITY_POOL = [
/**
* Clowning Around encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/69 | GitHub Issue #69}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3807 | GitHub Issue #3807}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const ClowningAroundEncounter: MysteryEncounter =
@ -334,13 +334,13 @@ export const ClowningAroundEncounter: MysteryEncounter =
randSeedShuffle(priorityTypes);
}
let newTypes;
let newTypes: Type[];
if (!originalTypes || originalTypes.length < 1) {
newTypes = priorityTypes?.length > 0 ? [priorityTypes.pop()] : [(randSeedInt(18) as Type)];
newTypes = priorityTypes && priorityTypes.length > 0 ? [priorityTypes.pop()!] : [(randSeedInt(18) as Type)];
} else {
newTypes = originalTypes.map(m => {
if (priorityTypes?.length > 0) {
const ret = priorityTypes.pop();
if (priorityTypes && priorityTypes.length > 0) {
const ret = priorityTypes.pop()!;
randSeedShuffle(priorityTypes);
return ret;
}

View File

@ -75,7 +75,7 @@ const SENSU_STYLE_BIOMES = [
/**
* Dancing Lessons encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/130 | GitHub Issue #130}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3823 | GitHub Issue #3823}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const DancingLessonsEncounter: MysteryEncounter =

View File

@ -71,7 +71,7 @@ const excludedBosses = [
/**
* Dark Deal encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/61 | GitHub Issue #61}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3806 | GitHub Issue #3806}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const DarkDealEncounter: MysteryEncounter =

View File

@ -33,7 +33,7 @@ const OPTION_3_DISALLOWED_MODIFIERS = [
/**
* Delibird-y encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/57 | GitHub Issue #57}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3804 | GitHub Issue #3804}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const DelibirdyEncounter: MysteryEncounter =
@ -115,7 +115,7 @@ export const DelibirdyEncounter: MysteryEncounter =
// At max stacks, give the first party pokemon a Shell Bell instead
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
scene.playSound("item_fanfare");
scene.playSound("bgm/item_fanfare");
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), undefined, true);
} else {
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.ABILITY_CHARM));
@ -190,7 +190,7 @@ export const DelibirdyEncounter: MysteryEncounter =
// At max stacks, give the first party pokemon a Shell Bell instead
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
scene.playSound("item_fanfare");
scene.playSound("bgm/item_fanfare");
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), undefined, true);
} else {
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.CANDY_JAR));
@ -203,7 +203,7 @@ export const DelibirdyEncounter: MysteryEncounter =
// At max stacks, give the first party pokemon a Shell Bell instead
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
scene.playSound("item_fanfare");
scene.playSound("bgm/item_fanfare");
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), undefined, true);
} else {
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.HEALING_CHARM));
@ -283,7 +283,7 @@ export const DelibirdyEncounter: MysteryEncounter =
// At max stacks, give the first party pokemon a Shell Bell instead
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
scene.playSound("item_fanfare");
scene.playSound("bgm/item_fanfare");
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), undefined, true);
} else {
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.BERRY_POUCH));

View File

@ -17,7 +17,7 @@ const namespace = "mysteryEncounter:departmentStoreSale";
/**
* Department Store Sale encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/33 | GitHub Issue #33}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3797 | GitHub Issue #3797}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const DepartmentStoreSaleEncounter: MysteryEncounter =

View File

@ -16,7 +16,7 @@ const namespace = "mysteryEncounter:fieldTrip";
/**
* Field Trip encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/17 | GitHub Issue #17}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3794 | GitHub Issue #3794}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const FieldTripEncounter: MysteryEncounter =
@ -126,10 +126,10 @@ export const FieldTripEncounter: MysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter;
if (encounter.misc.correctMove) {
const modifiers = [
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.ATK]),
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.DEF]),
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPD]),
generateModifierTypeOption(scene, modifierTypes.DIRE_HIT),
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.ATK])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.DEF])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPD])!,
generateModifierTypeOption(scene, modifierTypes.DIRE_HIT)!,
];
setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifiers, fillRemaining: false });
@ -218,10 +218,10 @@ export const FieldTripEncounter: MysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter;
if (encounter.misc.correctMove) {
const modifiers = [
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPATK]),
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPDEF]),
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPD]),
generateModifierTypeOption(scene, modifierTypes.DIRE_HIT),
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPATK])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPDEF])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPD])!,
generateModifierTypeOption(scene, modifierTypes.DIRE_HIT)!,
];
setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifiers, fillRemaining: false });
@ -304,10 +304,10 @@ export const FieldTripEncounter: MysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter;
if (encounter.misc.correctMove) {
const modifiers = [
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.ACC]),
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPD]),
generateModifierTypeOption(scene, modifierTypes.GREAT_BALL),
generateModifierTypeOption(scene, modifierTypes.IV_SCANNER),
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.ACC])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPD])!,
generateModifierTypeOption(scene, modifierTypes.GREAT_BALL)!,
generateModifierTypeOption(scene, modifierTypes.IV_SCANNER)!,
];
setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifiers, fillRemaining: false });

View File

@ -33,7 +33,7 @@ const DAMAGE_PERCENTAGE: number = 20;
/**
* Fiery Fallout encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/88 | GitHub Issue #88}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3814 | GitHub Issue #3814}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const FieryFalloutEncounter: MysteryEncounter =

View File

@ -30,7 +30,7 @@ const namespace = "mysteryEncounter:fightOrFlight";
/**
* Fight or Flight encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/24 | GitHub Issue #24}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3795 | GitHub Issue #3795}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const FightOrFlightEncounter: MysteryEncounter =

View File

@ -23,7 +23,7 @@ const namespace = "mysteryEncounter:lostAtSea";
/**
* Lost at sea encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/9 | GitHub Issue #9}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3793 | GitHub Issue #3793}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.LOST_AT_SEA)
@ -125,7 +125,6 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
* Generic handler for using a guiding pokemon to guide you back.
*
* @param scene Battle scene
* @param guidePokemon pokemon choosen as a guide
*/
async function handlePokemonGuidingYouPhase(scene: BattleScene) {
const laprasSpecies = getPokemonSpecies(Species.LAPRAS);

View File

@ -23,7 +23,7 @@ const namespace = "mysteryEncounter:mysteriousChallengers";
/**
* Mysterious Challengers encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/41 | GitHub Issue #41}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3801 | GitHub Issue #3801}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const MysteriousChallengersEncounter: MysteryEncounter =

View File

@ -15,7 +15,7 @@ const namespace = "mysteryEncounter:mysteriousChest";
/**
* Mysterious Chest encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/32 | GitHub Issue #32}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3796 | GitHub Issue #3796}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const MysteriousChestEncounter: MysteryEncounter =

View File

@ -17,7 +17,7 @@ const namespace = "mysteryEncounter:partTimer";
/**
* Part Timer encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/82 | GitHub Issue #82}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3813 | GitHub Issue #3813}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const PartTimerEncounter: MysteryEncounter =
@ -140,7 +140,7 @@ export const PartTimerEncounter: MysteryEncounter =
}
const moneyChange = scene.getWaveMoneyAmount(moneyMultiplier);
updatePlayerMoney(scene, moneyChange, true, false);
await showEncounterText(scene, i18next.t("mysteryEncounter:receive_money", { amount: moneyChange }));
await showEncounterText(scene, i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange }));
await showEncounterText(scene, `${namespace}.pokemon_tired`);
setEncounterRewards(scene, { fillRemaining: true });
@ -221,7 +221,7 @@ export const PartTimerEncounter: MysteryEncounter =
}
const moneyChange = scene.getWaveMoneyAmount(moneyMultiplier);
updatePlayerMoney(scene, moneyChange, true, false);
await showEncounterText(scene, i18next.t("mysteryEncounter:receive_money", { amount: moneyChange }));
await showEncounterText(scene, i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange }));
await showEncounterText(scene, `${namespace}.pokemon_tired`);
setEncounterRewards(scene, { fillRemaining: true });
@ -273,7 +273,7 @@ export const PartTimerEncounter: MysteryEncounter =
await showEncounterDialogue(scene, `${namespace}.job_complete_good`, `${namespace}.speaker`);
const moneyChange = scene.getWaveMoneyAmount(2.5);
updatePlayerMoney(scene, moneyChange, true, false);
await showEncounterText(scene, i18next.t("mysteryEncounter:receive_money", { amount: moneyChange }));
await showEncounterText(scene, i18next.t("mysteryEncounterMessages:receive_money", { amount: moneyChange }));
await showEncounterText(scene, `${namespace}.pokemon_tired`);
setEncounterRewards(scene, { fillRemaining: true });
@ -290,50 +290,50 @@ export const PartTimerEncounter: MysteryEncounter =
.build();
function doStrongWorkSfx(scene: BattleScene) {
scene.playSound("PRSFX- Horn Drill1");
scene.playSound("PRSFX- Horn Drill1");
scene.playSound("battle_anims/PRSFX- Horn Drill1");
scene.playSound("battle_anims/PRSFX- Horn Drill1");
scene.time.delayedCall(1000, () => {
scene.playSound("PRSFX- Guillotine2");
scene.playSound("battle_anims/PRSFX- Guillotine2");
});
scene.time.delayedCall(2000, () => {
scene.playSound("PRSFX- Heavy Slam2");
scene.playSound("battle_anims/PRSFX- Heavy Slam2");
});
scene.time.delayedCall(2500, () => {
scene.playSound("PRSFX- Guillotine2");
scene.playSound("battle_anims/PRSFX- Guillotine2");
});
}
function doDeliverySfx(scene: BattleScene) {
scene.playSound("PRSFX- Accelerock1");
scene.playSound("battle_anims/PRSFX- Accelerock1");
scene.time.delayedCall(1500, () => {
scene.playSound("PRSFX- Extremespeed1");
scene.playSound("battle_anims/PRSFX- Extremespeed1");
});
scene.time.delayedCall(2000, () => {
scene.playSound("PRSFX- Extremespeed1");
scene.playSound("battle_anims/PRSFX- Extremespeed1");
});
scene.time.delayedCall(2250, () => {
scene.playSound("PRSFX- Agility");
scene.playSound("battle_anims/PRSFX- Agility");
});
}
function doSalesSfx(scene: BattleScene) {
scene.playSound("PRSFX- Captivate");
scene.playSound("battle_anims/PRSFX- Captivate");
scene.time.delayedCall(1500, () => {
scene.playSound("PRSFX- Attract2");
scene.playSound("battle_anims/PRSFX- Attract2");
});
scene.time.delayedCall(2000, () => {
scene.playSound("PRSFX- Aurora Veil2");
scene.playSound("battle_anims/PRSFX- Aurora Veil2");
});
scene.time.delayedCall(3000, () => {
scene.playSound("PRSFX- Attract2");
scene.playSound("battle_anims/PRSFX- Attract2");
});
}

View File

@ -26,7 +26,7 @@ const TRAINER_THROW_ANIMATION_TIMES = [512, 184, 768];
/**
* Safari Zone encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/39 | GitHub Issue #39}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3800 | GitHub Issue #3800}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const SafariZoneEncounter: MysteryEncounter =
@ -322,7 +322,7 @@ async function throwBait(scene: BattleScene, pokemon: EnemyPokemon): Promise<boo
return new Promise(resolve => {
scene.trainer.setTexture(`trainer_${scene.gameData.gender === PlayerGender.FEMALE ? "f" : "m"}_back_pb`);
scene.time.delayedCall(TRAINER_THROW_ANIMATION_TIMES[0], () => {
scene.playSound("pb_throw");
scene.playSound("se/pb_throw");
// Trainer throw frames
scene.trainer.setFrame("2");
@ -351,12 +351,12 @@ async function throwBait(scene: BattleScene, pokemon: EnemyPokemon): Promise<boo
y: originalY - 5,
loop: 6,
onStart: () => {
scene.playSound("PRSFX- Bug Bite");
scene.playSound("battle-anims/PRSFX- Bug Bite");
bait.setFrame("0002.png");
},
onLoop: () => {
if (index % 2 === 0) {
scene.playSound("PRSFX- Bug Bite");
scene.playSound("battle-anims/PRSFX- Bug Bite");
}
if (index === 4) {
bait.setFrame("0003.png");
@ -388,7 +388,7 @@ async function throwMud(scene: BattleScene, pokemon: EnemyPokemon): Promise<bool
return new Promise(resolve => {
scene.trainer.setTexture(`trainer_${scene.gameData.gender === PlayerGender.FEMALE ? "f" : "m"}_back_pb`);
scene.time.delayedCall(TRAINER_THROW_ANIMATION_TIMES[0], () => {
scene.playSound("pb_throw");
scene.playSound("se/pb_throw");
// Trainer throw frames
scene.trainer.setFrame("2");
@ -407,7 +407,7 @@ async function throwMud(scene: BattleScene, pokemon: EnemyPokemon): Promise<bool
duration: 500,
onComplete: () => {
// Mud frame 2
scene.playSound("PRSFX- Sludge Bomb2");
scene.playSound("battle-anims/PRSFX- Sludge Bomb2");
mud.setFrame("0002.png");
// Mud splat
scene.time.delayedCall(200, () => {
@ -433,10 +433,10 @@ async function throwMud(scene: BattleScene, pokemon: EnemyPokemon): Promise<bool
y: originalY - 20,
loop: 1,
onStart: () => {
scene.playSound("PRSFX- Taunt2");
scene.playSound("battle-anims/PRSFX- Taunt2");
},
onLoop: () => {
scene.playSound("PRSFX- Taunt2");
scene.playSound("battle-anims/PRSFX- Taunt2");
},
onComplete: () => {
resolve(true);

View File

@ -19,7 +19,7 @@ const namespace = "mysteryEncounter:shadyVitaminDealer";
/**
* Shady Vitamin Dealer encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/34 | GitHub Issue #34}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3798 | GitHub Issue #3798}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const ShadyVitaminDealerEncounter: MysteryEncounter =
@ -79,8 +79,8 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
updatePlayerMoney(scene, -(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney);
// Calculate modifiers and dialogue tokens
const modifiers = [
generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER),
generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER),
generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER)!,
generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER)!,
];
encounter.setDialogueToken("boost1", modifiers[0].name);
encounter.setDialogueToken("boost2", modifiers[1].name);
@ -162,8 +162,8 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
updatePlayerMoney(scene, -(encounter.options[1].requirements[0] as MoneyRequirement).requiredMoney);
// Calculate modifiers and dialogue tokens
const modifiers = [
generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER),
generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER),
generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER)!,
generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER)!,
];
encounter.setDialogueToken("boost1", modifiers[0].name);
encounter.setDialogueToken("boost2", modifiers[1].name);

View File

@ -22,7 +22,7 @@ const namespace = "mysteryEncounter:slumberingSnorlax";
/**
* Sleeping Snorlax encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/103 | GitHub Issue #103}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3815 | GitHub Issue #3815}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const SlumberingSnorlaxEncounter: MysteryEncounter =

View File

@ -29,7 +29,7 @@ const MACHINE_INTERFACING_TYPES = [Type.ELECTRIC, Type.STEEL];
/**
* Teleporting Hijinks encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/119 | GitHub Issue #119}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3817 | GitHub Issue #3817}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const TeleportingHijinksEncounter: MysteryEncounter =
@ -140,10 +140,9 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
}],
};
const magnet = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.STEEL]);
const metalCoat = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.ELECTRIC]);
const magnet = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.STEEL])!;
const metalCoat = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.ELECTRIC])!;
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [magnet, metalCoat], fillRemaining: true });
setEncounterExp(scene, encounter.selectedOption!.primaryPokemon!.id, 100);
transitionMysteryEncounterIntroVisuals(scene, true, true);
await initBattleWithEnemyConfig(scene, config);
}

View File

@ -22,7 +22,7 @@ const MAX_POKEMON_PRICE_MULTIPLIER = 6;
/**
* Pokemon Salesman encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/36 | GitHub Issue #36}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3799 | GitHub Issue #3799}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const ThePokemonSalesmanEncounter: MysteryEncounter =

View File

@ -23,7 +23,7 @@ const namespace = "mysteryEncounter:theStrongStuff";
/**
* The Strong Stuff encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/54 | GitHub Issue #54}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3803 | GitHub Issue #3803}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const TheStrongStuffEncounter: MysteryEncounter =

View File

@ -26,7 +26,7 @@ const namespace = "mysteryEncounter:theWinstrateChallenge";
/**
* The Winstrate Challenge encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/136 | GitHub Issue #136}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3821 | GitHub Issue #3821}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const TheWinstrateChallengeEncounter: MysteryEncounter =

View File

@ -24,7 +24,7 @@ const namespace = "mysteryEncounter:trainingSession";
/**
* Training Session encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/43 | GitHub Issue #43}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3802 | GitHub Issue #3802}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const TrainingSessionEncounter: MysteryEncounter =

View File

@ -25,7 +25,7 @@ const SOUND_EFFECT_WAIT_TIME = 700;
/**
* Trash to Treasure encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/74 | GitHub Issue #74}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3809 | GitHub Issue #3809}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const TrashToTreasureEncounter: MysteryEncounter =
@ -177,7 +177,7 @@ async function tryApplyDigRewardItems(scene: BattleScene) {
}
}
scene.playSound("item_fanfare");
scene.playSound("bgm/item_fanfare");
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2 " + leftovers.name }), undefined, true);
// First Shell bell
@ -204,17 +204,17 @@ async function tryApplyDigRewardItems(scene: BattleScene) {
}
}
scene.playSound("item_fanfare");
scene.playSound("bgm/item_fanfare");
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2 " + shellBell.name }), undefined, true);
}
async function doGarbageDig(scene: BattleScene) {
scene.playSound("PRSFX- Dig2");
scene.playSound("battle-anims/PRSFX- Dig2");
scene.time.delayedCall(SOUND_EFFECT_WAIT_TIME, () => {
scene.playSound("PRSFX- Dig2");
scene.playSound("PRSFX- Venom Drench", { volume: 2 });
scene.playSound("battle-anims/PRSFX- Dig2");
scene.playSound("battle-anims/PRSFX- Venom Drench", { volume: 2 });
});
scene.time.delayedCall(SOUND_EFFECT_WAIT_TIME * 2, () => {
scene.playSound("PRSFX- Dig2");
scene.playSound("battle-anims/PRSFX- Dig2");
});
}

View File

@ -24,8 +24,8 @@ import { getLevelTotalExp } from "#app/data/exp";
/** i18n namespace for encounter */
const namespace = "mysteryEncounter:weirdDream";
/** Exclude Ultra Beasts (inludes Cosmog/Solgaleo/Lunala/Necrozma), Paradox (includes Miraidon/Koraidon), Eternatus, Urshifu, the Poison Chain trio, Ogerpon */
const excludedPokemon = [
/** Exclude Ultra Beasts, Paradox, Eternatus, and all legendary/mythical/trio pokemon that are below 570 BST */
const EXCLUDED_TRANSFORMATION_SPECIES = [
Species.ETERNATUS,
/** UBs */
Species.NIHILEGO,
@ -77,9 +77,18 @@ const excludedPokemon = [
Species.FEZANDIPITI,
];
const SUPER_LEGENDARY_BST_THRESHOLD = 600;
const NON_LEGENDARY_BST_THRESHOLD = 570;
const GAIN_OLD_GATEAU_ITEM_BST_THRESHOLD = 450;
/** Value ranges of the resulting species BST transformations after adding values to original species */
const HIGH_BST_TRANSFORM_BASE_VALUES = [90, 110];
const STANDARD_BST_TRANSFORM_BASE_VALUES = [40, 50];
/**
* Weird Dream encounter.
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/137 | GitHub Issue #137}
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3822 | GitHub Issue #3822}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const WeirdDreamEncounter: MysteryEncounter =
@ -225,9 +234,9 @@ function getTeamTransformations(scene: BattleScene): PokemonTransformation[] {
});
// Only 1 Pokemon can be transformed into BST higher than 600
let hasPokemonBstHigherThan600 = false;
let hasPokemonInSuperLegendaryBstThreshold = false;
// Only 1 other Pokemon can be transformed into BST between 570-600
let hasPokemonBstBetween570And600 = false;
let hasPokemonInLegendaryBstThreshold = false;
// First, roll 2 of the party members to new Pokemon at a +90 to +110 BST difference
// Then, roll the remainder of the party members at a +40 to +50 BST difference
@ -241,19 +250,19 @@ function getTeamTransformations(scene: BattleScene): PokemonTransformation[] {
const bst = getOriginalBst(scene, removed);
let newBstRange;
if (i < 2) {
newBstRange = [90, 110];
newBstRange = HIGH_BST_TRANSFORM_BASE_VALUES;
} else {
newBstRange = [40, 50];
newBstRange = STANDARD_BST_TRANSFORM_BASE_VALUES;
}
const newSpecies = getTransformedSpecies(bst, newBstRange, hasPokemonBstHigherThan600, hasPokemonBstBetween570And600, alreadyUsedSpecies);
const newSpecies = getTransformedSpecies(bst, newBstRange, hasPokemonInSuperLegendaryBstThreshold, hasPokemonInLegendaryBstThreshold, alreadyUsedSpecies);
const newSpeciesBst = newSpecies.getBaseStatTotal();
if (newSpeciesBst > 600) {
hasPokemonBstHigherThan600 = true;
if (newSpeciesBst > SUPER_LEGENDARY_BST_THRESHOLD) {
hasPokemonInSuperLegendaryBstThreshold = true;
}
if (newSpeciesBst <= 600 && newSpeciesBst >= 570) {
hasPokemonBstBetween570And600 = true;
if (newSpeciesBst <= SUPER_LEGENDARY_BST_THRESHOLD && newSpeciesBst >= NON_LEGENDARY_BST_THRESHOLD) {
hasPokemonInLegendaryBstThreshold = true;
}
@ -299,9 +308,8 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon
return newValue > iv ? newValue : iv;
});
// For pokemon at/below 570 BST or any shiny pokemon, unlock it permanently as if you had caught it
if (newPokemon.getSpeciesForm().getBaseStatTotal() <= 570 || newPokemon.isShiny()) {
if (newPokemon.getSpeciesForm().getBaseStatTotal() <= NON_LEGENDARY_BST_THRESHOLD || newPokemon.isShiny()) {
if (newPokemon.getSpeciesForm().abilityHidden && newPokemon.abilityIndex === newPokemon.getSpeciesForm().getAbilityCount() - 1) {
scene.validateAchv(achvs.HIDDEN_ABILITY);
}
@ -372,8 +380,8 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon
scene.addModifier(item, false, false, false, true);
}
// Any pokemon that is at or below 450 BST gets +20 permanent BST to 3 stats: HP, lowest of Atk/SpAtk, and lowest of Def/SpDef
if (newPokemon.getSpeciesForm().getBaseStatTotal() <= 450) {
// Any pokemon that is at or below 450 BST gets +20 permanent BST to 3 stats: HP (halved, +10), lowest of Atk/SpAtk, and lowest of Def/SpDef
if (newPokemon.getSpeciesForm().getBaseStatTotal() <= GAIN_OLD_GATEAU_ITEM_BST_THRESHOLD) {
const stats: Stat[] = [Stat.HP];
const baseStats = newPokemon.getSpeciesForm().baseStats.slice(0);
// Attack or SpAtk
@ -435,9 +443,9 @@ function getTransformedSpecies(originalBst: number, bstSearchRange: [number, num
const speciesBst = s.getBaseStatTotal();
const bstInRange = speciesBst >= bstMin && speciesBst <= bstCap;
// Checks that a Pokemon has not already been added in the +600 or 570-600 slots;
const validBst = (!hasPokemonBstBetween570And600 || (speciesBst < 570 || speciesBst > 600)) &&
(!hasPokemonBstHigherThan600 || speciesBst <= 600);
return bstInRange && validBst && !excludedPokemon.includes(s.speciesId);
const validBst = (!hasPokemonBstBetween570And600 || (speciesBst < NON_LEGENDARY_BST_THRESHOLD || speciesBst > SUPER_LEGENDARY_BST_THRESHOLD)) &&
(!hasPokemonBstHigherThan600 || speciesBst <= SUPER_LEGENDARY_BST_THRESHOLD);
return bstInRange && validBst && !EXCLUDED_TRANSFORMATION_SPECIES.includes(s.speciesId);
});
// There must be at least 20 species available before it will choose one

View File

@ -81,7 +81,7 @@ export default class MysteryEncounterOption implements IMysteryEncounterOption {
}
meetsPrimaryRequirementAndPrimaryPokemonSelected(scene: BattleScene) {
if (!this.primaryPokemonRequirements) {
if (!this.primaryPokemonRequirements || this.primaryPokemonRequirements.length === 0) {
return true;
}
let qualified: PlayerPokemon[] = scene.getParty();
@ -101,7 +101,7 @@ export default class MysteryEncounterOption implements IMysteryEncounterOption {
return false;
}
if (this.excludePrimaryFromSecondaryRequirements && this.secondaryPokemon) {
if (this.excludePrimaryFromSecondaryRequirements && this.secondaryPokemon && this.secondaryPokemon.length > 0) {
const truePrimaryPool: PlayerPokemon[] = [];
const overlap: PlayerPokemon[] = [];
for (const qp of qualified) {
@ -135,7 +135,7 @@ export default class MysteryEncounterOption implements IMysteryEncounterOption {
}
meetsSupportingRequirementAndSupportingPokemonSelected(scene: BattleScene) {
if (!this.secondaryPokemonRequirements) {
if (!this.secondaryPokemonRequirements || this.secondaryPokemonRequirements.length === 0) {
this.secondaryPokemon = [];
return true;
}

View File

@ -13,6 +13,8 @@ import { StatusEffect } from "../status-effect";
import { Type } from "../type";
import { WeatherType } from "../weather";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { AttackTypeBoosterModifier } from "#app/modifier/modifier";
import { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type";
export interface EncounterRequirement {
meetsRequirement(scene: BattleScene): boolean; // Boolean to see if a requirement is met
@ -420,11 +422,11 @@ export class TypeRequirement extends EncounterPokemonRequirement {
meetsRequirement(scene: BattleScene): boolean {
let partyPokemon = scene.getParty();
if (isNullOrUndefined(partyPokemon) || this?.requiredType?.length < 0) {
if (isNullOrUndefined(partyPokemon)) {
return false;
}
if (!this.excludeFainted) {
if (this.excludeFainted) {
partyPokemon = partyPokemon.filter((pokemon) => !pokemon.isFainted());
}
@ -795,7 +797,7 @@ export class HeldItemRequirement extends EncounterPokemonRequirement {
meetsRequirement(scene: BattleScene): boolean {
const partyPokemon = scene.getParty();
if (isNullOrUndefined(partyPokemon) || this?.requiredHeldItemModifiers?.length < 0) {
if (isNullOrUndefined(partyPokemon)) {
return false;
}
return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
@ -828,6 +830,53 @@ export class HeldItemRequirement extends EncounterPokemonRequirement {
}
}
export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRequirement {
requiredHeldItemTypes: Type[];
minNumberOfPokemon: number;
invertQuery: boolean;
constructor(heldItemTypes: Type | Type[], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
super();
this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery;
this.requiredHeldItemTypes = Array.isArray(heldItemTypes) ? heldItemTypes : [heldItemTypes];
}
meetsRequirement(scene: BattleScene): boolean {
const partyPokemon = scene.getParty();
if (isNullOrUndefined(partyPokemon)) {
return false;
}
return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
}
queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
if (!this.invertQuery) {
return partyPokemon.filter((pokemon) => this.requiredHeldItemTypes.some((heldItemType) => {
return pokemon.getHeldItems().some((it) => {
return it instanceof AttackTypeBoosterModifier && (it.type as AttackTypeBoosterModifierType).moveType === heldItemType;
});
}));
} else {
// for an inverted query, we only want to get the pokemon that have any held items that are NOT in requiredHeldItemModifiers
// E.g. functions as a blacklist
return partyPokemon.filter((pokemon) => pokemon.getHeldItems().filter((it) => {
return !this.requiredHeldItemTypes.some(heldItemType => it instanceof AttackTypeBoosterModifier && (it.type as AttackTypeBoosterModifierType).moveType === heldItemType);
}).length > 0);
}
}
getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const requiredItems = pokemon?.getHeldItems().filter((it) => {
return this.requiredHeldItemTypes.some(heldItemType => it instanceof AttackTypeBoosterModifier && (it.type as AttackTypeBoosterModifierType).moveType === heldItemType);
});
if (requiredItems && requiredItems.length > 0) {
return ["heldItem", requiredItems[0].type.name];
}
return ["heldItem", ""];
}
}
export class LevelRequirement extends EncounterPokemonRequirement {
requiredLevelRange: [number, number];
minNumberOfPokemon: number;

View File

@ -122,6 +122,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 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 */
doEncounterExp?: (scene: BattleScene) => boolean;
/** Will provide the player a rewards shop for that wave */
@ -261,7 +263,7 @@ export default class MysteryEncounter implements IMysteryEncounter {
}
meetsPrimaryRequirementAndPrimaryPokemonSelected(scene: BattleScene): boolean {
if (this.primaryPokemonRequirements.length === 0) {
if (!this.primaryPokemonRequirements || this.primaryPokemonRequirements.length === 0) {
const activeMon = scene.getParty().filter(p => p.isActive(true));
if (activeMon.length > 0) {
this.primaryPokemon = activeMon[0];
@ -284,7 +286,7 @@ export default class MysteryEncounter implements IMysteryEncounter {
return false;
}
if (this.excludePrimaryFromSupportRequirements && this.secondaryPokemon) {
if (this.excludePrimaryFromSupportRequirements && this.secondaryPokemon && this.secondaryPokemon.length > 0) {
const truePrimaryPool: PlayerPokemon[] = [];
const overlap: PlayerPokemon[] = [];
for (const qp of qualified) {
@ -318,7 +320,7 @@ export default class MysteryEncounter implements IMysteryEncounter {
}
meetsSecondaryRequirementAndSecondaryPokemonSelected(scene: BattleScene): boolean {
if (!this.secondaryPokemonRequirements) {
if (!this.secondaryPokemonRequirements || this.secondaryPokemonRequirements.length === 0) {
this.secondaryPokemon = [];
return true;
}

View File

@ -27,6 +27,7 @@ import { DancingLessonsEncounter } from "#app/data/mystery-encounters/encounters
import { WeirdDreamEncounter } from "#app/data/mystery-encounters/encounters/weird-dream-encounter";
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";
// 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;
@ -171,7 +172,8 @@ const anyBiomeEncounters: MysteryEncounterType[] = [
MysteryEncounterType.BERRIES_ABOUND,
MysteryEncounterType.CLOWNING_AROUND,
MysteryEncounterType.WEIRD_DREAM,
MysteryEncounterType.TELEPORTING_HIJINKS
MysteryEncounterType.TELEPORTING_HIJINKS,
MysteryEncounterType.BUG_TYPE_SUPERFAN
];
/**
@ -276,6 +278,7 @@ export function initMysteryEncounters() {
allMysteryEncounters[MysteryEncounterType.WEIRD_DREAM] = WeirdDreamEncounter;
allMysteryEncounters[MysteryEncounterType.THE_WINSTRATE_CHALLENGE] = TheWinstrateChallengeEncounter;
allMysteryEncounters[MysteryEncounterType.TELEPORTING_HIJINKS] = TeleportingHijinksEncounter;
allMysteryEncounters[MysteryEncounterType.BUG_TYPE_SUPERFAN] = BugTypeSuperfanEncounter;
// Add extreme encounters to biome map
extremeBiomeEncounters.forEach(encounter => {

View File

@ -36,8 +36,7 @@ export const DANCING_MOVES = [
Moves.QUIVER_DANCE,
Moves.SWORDS_DANCE,
Moves.TEETER_DANCE,
Moves.VICTORY_DANCE,
Moves.KNOCK_OFF
Moves.VICTORY_DANCE
];
export const DISTRACTION_MOVES = [

View File

@ -64,7 +64,7 @@ export function doTrainerExclamation(scene: BattleScene) {
}
});
scene.playSound("GEN8- Exclaim", { volume: 0.7 });
scene.playSound("battle_anims/GEN8- Exclaim", { volume: 0.7 });
}
export interface EnemyPokemonConfig {
@ -363,13 +363,13 @@ export function updatePlayerMoney(scene: BattleScene, changeValue: number, playS
scene.updateMoneyText();
scene.animateMoneyChanged(false);
if (playSound) {
scene.playSound("buy");
scene.playSound("se/buy");
}
if (showMessage) {
if (changeValue < 0) {
scene.queueMessage(i18next.t("mysteryEncounter:paid_money", { amount: -changeValue }), null, true);
scene.queueMessage(i18next.t("mysteryEncounterMessages:paid_money", { amount: -changeValue }), null, true);
} else {
scene.queueMessage(i18next.t("mysteryEncounter:receive_money", { amount: changeValue }), null, true);
scene.queueMessage(i18next.t("mysteryEncounterMessages:receive_money", { amount: changeValue }), null, true);
}
}
}
@ -380,17 +380,20 @@ export function updatePlayerMoney(scene: BattleScene, changeValue: number, playS
* @param modifier
* @param pregenArgs - can specify BerryType for berries, TM for TMs, AttackBoostType for item, etc.
*/
export function generateModifierType(scene: BattleScene, modifier: () => ModifierType, pregenArgs?: any[]): ModifierType {
const modifierId = Object.keys(modifierTypes).find(k => modifierTypes[k] === modifier)!;
let result: ModifierType = modifierTypes[modifierId]?.();
export function generateModifierType(scene: BattleScene, modifier: () => ModifierType, pregenArgs?: any[]): ModifierType | null {
const modifierId = Object.keys(modifierTypes).find(k => modifierTypes[k] === modifier);
if (!modifierId) {
return null;
}
let result: ModifierType = modifierTypes[modifierId]();
// Populates item id and tier (order matters)
result = result
.withIdFromFunc(modifierTypes[modifierId])
.withTierFromPool();
const generatedResult = result instanceof ModifierTypeGenerator ? result.generateType(scene.getParty(), pregenArgs) : result;
return generatedResult ?? result;
return result instanceof ModifierTypeGenerator ? result.generateType(scene.getParty(), pregenArgs) : result;
}
/**
@ -399,9 +402,12 @@ export function generateModifierType(scene: BattleScene, modifier: () => Modifie
* @param modifier
* @param pregenArgs - can specify BerryType for berries, TM for TMs, AttackBoostType for item, etc.
*/
export function generateModifierTypeOption(scene: BattleScene, modifier: () => ModifierType, pregenArgs?: any[]): ModifierTypeOption {
export function generateModifierTypeOption(scene: BattleScene, modifier: () => ModifierType, pregenArgs?: any[]): ModifierTypeOption | null {
const result = generateModifierType(scene, modifier, pregenArgs);
if (result) {
return new ModifierTypeOption(result, 0);
}
return result;
}
/**
@ -416,7 +422,7 @@ export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (p
return new Promise(resolve => {
const modeToSetOnExit = scene.ui.getMode();
// Open party screen to choose pokemon to train
// Open party screen to choose pokemon
scene.ui.setMode(Mode.PARTY, PartyUiMode.SELECT, -1, (slotIndex: integer, option: PartyOption) => {
if (slotIndex < scene.getParty().length) {
scene.ui.setMode(modeToSetOnExit).then(() => {
@ -446,12 +452,12 @@ export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (p
label: i18next.t("menu:cancel"),
handler: () => {
scene.ui.clearText();
scene.ui.setMode(Mode.MYSTERY_ENCOUNTER);
scene.ui.setMode(modeToSetOnExit);
resolve(false);
return true;
},
onHover: () => {
scene.ui.showText(i18next.t("mysteryEncounter:cancel_option"));
scene.ui.showText(i18next.t("mysteryEncounterMessages:cancel_option"));
}
});
@ -461,6 +467,11 @@ export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (p
yOffset: 0,
supportHover: true
};
// Do hover over the starting selection option
if (fullOptions[0].onHover) {
fullOptions[0].onHover();
}
scene.ui.setModeWithoutClear(Mode.OPTION_SELECT, config, null, true);
};
@ -484,6 +495,97 @@ export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (p
});
}
interface PokemonAndOptionSelected {
selectedPokemonIndex: number;
selectedOptionIndex: number;
}
/**
* This function is intended for use inside onPreOptionPhase() of an encounter option
* @param scene
* If a second option needs to be selected, onPokemonSelected should return a OptionSelectItem[] object
* @param options
* @param optionSelectPromptKey
* @param selectablePokemonFilter
* @param onHoverOverCancelOption
*/
export function selectOptionThenPokemon(scene: BattleScene, options: OptionSelectItem[], optionSelectPromptKey: string, selectablePokemonFilter?: PokemonSelectFilter, onHoverOverCancelOption?: () => void): Promise<PokemonAndOptionSelected | null> {
return new Promise<PokemonAndOptionSelected | null>(resolve => {
const modeToSetOnExit = scene.ui.getMode();
const displayOptions = (config: OptionSelectConfig) => {
scene.ui.setMode(Mode.MESSAGE).then(() => {
if (!optionSelectPromptKey) {
// Do hover over the starting selection option
if (fullOptions[0].onHover) {
fullOptions[0].onHover();
}
scene.ui.setMode(Mode.OPTION_SELECT, config);
} else {
showEncounterText(scene, optionSelectPromptKey).then(() => {
// Do hover over the starting selection option
if (fullOptions[0].onHover) {
fullOptions[0].onHover();
}
scene.ui.setMode(Mode.OPTION_SELECT, config);
});
}
});
};
const selectPokemonAfterOption = (selectedOptionIndex: number) => {
// Open party screen to choose a Pokemon
scene.ui.setMode(Mode.PARTY, PartyUiMode.SELECT, -1, (slotIndex: integer, option: PartyOption) => {
if (slotIndex < scene.getParty().length) {
// Pokemon and option selected
scene.ui.setMode(modeToSetOnExit).then(() => {
const result: PokemonAndOptionSelected = { selectedPokemonIndex: slotIndex, selectedOptionIndex: selectedOptionIndex };
resolve(result);
});
} else {
// Back to first option select screen
displayOptions(config);
}
}, selectablePokemonFilter);
};
// Always appends a cancel option to bottom of options
const fullOptions = options.map((option, index) => {
// Update handler to resolve promise
const onSelect = option.handler;
option.handler = () => {
onSelect();
selectPokemonAfterOption(index);
return true;
};
return option;
}).concat({
label: i18next.t("menu:cancel"),
handler: () => {
scene.ui.clearText();
scene.ui.setMode(modeToSetOnExit);
resolve(null);
return true;
},
onHover: () => {
if (onHoverOverCancelOption) {
onHoverOverCancelOption();
}
scene.ui.showText(i18next.t("mysteryEncounterMessages:cancel_option"));
}
});
const config: OptionSelectConfig = {
options: fullOptions,
maxOptions: 7,
yOffset: 0,
supportHover: true
};
displayOptions(config);
});
}
/**
* Will initialize reward phases to follow the mystery encounter
* Can have shop displayed or skipped

View File

@ -335,7 +335,7 @@ export function trainerThrowPokeball(scene: BattleScene, pokemon: EnemyPokemon,
return new Promise(resolve => {
scene.trainer.setTexture(`trainer_${scene.gameData.gender === PlayerGender.FEMALE ? "f" : "m"}_back_pb`);
scene.time.delayedCall(512, () => {
scene.playSound("pb_throw");
scene.playSound("se/pb_throw");
// Trainer throw frames
scene.trainer.setFrame("2");
@ -355,7 +355,7 @@ export function trainerThrowPokeball(scene: BattleScene, pokemon: EnemyPokemon,
onComplete: () => {
pokeball.setTexture("pb", `${pokeballAtlasKey}_opening`);
scene.time.delayedCall(17, () => pokeball.setTexture("pb", `${pokeballAtlasKey}_open`));
scene.playSound("pb_rel");
scene.playSound("se/pb_rel");
pokemon.tint(getPokeballTintColor(pokeballType));
addPokeballOpenParticles(scene, pokeball.x, pokeball.y, pokeballType);
@ -369,7 +369,7 @@ export function trainerThrowPokeball(scene: BattleScene, pokemon: EnemyPokemon,
onComplete: () => {
pokeball.setTexture("pb", `${pokeballAtlasKey}_opening`);
pokemon.setVisible(false);
scene.playSound("pb_catch");
scene.playSound("se/pb_catch");
scene.time.delayedCall(17, () => pokeball.setTexture("pb", `${pokeballAtlasKey}`));
const doShake = () => {
@ -397,13 +397,13 @@ export function trainerThrowPokeball(scene: BattleScene, pokemon: EnemyPokemon,
failCatch(scene, pokemon, originalY, pokeball, pokeballType).then(() => resolve(false));
} else if (shakeCount++ < 3) {
if (randSeedInt(65536) < ballTwitchRate) {
scene.playSound("pb_move");
scene.playSound("se/pb_move");
} else {
shakeCounter.stop();
failCatch(scene, pokemon, originalY, pokeball, pokeballType).then(() => resolve(false));
}
} else {
scene.playSound("pb_lock");
scene.playSound("se/pb_lock");
addPokeballCaptureStars(scene, pokeball);
const pbTint = scene.add.sprite(pokeball.x, pokeball.y, "pb", "pb");
@ -445,7 +445,7 @@ export function trainerThrowPokeball(scene: BattleScene, pokemon: EnemyPokemon,
function failCatch(scene: BattleScene, pokemon: EnemyPokemon, originalY: number, pokeball: Phaser.GameObjects.Sprite, pokeballType: PokeballType) {
return new Promise<void>(resolve => {
scene.playSound("pb_rel");
scene.playSound("se/pb_rel");
pokemon.setY(originalY);
if (pokemon.status?.effect !== StatusEffect.SLEEP) {
pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 });
@ -591,7 +591,7 @@ function removePb(scene: BattleScene, pokeball: Phaser.GameObjects.Sprite) {
export async function doPokemonFlee(scene: BattleScene, pokemon: EnemyPokemon): Promise<void> {
await new Promise<void>(resolve => {
scene.playSound("flee");
scene.playSound("se/flee");
// Ease pokemon out
scene.tweens.add({
targets: pokemon,
@ -635,3 +635,50 @@ export function doPlayerFlee(scene: BattleScene, pokemon: EnemyPokemon): Promise
});
});
}
// Bug Species and their corresponding weights
const GOLDEN_BUG_NET_SPECIES_POOL: [Species, number][] = [
[Species.SCYTHER, 40],
[Species.SCIZOR, 40],
[Species.KLEAVOR, 40],
[Species.PINSIR, 40],
[Species.HERACROSS, 40],
[Species.YANMA, 40],
[Species.YANMEGA, 40],
[Species.SHUCKLE, 40],
[Species.ANORITH, 40],
[Species.ARMALDO, 40],
[Species.ESCAVALIER, 40],
[Species.ACCELGOR, 40],
[Species.JOLTIK, 40],
[Species.GALVANTULA, 40],
[Species.DURANT, 40],
[Species.LARVESTA, 40],
[Species.VOLCARONA, 40],
[Species.DEWPIDER, 40],
[Species.ARAQUANID, 40],
[Species.WIMPOD, 40],
[Species.GOLISOPOD, 40],
[Species.SIZZLIPEDE, 40],
[Species.CENTISKORCH, 40],
[Species.NYMBLE, 40],
[Species.LOKIX, 40],
[Species.BUZZWOLE, 1],
[Species.PHEROMOSA, 1],
];
export function getGoldenBugNetSpecies(scene: BattleScene, waveIndex: integer, level: integer): PokemonSpecies {
const totalWeight = GOLDEN_BUG_NET_SPECIES_POOL.reduce((a, b) => a + b[1], 0);
const roll = randSeedInt(totalWeight);
let w = 0;
for (const species of GOLDEN_BUG_NET_SPECIES_POOL) {
w += species[1];
if (roll < w) {
return getPokemonSpecies(species);
}
}
// Defaults to Scyther
return getPokemonSpecies(GOLDEN_BUG_NET_SPECIES_POOL[0][0]);
}

View File

@ -2104,5 +2104,7 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyTemplates(trainerPartyTemplates.ONE_AVG),
[TrainerType.VITO]: new TrainerConfig(++t).setName("Vito").setTitle("The Winstrates")
.setMoneyMultiplier(2)
.setPartyTemplates(new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.STRONG)))
.setPartyTemplates(new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.STRONG))),
[TrainerType.BUG_TYPE_SUPERFAN]: new TrainerConfig(++t).setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.ACE_TRAINER)
.setPartyTemplates(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE))
};

View File

@ -24,5 +24,6 @@ export enum MysteryEncounterType {
DANCING_LESSONS,
WEIRD_DREAM,
THE_WINSTRATE_CHALLENGE,
TELEPORTING_HIJINKS
TELEPORTING_HIJINKS,
BUG_TYPE_SUPERFAN
}

View File

@ -94,6 +94,7 @@ export enum TrainerType {
VIVI,
VICKY,
VITO,
BUG_TYPE_SUPERFAN,
BROCK = 200,
MISTY,

View File

@ -59,6 +59,7 @@ import modifierSelectUiHandler from "./modifier-select-ui-handler.json";
import moveTriggers from "./move-trigger.json";
import runHistory from "./run-history.json";
import { mysteryEncounter } from "#app/locales/en/mystery-encounter";
import mysteryEncounterMessages from "./mystery-encounter-messages.json";
export const enConfig = {
ability,
@ -121,5 +122,6 @@ export const enConfig = {
modifierSelectUiHandler,
moveTriggers,
runHistory,
mysteryEncounter: mysteryEncounter
mysteryEncounter: mysteryEncounter,
mysteryEncounterMessages
};

View File

@ -841,7 +841,7 @@
"2": "We're pulling out all the stops to put your Pokémon down."
},
"victory": {
"1": "At times we battle, and sometimes we team up...\n $It's great how Trainers can interact."
"1": "At times we battle, and sometimes we team up...$It's great how Trainers can interact."
},
"defeat": {
"1": "You put up quite the display.\nBetter luck next time."
@ -857,7 +857,7 @@
},
"winstrates_victoria": {
"encounter": {
"1": "My goodness! Aren't you young?\n $You must be quite the trainer to beat my husband, though.\n $Now I suppose it's my turn to battle!"
"1": "My goodness! Aren't you young?$You must be quite the trainer to beat my husband, though.$Now I suppose it's my turn to battle!"
},
"victory": {
"1": "Uwah! Just how strong are you?!"
@ -865,7 +865,7 @@
},
"winstrates_vivi": {
"encounter": {
"1": "You're stronger than Mom? Wow!\n $But I'm strong, too!\nReally! Honestly!"
"1": "You're stronger than Mom? Wow!$But I'm strong, too!\nReally! Honestly!"
},
"victory": {
"1": "Huh? Did I really lose?\nSnivel... Grandmaaa!"
@ -873,7 +873,7 @@
},
"winstrates_vicky": {
"encounter": {
"1": "How dare you make my precious\ngranddaughter cry!\n $I see I need to teach you a lesson.\nPrepare to feel the sting of defeat!"
"1": "How dare you make my precious\ngranddaughter cry!$I see I need to teach you a lesson.\nPrepare to feel the sting of defeat!"
},
"victory": {
"1": "Whoa! So strong!\nMy granddaughter wasn't lying."
@ -881,7 +881,7 @@
},
"winstrates_vito": {
"encounter": {
"1": "I trained together with my whole family,\nevery one of us!\n $I'm not losing to anyone!"
"1": "I trained together with my whole family,\nevery one of us!$I'm not losing to anyone!"
},
"victory": {
"1": "I was better than everyone in my family.\nI've never lost before..."

View File

@ -841,7 +841,7 @@
"2": "We're pulling out all the stops to put your Pokémon down."
},
"victory": {
"1": "At times we battle, and sometimes we team up...\n $It's great how Trainers can interact."
"1": "At times we battle, and sometimes we team up...$It's great how Trainers can interact."
},
"defeat": {
"1": "You put up quite the display.\nBetter luck next time."
@ -857,7 +857,7 @@
},
"winstrates_victoria": {
"encounter": {
"1": "My goodness! Aren't you young?\n $You must be quite the trainer to beat my husband, though.\n $Now I suppose it's my turn to battle!"
"1": "My goodness! Aren't you young?$You must be quite the trainer to beat my husband, though.$Now I suppose it's my turn to battle!"
},
"victory": {
"1": "Uwah! Just how strong are you?!"
@ -865,7 +865,7 @@
},
"winstrates_vivi": {
"encounter": {
"1": "You're stronger than Mom? Wow!\n $But I'm strong, too!\nReally! Honestly!"
"1": "You're stronger than Mom? Wow!$But I'm strong, too!\nReally! Honestly!"
},
"victory": {
"1": "Huh? Did I really lose?\nSnivel... Grandmaaa!"
@ -873,7 +873,7 @@
},
"winstrates_vicky": {
"encounter": {
"1": "How dare you make my precious\ngranddaughter cry!\n $I see I need to teach you a lesson.\nPrepare to feel the sting of defeat!"
"1": "How dare you make my precious\ngranddaughter cry!$I see I need to teach you a lesson.\nPrepare to feel the sting of defeat!"
},
"victory": {
"1": "Whoa! So strong!\nMy granddaughter wasn't lying."
@ -881,7 +881,7 @@
},
"winstrates_vito": {
"encounter": {
"1": "I trained together with my whole family,\nevery one of us!\n $I'm not losing to anyone!"
"1": "I trained together with my whole family,\nevery one of us!$I'm not losing to anyone!"
},
"victory": {
"1": "I was better than everyone in my family.\nI've never lost before..."

View File

@ -259,9 +259,10 @@
"ENEMY_FUSED_CHANCE": { "name": "Fusion Token", "description": "Adds a 1% chance that a wild Pokémon will be a fusion." },
"MYSTERY_ENCOUNTER_SHUCKLE_JUICE": { "name": "Shuckle Juice" },
"MYSTERY_ENCOUNTER_BLACK_SLUDGE": { "name": "Black Sludge", "description": "The stench is so powerful that healing items are no longer available to purchase in shops." },
"MYSTERY_ENCOUNTER_BLACK_SLUDGE": { "name": "Black Sludge", "description": "The stench is so powerful that shops will only sell you items at a steep cost increase." },
"MYSTERY_ENCOUNTER_MACHO_BRACE": { "name": "Macho Brace", "description": "Defeating a Pokémon grants the holder a Macho Brace stack. Each stack slightly boosts stats, with an extra bonus at max stacks." },
"MYSTERY_ENCOUNTER_OLD_GATEAU": { "name": "Old Gateau", "description": "Increases the holder's {{stats}} stats by {{statValue}}." }
"MYSTERY_ENCOUNTER_OLD_GATEAU": { "name": "Old Gateau", "description": "Increases the holder's {{stats}} stats by {{statValue}}." },
"MYSTERY_ENCOUNTER_GOLDEN_BUG_NET": { "name": "Golden Bug Net", "description": "Imbues the owner with luck to find Bug Type Pokémon more often. Has a strange heft to it." }
},
"SpeciesBoosterItem": {
"LIGHT_BALL": { "name": "Light Ball", "description": "It's a mysterious orb that boosts Pikachu's Attack and Sp. Atk stats." },

View File

@ -0,0 +1,6 @@
{
"paid_money": "You paid ₽{{amount, number}}.",
"receive_money": "You received ₽{{amount, number}}!",
"affects_pokedex": "Affects Pokédex Data",
"cancel_option": "Return to encounter option select."
}

View File

@ -24,6 +24,7 @@ import dancingLessonsDialogue from "#app/locales/en/mystery-encounters/dancing-l
import weirdDreamDialogue from "#app/locales/en/mystery-encounters/weird-dream-dialogue.json";
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";
/**
* Injection patterns that can be used:
@ -44,12 +45,6 @@ export const mysteryEncounter = {
// DO NOT REMOVE
"unit_test_dialogue": "{{test}}{{test}} {{test{{test}}}} {{test1}} {{test\}} {{test\\}} {{test\\\}} {test}}",
// General use content
"paid_money": "You paid ₽{{amount, number}}.",
"receive_money": "You received ₽{{amount, number}}!",
"affects_pokedex": "Affects Pokédex Data",
"cancel_option": "Return to encounter option select.",
mysteriousChallengers: mysteriousChallengersDialogue,
mysteriousChest: mysteriousChestDialogue,
darkDeal: darkDealDialogue,
@ -75,5 +70,6 @@ export const mysteryEncounter = {
dancingLessons: dancingLessonsDialogue,
weirdDream: weirdDreamDialogue,
theWinstrateChallenge: theWinstrateChallengeDialogue,
teleportingHijinks: teleportingHijinksDialogue
teleportingHijinks: teleportingHijinksDialogue,
bugTypeSuperfan: bugTypeSuperfanDialogue
} as const;

View File

@ -1,29 +1,29 @@
{
"intro": "An extremely strong trainer approaches you...",
"buck": {
"intro_dialogue": "Yo, trainer! My name's Buck.\n $I have a super awesome proposal\nfor a strong trainer such as yourself!\n $I'm carrying two rare Pokémon Eggs with me,\nbut I'd like someone else to care for one.\n $If you can prove your strength as a trainer to me,\nI'll give you the rarer egg!",
"intro_dialogue": "Yo, trainer! My name's Buck.$I have a super awesome proposal\nfor a strong trainer such as yourself!$I'm carrying two rare Pokémon Eggs with me,\nbut I'd like someone else to care for one.$If you can prove your strength as a trainer to me,\nI'll give you the rarer egg!",
"accept": "Whoooo, I'm getting fired up!",
"decline": "Darn, it looks like your\nteam isn't in peak condition.\n $Here, let me help with that."
"decline": "Darn, it looks like your\nteam isn't in peak condition.$Here, let me help with that."
},
"cheryl": {
"intro_dialogue": "Hello, my name's Cheryl.\n $I have a particularly interesting request,\nfor a strong trainer such as yourself.\n $I'm carrying two rare Pokémon Eggs with me,\nbut I'd like someone else to care for one.\n $If you can prove your strength as a trainer to me,\nI'll give you the rarer Egg!",
"intro_dialogue": "Hello, my name's Cheryl.$I have a particularly interesting request,\nfor a strong trainer such as yourself.$I'm carrying two rare Pokémon Eggs with me,\nbut I'd like someone else to care for one.$If you can prove your strength as a trainer to me,\nI'll give you the rarer Egg!",
"accept": "I hope you're ready!",
"decline": "I understand, it looks like your team\nisn't in the best condition at the moment.\n $Here, let me help with that."
"decline": "I understand, it looks like your team\nisn't in the best condition at the moment.$Here, let me help with that."
},
"marley": {
"intro_dialogue": "...@d{64} I'm Marley.\n $I have an offer for you...\n $I'm carrying two Pokémon Eggs with me,\nbut I'd like someone else to care for one.\n $If you're stronger than me,\nI'll give you the rarer Egg.",
"intro_dialogue": "...@d{64} I'm Marley.$I have an offer for you...$I'm carrying two Pokémon Eggs with me,\nbut I'd like someone else to care for one.$If you're stronger than me,\nI'll give you the rarer Egg.",
"accept": "... I see.",
"decline": "... I see.\n $Your Pokémon look hurt...\nLet me help."
"decline": "... I see.$Your Pokémon look hurt...\nLet me help."
},
"mira": {
"intro_dialogue": "Hi! I'm Mira!\n $Mira has a request\nfor a strong trainer like you!\n $Mira has two rare Pokémon Eggs,\nbut Mira wants someone else to take one!\n $If you show Mira that you're strong,\nMira will give you the rarer Egg!",
"intro_dialogue": "Hi! I'm Mira!$Mira has a request\nfor a strong trainer like you!$Mira has two rare Pokémon Eggs,\nbut Mira wants someone else to take one!$If you show Mira that you're strong,\nMira will give you the rarer Egg!",
"accept": "You'll battle Mira?\nYay!",
"decline": "Aww, no battle?\nThat's okay!\n $Here, Mira will heal your team!"
"decline": "Aww, no battle?\nThat's okay!$Here, Mira will heal your team!"
},
"riley": {
"intro_dialogue": "I'm Riley.\n $I have an odd proposal\nfor a strong trainer such as yourself.\n $I'm carrying two rare Pokémon Eggs with me,\nbut I'd like to give one to another trainer.\n $If you can prove your strength to me,\nI'll give you the rarer Egg!",
"intro_dialogue": "I'm Riley.$I have an odd proposal\nfor a strong trainer such as yourself.$I'm carrying two rare Pokémon Eggs with me,\nbut I'd like to give one to another trainer.$If you can prove your strength to me,\nI'll give you the rarer Egg!",
"accept": "That look you have...\nLet's do this.",
"decline": "I understand, your team looks beat up.\n $Here, let me help with that."
"decline": "I understand, your team looks beat up.$Here, let me help with that."
},
"title": "A Trainer's Test",
"description": "It seems this trainer is willing to give you an Egg regardless of your decision. However, if you can manage to defeat this strong trainer, you'll receive a much rarer Egg.",

View File

@ -9,17 +9,17 @@
"tooltip": "(-) Tough Battle\n(+) Rewards from its Berry Hoard",
"selected": "The Greedent stuffs its cheeks\nand prepares for battle!",
"boss_enraged": "Greedent's fierce love for food has it incensed!",
"food_stash": "It looks like the Greedent was guarding an enormous stash of food!\n $@s{item_fanfare}Each Pokémon in your party gains 1x Reviver Seed!"
"food_stash": "It looks like the Greedent was guarding an enormous stash of food!$@s{item_fanfare}Each Pokémon in your party gains 1x Reviver Seed!"
},
"2": {
"label": "Reason with It",
"tooltip": "(+) Regain Some Lost Berries",
"selected": "Your pleading strikes a chord with the Greedent.\n $It doesn't give all your berries back, but still tosses a few in your direction."
"selected": "Your pleading strikes a chord with the Greedent.$It doesn't give all your berries back, but still tosses a few in your direction."
},
"3": {
"label": "Let It Have the Food",
"tooltip": "(-) Lose All Berries\n(?) The Greedent Will Like You",
"selected": "The Greedent devours the entire\nstash of berries in a flash!\n $Patting its stomach,\nit looks at you appreciatively.\n $Perhaps you could feed it\nmore berries on your adventure...\n $@s{level_up_fanfare}The Greedent wants to join your party!"
"selected": "The Greedent devours the entire\nstash of berries in a flash!$Patting its stomach,\nit looks at you appreciatively.$Perhaps you could feed it\nmore berries on your adventure...$@s{level_up_fanfare}The Greedent wants to join your party!"
}
}
}

View File

@ -1,7 +1,7 @@
{
"intro": "You're stopped by a rich looking boy.",
"speaker": "Rich Boy",
"intro_dialogue": "Good day to you.\n $I can't help but notice that your\n{{strongestPokemon}} looks positively divine!\n $I've always wanted to have a pet like that!\n $I'd pay you handsomely,\nand also give you this old bauble!",
"intro_dialogue": "Good day to you.$I can't help but notice that your\n{{strongestPokemon}} looks positively divine!$I've always wanted to have a pet like that!$I'd pay you handsomely,\nand also give you this old bauble!",
"title": "An Offer You Can't Refuse",
"description": "You're being offered a @[TOOLTIP_TITLE]{Shiny Charm} and {{price, money}} for your {{strongestPokemon}}!\n\nIt's an extremely good deal, but can you really bear to part with such a strong team member?",
"query": "What will you do?",
@ -9,7 +9,7 @@
"1": {
"label": "Accept the Deal",
"tooltip": "(-) Lose {{strongestPokemon}}\n(+) Gain a @[TOOLTIP_TITLE]{Shiny Charm}\n(+) Gain {{price, money}}",
"selected": "Wonderful!@d{32} Come along, {{strongestPokemon}}!\n $It's time to show you off to everyone at the yacht club!\n $They'll be so jealous!"
"selected": "Wonderful!@d{32} Come along, {{strongestPokemon}}!$It's time to show you off to everyone at the yacht club!$They'll be so jealous!"
},
"2": {
"label": "Extort the Kid",
@ -20,7 +20,7 @@
"3": {
"label": "Leave",
"tooltip": "(-) No Rewards",
"selected": "What a rotten day...\n $Ah, well. Let's return to the yacht club then, Liepard."
"selected": "What a rotten day...$Ah, well. Let's return to the yacht club then, Liepard."
}
}
}

View File

@ -13,8 +13,8 @@
"2": {
"label": "Race to the Bush",
"tooltip": "(-) {{fastestPokemon}} Uses its Speed\n(+) Gain Berries",
"selected": "Your {{fastestPokemon}} races for the berry bush!\n $It manages to nab {{numBerries}} before the {{enemyPokemon}} can react!\n $You quickly retreat with your newfound prize.",
"selected_bad": "Your {{fastestPokemon}} races for the berry bush!\n $Oh no! The {{enemyPokemon}} was faster and blocked off the approach!",
"selected": "Your {{fastestPokemon}} races for the berry bush!$It manages to nab {{numBerries}} before the {{enemyPokemon}} can react!$You quickly retreat with your newfound prize.",
"selected_bad": "Your {{fastestPokemon}} races for the berry bush!$Oh no! The {{enemyPokemon}} was faster and blocked off the approach!",
"boss_enraged": "The opposing {{enemyPokemon}} has become enraged!"
},
"3": {

View File

@ -0,0 +1,38 @@
{
"intro": "An unusual trainer with all kinds of Bug paraphernalia blocks your way!",
"intro_dialogue": "Hey, trainer! I'm on a mission to find the rarest Bug Pokémon in existence!$You must love Bug Pokémon too, right?\nEveryone loves Bug Pokémon!",
"title": "The Bug-Type Superfan",
"speaker": "Bug-Type Superfan",
"description": "The trainer prattles, not even waiting for a response...\n\nIt seems the only way to get out of this situation is by catching the trainer's attention!",
"query": "What will you do?",
"option": {
"1": {
"label": "Offer to Battle",
"tooltip": "(-) Challenging Battle\n(+) Teach a Pokémon a Bug Type Move",
"selected": "A challenge, eh?\nMy bugs are more than ready for you!"
},
"2": {
"label": "Show Your Bug Types",
"tooltip": "(+) Receive a Gift Item",
"disabled_tooltip": "You need at least 1 Bug Type Pokémon on your team to select this.",
"selected": "You show the trainer all your Bug Type Pokémon...",
"selected_0_to_1": "Huh? You only have {{numBugTypes}}...$Guess I'm wasting my breath on someone like you...",
"selected_2_3": "Hey, you've got {{numBugTypes}} Bug Types!\nNot bad.$Here, this might help you on your journey to catch more!",
"selected_4_to_5": "What? You have {{numBugTypes}} Bug Types?\nNice!$You're not quite at my level, but I can see shades of myself in you!\n$Take this, my young apprentice!",
"selected_6": "Whoa! {{numBugTypes}} Bug Types!\n$You must love Bug Types almost as much as I do!$Here, take this as a token of our camaraderie!"
},
"3": {
"label": "Gift a Bug Item",
"tooltip": "(-) Give the trainer a Quick Claw, Grip Claw, or Silver Powder\n(+) Receive a Gift Item",
"disabled_tooltip": "You need to have a Quick Claw, Grip Claw, or Silver Powder to select this.",
"select_prompt": "Select an item to give.",
"invalid_selection": "Pokémon doesn't have that kind of item.",
"selected": "You hand the trainer a {{selectedItem}}.",
"selected_dialogue": "Whoa! A {{selectedItem}}, for me?\nYou're not so bad, kid!$As a token of my appreciation,\nI want you to have this special gift!$It's been passed all through my family, and now I want you to have it!"
}
},
"battle_won": "Your knowledge and skill were perfect at exploiting our weaknesses!$In exchange for the valuable lesson,\nallow me to teach one of your Pokémon a Bug Type Move!",
"teach_move_prompt": "Select a move to teach a Pokémon.",
"confirm_no_teach": "You sure you don't want to learn one of these great moves?",
"outro": "I see great Bug Pokémon in your future!\nMay our paths cross again!$Bug out!"
}

View File

@ -13,14 +13,14 @@
"2": {
"label": "Learn Its Dance",
"tooltip": "(+) Teach a Pokémon Revelation Dance",
"selected": "You watch the Oricorio closely as it performs its dance...\n $@s{level_up_fanfare}Your {{selectedPokemon}} wants to learn Revelation Dance!"
"selected": "You watch the Oricorio closely as it performs its dance...$@s{level_up_fanfare}Your {{selectedPokemon}} wants to learn Revelation Dance!"
},
"3": {
"label": "Show It a Dance",
"tooltip": "(-) Teach the Oricorio a Dance Move\n(+) The Oricorio Will Like You",
"disabled_tooltip": "Your Pokémon need to know a Dance move for this.",
"select_prompt": "Select a Dance type move to use.",
"selected": "The Oricorio watches in fascination as\n{{selectedPokemon}} shows off {{selectedMove}}!\n $It loves the display!\n $@s{level_up_fanfare}The Oricorio wants to join your party!"
"selected": "The Oricorio watches in fascination as\n{{selectedPokemon}} shows off {{selectedMove}}!$It loves the display!$@s{level_up_fanfare}The Oricorio wants to join your party!"
}
},
"invalid_selection": "This Pokémon doesn't know a Dance move"

View File

@ -3,7 +3,7 @@
{
"intro": "A strange man in a tattered coat\nstands in your way...",
"speaker": "Shady Guy",
"intro_dialogue": "Hey, you!\n $I've been working on a new device\nto bring out a Pokémon's latent power!\n $It completely rebinds the Pokémon's atoms\nat a molecular level into a far more powerful form.\n $Hehe...@d{64} I just need some sac-@d{32}\nErr, test subjects, to prove it works.",
"intro_dialogue": "Hey, you!$I've been working on a new device\nto bring out a Pokémon's latent power!$It completely rebinds the Pokémon's atoms\nat a molecular level into a far more powerful form.$Hehe...@d{64} I just need some sac-@d{32}\nErr, test subjects, to prove it works.",
"title": "Dark Deal",
"description": "The disturbing fellow holds up some Pokéballs.\n\"I'll make it worth your while! You can have these strong Pokéballs as payment, All I need is a Pokémon from your team! Hehe...\"",
"query": "What will you do?",
@ -11,8 +11,8 @@
"1": {
"label": "Accept",
"tooltip": "(+) 5 Rogue Balls\n(?) Enhance a Random Pokémon",
"selected_dialogue": "Let's see, that {{pokeName}} will do nicely!\n $Remember, I'm not responsible\nif anything bad happens!@d{32} Hehe...",
"selected_message": "The man hands you 5 Rogue Balls.\n ${{pokeName}} hops into the strange machine...\n $Flashing lights and weird noises\nstart coming from the machine!\n $...@d{96} Something emerges\nfrom the device, raging wildly!"
"selected_dialogue": "Let's see, that {{pokeName}} will do nicely!$Remember, I'm not responsible\nif anything bad happens!@d{32} Hehe...",
"selected_message": "The man hands you 5 Rogue Balls.${{pokeName}} hops into the strange machine...$Flashing lights and weird noises\nstart coming from the machine!$...@d{96} Something emerges\nfrom the device, raging wildly!"
},
"2": {
"label": "Refuse",

View File

@ -10,20 +10,20 @@
"1": {
"label": "Give Money",
"tooltip": "(-) Give the Delibirds {{money, money}}\n(+) Receive a Gift Item",
"selected": "You toss the money to the Delibirds,\nwho chatter amongst themselves excitedly.\n $They turn back to you and happily give you a present!"
"selected": "You toss the money to the Delibirds,\nwho chatter amongst themselves excitedly.$They turn back to you and happily give you a present!"
},
"2": {
"label": "Give Food",
"tooltip": "(-) Give the Delibirds a Berry or Reviver Seed\n(+) Receive a Gift Item",
"select_prompt": "Select an item to give.",
"selected": "You toss the {{chosenItem}} to the Delibirds,\nwho chatter amongst themselves excitedly.\n $They turn back to you and happily give you a present!"
"selected": "You toss the {{chosenItem}} to the Delibirds,\nwho chatter amongst themselves excitedly.$They turn back to you and happily give you a present!"
},
"3": {
"label": "Give an Item",
"tooltip": "(-) Give the Delibirds a Held Item\n(+) Receive a Gift Item",
"select_prompt": "Select an item to give.",
"selected": "You toss the {{chosenItem}} to the Delibirds,\nwho chatter amongst themselves excitedly.\n $They turn back to you and happily give you a present!"
"selected": "You toss the {{chosenItem}} to the Delibirds,\nwho chatter amongst themselves excitedly.$They turn back to you and happily give you a present!"
}
},
"outro": "The Delibird pack happily waddles off into the distance.\n $What a curious little exchange!"
"outro": "The Delibird pack happily waddles off into the distance.$What a curious little exchange!"
}

View File

@ -1,7 +1,7 @@
{
"intro": "It's a lady with a ton of shopping bags.",
"speaker": "Shopper",
"intro_dialogue": "Hello! Are you here for\nthe amazing sales too?\n $There's a special coupon that you can\nredeem for a free item during the sale!\n $I have an extra one. Here you go!",
"intro_dialogue": "Hello! Are you here for\nthe amazing sales too?$There's a special coupon that you can\nredeem for a free item during the sale!$I have an extra one. Here you go!",
"title": "Department Store Sale",
"description": "There is merchandise in every direction! It looks like there are 4 counters where you can redeem the coupon for various items. The possibilities are endless!",
"query": "Which counter will you go to?",

View File

@ -1,7 +1,7 @@
{
"intro": "It's a teacher and some school children!",
"speaker": "Teacher",
"intro_dialogue": "Hello, there! Would you be able to\nspare a minute for my students?\n $I'm teaching them about Pokémon moves\nand would love to show them a demonstration.\n $Would you mind showing us one of\nthe moves your Pokémon can use?",
"intro_dialogue": "Hello, there! Would you be able to\nspare a minute for my students?$I'm teaching them about Pokémon moves\nand would love to show them a demonstration.$Would you mind showing us one of\nthe moves your Pokémon can use?",
"title": "Field Trip",
"description": "A teacher is requesting a move demonstration from a Pokémon. Depending on the move you choose, she might have something useful for you in exchange.",
"query": "Which move category will you show off?",
@ -19,8 +19,8 @@
"tooltip": "(+) Status Item Rewards"
},
"selected": "{{pokeName}} shows off an awesome display of {{move}}!",
"incorrect": "...\n $That isn't a {{moveCategory}} move!\n $I'm sorry, but I can't give you anything.",
"lesson_learned": "Looks like you learned a valuable lesson?\n $Your Pokémon also gained some knowledge."
"incorrect": "...$That isn't a {{moveCategory}} move!$I'm sorry, but I can't give you anything.",
"lesson_learned": "Looks like you learned a valuable lesson?$Your Pokémon also gained some knowledge."
},
"second_option_prompt": "Choose a move for your Pokémon to use.",
"outro_good": "Thank you so much for your kindness!\nI hope the items I had were helpful!",

View File

@ -7,20 +7,20 @@
"1": {
"label": "Find the Source",
"tooltip": "(?) Discover the source\n(-) Hard Battle",
"selected": "You push through the storm, and find two Volcarona in the middle of a mating dance!\n $They don't take kindly to the interruption and attack!"
"selected": "You push through the storm, and find two Volcarona in the middle of a mating dance!$They don't take kindly to the interruption and attack!"
},
"2": {
"label": "Hunker Down",
"tooltip": "(-) Suffer the effects of the weather",
"selected": "The weather effects cause significant\nharm as you struggle to find shelter!\n $Your party takes 20% Max HP damage!",
"selected": "The weather effects cause significant\nharm as you struggle to find shelter!$Your party takes 20% Max HP damage!",
"target_burned": "Your {{burnedPokemon}} also became burned!"
},
"3": {
"label": "Your Fire Types Help",
"tooltip": "(+) End the conditions\n(+) Gain a Charcoal",
"disabled_tooltip": "You need at least 2 Fire Type Pokémon to choose this",
"selected": "Your {{option3PrimaryName}} and {{option3SecondaryName}} guide you to where two Volcarona are in the middle of a mating dance!\n $Thankfully, your Pokémon are able to calm them,\nand they depart without issue."
"selected": "Your {{option3PrimaryName}} and {{option3SecondaryName}} guide you to where two Volcarona are in the middle of a mating dance!$Thankfully, your Pokémon are able to calm them,\nand they depart without issue."
}
},
"found_charcoal": "After the weather clears,\nyour {{leadPokemon}} spots something on the ground.\n $@s{item_fanfare}{{leadPokemon}} gained a Charcoal!"
"found_charcoal": "After the weather clears,\nyour {{leadPokemon}} spots something on the ground.$@s{item_fanfare}{{leadPokemon}} gained a Charcoal!"
}

View File

@ -13,7 +13,7 @@
"label": "Steal the Item",
"disabled_tooltip": "Your Pokémon need to know certain moves to choose this",
"tooltip": "(+) {{option2PrimaryName}} uses {{option2PrimaryMove}}",
"selected": ".@d{32}.@d{32}.@d{32}\n $Your {{option2PrimaryName}} helps you out and uses {{option2PrimaryMove}}!\n $You nabbed the item!"
"selected": ".@d{32}.@d{32}.@d{32}$Your {{option2PrimaryName}} helps you out and uses {{option2PrimaryMove}}!$You nabbed the item!"
},
"3": {
"label": "Leave",

View File

@ -9,19 +9,19 @@
"label_disabled": "Can't {{option1RequiredMove}}",
"tooltip": "(+) {{option1PrimaryName}} saves you\n(+) {{option1PrimaryName}} gains some EXP",
"tooltip_disabled": "You have no Pokémon to {{option1RequiredMove}} on",
"selected": "{{option1PrimaryName}} swims ahead, guiding you back on track.\n ${{option1PrimaryName}} seems to also have gotten stronger in this time of need!"
"selected": "{{option1PrimaryName}} swims ahead, guiding you back on track.${{option1PrimaryName}} seems to also have gotten stronger in this time of need!"
},
"2": {
"label": "{{option2PrimaryName}} Might Help",
"label_disabled": "Can't {{option2RequiredMove}}",
"tooltip": "(+) {{option2PrimaryName}} saves you\n(+) {{option2PrimaryName}} gains some EXP",
"tooltip_disabled": "You have no Pokémon to {{option2RequiredMove}} with",
"selected": "{{option2PrimaryName}} flies ahead of your boat, guiding you back on track.\n ${{option2PrimaryName}} seems to also have gotten stronger in this time of need!"
"selected": "{{option2PrimaryName}} flies ahead of your boat, guiding you back on track.${{option2PrimaryName}} seems to also have gotten stronger in this time of need!"
},
"3": {
"label": "Wander Aimlessly",
"tooltip": "(-) Each of your Pokémon lose {{damagePercentage}}% of their total HP",
"selected": "You float about in the boat, steering without direction until you finally spot a landmark you remember.\n $You and your Pokémon are fatigued from the whole ordeal."
"selected": "You float about in the boat, steering without direction until you finally spot a landmark you remember.$You and your Pokémon are fatigued from the whole ordeal."
}
},
"outro": "You are back on track."

View File

@ -12,7 +12,7 @@
"good": "Some pretty nice tools and items.",
"great": "A couple great tools and items!",
"amazing": "Whoa! An amazing item!",
"bad": "Oh no!@d{32}\nThe chest was trapped!\n $Your {{pokeName}} jumps in front of you\nbut is KOed in the process."
"bad": "Oh no!@d{32}\nThe chest was trapped!$Your {{pokeName}} jumps in front of you\nbut is KOed in the process."
},
"2": {
"label": "Too Risky, Leave",

View File

@ -1,7 +1,7 @@
{
"intro": "A busy worker flags you down.",
"speaker": "Worker",
"intro_dialogue": "You look like someone with lots of capable Pokémon!\n $We can pay you if you're able to help us with some part-time work!",
"intro_dialogue": "You look like someone with lots of capable Pokémon!$We can pay you if you're able to help us with some part-time work!",
"title": "Part-Timer",
"description": "Looks like there are plenty of tasks that need to be done. Depending how well-suited your Pokémon is to a task, they might earn more or less money.",
"query": "Which job will you choose?",
@ -24,8 +24,8 @@
"selected": "Your {{option3PrimaryName}} spends the day using {{option3PrimaryMove}} to attract customers to the business!"
}
},
"job_complete_good": "Thanks for the assistance!\nYour {{selectedPokemon}} was incredibly helpful!\n $Here's your check for the day.",
"job_complete_bad": "Your {{selectedPokemon}} helped us out a bit!\n $Here's your check for the day.",
"job_complete_good": "Thanks for the assistance!\nYour {{selectedPokemon}} was incredibly helpful!$Here's your check for the day.",
"job_complete_bad": "Your {{selectedPokemon}} helped us out a bit!$Here's your check for the day.",
"pokemon_tired": "Your {{selectedPokemon}} is worn out!\nThe PP of all its moves was reduced to 2!",
"outro": "Come back and help out again sometime!"
}

View File

@ -1,7 +1,7 @@
{
"intro": "A man in a dark coat approaches you.",
"speaker": "Shady Salesman",
"intro_dialogue": ".@d{16}.@d{16}.@d{16}\n $I've got the goods if you've got the money.\n $Make sure your Pokémon can handle it though.",
"intro_dialogue": ".@d{16}.@d{16}.@d{16}$I've got the goods if you've got the money.$Make sure your Pokémon can handle it though.",
"title": "The Vitamin Dealer",
"description": "The man opens his jacket to reveal some Pokémon vitamins. The numbers he quotes seem like a really good deal. Almost too good...\nHe offers two package deals to choose from.",
"query": "Which deal will choose?",
@ -20,10 +20,10 @@
"tooltip": "(-) No Rewards",
"selected": "Heh, wouldn't have figured you for a coward."
},
"selected": "The man hands you two bottles and quickly disappears.\n ${{selectedPokemon}} gained {{boost1}} and {{boost2}} boosts!"
"selected": "The man hands you two bottles and quickly disappears.${{selectedPokemon}} gained {{boost1}} and {{boost2}} boosts!"
},
"damage_only": "But the medicine had some side effects!\n $Your {{selectedPokemon}} takes some damage...",
"bad_poison": "But the medicine had some side effects!\n $Your {{selectedPokemon}} takes some damage\nand becomes badly poisoned...",
"poison": "But the medicine had some side effects!\n $Your {{selectedPokemon}} becomes poisoned...",
"damage_only": "But the medicine had some side effects!$Your {{selectedPokemon}} takes some damage...",
"bad_poison": "But the medicine had some side effects!$Your {{selectedPokemon}} takes some damage\nand becomes badly poisoned...",
"poison": "But the medicine had some side effects!$Your {{selectedPokemon}} becomes poisoned...",
"no_bad_effects": "Looks like there were no side-effects this time."
}

View File

@ -1,5 +1,5 @@
{
"intro": "As you walk down a narrow pathway, you see a towering silhouette blocking your path.\n $You get closer to see a Snorlax sleeping peacefully.\nIt seems like there's no way around it.",
"intro": "As you walk down a narrow pathway, you see a towering silhouette blocking your path.$You get closer to see a Snorlax sleeping peacefully.\nIt seems like there's no way around it.",
"title": "Slumbering Snorlax",
"description": "You could attack it to try and get it to move, or simply wait for it to wake up. Who knows how long that could take, though...",
"query": "What will you do?",
@ -12,14 +12,14 @@
"2": {
"label": "Wait for It to Move",
"tooltip": "(-) Wait a Long Time\n(+) Recover Party",
"selected": ".@d{32}.@d{32}.@d{32}\n $You wait for a time, but the Snorlax's yawns make your party sleepy...",
"selected": ".@d{32}.@d{32}.@d{32}$You wait for a time, but the Snorlax's yawns make your party sleepy...",
"rest_result": "When you all awaken, the Snorlax is no where to be found -\nbut your Pokémon are all healed!"
},
"3": {
"label": "Steal Its Item",
"tooltip": "(+) {{option3PrimaryName}} uses {{option3PrimaryMove}}\n(+) Special Reward",
"disabled_tooltip": "Your Pokémon need to know certain moves to choose this",
"selected": "Your {{option3PrimaryName}} uses {{option3PrimaryMove}}!\n $@s{item_fanfare}It steals Leftovers off the sleeping\nSnorlax and you make out like bandits!"
"selected": "Your {{option3PrimaryName}} uses {{option3PrimaryMove}}!$@s{item_fanfare}It steals Leftovers off the sleeping\nSnorlax and you make out like bandits!"
}
}
}

View File

@ -13,15 +13,15 @@
"label": "A Pokémon Helps",
"tooltip": "(-) {{option2PrimaryName}} Helps\n(+) {{option2PrimaryName}} gains EXP\n(?) Teleport to New Biome",
"disabled_tooltip": "You need a Steel or Electric Type Pokémon to choose this",
"selected": "{{option2PrimaryName}}'s Type allows it to bypass the machine's paywall!\n $The capsule opens, and you step inside..."
"selected": "{{option2PrimaryName}}'s Type allows it to bypass the machine's paywall!$The capsule opens, and you step inside..."
},
"3": {
"label": "Inspect the Machine",
"tooltip": "(-) Pokémon Battle",
"selected": "You are drawn in by the blinking lights\nand strange noises coming from the machine...\n $You don't even notice as a wild\nPokémon sneaks up and ambushes you!"
"selected": "You are drawn in by the blinking lights\nand strange noises coming from the machine...$You don't even notice as a wild\nPokémon sneaks up and ambushes you!"
}
},
"transport": "The machine shakes violently,\nmaking all sorts of strange noises!\n $Just as soon as it had started, it quiets once more.",
"attacked": "You step out into a completely new area, startling a wild Pokémon!\n $The wild Pokémon attacks!",
"transport": "The machine shakes violently,\nmaking all sorts of strange noises!$Just as soon as it had started, it quiets once more.",
"attacked": "You step out into a completely new area, startling a wild Pokémon!$The wild Pokémon attacks!",
"boss_enraged": "The opposing {{enemyPokemon}} has become enraged!"
}

View File

@ -12,12 +12,12 @@
"tooltip": "(-) Pay {{price, money}}\n(+) Gain a {{purchasePokemon}} with its Hidden Ability",
"tooltip_shiny": "(-) Pay {{price, money}}\n(+) Gain a shiny {{purchasePokemon}}",
"selected_message": "You paid an outrageous sum and bought the {{purchasePokemon}}.",
"selected_dialogue": "Excellent choice!\n $I can see you've a keen eye for business.\n $Oh, yeah...@d{64} Returns not accepted, got that?"
"selected_dialogue": "Excellent choice!$I can see you've a keen eye for business.$Oh, yeah...@d{64} Returns not accepted, got that?"
},
"2": {
"label": "Refuse",
"tooltip": "(-) No Rewards",
"selected": "No?@d{32} You say no?\n $I'm only doing this as a favor to you!"
"selected": "No?@d{32} You say no?$I'm only doing this as a favor to you!"
}
}
}

View File

@ -8,7 +8,7 @@
"label": "Let It Touch You",
"tooltip": "(?) Something awful or amazing might happen",
"selected": "You black out.",
"selected_2": "@f{150}When you awaken, the Shuckle is gone\nand juice stash completely drained.\n $Your {{highBstPokemon}} feels a\nterrible lethargy come over it!\n $Its base stats were reduced by 20 in each stat!\n $Your remaining Pokémon feel an incredible vigor, though!\n $Their base stats are increased by 10 in each stat!"
"selected_2": "@f{150}When you awaken, the Shuckle is gone\nand juice stash completely drained.$Your {{highBstPokemon}} feels a\nterrible lethargy come over it!$Its base stats were reduced by 20 in each stat!$Your remaining Pokémon feel an incredible vigor, though!$Their base stats are increased by 10 in each stat!"
},
"2": {
"label": "Battle the Shuckle",

View File

@ -1,7 +1,7 @@
{
"intro": "It's a family standing outside their house!",
"speaker": "The Winstrates",
"intro_dialogue": "We're the Winstrates!\n $What do you say to taking on our family in a series of Pokémon battles?",
"intro_dialogue": "We're the Winstrates!$What do you say to taking on our family in a series of Pokémon battles?",
"title": "The Winstrate Challenge",
"description": "The Winstrates are a family of 5 trainers, and they want to battle! If you beat all of them back-to-back, they'll give you a grand prize. But can you handle the heat?",
"query": "What will you do?",
@ -17,5 +17,5 @@
"selected": "That's too bad. Say, your team looks worn out, why don't you stay awhile and rest?"
}
},
"victory": "Congratulations on beating our challenge!\n $Our family uses this Macho Brace to strengthen our Pokémon more effectively during their training.\n $You may not need it, considering that you beat the whole lot of us, but we hope you'll accept it anyway!"
"victory": "Congratulations on beating our challenge!$Our family uses this Macho Brace to strengthen our Pokémon more effectively during their training.$You may not need it, considering that you beat the whole lot of us, but we hope you'll accept it anyway!"
}

View File

@ -8,19 +8,19 @@
"1": {
"label": "Light Training",
"tooltip": "(-) Light Battle\n(+) Improve 2 Random IVs of Pokémon",
"finished": "{{selectedPokemon}} returns, feeling\nworn out but accomplished!\n $Its {{stat1}} and {{stat2}} IVs were improved!"
"finished": "{{selectedPokemon}} returns, feeling\nworn out but accomplished!$Its {{stat1}} and {{stat2}} IVs were improved!"
},
"2": {
"label": "Moderate Training",
"tooltip": "(-) Moderate Battle\n(+) Change Pokémon's Nature",
"select_prompt": "Select a new nature\nto train your Pokémon in.",
"finished": "{{selectedPokemon}} returns, feeling\nworn out but accomplished!\n $Its nature was changed to {{nature}}!"
"finished": "{{selectedPokemon}} returns, feeling\nworn out but accomplished!$Its nature was changed to {{nature}}!"
},
"3": {
"label": "Heavy Training",
"tooltip": "(-) Harsh Battle\n(+) Change Pokémon's Ability",
"select_prompt": "Select a new ability\nto train your Pokémon in.",
"finished": "{{selectedPokemon}} returns, feeling\nworn out but accomplished!\n $Its ability was changed to {{ability}}!"
"finished": "{{selectedPokemon}} returns, feeling\nworn out but accomplished!$Its ability was changed to {{ability}}!"
},
"selected": "{{selectedPokemon}} moves across\nthe clearing to face you..."
},

View File

@ -7,7 +7,7 @@
"1": {
"label": "Dig for Valuables",
"tooltip": "(-) Lose Healing Items in Shops\n(+) Gain Amazing Items",
"selected": "You wade through the garbage pile, becoming mired in filth.\n $There's no way any respectable shopkeepers\nwill sell you anything in your grimy state!\n $You'll just have to make do without shop healing items.\n $However, you found some incredible items in the garbage!"
"selected": "You wade through the garbage pile, becoming mired in filth.$There's no way any respectable shopkeepers\nwill sell you anything in your grimy state!$You'll just have to make do without shop healing items.$However, you found some incredible items in the garbage!"
},
"2": {
"label": "Investigate Further",

View File

@ -1,7 +1,7 @@
{
"intro": "A shadowy woman blocks your path.\nSomething about her is unsettling...",
"speaker": "Woman",
"intro_dialogue": "I have seen your futures, your pasts...\n $Child, do you see them too?",
"intro_dialogue": "I have seen your futures, your pasts...$Child, do you see them too?",
"title": "???",
"description": "The woman's words echo in your head. It wasn't just a singular voice, but a vast multitude, from all timelines and realities. You begin to feel dizzy, the question lingering on your mind...\n\n@[TOOLTIP_TITLE]{\"I have seen your futures, your pasts... Child, do you see them too?\"}",
"query": "What will you do?",
@ -9,14 +9,14 @@
"1": {
"label": "\"I See Them\"",
"tooltip": "@[SUMMARY_GREEN]{(?) Affects your Pokémon}",
"selected": "Her hand reaches out to touch you,\nand everything goes black.\n $Then...@d{64} You see everything.\nEvery timeline, all your different selves,\n past and future.\n $Everything that has made you,\neverything you will become...@d{64}",
"selected": "Her hand reaches out to touch you,\nand everything goes black.$Then...@d{64} You see everything.\nEvery timeline, all your different selves,\n past and future.$Everything that has made you,\neverything you will become...@d{64}",
"cutscene": "You see your Pokémon,@d{32} converging from\nevery reality to become something new...@d{64}",
"dream_complete": "When you awaken, the woman - was it a woman or a ghost? - is gone...\n $.@d{32}.@d{32}.@d{32}\n $Your Pokémon team has changed...\nOr is it the same team you've always had?"
"dream_complete": "When you awaken, the woman - was it a woman or a ghost? - is gone...$.@d{32}.@d{32}.@d{32}$Your Pokémon team has changed...\nOr is it the same team you've always had?"
},
"2": {
"label": "Quickly Leave",
"tooltip": "(-) Affects your Pokémon",
"selected": "You tear your mind from a numbing grip, and hastily depart.\n $When you finally stop to collect yourself, you check the Pokémon in your team.\n $For some reason, all of their levels have decreased!"
"selected": "You tear your mind from a numbing grip, and hastily depart.$When you finally stop to collect yourself, you check the Pokémon in your team.$For some reason, all of their levels have decreased!"
}
}
}

View File

@ -117,15 +117,5 @@
"plasma_grunts": "Plasma Grunts",
"flare_grunt": "Flare Grunt",
"flare_grunt_female": "Flare Grunt",
"flare_grunts": "Flare Grunts",
"buck": "Buck",
"cheryl": "Cheryl",
"marley": "Marley",
"mira": "Mira",
"riley": "Riley",
"victor": "Victor",
"victoria": "Victoria",
"vivi": "Vivi",
"vicky": "Vicky",
"vito": "Vito"
"flare_grunts": "Flare Grunts"
}

View File

@ -152,5 +152,16 @@
"alder_iris_double": "Alder & Iris",
"iris_alder_double": "Iris & Alder",
"marnie_piers_double": "Marnie & Piers",
"piers_marnie_double": "Piers & Marnie"
"piers_marnie_double": "Piers & Marnie",
"buck": "Buck",
"cheryl": "Cheryl",
"marley": "Marley",
"mira": "Mira",
"riley": "Riley",
"victor": "Victor",
"victoria": "Victoria",
"vivi": "Vivi",
"vicky": "Vicky",
"vito": "Vito",
"bug_type_superfan": "Bug-Type Superfan"
}

View File

@ -1536,8 +1536,9 @@ export const modifierTypes = {
}
return new PokemonBaseStatFlatModifierType(Utils.randSeedInt(20), [Stat.HP, Stat.ATK, Stat.DEF]);
}),
MYSTERY_ENCOUNTER_BLACK_SLUDGE: () => new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_BLACK_SLUDGE", "black_sludge", (type, _args) => new Modifiers.RemoveHealShopModifier(type)),
MYSTERY_ENCOUNTER_BLACK_SLUDGE: () => new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_BLACK_SLUDGE", "black_sludge", (type, _args) => new Modifiers.HealShopCostModifier(type)),
MYSTERY_ENCOUNTER_MACHO_BRACE: () => new PokemonHeldItemModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_MACHO_BRACE", "macho_brace", (type, args) => new Modifiers.PokemonIncrementingStatModifier(type, (args[0] as Pokemon).id)),
MYSTERY_ENCOUNTER_GOLDEN_BUG_NET: () => new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET", "golden_net", (type, _args) => new Modifiers.BoostBugSpawnModifier(type)),
};
interface ModifierPool {

View File

@ -734,7 +734,8 @@ export class PokemonBaseStatTotalModifier extends PokemonHeldItemModifier {
apply(args: any[]): boolean {
// Modifies the passed in baseStats[] array
args[1].forEach((v, i) => {
const newVal = Math.floor(v + this.statModifier);
// HP is affected by half as much as other stats
const newVal = i === 0 ? Math.floor(v + this.statModifier / 2) : Math.floor(v + this.statModifier);
args[1][i] = Math.min(Math.max(newVal, 1), 999999);
});
@ -2366,17 +2367,41 @@ export class LockModifierTiersModifier extends PersistentModifier {
}
}
export class RemoveHealShopModifier extends PersistentModifier {
export class HealShopCostModifier extends PersistentModifier {
constructor(type: ModifierType, stackCount?: integer) {
super(type, stackCount);
}
match(modifier: Modifier): boolean {
return modifier instanceof RemoveHealShopModifier;
return modifier instanceof HealShopCostModifier;
}
clone(): RemoveHealShopModifier {
return new RemoveHealShopModifier(this.type, this.stackCount);
clone(): HealShopCostModifier {
return new HealShopCostModifier(this.type, this.stackCount);
}
apply(args: any[]): boolean {
(args[0] as Utils.IntegerHolder).value *= Math.pow(3, this.getStackCount());
return true;
}
getMaxStackCount(scene: BattleScene): integer {
return 1;
}
}
export class BoostBugSpawnModifier extends PersistentModifier {
constructor(type: ModifierType, stackCount?: integer) {
super(type, stackCount);
}
match(modifier: Modifier): boolean {
return modifier instanceof BoostBugSpawnModifier;
}
clone(): HealShopCostModifier {
return new BoostBugSpawnModifier(this.type, this.stackCount);
}
apply(args: any[]): boolean {

View File

@ -130,7 +130,8 @@ class DefaultOverrides {
// -------------------------
// MYSTERY ENCOUNTER OVERRIDES
// -------------------------
// 1 to 256, set to null to ignore
/** 1 to 256, set to null to ignore */
readonly MYSTERY_ENCOUNTER_RATE_OVERRIDE: number | null = null;
readonly MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier | null = null;
readonly MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType | null = null;

View File

@ -31,6 +31,8 @@ import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import { doTrainerExclamation } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases";
import { randSeedInt } from "#app/utils";
import { getGoldenBugNetSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
export class EncounterPhase extends BattlePhase {
private loaded: boolean;
@ -89,7 +91,11 @@ export class EncounterPhase extends BattlePhase {
if (battle.battleType === BattleType.TRAINER) {
battle.enemyParty[e] = battle.trainer?.genPartyMember(e)!; // TODO:: is the bang correct here?
} else {
const enemySpecies = this.scene.randomSpecies(battle.waveIndex, level, true);
let enemySpecies = this.scene.randomSpecies(battle.waveIndex, level, true);
// If player has golden bug net, rolls 10% chance to replace with species from the golden bug net bug pool
if (randSeedInt(10) === 0) {
enemySpecies = getGoldenBugNetSpecies(this.scene, battle.waveIndex, level);
}
battle.enemyParty[e] = this.scene.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, !!this.scene.getEncounterBossSegments(battle.waveIndex, level, enemySpecies));
if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
battle.enemyParty[e].ivs = new Array(6).fill(31);

View File

@ -22,7 +22,7 @@ export class ModifierRewardPhase extends BattlePhase {
return new Promise<void>(resolve => {
const newModifier = this.modifierType.newModifier();
this.scene.addModifier(newModifier).then(() => {
this.scene.playSound("item_fanfare");
this.scene.playSound("bgm/item_fanfare");
this.scene.ui.showText(i18next.t("battle:rewardGain", { modifierName: newModifier?.type.name }), null, () => resolve(), null, true);
});
});

View File

@ -418,23 +418,35 @@ export class MysteryEncounterRewardsPhase extends Phase {
});
} else {
this.scene.executeWithSeedOffset(() => {
if (this.scene.currentBattle.mysteryEncounter.doEncounterExp) {
this.scene.currentBattle.mysteryEncounter.doEncounterExp(this.scene);
if (encounter.onRewards) {
encounter.onRewards(this.scene).then(() => {
this.doEncounterRewardsAndContinue();
});
} else {
this.doEncounterRewardsAndContinue();
}
// Do not use ME's seedOffset for rewards, these should always be consistent with waveIndex (once per wave)
}, this.scene.currentBattle.waveIndex * 1000);
}
}
if (this.scene.currentBattle.mysteryEncounter.doEncounterRewards) {
this.scene.currentBattle.mysteryEncounter.doEncounterRewards(this.scene);
doEncounterRewardsAndContinue() {
const encounter = this.scene.currentBattle.mysteryEncounter;
if (encounter.doEncounterExp) {
encounter.doEncounterExp(this.scene);
}
if (encounter.doEncounterRewards) {
encounter.doEncounterRewards(this.scene);
} else if (this.addHealPhase) {
this.scene.tryRemovePhase(p => p instanceof SelectModifierPhase);
this.scene.unshiftPhase(new SelectModifierPhase(this.scene, 0, undefined, { fillRemaining: false, rerollMultiplier: 0 }));
}
// Do not use ME's seedOffset for rewards, these should always be consistent with waveIndex (once per wave)
}, this.scene.currentBattle.waveIndex * 1000);
this.scene.pushPhase(new PostMysteryEncounterPhase(this.scene));
this.end();
}
}
}
/**

View File

@ -53,7 +53,7 @@ describe("Final Boss", () => {
expect(game.scene.getEnemyPokemon()!.species.speciesId).not.toBe(Species.ETERNATUS);
});
it("should not have passive enabled on Eternatus", async () => {
it("should NOT have passive enabled on Eternatus", async () => {
await game.runToFinalBossEncounter(game, [Species.BIDOOF], GameModes.CLASSIC);
const eternatus = game.scene.getEnemyPokemon();

View File

@ -150,8 +150,9 @@ async function handleSecondaryOptionSelect(game: GameManager, pokemonNo: number,
/**
* For any MysteryEncounter that has a battle, can call this to skip battle and proceed to MysteryEncounterRewardsPhase
* @param game
* @param runRewardsPhase
*/
export async function skipBattleRunMysteryEncounterRewardsPhase(game: GameManager) {
export async function skipBattleRunMysteryEncounterRewardsPhase(game: GameManager, runRewardsPhase: boolean = true) {
game.scene.clearPhaseQueue();
game.scene.clearPhaseQueueSplice();
game.scene.getEnemyParty().forEach(p => {
@ -161,5 +162,5 @@ export async function skipBattleRunMysteryEncounterRewardsPhase(game: GameManage
});
game.scene.pushPhase(new VictoryPhase(game.scene, 0));
game.phaseInterceptor.superEndPhase();
await game.phaseInterceptor.to(MysteryEncounterRewardsPhase, true);
await game.phaseInterceptor.to(MysteryEncounterRewardsPhase, runRewardsPhase);
}

View File

@ -6,7 +6,7 @@ import { Species } from "#app/enums/species";
import GameManager from "#app/test/utils/gameManager";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounter-test-utils";
import BattleScene from "#app/battle-scene";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";

View File

@ -4,7 +4,7 @@ import { Species } from "#app/enums/species";
import GameManager from "#app/test/utils/gameManager";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounter-test-utils";
import BattleScene from "#app/battle-scene";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";

View File

@ -6,7 +6,7 @@ import { Species } from "#app/enums/species";
import GameManager from "#app/test/utils/gameManager";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils";
import BattleScene from "#app/battle-scene";
import { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
import { AnOfferYouCantRefuseEncounter } from "#app/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter";

View File

@ -4,7 +4,7 @@ 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, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounter-test-utils";
import BattleScene from "#app/battle-scene";
import { Mode } from "#app/ui/ui";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";

View File

@ -0,0 +1,585 @@
import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters";
import { Biome } from "#app/enums/biome";
import { MysteryEncounterType } from "#app/enums/mystery-encounter-type";
import { Species } from "#app/enums/species";
import GameManager from "#app/test/utils/gameManager";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounter-test-utils";
import { Moves } from "#enums/moves";
import BattleScene from "#app/battle-scene";
import { PokemonMove } from "#app/field/pokemon";
import { 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 { TrainerType } from "#enums/trainer-type";
import { MysteryEncounterPhase, MysteryEncounterRewardsPhase } from "#app/phases/mystery-encounter-phases";
import { ContactHeldItemTransferChanceModifier } from "#app/modifier/modifier";
import { CommandPhase } from "#app/phases/command-phase";
import { BugTypeSuperfanEncounter } from "#app/data/mystery-encounters/encounters/bug-type-superfan-encounter";
import * as encounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
const namespace = "mysteryEncounter:bugTypeSuperfan";
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.WEEDLE];
const defaultBiome = Biome.CAVE;
const defaultWave = 24;
const POOL_1_POKEMON = [
Species.PARASECT,
Species.VENOMOTH,
Species.LEDIAN,
Species.ARIADOS,
Species.YANMA,
Species.BEAUTIFLY,
Species.DUSTOX,
Species.MASQUERAIN,
Species.NINJASK,
Species.VOLBEAT,
Species.ILLUMISE,
Species.ANORITH,
Species.KRICKETUNE,
Species.WORMADAM,
Species.MOTHIM,
Species.SKORUPI,
Species.JOLTIK,
Species.LARVESTA,
Species.VIVILLON,
Species.CHARJABUG,
Species.RIBOMBEE,
Species.SPIDOPS,
Species.LOKIX
];
const POOL_2_POKEMON = [
Species.SCYTHER,
Species.PINSIR,
Species.HERACROSS,
Species.FORRETRESS,
Species.SCIZOR,
Species.SHUCKLE,
Species.SHEDINJA,
Species.ARMALDO,
Species.VESPIQUEN,
Species.DRAPION,
Species.YANMEGA,
Species.LEAVANNY,
Species.SCOLIPEDE,
Species.CRUSTLE,
Species.ESCAVALIER,
Species.ACCELGOR,
Species.GALVANTULA,
Species.VIKAVOLT,
Species.ARAQUANID,
Species.ORBEETLE,
Species.CENTISKORCH,
Species.FROSMOTH,
Species.KLEAVOR,
];
const POOL_3_POKEMON: { species: Species, formIndex?: number }[] = [
{
species: Species.PINSIR,
formIndex: 1
},
{
species: Species.SCIZOR,
formIndex: 1
},
{
species: Species.HERACROSS,
formIndex: 1
},
{
species: Species.ORBEETLE,
formIndex: 1
},
{
species: Species.CENTISKORCH,
formIndex: 1
},
{
species: Species.DURANT,
},
{
species: Species.VOLCARONA,
},
{
species: Species.GOLISOPOD,
},
];
const POOL_4_POKEMON = [
Species.GENESECT,
Species.SLITHER_WING,
Species.BUZZWOLE,
Species.PHEROMOSA
];
const PHYSICAL_TUTOR_MOVES = [
Moves.MEGAHORN,
Moves.X_SCISSOR,
Moves.ATTACK_ORDER,
Moves.PIN_MISSILE,
Moves.FIRST_IMPRESSION
];
const SPECIAL_TUTOR_MOVES = [
Moves.SILVER_WIND,
Moves.BUG_BUZZ,
Moves.SIGNAL_BEAM,
Moves.POLLEN_PUFF
];
const STATUS_TUTOR_MOVES = [
Moves.STRING_SHOT,
Moves.STICKY_WEB,
Moves.SILK_TRAP,
Moves.RAGE_POWDER,
Moves.HEAL_ORDER
];
const MISC_TUTOR_MOVES = [
Moves.BUG_BITE,
Moves.LEECH_LIFE,
Moves.DEFEND_ORDER,
Moves.QUIVER_DANCE,
Moves.TAIL_GLOW,
Moves.INFESTATION,
Moves.U_TURN
];
describe("Bug-Type Superfan - Mystery Encounter", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
let scene: BattleScene;
beforeAll(() => {
phaserGame = new Phaser.Game({ type: Phaser.HEADLESS });
});
beforeEach(async () => {
game = new GameManager(phaserGame);
scene = game.scene;
game.override.mysteryEncounterChance(100);
game.override.startingWave(defaultWave);
game.override.startingBiome(defaultBiome);
game.override.disableTrainerWaves();
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(
new Map<Biome, MysteryEncounterType[]>([
[Biome.CAVE, [MysteryEncounterType.BUG_TYPE_SUPERFAN]],
])
);
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
vi.clearAllMocks();
vi.resetAllMocks();
});
it("should have the correct properties", async () => {
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, defaultParty);
expect(BugTypeSuperfanEncounter.encounterType).toBe(MysteryEncounterType.BUG_TYPE_SUPERFAN);
expect(BugTypeSuperfanEncounter.encounterTier).toBe(MysteryEncounterTier.GREAT);
expect(BugTypeSuperfanEncounter.dialogue).toBeDefined();
expect(BugTypeSuperfanEncounter.dialogue.intro).toStrictEqual([
{
text: `${namespace}.intro`,
},
{
speaker: `${namespace}.speaker`,
text: `${namespace}.intro_dialogue`,
},
]);
expect(BugTypeSuperfanEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`);
expect(BugTypeSuperfanEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}.description`);
expect(BugTypeSuperfanEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}.query`);
expect(BugTypeSuperfanEncounter.options.length).toBe(3);
});
it("should not run below wave 10", async () => {
game.override.startingWave(9);
await game.runToMysteryEncounter();
expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.BUG_TYPE_SUPERFAN);
});
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 = BugTypeSuperfanEncounter;
const { onInit } = BugTypeSuperfanEncounter;
expect(BugTypeSuperfanEncounter.onInit).toBeDefined();
BugTypeSuperfanEncounter.populateDialogueTokensFromRequirements(scene);
const onInitResult = onInit!(scene);
const config = BugTypeSuperfanEncounter.enemyPartyConfigs[0];
expect(config).toBeDefined();
expect(config.trainerConfig?.trainerType).toBe(TrainerType.BUG_TYPE_SUPERFAN);
expect(config.trainerConfig?.partyTemplates).toBeDefined();
expect(config.female).toBe(true);
expect(onInitResult).toBe(true);
});
describe("Option 1 - Battle the Bug-Type Superfan", () => {
it("should have the correct properties", () => {
const option = BugTypeSuperfanEncounter.options[0];
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
expect(option.dialogue).toBeDefined();
expect(option.dialogue).toStrictEqual({
buttonLabel: `${namespace}.option.1.label`,
buttonTooltip: `${namespace}.option.1.tooltip`,
selected: [
{
speaker: `${namespace}.speaker`,
text: `${namespace}.option.1.selected`,
},
],
});
});
it("should start battle against the Bug-Type Superfan with wave 30 party template", async () => {
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, defaultParty);
await runMysteryEncounterToEnd(game, 1, undefined, true);
const enemyParty = scene.getEnemyParty();
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
expect(enemyParty.length).toBe(2);
expect(scene.currentBattle.trainer?.config.trainerType).toBe(TrainerType.BUG_TYPE_SUPERFAN);
expect(enemyParty[0].species.speciesId).toBe(Species.BEEDRILL);
expect(enemyParty[1].species.speciesId).toBe(Species.BUTTERFREE);
});
it("should start battle against the Bug-Type Superfan with wave 50 party template", async () => {
game.override.startingWave(43);
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, defaultParty);
await runMysteryEncounterToEnd(game, 1, undefined, true);
const enemyParty = scene.getEnemyParty();
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
expect(enemyParty.length).toBe(3);
expect(scene.currentBattle.trainer?.config.trainerType).toBe(TrainerType.BUG_TYPE_SUPERFAN);
expect(enemyParty[0].species.speciesId).toBe(Species.BEEDRILL);
expect(enemyParty[1].species.speciesId).toBe(Species.BUTTERFREE);
expect(POOL_1_POKEMON.includes(enemyParty[2].species.speciesId)).toBe(true);
});
it("should start battle against the Bug-Type Superfan with wave 70 party template", async () => {
game.override.startingWave(61);
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, defaultParty);
await runMysteryEncounterToEnd(game, 1, undefined, true);
const enemyParty = scene.getEnemyParty();
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
expect(enemyParty.length).toBe(4);
expect(scene.currentBattle.trainer?.config.trainerType).toBe(TrainerType.BUG_TYPE_SUPERFAN);
expect(enemyParty[0].species.speciesId).toBe(Species.BEEDRILL);
expect(enemyParty[1].species.speciesId).toBe(Species.BUTTERFREE);
expect(POOL_1_POKEMON.includes(enemyParty[2].species.speciesId)).toBe(true);
expect(POOL_2_POKEMON.includes(enemyParty[3].species.speciesId)).toBe(true);
});
it("should start battle against the Bug-Type Superfan with wave 100 party template", async () => {
game.override.startingWave(81);
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, defaultParty);
await runMysteryEncounterToEnd(game, 1, undefined, true);
const enemyParty = scene.getEnemyParty();
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
expect(enemyParty.length).toBe(5);
expect(scene.currentBattle.trainer?.config.trainerType).toBe(TrainerType.BUG_TYPE_SUPERFAN);
expect(enemyParty[0].species.speciesId).toBe(Species.BEEDRILL);
expect(enemyParty[1].species.speciesId).toBe(Species.BUTTERFREE);
expect(POOL_1_POKEMON.includes(enemyParty[2].species.speciesId)).toBe(true);
expect(POOL_2_POKEMON.includes(enemyParty[3].species.speciesId)).toBe(true);
expect(POOL_2_POKEMON.includes(enemyParty[4].species.speciesId)).toBe(true);
});
it("should start battle against the Bug-Type Superfan with wave 120 party template", async () => {
game.override.startingWave(111);
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, defaultParty);
await runMysteryEncounterToEnd(game, 1, undefined, true);
const enemyParty = scene.getEnemyParty();
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
expect(enemyParty.length).toBe(5);
expect(scene.currentBattle.trainer?.config.trainerType).toBe(TrainerType.BUG_TYPE_SUPERFAN);
expect(enemyParty[0].species.speciesId).toBe(Species.BEEDRILL);
expect(enemyParty[0].formIndex).toBe(1);
expect(enemyParty[1].species.speciesId).toBe(Species.BUTTERFREE);
expect(enemyParty[1].formIndex).toBe(1);
expect(POOL_2_POKEMON.includes(enemyParty[2].species.speciesId)).toBe(true);
expect(POOL_2_POKEMON.includes(enemyParty[3].species.speciesId)).toBe(true);
expect(POOL_3_POKEMON.some(config => enemyParty[4].species.speciesId === config.species)).toBe(true);
});
it("should start battle against the Bug-Type Superfan with wave 140 party template", async () => {
game.override.startingWave(131);
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, defaultParty);
await runMysteryEncounterToEnd(game, 1, undefined, true);
const enemyParty = scene.getEnemyParty();
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
expect(enemyParty.length).toBe(5);
expect(scene.currentBattle.trainer?.config.trainerType).toBe(TrainerType.BUG_TYPE_SUPERFAN);
expect(enemyParty[0].species.speciesId).toBe(Species.BEEDRILL);
expect(enemyParty[0].formIndex).toBe(1);
expect(enemyParty[1].species.speciesId).toBe(Species.BUTTERFREE);
expect(enemyParty[1].formIndex).toBe(1);
expect(POOL_2_POKEMON.includes(enemyParty[2].species.speciesId)).toBe(true);
expect(POOL_3_POKEMON.some(config => enemyParty[3].species.speciesId === config.species)).toBe(true);
expect(POOL_3_POKEMON.some(config => enemyParty[4].species.speciesId === config.species)).toBe(true);
});
it("should start battle against the Bug-Type Superfan with wave 160 party template", async () => {
game.override.startingWave(151);
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, defaultParty);
await runMysteryEncounterToEnd(game, 1, undefined, true);
const enemyParty = scene.getEnemyParty();
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
expect(enemyParty.length).toBe(5);
expect(scene.currentBattle.trainer?.config.trainerType).toBe(TrainerType.BUG_TYPE_SUPERFAN);
expect(enemyParty[0].species.speciesId).toBe(Species.BEEDRILL);
expect(enemyParty[0].formIndex).toBe(1);
expect(enemyParty[1].species.speciesId).toBe(Species.BUTTERFREE);
expect(enemyParty[1].formIndex).toBe(1);
expect(POOL_2_POKEMON.includes(enemyParty[2].species.speciesId)).toBe(true);
expect(POOL_3_POKEMON.some(config => enemyParty[3].species.speciesId === config.species)).toBe(true);
expect(POOL_4_POKEMON.includes(enemyParty[4].species.speciesId)).toBe(true);
});
it("should start battle against the Bug-Type Superfan with wave 180 party template", async () => {
game.override.startingWave(171);
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, defaultParty);
await runMysteryEncounterToEnd(game, 1, undefined, true);
const enemyParty = scene.getEnemyParty();
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
expect(enemyParty.length).toBe(5);
expect(scene.currentBattle.trainer?.config.trainerType).toBe(TrainerType.BUG_TYPE_SUPERFAN);
expect(enemyParty[0].species.speciesId).toBe(Species.BEEDRILL);
expect(enemyParty[0].formIndex).toBe(1);
expect(enemyParty[0].isBoss()).toBe(true);
expect(enemyParty[0].bossSegments).toBe(2);
expect(enemyParty[1].species.speciesId).toBe(Species.BUTTERFREE);
expect(enemyParty[1].formIndex).toBe(1);
expect(enemyParty[1].isBoss()).toBe(true);
expect(enemyParty[1].bossSegments).toBe(2);
expect(POOL_3_POKEMON.some(config => enemyParty[2].species.speciesId === config.species)).toBe(true);
expect(POOL_3_POKEMON.some(config => enemyParty[3].species.speciesId === config.species)).toBe(true);
expect(POOL_4_POKEMON.includes(enemyParty[4].species.speciesId)).toBe(true);
});
it("should let the player learn a Bug move after battle ends", async () => {
const selectOptionSpy = vi.spyOn(encounterPhaseUtils, "selectOptionThenPokemon");
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, defaultParty);
await runMysteryEncounterToEnd(game, 1, undefined, true);
await skipBattleRunMysteryEncounterRewardsPhase(game, false);
expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterRewardsPhase.name);
game.phaseInterceptor["prompts"] = []; // Clear out prompt handlers
game.onNextPrompt("MysteryEncounterRewardsPhase", Mode.OPTION_SELECT, () => {
game.phaseInterceptor.superEndPhase();
});
await game.phaseInterceptor.run(MysteryEncounterRewardsPhase);
expect(selectOptionSpy).toHaveBeenCalledTimes(1);
const optionData = selectOptionSpy.mock.calls[0][1];
expect(PHYSICAL_TUTOR_MOVES.some(move => new PokemonMove(move).getName() === optionData[0].label)).toBe(true);
expect(SPECIAL_TUTOR_MOVES.some(move => new PokemonMove(move).getName() === optionData[1].label)).toBe(true);
expect(STATUS_TUTOR_MOVES.some(move => new PokemonMove(move).getName() === optionData[2].label)).toBe(true);
expect(MISC_TUTOR_MOVES.some(move => new PokemonMove(move).getName() === optionData[3].label)).toBe(true);
});
});
describe("Option 2 - Show off Bug Types", () => {
it("should have the correct properties", () => {
const option = BugTypeSuperfanEncounter.options[1];
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT);
expect(option.dialogue).toBeDefined();
expect(option.dialogue).toStrictEqual({
buttonLabel: `${namespace}.option.2.label`,
buttonTooltip: `${namespace}.option.2.tooltip`,
disabledButtonTooltip: `${namespace}.option.2.disabled_tooltip`
});
});
it("should NOT be selectable if the player doesn't have any Bug types", async () => {
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, [Species.ABRA]);
await game.phaseInterceptor.to(MysteryEncounterPhase, false);
const encounterPhase = scene.getCurrentPhase();
expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name);
const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase;
vi.spyOn(mysteryEncounterPhase, "continueEncounter");
vi.spyOn(mysteryEncounterPhase, "handleOptionSelect");
vi.spyOn(scene.ui, "playError");
await runSelectMysteryEncounterOption(game, 2);
expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name);
expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled
expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled();
expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled();
});
it("should proceed to rewards screen with 0-1 Bug Types reward options", async () => {
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, defaultParty);
await runMysteryEncounterToEnd(game, 2);
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(2);
expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toBe("SUPER_LURE");
expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toBe("GREAT_BALL");
});
it("should proceed to rewards screen with 2-3 Bug Types reward options", async () => {
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, [Species.BUTTERFREE, Species.BEEDRILL]);
await runMysteryEncounterToEnd(game, 2);
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(3);
expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toBe("QUICK_CLAW");
expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toBe("MAX_LURE");
expect(modifierSelectHandler.options[2].modifierTypeOption.type.id).toBe("ULTRA_BALL");
});
it("should proceed to rewards screen with 4-5 Bug Types reward options", async () => {
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, [Species.BUTTERFREE, Species.BEEDRILL, Species.GALVANTULA, Species.VOLCARONA]);
await runMysteryEncounterToEnd(game, 2);
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(3);
expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toBe("GRIP_CLAW");
expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toBe("MAX_LURE");
expect(modifierSelectHandler.options[2].modifierTypeOption.type.id).toBe("ROGUE_BALL");
});
it("should proceed to rewards screen with 6 Bug Types reward options (including form change item)", async () => {
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, [Species.BUTTERFREE, Species.BEEDRILL, Species.GALVANTULA, Species.VOLCARONA, Species.ANORITH, Species.GENESECT]);
await runMysteryEncounterToEnd(game, 2);
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(3);
expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toBe("MASTER_BALL");
expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toBe("MAX_LURE");
expect(modifierSelectHandler.options[2].modifierTypeOption.type.id).toBe("FORM_CHANGE_ITEM");
});
it("should leave encounter without battle", async () => {
const leaveEncounterWithoutBattleSpy = vi.spyOn(encounterPhaseUtils, "leaveEncounterWithoutBattle");
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, defaultParty);
await runMysteryEncounterToEnd(game, 2);
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
});
});
describe("Option 3 - Give a Bug Item", () => {
it("should have the correct properties", () => {
const option = BugTypeSuperfanEncounter.options[2];
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT);
expect(option.dialogue).toBeDefined();
expect(option.dialogue).toStrictEqual({
buttonLabel: `${namespace}.option.3.label`,
buttonTooltip: `${namespace}.option.3.tooltip`,
disabledButtonTooltip: `${namespace}.option.3.disabled_tooltip`,
selected: [
{
text: `${namespace}.option.3.selected`,
},
{
speaker: `${namespace}.speaker`,
text: `${namespace}.option.3.selected_dialogue`,
},
],
secondOptionPrompt: `${namespace}.option.3.select_prompt`,
});
});
it("should NOT be selectable if the player doesn't have any Bug items", async () => {
game.scene.modifiers = [];
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, defaultParty);
await game.phaseInterceptor.to(MysteryEncounterPhase, false);
game.scene.modifiers = [];
const encounterPhase = scene.getCurrentPhase();
expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name);
const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase;
vi.spyOn(mysteryEncounterPhase, "continueEncounter");
vi.spyOn(mysteryEncounterPhase, "handleOptionSelect");
vi.spyOn(scene.ui, "playError");
await runSelectMysteryEncounterOption(game, 3);
expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name);
expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled
expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled();
expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled();
});
it("should remove the gifted item and proceed to rewards screen", async () => {
game.override.startingHeldItems([{name: "GRIP_CLAW", count: 1}]);
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, [Species.BUTTERFREE]);
const gripClawCountBefore = scene.findModifier(m => m instanceof ContactHeldItemTransferChanceModifier)?.stackCount ?? 0;
await runMysteryEncounterToEnd(game, 3, { pokemonNo: 1, optionNo: 1 });
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(2);
expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toBe("MYSTERY_ENCOUNTER_GOLDEN_BUG_NET");
expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toBe("REVIVER_SEED");
const gripClawCountAfter = scene.findModifier(m => m instanceof ContactHeldItemTransferChanceModifier)?.stackCount ?? 0;
expect(gripClawCountBefore - 1).toBe(gripClawCountAfter);
});
it("should leave encounter without battle", async () => {
game.override.startingHeldItems([{name: "GRIP_CLAW", count: 1}]);
const leaveEncounterWithoutBattleSpy = vi.spyOn(encounterPhaseUtils, "leaveEncounterWithoutBattle");
await game.runToMysteryEncounter(MysteryEncounterType.BUG_TYPE_SUPERFAN, [Species.BUTTERFREE]);
await runMysteryEncounterToEnd(game, 3, { pokemonNo: 1, optionNo: 1 });
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
});
});
});

View File

@ -8,7 +8,7 @@ import { getPokemonSpecies } from "#app/data/pokemon-species";
import * as BattleAnims from "#app/data/battle-anims";
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { generateModifierType } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounter-test-utils";
import { Moves } from "#enums/moves";
import BattleScene from "#app/battle-scene";
import Pokemon, { PokemonMove } from "#app/field/pokemon";
@ -301,7 +301,7 @@ describe("Clowning Around - Mystery Encounter", () => {
expect(secondItemsAfter.length).toBe(1);
expect(secondItemsAfter[0].type.id).toBe("SOUL_DEW");
expect(secondItemsAfter[0]?.stackCount).toBe(5);
}, 2000000);
});
it("should leave encounter without battle", async () => {
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");

View File

@ -4,7 +4,7 @@ import { Species } from "#app/enums/species";
import GameManager from "#app/test/utils/gameManager";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounter-test-utils";
import BattleScene from "#app/battle-scene";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";

View File

@ -4,7 +4,7 @@ import { Species } from "#app/enums/species";
import GameManager from "#app/test/utils/gameManager";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption } from "#test/mystery-encounter/encounter-test-utils";
import BattleScene from "#app/battle-scene";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
@ -137,7 +137,7 @@ describe("Delibird-y - Mystery Encounter", () => {
// 5 Healing Charms
scene.modifiers = [];
const abilityCharm = generateModifierType(scene, modifierTypes.ABILITY_CHARM).newModifier() as HiddenAbilityRateBoosterModifier;
const abilityCharm = generateModifierType(scene, modifierTypes.ABILITY_CHARM)!.newModifier() as HiddenAbilityRateBoosterModifier;
abilityCharm.stackCount = 4;
await scene.addModifier(abilityCharm, true, false, false, true);
await scene.updateModifiers(true);
@ -206,7 +206,7 @@ describe("Delibird-y - Mystery Encounter", () => {
// Set 2 Sitrus berries on party lead
scene.modifiers = [];
const sitrus = generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]);
const sitrus = generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS])!;
const sitrusMod = sitrus.newModifier(scene.getParty()[0]) as BerryModifier;
sitrusMod.stackCount = 2;
await scene.addModifier(sitrusMod, true, false, false, true);
@ -227,7 +227,7 @@ describe("Delibird-y - Mystery Encounter", () => {
// Set 1 Reviver Seed on party lead
scene.modifiers = [];
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED);
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED)!;
const modifier = revSeed.newModifier(scene.getParty()[0]) as PokemonInstantReviveModifier;
modifier.stackCount = 1;
await scene.addModifier(modifier, true, false, false, true);
@ -248,10 +248,10 @@ describe("Delibird-y - Mystery Encounter", () => {
// 99 Candy Jars
scene.modifiers = [];
const candyJar = generateModifierType(scene, modifierTypes.CANDY_JAR).newModifier() as LevelIncrementBoosterModifier;
const candyJar = generateModifierType(scene, modifierTypes.CANDY_JAR)!.newModifier() as LevelIncrementBoosterModifier;
candyJar.stackCount = 99;
await scene.addModifier(candyJar, true, false, false, true);
const sitrus = generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]);
const sitrus = generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS])!;
// Sitrus berries on party
const sitrusMod = sitrus.newModifier(scene.getParty()[0]) as BerryModifier;
@ -277,12 +277,12 @@ describe("Delibird-y - Mystery Encounter", () => {
// 5 Healing Charms
scene.modifiers = [];
const healingCharm = generateModifierType(scene, modifierTypes.HEALING_CHARM).newModifier() as HealingBoosterModifier;
const healingCharm = generateModifierType(scene, modifierTypes.HEALING_CHARM)!.newModifier() as HealingBoosterModifier;
healingCharm.stackCount = 5;
await scene.addModifier(healingCharm, true, false, false, true);
// Set 1 Reviver Seed on party lead
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED);
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED)!;
const modifier = revSeed.newModifier(scene.getParty()[0]) as PokemonInstantReviveModifier;
modifier.stackCount = 1;
await scene.addModifier(modifier, true, false, false, true);
@ -306,7 +306,7 @@ describe("Delibird-y - Mystery Encounter", () => {
// Set 1 Soul Dew on party lead
scene.modifiers = [];
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW);
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW)!;
const modifier = soulDew.newModifier(scene.getParty()[0]);
await scene.addModifier(modifier, true, false, false, true);
await scene.updateModifiers(true);
@ -334,7 +334,7 @@ describe("Delibird-y - Mystery Encounter", () => {
await game.runToMysteryEncounter(MysteryEncounterType.DELIBIRDY, defaultParty);
// Set 1 Reviver Seed on party lead
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED);
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED)!;
const modifier = revSeed.newModifier(scene.getParty()[0]) as PokemonInstantReviveModifier;
modifier.stackCount = 1;
await scene.addModifier(modifier, true, false, false, true);
@ -368,7 +368,7 @@ describe("Delibird-y - Mystery Encounter", () => {
// Set 2 Soul Dew on party lead
scene.modifiers = [];
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW);
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW)!;
const modifier = soulDew.newModifier(scene.getParty()[0]) as PokemonNatureWeightModifier;
modifier.stackCount = 2;
await scene.addModifier(modifier, true, false, false, true);
@ -389,7 +389,7 @@ describe("Delibird-y - Mystery Encounter", () => {
// Set 1 Soul Dew on party lead
scene.modifiers = [];
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW);
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW)!;
const modifier = soulDew.newModifier(scene.getParty()[0]) as PokemonNatureWeightModifier;
modifier.stackCount = 1;
await scene.addModifier(modifier, true, false, false, true);
@ -410,12 +410,12 @@ describe("Delibird-y - Mystery Encounter", () => {
// 5 Healing Charms
scene.modifiers = [];
const healingCharm = generateModifierType(scene, modifierTypes.BERRY_POUCH).newModifier() as PreserveBerryModifier;
const healingCharm = generateModifierType(scene, modifierTypes.BERRY_POUCH)!.newModifier() as PreserveBerryModifier;
healingCharm.stackCount = 3;
await scene.addModifier(healingCharm, true, false, false, true);
// Set 1 Soul Dew on party lead
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW);
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW)!;
const modifier = soulDew.newModifier(scene.getParty()[0]) as PokemonNatureWeightModifier;
modifier.stackCount = 1;
await scene.addModifier(modifier, true, false, false, true);
@ -439,7 +439,7 @@ describe("Delibird-y - Mystery Encounter", () => {
// Set 1 Reviver Seed on party lead
scene.modifiers = [];
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED);
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED)!;
const modifier = revSeed.newModifier(scene.getParty()[0]);
await scene.addModifier(modifier, true, false, false, true);
await scene.updateModifiers(true);
@ -468,7 +468,7 @@ describe("Delibird-y - Mystery Encounter", () => {
// Set 1 Soul Dew on party lead
scene.modifiers = [];
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW);
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW)!;
const modifier = soulDew.newModifier(scene.getParty()[0]) as PokemonNatureWeightModifier;
modifier.stackCount = 1;
await scene.addModifier(modifier, true, false, false, true);

View File

@ -5,7 +5,7 @@ import { Species } from "#app/enums/species";
import GameManager from "#app/test/utils/gameManager";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils";
import BattleScene from "#app/battle-scene";
import { Mode } from "#app/ui/ui";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";

View File

@ -9,7 +9,7 @@ import { Gender } from "#app/data/gender";
import { getPokemonSpecies } from "#app/data/pokemon-species";
import * as BattleAnims from "#app/data/battle-anims";
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounter-test-utils";
import { Moves } from "#enums/moves";
import BattleScene from "#app/battle-scene";
import { PokemonHeldItemModifier } from "#app/modifier/modifier";

View File

@ -4,7 +4,7 @@ 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, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounter-test-utils";
import { Moves } from "#enums/moves";
import BattleScene from "#app/battle-scene";
import { PokemonMove } from "#app/field/pokemon";

View File

@ -8,7 +8,7 @@ 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 "../encounterTestUtils";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption } from "../encounter-test-utils";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils";

View File

@ -5,7 +5,7 @@ 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, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } 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";

View File

@ -5,7 +5,7 @@ import { Species } from "#app/enums/species";
import GameManager from "#app/test/utils/gameManager";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption } from "#test/mystery-encounter/encounter-test-utils";
import BattleScene from "#app/battle-scene";
import { CIVILIZATION_ENCOUNTER_BIOMES } from "#app/data/mystery-encounters/mystery-encounters";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";

View File

@ -4,7 +4,7 @@ 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, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounter-test-utils";
import BattleScene from "#app/battle-scene";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
@ -151,7 +151,6 @@ describe("Teleporting Hijinks - Mystery Encounter", () => {
it("should NOT be selectable if the player doesn't have enough money", async () => {
game.scene.money = 0;
await game.runToMysteryEncounter(MysteryEncounterType.TELEPORTING_HIJINKS, defaultParty);
scene.getParty().forEach(p => p.moveset = []);
await game.phaseInterceptor.to(MysteryEncounterPhase, false);
const encounterPhase = scene.getCurrentPhase();

View File

@ -5,7 +5,7 @@ import { Species } from "#app/enums/species";
import GameManager from "#app/test/utils/gameManager";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption } from "#test/mystery-encounter/encounter-test-utils";
import BattleScene from "#app/battle-scene";
import { PlayerPokemon } from "#app/field/pokemon";
import { HUMAN_TRANSITABLE_BIOMES } from "#app/data/mystery-encounters/mystery-encounters";

View File

@ -7,7 +7,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite
import { getPokemonSpecies } from "#app/data/pokemon-species";
import * as BattleAnims from "#app/data/battle-anims";
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounter-test-utils";
import { Moves } from "#enums/moves";
import BattleScene from "#app/battle-scene";
import { TheStrongStuffEncounter } from "#app/data/mystery-encounters/encounters/the-strong-stuff-encounter";
@ -164,9 +164,10 @@ describe("The Strong Stuff - Mystery Encounter", () => {
return baseStats.reduce((a, b) => a + b);
});
expect(bstsAfter[0]).toEqual(bstsPrior[0] - 20 * 6);
expect(bstsAfter[1]).toEqual(bstsPrior[1] + 10 * 6);
expect(bstsAfter[2]).toEqual(bstsPrior[2] + 10 * 6);
// HP stat changes are halved compared to other values
expect(bstsAfter[0]).toEqual(bstsPrior[0] - 20 * 5 - 10);
expect(bstsAfter[1]).toEqual(bstsPrior[1] + 10 * 5 + 5);
expect(bstsAfter[2]).toEqual(bstsPrior[2] + 10 * 5 + 5);
});
it("should leave encounter without battle", async () => {

Some files were not shown because too many files have changed in this diff Show More