dialogue updates and test fixes for MEs

This commit is contained in:
ImperialSympathizer 2024-09-09 17:04:28 -04:00
parent de18120786
commit 8dd16f40f9
40 changed files with 157 additions and 107 deletions

View File

@ -1,4 +1,4 @@
VITE_BYPASS_LOGIN=1
VITE_BYPASS_LOGIN=0
VITE_BYPASS_TUTORIAL=0
VITE_SERVER_URL=http://localhost:8001
VITE_DISCORD_CLIENT_ID=1234567890

View File

@ -256,7 +256,7 @@ export default class BattleScene extends SceneBase {
public money: integer;
public pokemonInfoContainer: PokemonInfoContainer;
private party: PlayerPokemon[];
public mysteryEncounterSaveData: MysteryEncounterSaveData = new MysteryEncounterSaveData(null);
public mysteryEncounterSaveData: MysteryEncounterSaveData = new MysteryEncounterSaveData();
public lastMysteryEncounter?: MysteryEncounter;
/** Combined Biome and Wave count text */
private biomeWaveText: Phaser.GameObjects.Text;

View File

@ -225,6 +225,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
};
encounter.enemyPartyConfigs = [config];
encounter.setDialogueToken("greedentName", getPokemonSpecies(Species.GREEDENT).getName());
return true;
})
@ -251,6 +252,9 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
party.forEach(p => {
if (revSeed) {
const seedModifier = revSeed.newModifier(p);
if (seedModifier) {
encounter.setDialogueToken("foodReward", seedModifier.type.name);
}
scene.addModifier(seedModifier, false, false, false, true);
}
});

View File

@ -83,6 +83,8 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
}
}
encounter.setDialogueToken("liepardName", getPokemonSpecies(Species.LIEPARD).getName());
return true;
})
.withOption(

View File

@ -1,5 +1,5 @@
import {
EnemyPartyConfig,
EnemyPartyConfig, generateModifierType,
generateModifierTypeOption,
initBattleWithEnemyConfig,
leaveEncounterWithoutBattle,
@ -223,6 +223,15 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
},
];
const requiredItems = [
generateModifierType(scene, modifierTypes.QUICK_CLAW),
generateModifierType(scene, modifierTypes.GRIP_CLAW),
generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.BUG]),
];
const requiredItemString = requiredItems.map(m => m?.name ?? "unknown").join("/");
encounter.setDialogueToken("requiredBugItems", requiredItemString);
return true;
})
.withTitle(`${namespace}.title`)
@ -361,6 +370,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
})
.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 => {

View File

@ -129,7 +129,7 @@ export const ClowningAroundEncounter: MysteryEncounter =
},
{ // Blacephalon has the random ability from pool, and 2 entirely random types to fit with the theme of the encounter
species: getPokemonSpecies(Species.BLACEPHALON),
mysteryEncounterPokemonData: new MysteryEncounterPokemonData(undefined, ability, undefined, [randSeedInt(18), randSeedInt(18)]),
mysteryEncounterPokemonData: new MysteryEncounterPokemonData({ ability: ability, types: [randSeedInt(18), randSeedInt(18)] }),
isBoss: true,
moveSet: [Moves.TRICK, Moves.HYPNOSIS, Moves.SHADOW_BALL, Moves.MIND_BLOWN]
},
@ -140,6 +140,8 @@ export const ClowningAroundEncounter: MysteryEncounter =
// Load animations/sfx for start of fight moves
loadCustomMovesForEncounter(scene, [Moves.ROLE_PLAY, Moves.TAUNT]);
encounter.setDialogueToken("blacephalonName", getPokemonSpecies(Species.BLACEPHALON).getName());
return true;
})
.withTitle(`${namespace}.title`)
@ -345,10 +347,9 @@ export const ClowningAroundEncounter: MysteryEncounter =
}
newTypes.push(secondType);
if (!pokemon.mysteryEncounterPokemonData) {
pokemon.mysteryEncounterPokemonData = new MysteryEncounterPokemonData(undefined, undefined, undefined, newTypes);
} else {
pokemon.mysteryEncounterPokemonData.types = newTypes;
pokemon.mysteryEncounterPokemonData = new MysteryEncounterPokemonData();
}
pokemon.mysteryEncounterPokemonData.types = newTypes;
}
})
.withOptionPhase(async (scene: BattleScene) => {
@ -410,11 +411,12 @@ function displayYesNoOptions(scene: BattleScene, resolve) {
function onYesAbilitySwap(scene: BattleScene, resolve) {
const onPokemonSelected = (pokemon: PlayerPokemon) => {
// Do ability swap
const encounter = scene.currentBattle.mysteryEncounter!;
if (!pokemon.mysteryEncounterPokemonData) {
pokemon.mysteryEncounterPokemonData = new MysteryEncounterPokemonData(undefined, Abilities.AERILATE);
pokemon.mysteryEncounterPokemonData = new MysteryEncounterPokemonData();
}
pokemon.mysteryEncounterPokemonData.ability = scene.currentBattle.mysteryEncounter!.misc.ability;
scene.currentBattle.mysteryEncounter!.setDialogueToken("chosenPokemon", pokemon.getNameToRender());
pokemon.mysteryEncounterPokemonData.ability = encounter.misc.ability;
encounter.setDialogueToken("chosenPokemon", pokemon.getNameToRender());
scene.ui.setMode(Mode.MESSAGE).then(() => resolve(true));
};

View File

@ -162,6 +162,8 @@ export const DancingLessonsEncounter: MysteryEncounter =
oricorioData
};
encounter.setDialogueToken("oricorioName", getPokemonSpecies(Species.ORICORIO).getName());
return true;
})
.withOption(

View File

@ -15,6 +15,7 @@ import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
import { applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import i18next from "#app/plugins/i18n";
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
import { getPokemonSpecies } from "#app/data/pokemon-species";
/** the i18n namespace for this encounter */
const namespace = "mysteryEncounter:delibirdy";
@ -88,6 +89,11 @@ export const DelibirdyEncounter: MysteryEncounter =
text: `${namespace}.outro`,
}
])
.withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!;
encounter.setDialogueToken("delibirdName", getPokemonSpecies(Species.DELIBIRD).getName());
return true;
})
.withOption(
MysteryEncounterOptionBuilder
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)

View File

@ -100,6 +100,8 @@ export const FieryFalloutEncounter: MysteryEncounter =
scene.arena.trySetWeather(WeatherType.SUNNY, true);
encounter.setDialogueToken("volcaronaName", getPokemonSpecies(Species.VOLCARONA).getName());
return true;
})
.withOnVisualsStart((scene: BattleScene) => {

View File

@ -77,7 +77,9 @@ export const FunAndGamesEncounter: MysteryEncounter =
.withDescription(`${namespace}.description`)
.withQuery(`${namespace}.query`)
.withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!;
scene.loadBgm("mystery_encounter_fun_and_games", "mystery_encounter_fun_and_games.mp3");
encounter.setDialogueToken("wobbuffetName", getPokemonSpecies(Species.WOBBUFFET).getName());
return true;
})
.withOnVisualsStart((scene: BattleScene) => {

View File

@ -215,7 +215,8 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter!;
const onPokemonSelected = (pokemon: PlayerPokemon) => {
// Randomly generate a Wonder Trade pokemon
const randomTradeOption = generateTradeOption(scene.getParty().map(p => p.species));
// const randomTradeOption = generateTradeOption(scene.getParty().map(p => p.species));
const randomTradeOption = getPokemonSpecies(Species.BURMY);
const tradePokemon = new EnemyPokemon(scene, randomTradeOption, pokemon.level, TrainerSlot.NONE, false);
// Extra shiny roll at 1/128 odds (boosted by events and charms)
if (!tradePokemon.shiny) {
@ -265,7 +266,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
receivedPokemonData.passive = tradedPokemon.passive;
receivedPokemonData.pokeball = randSeedInt(5);
const dataSource = new PokemonData(receivedPokemonData);
const newPlayerPokemon = scene.addPlayerPokemon(receivedPokemonData.species, receivedPokemonData.level, undefined, undefined, undefined, undefined, undefined, undefined, undefined, dataSource);
const newPlayerPokemon = scene.addPlayerPokemon(receivedPokemonData.species, receivedPokemonData.level, dataSource.abilityIndex, dataSource.formIndex, dataSource.gender, dataSource.shiny, dataSource.variant, dataSource.ivs, dataSource.nature, dataSource);
scene.getParty().push(newPlayerPokemon);
await newPlayerPokemon.loadAssets();

View File

@ -1,5 +1,5 @@
import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, loadCustomMovesForEncounter, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { getHighestLevelPlayerPokemon, koPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import { ModifierTier } from "#app/modifier/modifier-tier";
import { randSeedInt } from "#app/utils.js";
@ -60,7 +60,7 @@ export const MysteriousChestEncounter: MysteryEncounter =
// Calculate boss mon
const config: EnemyPartyConfig = {
levelAdditiveMultiplier: 1,
levelAdditiveMultiplier: 0.5,
disableSwitch: true,
pokemonConfigs: [
{
@ -74,7 +74,7 @@ export const MysteriousChestEncounter: MysteryEncounter =
encounter.enemyPartyConfigs = [config];
loadCustomMovesForEncounter(scene, [Moves.CONFUSE_RAY, Moves.ASTONISH]);
encounter.setDialogueToken("gimmighoulName", getPokemonSpecies(Species.GIMMIGHOUL).getName());
return true;
})

View File

@ -68,6 +68,8 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
// Load animations/sfx for Snorlax fight start moves
loadCustomMovesForEncounter(scene, [Moves.SNORE]);
encounter.setDialogueToken("snorlaxName", getPokemonSpecies(Species.SNORLAX).getName());
return true;
})
.withTitle(`${namespace}.title`)

View File

@ -76,7 +76,7 @@ export const TheStrongStuffEncounter: MysteryEncounter =
species: getPokemonSpecies(Species.SHUCKLE),
isBoss: true,
bossSegments: 5,
mysteryEncounterPokemonData: new MysteryEncounterPokemonData(1.25),
mysteryEncounterPokemonData: new MysteryEncounterPokemonData({ spriteScale: 1.25 }),
nature: Nature.BOLD,
moveSet: [Moves.INFESTATION, Moves.SALT_CURE, Moves.GASTRO_ACID, Moves.HEAL_ORDER],
modifierConfigs: [
@ -110,6 +110,8 @@ export const TheStrongStuffEncounter: MysteryEncounter =
loadCustomMovesForEncounter(scene, [Moves.GASTRO_ACID, Moves.STEALTH_ROCK]);
encounter.setDialogueToken("shuckleName", getPokemonSpecies(Species.SHUCKLE).getName());
return true;
})
.withTitle(`${namespace}.title`)

View File

@ -77,6 +77,7 @@ export const TrashToTreasureEncounter: MysteryEncounter =
scene.loadSe("PRSFX- Dig2", "battle_anims", "PRSFX- Dig2.wav");
scene.loadSe("PRSFX- Venom Drench", "battle_anims", "PRSFX- Venom Drench.wav");
return true;
})
.withOption(

View File

@ -174,16 +174,17 @@ export const UncommonBreedEncounter: MysteryEncounter =
// Remove 4 random berries from player's party
// Get all player berry items, remove from party, and store reference
let berryItems: BerryModifier[] = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
const berryItems: BerryModifier[]= scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
for (let i = 0; i < 4; i++) {
berryItems = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
const randBerry = berryItems[randSeedInt(berryItems.length)];
const index = randSeedInt(berryItems.length);
const randBerry = berryItems[index];
randBerry.stackCount--;
if (randBerry.stackCount === 0) {
scene.removeModifier(randBerry);
berryItems.splice(index, 1);
}
}
scene.updateModifiers(true, true);
}
// Pokemon joins the team, with 2 egg moves
const encounter = scene.currentBattle.mysteryEncounter!;

View File

@ -370,10 +370,9 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon
}
newTypes.push(newType);
if (!newPokemon.mysteryEncounterPokemonData) {
newPokemon.mysteryEncounterPokemonData = new MysteryEncounterPokemonData(undefined, undefined, undefined, newTypes);
} else {
newPokemon.mysteryEncounterPokemonData.types = newTypes;
newPokemon.mysteryEncounterPokemonData = new MysteryEncounterPokemonData();
}
newPokemon.mysteryEncounterPokemonData.types = newTypes;
for (const item of transformation.heldItems) {
item.pokemonId = newPokemon.id;

View File

@ -1,5 +1,6 @@
import { Abilities } from "#enums/abilities";
import { Type } from "#app/data/type";
import { isNullOrUndefined } from "#app/utils";
export class MysteryEncounterPokemonData {
public spriteScale: number;
@ -7,10 +8,14 @@ export class MysteryEncounterPokemonData {
public passive: Abilities | -1;
public types: Type[];
constructor(spriteScale?: number, ability?: Abilities, passive?: Abilities, types?: Type[]) {
this.spriteScale = spriteScale ?? -1;
this.ability = ability ?? -1;
this.passive = passive ?? -1;
this.types = types ?? [];
constructor(data?: MysteryEncounterPokemonData | Partial<MysteryEncounterPokemonData>) {
if (!isNullOrUndefined(data)) {
Object.assign(this, data);
}
this.spriteScale = this.spriteScale ?? -1;
this.ability = this.ability ?? -1;
this.passive = this.passive ?? -1;
this.types = this.types ?? [];
}
}

View File

@ -27,9 +27,12 @@ export class MysteryEncounterSaveData {
encounterSpawnChance: number = BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT;
queuedEncounters: QueuedEncounter[] = [];
constructor(data: MysteryEncounterSaveData | null) {
constructor(data?: MysteryEncounterSaveData) {
if (!isNullOrUndefined(data)) {
Object.assign(this, data);
}
this.encounteredEvents = this.encounteredEvents ?? [];
this.queuedEncounters = this.queuedEncounters ?? [];
}
}

View File

@ -5,7 +5,7 @@ import { variantData } from "#app/data/variant";
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "../ui/battle-info";
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, VariableMoveTypeAttr, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatStagesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatStageChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, OneHitKOAccuracyAttr, RespectAttackTypeImmunityAttr } from "../data/move";
import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species";
import { Constructor, randSeedInt } from "#app/utils";
import { Constructor, isNullOrUndefined, randSeedInt } from "#app/utils";
import * as Utils from "../utils";
import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from "../data/type";
import { getLevelTotalExp } from "../data/exp";
@ -202,7 +202,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.fusionGender = dataSource.fusionGender;
this.fusionLuck = dataSource.fusionLuck;
this.usedTMs = dataSource.usedTMs ?? [];
this.mysteryEncounterPokemonData = dataSource.mysteryEncounterPokemonData ?? new MysteryEncounterPokemonData();
this.mysteryEncounterPokemonData = new MysteryEncounterPokemonData(dataSource.mysteryEncounterPokemonData);
} else {
this.id = Utils.randSeedInt(4294967296);
this.ivs = ivs || Utils.getIvsFromId(this.id);
@ -548,12 +548,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (!ignoreOverride && this.summonData?.speciesForm) {
return this.summonData.speciesForm;
}
if (!this.species.forms?.length) {
return this.species;
}
if (this.species.forms && this.species.forms.length > 0) {
return this.species.forms[this.formIndex];
}
return this.species;
}
getFusionSpeciesForm(ignoreOverride?: boolean): PokemonSpeciesForm {
if (!ignoreOverride && this.summonData?.speciesForm) {
return this.summonData.fusionSpeciesForm;
@ -1151,7 +1152,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (Overrides.OPP_ABILITY_OVERRIDE && !this.isPlayer()) {
return allAbilities[Overrides.OPP_ABILITY_OVERRIDE];
}
if (this.mysteryEncounterPokemonData.ability !== -1) {
if (!isNullOrUndefined(this.mysteryEncounterPokemonData.ability) && this.mysteryEncounterPokemonData.ability !== -1) {
return allAbilities[this.mysteryEncounterPokemonData.ability];
}
if (this.isFusion()) {
@ -1178,7 +1179,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (Overrides.OPP_PASSIVE_ABILITY_OVERRIDE && !this.isPlayer()) {
return allAbilities[Overrides.OPP_PASSIVE_ABILITY_OVERRIDE];
}
if (this.mysteryEncounterPokemonData.passive !== -1) {
if (!isNullOrUndefined(this.mysteryEncounterPokemonData.passive) && this.mysteryEncounterPokemonData.passive !== -1) {
return allAbilities[this.mysteryEncounterPokemonData.passive];
}

View File

@ -1,25 +1,25 @@
{
"intro": "A Greedent ambushes you\nand steals your party's berries!",
"intro": "A {{greedentName}} ambushes you\nand steals your party's berries!",
"title": "Absolute Avarice",
"description": "The Greedent has caught you totally off guard now all your berries are gone!\n\nThe Greedent looks like it's about to eat them when it pauses to look at you, interested.",
"description": "The {{greedentName}} has caught you totally off guard now all your berries are gone!\n\nThe {{greedentName}} looks like it's about to eat them when it pauses to look at you, interested.",
"query": "What will you do?",
"option": {
"1": {
"label": "Battle It",
"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!$@s{item_fanfare}Each Pokémon in your party gains 1x Reviver Seed!"
"selected": "The {{greedentName}} stuffs its cheeks\nand prepares for battle!",
"boss_enraged": "{{greedentName}}'s fierce love for food has it incensed!",
"food_stash": "It looks like the {{greedentName}} was guarding an enormous stash of food!$@s{item_fanfare}Each Pokémon in your party gains a {{foodReward}}!"
},
"2": {
"label": "Reason with It",
"tooltip": "(+) Regain Some Lost Berries",
"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."
"selected": "Your pleading strikes a chord with the {{greedentName}}.$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!$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!"
"tooltip": "(-) Lose All Berries\n(?) The {{greedentName}} Will Like You",
"selected": "The {{greedentName}} 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 {{greedentName}} wants to join your party!"
}
}
}

View File

@ -15,12 +15,12 @@
"label": "Extort the Kid",
"tooltip": "(+) {{option2PrimaryName}} uses {{moveOrAbility}}\n(+) Gain {{price, money}}",
"tooltip_disabled": "Your Pokémon need to have certain moves or abilities to choose this",
"selected": "My word, we're being robbed, Liepard!\n $You'll be hearing from my lawyers for this!"
"selected": "My word, we're being robbed, {{liepardName}}!$You'll be hearing from my lawyers for this!"
},
"3": {
"label": "Leave",
"tooltip": "(-) No Rewards",
"selected": "What a rotten day...$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, {{liepardName}}."
}
}
}

View File

@ -1,7 +1,7 @@
{
"intro": "There's a huge berry bush\nnear that Pokémon!",
"title": "Berries Abound",
"description": "It looks like there's a strong Pokémon guarding a berry bush. Battling is the straightforward approach, but this Pokémon looks strong. Maybe a fast Pokémon would be able to grab some without getting caught?",
"description": "It looks like there's a strong Pokémon guarding a berry bush. Battling is the straightforward approach, but it looks strong. Perhaps a fast Pokémon could grab some berries without getting caught?",
"query": "What will you do?",
"berries": "Berries!",
"option": {

View File

@ -23,8 +23,8 @@
},
"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.",
"tooltip": "(-) Give the trainer a {{requiredBugItems}}\n(+) Receive a Gift Item",
"disabled_tooltip": "You need to have a {{requiredBugItems}} 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}}.",

View File

@ -3,7 +3,7 @@
"speaker": "Clown",
"intro_dialogue": "Bumbling buffoon, brace for a brilliant battle!\nYou'll be beaten by this brawling busker!",
"title": "Clowning Around",
"description": "Something is off about this encounter. The clown seems eager to goad you into a battle, but to what end?\n\nThe Blacephalon is especially strange, like it has @[TOOLTIP_TITLE]{weird types and ability.}",
"description": "Something is off about this encounter. The clown seems eager to goad you into a battle, but to what end?\n\nThe {{blacephalonName}} is especially strange, like it has @[TOOLTIP_TITLE]{weird types and ability.}",
"query": "What will you do?",
"option": {
"1": {
@ -19,14 +19,14 @@
"label": "Remain Unprovoked",
"tooltip": "(-) Upsets the Clown\n(?) Affects Pokémon Items",
"selected": "Dismal dodger, you deny a delightful duel?\nFeel my fury!",
"selected_2": "The clown's Blacephalon uses Trick!\nAll of your {{switchPokemon}}'s items were randomly swapped!",
"selected_2": "The clown's {{blacephalonName}} uses Trick!\nAll of your {{switchPokemon}}'s items were randomly swapped!",
"selected_3": "Flustered fool, fall for my flawless deception!"
},
"3": {
"label": "Return the Insults",
"tooltip": "(-) Upsets the Clown\n(?) Affects Pokémon Types",
"selected": "Dismal dodger, you deny a delightful duel?\nFeel my fury!",
"selected_2": "The clown's Blacephalon uses a strange move!\nAll of your team's types were randomly swapped!",
"selected_2": "The clown's {{blacephalonName}} uses a strange move!\nAll of your team's types were randomly swapped!",
"selected_3": "Flustered fool, fall for my flawless deception!"
}
},

View File

@ -1,26 +1,26 @@
{
"intro": "An Oricorio dances sadly alone, without a partner.",
"intro": "An {{oricorioName}} dances sadly alone, without a partner.",
"title": "Dancing Lessons",
"description": "The Oricorio doesn't seem aggressive, if anything it seems sad.\n\nMaybe it just wants someone to dance with...",
"description": "The {{oricorioName}} doesn't seem aggressive, if anything it seems sad.\n\nMaybe it just wants someone to dance with...",
"query": "What will you do?",
"option": {
"1": {
"label": "Battle It",
"tooltip": "(-) Tough Battle\n(+) Gain a Baton",
"selected": "The Oricorio is distraught and moves to defend itself!",
"boss_enraged": "The Oricorio's fear boosted its stats!"
"selected": "The {{oricorioName}} is distraught and moves to defend itself!",
"boss_enraged": "The {{oricorioName}}'s fear boosted its stats!"
},
"2": {
"label": "Learn Its Dance",
"tooltip": "(+) Teach a Pokémon Revelation Dance",
"selected": "You watch the Oricorio closely as it performs its dance...$@s{level_up_fanfare}Your {{selectedPokemon}} learned from the Oricorio!"
"selected": "You watch the {{oricorioName}} closely as it performs its dance...$@s{level_up_fanfare}Your {{selectedPokemon}} learned from the {{oricorioName}}!"
},
"3": {
"label": "Show It a Dance",
"tooltip": "(-) Teach the Oricorio a Dance Move\n(+) The Oricorio Will Like You",
"tooltip": "(-) Teach the {{oricorioName}} a Dance Move\n(+) The {{oricorioName}} 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}}!$It loves the display!$@s{level_up_fanfare}The Oricorio wants to join your party!"
"selected": "The {{oricorioName}} watches in fascination as\n{{selectedPokemon}} shows off {{selectedMove}}!$It loves the display!$@s{level_up_fanfare}The {{oricorioName}} wants to join your party!"
}
},
"invalid_selection": "This Pokémon doesn't know a Dance move"

View File

@ -1,29 +1,29 @@
{
"intro": "A pack of Delibird have appeared!",
"intro": "A pack of {{delibirdName}} have appeared!",
"title": "Delibir-dy",
"description": "The Delibirds are looking at you expectantly, as if they want something. Perhaps giving them an item or some money would satisfy them?",
"description": "The {{delibirdName}}s are looking at you expectantly, as if they want something. Perhaps giving them an item or some money would satisfy them?",
"query": "What will you give them?",
"invalid_selection": "Pokémon doesn't have that kind of item.",
"option": {
"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.$They turn back to you and happily give you a present!"
"tooltip": "(-) Give the {{delibirdName}}s {{money, money}}\n(+) Receive a Gift Item",
"selected": "You toss the money to the {{delibirdName}}s,\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",
"tooltip": "(-) Give the {{delibirdName}}s 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.$They turn back to you and happily give you a present!"
"selected": "You toss the {{chosenItem}} to the {{delibirdName}}s,\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",
"tooltip": "(-) Give the {{delibirdName}}s 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.$They turn back to you and happily give you a present!"
"selected": "You toss the {{chosenItem}} to the {{delibirdName}}s,\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.$What a curious little exchange!"
"outro": "The {{delibirdName}} pack happily waddles off into the distance.$What a curious little exchange!"
}

View File

@ -7,7 +7,7 @@
"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!$They don't take kindly to the interruption and attack!"
"selected": "You push through the storm, and find two {{volcaronaName}}s in the middle of a mating dance!$They don't take kindly to the interruption and attack!"
},
"2": {
"label": "Hunker Down",
@ -19,7 +19,7 @@
"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!$Thankfully, your Pokémon are able to calm them,\nand they depart without issue."
"selected": "Your {{option3PrimaryName}} and {{option3SecondaryName}} guide you to where two {{volcaronaName}}s 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.$@s{item_fanfare}{{leadPokemon}} gained a Charcoal!"

View File

@ -1,7 +1,7 @@
{
"intro": "Something shiny is sparkling\non the ground near that Pokémon!",
"title": "Fight or Flight",
"description": "It looks like there's a strong Pokémon guarding an item. Battling is the straightforward approach, but this Pokémon looks strong. You could also try to sneak around, though the Pokémon might catch you.",
"description": "It looks like there's a strong Pokémon guarding an item. Battling is the straightforward approach, but it looks strong. Perhaps you could steal the item, if you have the right Pokémon for the job.",
"query": "What will you do?",
"option": {
"1": {

View File

@ -1,13 +1,13 @@
{
"intro_dialogue": "Step right up, folks! Try your luck\non the brand new Wobbuffet Whack-o-matic!",
"intro_dialogue": "Step right up, folks! Try your luck\non the brand new {{wobbuffetName}} Whack-o-matic!",
"speaker": "Showman",
"title": "Fun And Games!",
"description": "You've encountered a traveling show with a prize game! You will have @[TOOLTIP_TITLE]{3 turns} to bring the Wobbuffet as close to @[TOOLTIP_TITLE]{1 HP} as possible @[TOOLTIP_TITLE]{without KOing it} so it can wind up a huge Counter on the bell-ringing machine.\nBut be careful! If you KO the Wobbuffet, you'll have to pay for the cost of reviving it!",
"description": "You've encountered a traveling show with a prize game! You will have @[TOOLTIP_TITLE]{3 turns} to bring the {{wobbuffetName}} as close to @[TOOLTIP_TITLE]{1 HP} as possible @[TOOLTIP_TITLE]{without KOing it} so it can wind up a huge Counter on the bell-ringing machine.\nBut be careful! If you KO the {{wobbuffetName}}, you'll have to pay for the cost of reviving it!",
"query": "Would you like to play?",
"option": {
"1": {
"label": "Play the Game",
"tooltip": "(-) Pay {{option1Money, money}}\n(+) Play Wobbuffet Whack-o-matic",
"tooltip": "(-) Pay {{option1Money, money}}\n(+) Play {{wobbuffetName}} Whack-o-matic",
"selected": "Time to test your luck!"
},
"2": {
@ -16,15 +16,15 @@
"selected": "You hurry along your way,\nwith a slight feeling of regret."
}
},
"ko": "Oh no! The Wobbuffet fainted!$You lose the game and\nhave to pay for the revive cost...",
"ko": "Oh no! The {{wobbuffetName}} fainted!$You lose the game and\nhave to pay for the revive cost...",
"charging_continue": "The Wubboffet keeps charging its counter-swing!",
"turn_remaining_3": "Three turns remaining!",
"turn_remaining_2": "Two turns remaining!",
"turn_remaining_1": "One turn remaining!",
"end_game": "Time's up!$The Wobbuffet winds up to counter-swing and@d{16}.@d{16}.@d{16}.",
"best_result": "The Wobbuffet smacks the button so hard\nthe bell breaks off the top!$You win the grand prize!",
"great_result": "The Wobbuffet smacks the button, nearly hitting the bell!$So close!\nYou earn the second tier prize!",
"good_result": "The Wobbuffet hits the button hard enough to go midway up the scale!$You earn the third tier prize!",
"bad_result": "The Wobbuffet barely taps the button and nothing happens...$Oh no!\nYou don't win anything!",
"end_game": "Time's up!$The {{wobbuffetName}} winds up to counter-swing and@d{16}.@d{16}.@d{16}.",
"best_result": "The {{wobbuffetName}} smacks the button so hard\nthe bell breaks off the top!$You win the grand prize!",
"great_result": "The {{wobbuffetName}} smacks the button, nearly hitting the bell!$So close!\nYou earn the second tier prize!",
"good_result": "The {{wobbuffetName}} hits the button hard enough to go midway up the scale!$You earn the third tier prize!",
"bad_result": "The {{wobbuffetName}} barely taps the button and nothing happens...$Oh no!\nYou don't win anything!",
"outro": "That was a fun little game!"
}

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 actually a Gimmighoul in disguise!$Your {{pokeName}} jumps in front of you\nbut is KOed in the process!"
"bad": "Oh no!@d{32}\nThe chest was actually a {{gimmighoulName}} in disguise!$Your {{pokeName}} jumps in front of you\nbut is KOed in the process!"
},
"2": {
"label": "Too Risky, Leave",

View File

@ -1,25 +1,25 @@
{
"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",
"intro": "As you walk down a narrow pathway, you see a towering silhouette blocking your path.$You get closer to see a {{snorlaxName}} sleeping peacefully.\nIt seems like there's no way around it.",
"title": "Slumbering {{snorlaxName}}",
"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?",
"option": {
"1": {
"label": "Battle It",
"tooltip": "(-) Fight Sleeping Snorlax\n(+) Special Reward",
"tooltip": "(-) Fight Sleeping {{snorlaxName}}\n(+) Special Reward",
"selected": "You approach the\nPokémon without fear."
},
"2": {
"label": "Wait for It to Move",
"tooltip": "(-) Wait a Long Time\n(+) Recover Party",
"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!"
"selected": ".@d{32}.@d{32}.@d{32}$You wait for a time, but the {{snorlaxName}}'s yawns make your party sleepy...",
"rest_result": "When you all awaken, the {{snorlaxName}} 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}}!$@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\n{{snorlaxName}} and you make out like bandits!"
}
}
}

View File

@ -1,20 +1,20 @@
{
"intro": "It's a massive Shuckle and what appears\nto be a large stash of... juice?",
"intro": "It's a massive {{shuckleName}} and what appears\nto be a large stash of... juice?",
"title": "The Strong Stuff",
"description": "The Shuckle that blocks your path looks incredibly strong. Meanwhile, the juice next to it is emanating power of some kind.\n\nThe Shuckle extends its feelers in your direction. It seems like it wants to do something...",
"description": "The {{shuckleName}} that blocks your path looks incredibly strong. Meanwhile, the juice next to it is emanating power of some kind.\n\nThe {{shuckleName}} extends its feelers in your direction. It seems like it wants to do something...",
"query": "What will you do?",
"option": {
"1": {
"label": "Approach the Shuckle",
"label": "Approach the {{shuckleName}}",
"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.${{highBstPokemon1}} and {{highBstPokemon2}}\nfeel a terrible lethargy come over them!$Their base stats were reduced by {{reductionValue}}!$Your remaining Pokémon feel an incredible vigor, though!\nTheir base stats are increased by {{increaseValue}}!"
"selected_2": "@f{150}When you awaken, the {{shuckleName}} is gone\nand juice stash completely drained.${{highBstPokemon1}} and {{highBstPokemon2}}\nfeel a terrible lethargy come over them!$Their base stats were reduced by {{reductionValue}}!$Your remaining Pokémon feel an incredible vigor, though!\nTheir base stats are increased by {{increaseValue}}!"
},
"2": {
"label": "Battle the Shuckle",
"label": "Battle the {{shuckleName}}",
"tooltip": "(-) Hard Battle\n(+) Special Rewards",
"selected": "Enraged, the Shuckle drinks some of its juice and attacks!",
"stat_boost": "The Shuckle's juice boosts its stats!"
"selected": "Enraged, the {{shuckleName}} drinks some of its juice and attacks!",
"stat_boost": "The {{shuckleName}}'s juice boosts its stats!"
}
},
"outro": "What a bizarre turn of events."

View File

@ -1,5 +1,5 @@
import BattleScene from "#app/battle-scene";
import { BattleType, BattlerIndex } from "#app/battle";
import { BattlerIndex, BattleType } from "#app/battle";
import { applyAbAttrs, SyncEncounterNatureAbAttr } from "#app/data/ability";
import { getCharVariantFromDialogue } from "#app/data/dialogue";
import { TrainerSlot } from "#app/data/trainer-config";
@ -10,7 +10,7 @@ import { Species } from "#app/enums/species";
import { EncounterPhaseEvent } from "#app/events/battle-scene";
import Pokemon, { FieldPosition } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages";
import { regenerateModifierPoolThresholds, ModifierPoolType } from "#app/modifier/modifier-type";
import { ModifierPoolType, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
import { BoostBugSpawnModifier, IvScannerModifier, TurnHeldItemTransferModifier } from "#app/modifier/modifier";
import { achvs } from "#app/system/achv";
import { handleTutorial, Tutorial } from "#app/tutorial";
@ -18,6 +18,7 @@ import { Mode } from "#app/ui/ui";
import i18next from "i18next";
import { BattlePhase } from "./battle-phase";
import * as Utils from "#app/utils";
import { randSeedInt } from "#app/utils";
import { CheckSwitchPhase } from "./check-switch-phase";
import { GameOverPhase } from "./game-over-phase";
import { PostSummonPhase } from "./post-summon-phase";
@ -32,7 +33,6 @@ 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 {
@ -153,8 +153,7 @@ export class EncounterPhase extends BattlePhase {
loadEnemyAssets.push(battle.trainer?.loadAssets().then(() => battle.trainer?.initSprite())!); // TODO: is this bang correct?
} else if (battle.battleType === BattleType.MYSTERY_ENCOUNTER) {
if (!battle.mysteryEncounter) {
const newEncounter = this.scene.getMysteryEncounter(mysteryEncounter);
battle.mysteryEncounter = newEncounter;
battle.mysteryEncounter = this.scene.getMysteryEncounter(mysteryEncounter?.encounterType);
}
if (battle.mysteryEncounter.introVisuals) {
loadEnemyAssets.push(battle.mysteryEncounter.introVisuals.loadAssets().then(() => battle.mysteryEncounter!.introVisuals!.initSprite()));

View File

@ -952,7 +952,7 @@ export class GameData {
gameVersion: scene.game.config.gameVersion,
timestamp: new Date().getTime(),
challenges: scene.gameMode.challenges.map(c => new ChallengeData(c)),
mysteryEncounterType: scene.currentBattle.mysteryEncounter?.encounterType,
mysteryEncounterType: scene.currentBattle.mysteryEncounter?.encounterType ?? -1,
mysteryEncounterSaveData: scene.mysteryEncounterSaveData
} as SessionSaveData;
}
@ -1044,7 +1044,7 @@ export class GameData {
scene.score = sessionData.score;
scene.updateScoreText();
scene.mysteryEncounterSaveData = sessionData?.mysteryEncounterSaveData ?? new MysteryEncounterSaveData(null);
scene.mysteryEncounterSaveData = new MysteryEncounterSaveData(sessionData.mysteryEncounterSaveData);
scene.newArena(sessionData.arena.biome);

View File

@ -103,7 +103,7 @@ export default class PokemonData {
this.fusionLuck = source.fusionLuck !== undefined ? source.fusionLuck : (source.fusionShiny ? source.fusionVariant + 1 : 0);
this.usedTMs = source.usedTMs ?? [];
this.mysteryEncounterPokemonData = source.mysteryEncounterPokemonData ?? new MysteryEncounterPokemonData();
this.mysteryEncounterPokemonData = new MysteryEncounterPokemonData(source.mysteryEncounterPokemonData);
if (!forHistory) {
this.boss = (source instanceof EnemyPokemon && !!source.bossSegments) || (!this.player && !!source.boss);

View File

@ -39,6 +39,8 @@ describe("Berries Abound - Mystery Encounter", () => {
game.override.startingWave(defaultWave);
game.override.startingBiome(defaultBiome);
game.override.disableTrainerWaves();
game.override.startingModifier([]);
game.override.startingHeldItems([]);
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(
new Map<Biome, MysteryEncounterType[]>([
@ -130,11 +132,15 @@ describe("Berries Abound - Mystery Encounter", () => {
expect(enemyField[0].species.speciesId).toBe(speciesToSpawn);
});
it("should reward the player with X berries based on wave", { retry: 5 }, async () => {
it("should reward the player with X berries based on wave", async () => {
await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty);
const numBerries = game.scene.currentBattle.mysteryEncounter!.misc.numBerries;
scene.modifiers = [];
// Clear out any pesky mods that slipped through test spin-up
scene.modifiers.forEach(mod => {
scene.removeModifier(mod);
});
await runMysteryEncounterToEnd(game, 1, undefined, true);
await skipBattleRunMysteryEncounterRewardsPhase(game);

View File

@ -165,7 +165,7 @@ describe("Global Trade System - Mystery Encounter", () => {
});
});
it("Should trade a Pokemon from the player's party for the a random wonder trade Pokemon", async () => {
it("Should trade a Pokemon from the player's party for a random wonder trade Pokemon", async () => {
await game.runToMysteryEncounter(MysteryEncounterType.GLOBAL_TRADE_SYSTEM, defaultParty);
const speciesBefore = scene.getParty()[2].species.speciesId;

View File

@ -121,7 +121,7 @@ describe("The Strong Stuff - Mystery Encounter", () => {
species: getPokemonSpecies(Species.SHUCKLE),
isBoss: true,
bossSegments: 5,
mysteryEncounterPokemonData: new MysteryEncounterPokemonData(1.25),
mysteryEncounterPokemonData: new MysteryEncounterPokemonData({ spriteScale: 1.25 }),
nature: Nature.BOLD,
moveSet: [Moves.INFESTATION, Moves.SALT_CURE, Moves.GASTRO_ACID, Moves.HEAL_ORDER],
modifierConfigs: expect.any(Array),

View File

@ -164,9 +164,9 @@ describe("Uncommon Breed - Mystery Encounter", () => {
});
it("should NOT be selectable if the player doesn't have enough berries", async () => {
game.override.startingHeldItems([]);
await game.runToMysteryEncounter(MysteryEncounterType.UNCOMMON_BREED, defaultParty);
await game.phaseInterceptor.to(MysteryEncounterPhase, false);
game.scene.modifiers = [];
const encounterPhase = scene.getCurrentPhase();
expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name);