mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2024-12-04 12:46:10 +00:00
first implementation pass at clowning around
This commit is contained in:
parent
6d2129a3f0
commit
afe1015094
1694
public/battle-anims/encounter-smokescreen.json
Normal file
1694
public/battle-anims/encounter-smokescreen.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -110,7 +110,8 @@ export enum CommonAnim {
|
|||||||
*/
|
*/
|
||||||
export enum EncounterAnim {
|
export enum EncounterAnim {
|
||||||
MAGMA_BG,
|
MAGMA_BG,
|
||||||
MAGMA_SPOUT
|
MAGMA_SPOUT,
|
||||||
|
SMOKESCREEN
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AnimConfig {
|
export class AnimConfig {
|
||||||
@ -533,16 +534,16 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
|
|||||||
export async function initEncounterAnims(scene: BattleScene, encounterAnim: EncounterAnim | EncounterAnim[]): Promise<void> {
|
export async function initEncounterAnims(scene: BattleScene, encounterAnim: EncounterAnim | EncounterAnim[]): Promise<void> {
|
||||||
const anims = Array.isArray(encounterAnim) ? encounterAnim : [encounterAnim];
|
const anims = Array.isArray(encounterAnim) ? encounterAnim : [encounterAnim];
|
||||||
const encounterAnimNames = Utils.getEnumKeys(EncounterAnim);
|
const encounterAnimNames = Utils.getEnumKeys(EncounterAnim);
|
||||||
const encounterAnimIds = Utils.getEnumValues(EncounterAnim);
|
// const encounterAnimIds = Utils.getEnumValues(EncounterAnim);
|
||||||
const encounterAnimFetches = [];
|
const encounterAnimFetches = [];
|
||||||
for (const anim of anims) {
|
for (const anim of anims) {
|
||||||
if (encounterAnims.has(anim) && !isNullOrUndefined(encounterAnims.get(anim))) {
|
if (encounterAnims.has(anim) && !isNullOrUndefined(encounterAnims.get(anim))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const encounterAnimId = encounterAnimIds[anim];
|
// const encounterAnimId = encounterAnimIds[anim];
|
||||||
encounterAnimFetches.push(scene.cachedFetch(`./battle-anims/encounter-${encounterAnimNames[anim].toLowerCase().replace(/\_/g, "-")}.json`)
|
encounterAnimFetches.push(scene.cachedFetch(`./battle-anims/encounter-${encounterAnimNames[anim].toLowerCase().replace(/\_/g, "-")}.json`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(cas => encounterAnims.set(encounterAnimId, new AnimConfig(cas))));
|
.then(cas => encounterAnims.set(anim, new AnimConfig(cas))));
|
||||||
}
|
}
|
||||||
await Promise.allSettled(encounterAnimFetches);
|
await Promise.allSettled(encounterAnimFetches);
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ export const AnOfferYouCantRefuseEncounter: IMysteryEncounter =
|
|||||||
const pokemon = getHighestStatTotalPlayerPokemon(scene, false);
|
const pokemon = getHighestStatTotalPlayerPokemon(scene, false);
|
||||||
const price = scene.getWaveMoneyAmount(10);
|
const price = scene.getWaveMoneyAmount(10);
|
||||||
|
|
||||||
encounter.setDialogueToken("strongestPokemon", pokemon.name);
|
encounter.setDialogueToken("strongestPokemon", pokemon.getNameToRender());
|
||||||
encounter.setDialogueToken("price", price.toString());
|
encounter.setDialogueToken("price", price.toString());
|
||||||
|
|
||||||
// Store pokemon and price
|
// Store pokemon and price
|
||||||
|
@ -1,181 +0,0 @@
|
|||||||
import {
|
|
||||||
EnemyPartyConfig,
|
|
||||||
initBattleWithEnemyConfig,
|
|
||||||
setEncounterRewards,
|
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
|
||||||
import {
|
|
||||||
trainerConfigs,
|
|
||||||
TrainerPartyCompoundTemplate,
|
|
||||||
TrainerPartyTemplate,
|
|
||||||
} from "#app/data/trainer-config";
|
|
||||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
|
||||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
|
||||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
|
||||||
import BattleScene from "#app/battle-scene";
|
|
||||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
|
||||||
import { Species } from "#enums/species";
|
|
||||||
import { TrainerType } from "#enums/trainer-type";
|
|
||||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
|
||||||
const namespace = "mysteryEncounter:clowningAround";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clowning Around encounter.
|
|
||||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/69 | GitHub Issue #69}
|
|
||||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
|
||||||
*/
|
|
||||||
export const ClowningAroundEncounter: IMysteryEncounter =
|
|
||||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.CLOWNING_AROUND)
|
|
||||||
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
|
||||||
.withSceneWaveRangeRequirement(10, 180) // waves 10 to 180
|
|
||||||
.withIntroSpriteConfigs([
|
|
||||||
{
|
|
||||||
spriteKey: Species.MR_MIME.toString(),
|
|
||||||
fileRoot: "pokemon",
|
|
||||||
hasShadow: true,
|
|
||||||
repeat: true,
|
|
||||||
x: -25,
|
|
||||||
tint: 0.3,
|
|
||||||
y: -3,
|
|
||||||
yShadow: -3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
spriteKey: Species.BLACEPHALON.toString(),
|
|
||||||
fileRoot: "pokemon/exp",
|
|
||||||
hasShadow: true,
|
|
||||||
repeat: true,
|
|
||||||
x: 25,
|
|
||||||
tint: 0.3,
|
|
||||||
y: -3,
|
|
||||||
yShadow: -3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
spriteKey: "harlequin",
|
|
||||||
fileRoot: "trainer",
|
|
||||||
hasShadow: true,
|
|
||||||
x: 0
|
|
||||||
},
|
|
||||||
])
|
|
||||||
.withIntroDialogue([
|
|
||||||
{
|
|
||||||
text: `${namespace}.intro`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: `${namespace}.intro_dialogue`,
|
|
||||||
speaker: `${namespace}.speaker`
|
|
||||||
},
|
|
||||||
])
|
|
||||||
.withOnInit((scene: BattleScene) => {
|
|
||||||
const encounter = scene.currentBattle.mysteryEncounter;
|
|
||||||
|
|
||||||
// Clown trainer is pulled from pool of boss trainers (gym leaders) for the biome
|
|
||||||
// They are given an E4 template team, so will be stronger than usual boss encounter and always have 6 mons
|
|
||||||
const clownTrainerType = TrainerType.HARLEQUIN;
|
|
||||||
const clownPartyTemplate = new TrainerPartyCompoundTemplate(
|
|
||||||
new TrainerPartyTemplate(1, PartyMemberStrength.STRONG),
|
|
||||||
new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER),
|
|
||||||
new TrainerPartyTemplate(1, PartyMemberStrength.STRONG));
|
|
||||||
const clownConfig = trainerConfigs[clownTrainerType].copy();
|
|
||||||
clownConfig.setPartyTemplates(clownPartyTemplate);
|
|
||||||
clownConfig.partyTemplateFunc = null; // Overrides party template func
|
|
||||||
|
|
||||||
encounter.enemyPartyConfigs.push({
|
|
||||||
trainerConfig: clownConfig,
|
|
||||||
pokemonConfigs: [ // Overrides first 2 pokemon to be Mr. Mime and Blacephalon
|
|
||||||
{
|
|
||||||
species: getPokemonSpecies(Species.MR_MIME),
|
|
||||||
isBoss: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
species: getPokemonSpecies(Species.BLACEPHALON),
|
|
||||||
isBoss: true
|
|
||||||
},
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
})
|
|
||||||
.withTitle(`${namespace}.title`)
|
|
||||||
.withDescription(`${namespace}.description`)
|
|
||||||
.withQuery(`${namespace}.query`)
|
|
||||||
.withSimpleOption(
|
|
||||||
{
|
|
||||||
buttonLabel: `${namespace}.option.1.label`,
|
|
||||||
buttonTooltip: `${namespace}.option.1.tooltip`,
|
|
||||||
selected: [
|
|
||||||
{
|
|
||||||
text: `${namespace}.option.selected`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
async (scene: BattleScene) => {
|
|
||||||
const encounter = scene.currentBattle.mysteryEncounter;
|
|
||||||
// Spawn battle
|
|
||||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
|
|
||||||
|
|
||||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM], fillRemaining: true });
|
|
||||||
await initBattleWithEnemyConfig(scene, config);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.withSimpleOption(
|
|
||||||
{
|
|
||||||
buttonLabel: `${namespace}.option.2.label`,
|
|
||||||
buttonTooltip: `${namespace}.option.2.tooltip`,
|
|
||||||
selected: [
|
|
||||||
{
|
|
||||||
text: `${namespace}.option.selected`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
async (scene: BattleScene) => {
|
|
||||||
const encounter = scene.currentBattle.mysteryEncounter;
|
|
||||||
// Spawn hard fight with ULTRA/GREAT reward (can improve with luck)
|
|
||||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1];
|
|
||||||
|
|
||||||
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], fillRemaining: true });
|
|
||||||
|
|
||||||
// Seed offsets to remove possibility of different trainers having exact same teams
|
|
||||||
let ret;
|
|
||||||
scene.executeWithSeedOffset(() => {
|
|
||||||
ret = initBattleWithEnemyConfig(scene, config);
|
|
||||||
}, scene.currentBattle.waveIndex * 100);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.withSimpleOption(
|
|
||||||
{
|
|
||||||
buttonLabel: `${namespace}.option.3.label`,
|
|
||||||
buttonTooltip: `${namespace}.option.3.tooltip`,
|
|
||||||
selected: [
|
|
||||||
{
|
|
||||||
text: `${namespace}.option.selected`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
async (scene: BattleScene) => {
|
|
||||||
const encounter = scene.currentBattle.mysteryEncounter;
|
|
||||||
// Spawn brutal fight with ROGUE/ULTRA/GREAT reward (can improve with luck)
|
|
||||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[2];
|
|
||||||
|
|
||||||
// To avoid player level snowballing from picking this option
|
|
||||||
encounter.expMultiplier = 0.9;
|
|
||||||
|
|
||||||
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT], fillRemaining: true });
|
|
||||||
|
|
||||||
// Seed offsets to remove possibility of different trainers having exact same teams
|
|
||||||
let ret;
|
|
||||||
scene.executeWithSeedOffset(() => {
|
|
||||||
ret = initBattleWithEnemyConfig(scene, config);
|
|
||||||
}, scene.currentBattle.waveIndex * 1000);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.withOutroDialogue([
|
|
||||||
{
|
|
||||||
text: `${namespace}.outro`,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
.build();
|
|
@ -0,0 +1,469 @@
|
|||||||
|
import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, loadCustomMovesForEncounter, selectPokemonForOption, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
|
import { trainerConfigs, TrainerPartyCompoundTemplate, TrainerPartyTemplate, } from "#app/data/trainer-config";
|
||||||
|
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||||
|
import { BerryModifierType, modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||||
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
|
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||||
|
import BattleScene from "#app/battle-scene";
|
||||||
|
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||||
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import { TrainerType } from "#enums/trainer-type";
|
||||||
|
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
|
import { Type } from "#app/data/type";
|
||||||
|
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
|
import { randSeedInt, randSeedShuffle } from "#app/utils";
|
||||||
|
import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
|
import { Mode } from "#app/ui/ui";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler";
|
||||||
|
import { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||||
|
import { Ability } from "#app/data/ability";
|
||||||
|
import { BerryModifier } from "#app/modifier/modifier";
|
||||||
|
import { BerryType } from "#enums/berry-type";
|
||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { EncounterAnim, EncounterBattleAnim } from "#app/data/battle-anims";
|
||||||
|
import { MoveCategory } from "#app/data/move";
|
||||||
|
import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/mystery-encounter-pokemon-data";
|
||||||
|
|
||||||
|
/** the i18n namespace for the encounter */
|
||||||
|
const namespace = "mysteryEncounter:clowningAround";
|
||||||
|
|
||||||
|
const RANDOM_ABILITY_POOL = [
|
||||||
|
Abilities.STURDY,
|
||||||
|
Abilities.PICKUP,
|
||||||
|
Abilities.INTIMIDATE,
|
||||||
|
Abilities.GUTS,
|
||||||
|
Abilities.DROUGHT,
|
||||||
|
Abilities.DRIZZLE,
|
||||||
|
Abilities.SNOW_WARNING,
|
||||||
|
Abilities.SAND_STREAM,
|
||||||
|
Abilities.ELECTRIC_SURGE,
|
||||||
|
Abilities.PSYCHIC_SURGE,
|
||||||
|
Abilities.GRASSY_SURGE,
|
||||||
|
Abilities.MISTY_SURGE,
|
||||||
|
Abilities.MAGICIAN,
|
||||||
|
Abilities.SHEER_FORCE,
|
||||||
|
Abilities.PRANKSTER
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clowning Around encounter.
|
||||||
|
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/69 | GitHub Issue #69}
|
||||||
|
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||||
|
*/
|
||||||
|
export const ClowningAroundEncounter: IMysteryEncounter =
|
||||||
|
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.CLOWNING_AROUND)
|
||||||
|
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
||||||
|
.withSceneWaveRangeRequirement(80, 180)
|
||||||
|
.withAnimations(EncounterAnim.SMOKESCREEN)
|
||||||
|
.withAutoHideIntroVisuals(false)
|
||||||
|
.withIntroSpriteConfigs([
|
||||||
|
{
|
||||||
|
spriteKey: Species.MR_MIME.toString(),
|
||||||
|
fileRoot: "pokemon",
|
||||||
|
hasShadow: true,
|
||||||
|
repeat: true,
|
||||||
|
x: -25,
|
||||||
|
tint: 0.3,
|
||||||
|
y: -3,
|
||||||
|
yShadow: -3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spriteKey: Species.BLACEPHALON.toString(),
|
||||||
|
fileRoot: "pokemon/exp",
|
||||||
|
hasShadow: true,
|
||||||
|
repeat: true,
|
||||||
|
x: 25,
|
||||||
|
tint: 0.3,
|
||||||
|
y: -3,
|
||||||
|
yShadow: -3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spriteKey: "harlequin",
|
||||||
|
fileRoot: "trainer",
|
||||||
|
hasShadow: true,
|
||||||
|
x: 0,
|
||||||
|
y: 2,
|
||||||
|
yShadow: 2
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.withIntroDialogue([
|
||||||
|
{
|
||||||
|
text: `${namespace}.intro`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: `${namespace}.intro_dialogue`,
|
||||||
|
speaker: `${namespace}.speaker`
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.withOnInit((scene: BattleScene) => {
|
||||||
|
const encounter = scene.currentBattle.mysteryEncounter;
|
||||||
|
|
||||||
|
// Clown trainer is pulled from pool of boss trainers (gym leaders) for the biome
|
||||||
|
// They are given an E4 template team, so will be stronger than usual boss encounter and always have 6 mons
|
||||||
|
const clownTrainerType = TrainerType.HARLEQUIN;
|
||||||
|
const clownPartyTemplate = new TrainerPartyCompoundTemplate(
|
||||||
|
new TrainerPartyTemplate(1, PartyMemberStrength.STRONG),
|
||||||
|
new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER));
|
||||||
|
const clownConfig = trainerConfigs[clownTrainerType].copy();
|
||||||
|
clownConfig.setPartyTemplates(clownPartyTemplate);
|
||||||
|
clownConfig.setDoubleOnly();
|
||||||
|
clownConfig.partyTemplateFunc = null; // Overrides party template func
|
||||||
|
|
||||||
|
// Generate random ability for Blacephalon from pool
|
||||||
|
const ability = RANDOM_ABILITY_POOL[randSeedInt(RANDOM_ABILITY_POOL.length)];
|
||||||
|
encounter.setDialogueToken("ability", new Ability(ability, 3).name);
|
||||||
|
encounter.misc = { ability };
|
||||||
|
|
||||||
|
encounter.enemyPartyConfigs.push({
|
||||||
|
trainerConfig: clownConfig,
|
||||||
|
pokemonConfigs: [ // Overrides first 2 pokemon to be Mr. Mime and Blacephalon
|
||||||
|
{
|
||||||
|
species: getPokemonSpecies(Species.MR_MIME),
|
||||||
|
isBoss: true,
|
||||||
|
moveSet: [Moves.TEETER_DANCE, Moves.ALLY_SWITCH, Moves.DAZZLING_GLEAM, Moves.PSYCHIC]
|
||||||
|
},
|
||||||
|
{ // Blacephalon has the random ability from pool, and 2 entirely random types to fit with the theme of the encounter
|
||||||
|
species: getPokemonSpecies(Species.BLACEPHALON),
|
||||||
|
ability: ability,
|
||||||
|
mysteryEncounterData: new MysteryEncounterPokemonData(null, null, null, [randSeedInt(18), randSeedInt(18)]),
|
||||||
|
isBoss: true,
|
||||||
|
moveSet: [Moves.TRICK, Moves.HYPNOSIS, Moves.SHADOW_BALL, Moves.MIND_BLOWN]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
doubleBattle: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load animations/sfx for start of fight moves
|
||||||
|
loadCustomMovesForEncounter(scene, [Moves.ROLE_PLAY, Moves.TAUNT]);
|
||||||
|
|
||||||
|
// These have to be defined at runtime so that modifierTypes exist
|
||||||
|
encounter.misc.RANDOM_ULTRA_POOL = [
|
||||||
|
modifierTypes.REVIVER_SEED,
|
||||||
|
modifierTypes.GOLDEN_PUNCH,
|
||||||
|
modifierTypes.ATTACK_TYPE_BOOSTER,
|
||||||
|
modifierTypes.QUICK_CLAW,
|
||||||
|
modifierTypes.WIDE_LENS,
|
||||||
|
modifierTypes.WHITE_HERB
|
||||||
|
];
|
||||||
|
|
||||||
|
encounter.misc.RANDOM_ROGUE_POOL = [
|
||||||
|
modifierTypes.LEFTOVERS,
|
||||||
|
modifierTypes.SHELL_BELL,
|
||||||
|
modifierTypes.SOUL_DEW,
|
||||||
|
modifierTypes.SOOTHE_BELL,
|
||||||
|
modifierTypes.SCOPE_LENS,
|
||||||
|
modifierTypes.BATON,
|
||||||
|
modifierTypes.FOCUS_BAND,
|
||||||
|
modifierTypes.KINGS_ROCK,
|
||||||
|
modifierTypes.GRIP_CLAW
|
||||||
|
];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.withTitle(`${namespace}.title`)
|
||||||
|
.withDescription(`${namespace}.description`)
|
||||||
|
.withQuery(`${namespace}.query`)
|
||||||
|
.withOption(
|
||||||
|
new MysteryEncounterOptionBuilder()
|
||||||
|
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||||
|
.withDialogue({
|
||||||
|
buttonLabel: `${namespace}.option.1.label`,
|
||||||
|
buttonTooltip: `${namespace}.option.1.tooltip`,
|
||||||
|
selected: [
|
||||||
|
{
|
||||||
|
text: `${namespace}.option.1.selected`,
|
||||||
|
speaker: `${namespace}.speaker`
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.withOptionPhase(async (scene: BattleScene) => {
|
||||||
|
const encounter = scene.currentBattle.mysteryEncounter;
|
||||||
|
// Spawn battle
|
||||||
|
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
|
||||||
|
|
||||||
|
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM], fillRemaining: true });
|
||||||
|
|
||||||
|
// TODO: when Magic Room and Wonder Room are implemented, add those to start of battle
|
||||||
|
encounter.startOfBattleEffects.push(
|
||||||
|
{ // Mr. Mime copies the Blacephalon's random ability
|
||||||
|
sourceBattlerIndex: BattlerIndex.ENEMY,
|
||||||
|
targets: [BattlerIndex.ENEMY_2],
|
||||||
|
move: new PokemonMove(Moves.ROLE_PLAY),
|
||||||
|
ignorePp: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sourceBattlerIndex: BattlerIndex.ENEMY_2,
|
||||||
|
targets: [BattlerIndex.PLAYER],
|
||||||
|
move: new PokemonMove(Moves.TAUNT),
|
||||||
|
ignorePp: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sourceBattlerIndex: BattlerIndex.ENEMY_2,
|
||||||
|
targets: [BattlerIndex.PLAYER_2],
|
||||||
|
move: new PokemonMove(Moves.TAUNT),
|
||||||
|
ignorePp: true
|
||||||
|
});
|
||||||
|
|
||||||
|
await transitionMysteryEncounterIntroVisuals(scene);
|
||||||
|
await initBattleWithEnemyConfig(scene, config);
|
||||||
|
})
|
||||||
|
.withPostOptionPhase(async (scene: BattleScene): Promise<boolean> => {
|
||||||
|
// After the battle, offer the player the opportunity to permanently swap ability
|
||||||
|
const abilityWasSwapped = await handleSwapAbility(scene);
|
||||||
|
if (abilityWasSwapped) {
|
||||||
|
await scene.ui.setMode(Mode.MESSAGE);
|
||||||
|
await showEncounterText(scene, `${namespace}.option.1.ability_gained`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play animations once ability swap is complete
|
||||||
|
// Trainer sprite that is shown at end of battle is not the same as mystery encounter intro visuals
|
||||||
|
scene.tweens.add({
|
||||||
|
targets: scene.currentBattle.trainer,
|
||||||
|
x: "+=16",
|
||||||
|
y: "-=16",
|
||||||
|
alpha: 0,
|
||||||
|
ease: "Sine.easeInOut",
|
||||||
|
duration: 250
|
||||||
|
});
|
||||||
|
const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, scene.getPlayerPokemon(), scene.getPlayerPokemon());
|
||||||
|
background.playWithoutTargets(scene, 230, 40, 2);
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.withOption(
|
||||||
|
new MysteryEncounterOptionBuilder()
|
||||||
|
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||||
|
.withDialogue({
|
||||||
|
buttonLabel: `${namespace}.option.2.label`,
|
||||||
|
buttonTooltip: `${namespace}.option.2.tooltip`,
|
||||||
|
selected: [
|
||||||
|
{
|
||||||
|
text: `${namespace}.option.2.selected`,
|
||||||
|
speaker: `${namespace}.speaker`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: `${namespace}.option.2.selected_2`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: `${namespace}.option.2.selected_3`,
|
||||||
|
speaker: `${namespace}.speaker`
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||||
|
// Swap player's items on pokemon with the most items
|
||||||
|
// Item comparisons look at whichever Pokemon has the greatest number of TRANSFERABLE, non-berry items
|
||||||
|
// So Vitamins, form change items, etc. are not included
|
||||||
|
const encounter = scene.currentBattle.mysteryEncounter;
|
||||||
|
|
||||||
|
const party = scene.getParty();
|
||||||
|
let mostHeldItemsPokemon = party[0];
|
||||||
|
let count = mostHeldItemsPokemon.getHeldItems()
|
||||||
|
.filter(m => m.isTransferrable && !(m instanceof BerryModifier))
|
||||||
|
.reduce((v, m) => v + m.stackCount, 0);
|
||||||
|
|
||||||
|
party.forEach(pokemon => {
|
||||||
|
const nextCount = pokemon.getHeldItems()
|
||||||
|
.filter(m => m.isTransferrable && !(m instanceof BerryModifier))
|
||||||
|
.reduce((v, m) => v + m.stackCount, 0);
|
||||||
|
if (nextCount > count) {
|
||||||
|
mostHeldItemsPokemon = pokemon;
|
||||||
|
count = nextCount;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
encounter.setDialogueToken("switchPokemon", mostHeldItemsPokemon.getNameToRender());
|
||||||
|
|
||||||
|
const items = mostHeldItemsPokemon.getHeldItems();
|
||||||
|
|
||||||
|
// Shuffles Berries (if they have any)
|
||||||
|
const berries = items.filter(m => m instanceof BerryModifier);
|
||||||
|
|
||||||
|
berries.forEach(berry => {
|
||||||
|
const stackCount = berry.stackCount;
|
||||||
|
scene.removeModifier(berry);
|
||||||
|
const newBerry = generateModifierTypeOption(scene, modifierTypes.BERRY, [randSeedInt(Object.keys(BerryType).filter(s => !isNaN(Number(s))).length) as BerryType]).type as BerryModifierType;
|
||||||
|
for (let i = 0; i < stackCount; i++) {
|
||||||
|
applyModifierTypeToPlayerPokemon(scene, mostHeldItemsPokemon, newBerry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Shuffle Transferable held items in the same tier (only shuffles Ultra and Rogue atm)
|
||||||
|
const transferableItems = items.filter(m => m.isTransferrable && !(m instanceof BerryModifier));
|
||||||
|
|
||||||
|
transferableItems.forEach(transferableItem => {
|
||||||
|
const stackCount = transferableItem.stackCount;
|
||||||
|
transferableItem.type.withTierFromPool();
|
||||||
|
|
||||||
|
// Lucky Eggs and other items that do not appear in item pools are treated as Ultra rarity
|
||||||
|
const tier = transferableItem.type.tier ?? ModifierTier.ULTRA;
|
||||||
|
|
||||||
|
if (tier === ModifierTier.ULTRA) {
|
||||||
|
scene.removeModifier(transferableItem);
|
||||||
|
for (let i = 0; i < stackCount; i++) {
|
||||||
|
const newItemType = encounter.misc.RANDOM_ULTRA_POOL[randSeedInt(encounter.misc.RANDOM_ULTRA_POOL.length)];
|
||||||
|
const newMod = generateModifierTypeOption(scene, newItemType).type as PokemonHeldItemModifierType;
|
||||||
|
applyModifierTypeToPlayerPokemon(scene, mostHeldItemsPokemon, newMod);
|
||||||
|
}
|
||||||
|
} else if (tier === ModifierTier.ROGUE) {
|
||||||
|
scene.removeModifier(transferableItem);
|
||||||
|
for (let i = 0; i < stackCount; i++) {
|
||||||
|
const newItemType = encounter.misc.RANDOM_ROGUE_POOL[randSeedInt(encounter.misc.RANDOM_ROGUE_POOL.length)];
|
||||||
|
const newMod = generateModifierTypeOption(scene, newItemType).type as PokemonHeldItemModifierType;
|
||||||
|
applyModifierTypeToPlayerPokemon(scene, mostHeldItemsPokemon, newMod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
.withOptionPhase(async (scene: BattleScene) => {
|
||||||
|
leaveEncounterWithoutBattle(scene, true);
|
||||||
|
})
|
||||||
|
.withPostOptionPhase(async (scene: BattleScene) => {
|
||||||
|
// Play animations
|
||||||
|
const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, scene.getPlayerPokemon(), scene.getPlayerPokemon());
|
||||||
|
background.playWithoutTargets(scene, 230, 40, 2);
|
||||||
|
await transitionMysteryEncounterIntroVisuals(scene);
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.withOption(
|
||||||
|
new MysteryEncounterOptionBuilder()
|
||||||
|
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||||
|
.withDialogue({
|
||||||
|
buttonLabel: `${namespace}.option.3.label`,
|
||||||
|
buttonTooltip: `${namespace}.option.3.tooltip`,
|
||||||
|
selected: [
|
||||||
|
{
|
||||||
|
text: `${namespace}.option.3.selected`,
|
||||||
|
speaker: `${namespace}.speaker`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: `${namespace}.option.3.selected_2`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: `${namespace}.option.3.selected_3`,
|
||||||
|
speaker: `${namespace}.speaker`
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.withPreOptionPhase(async (scene: BattleScene) => {
|
||||||
|
// Swap player's types on all party pokemon
|
||||||
|
// If a Pokemon had a single type prior, they will still have a single type after
|
||||||
|
for (const pokemon of scene.getParty()) {
|
||||||
|
const originalTypes = pokemon.getTypes(false, false, true);
|
||||||
|
|
||||||
|
// If the Pokemon has non-status moves that don't match the Pokemon's type, prioritizes those as the new type
|
||||||
|
// Makes the "randomness" of the shuffle slightly less punishing
|
||||||
|
let priorityTypes = pokemon.moveset
|
||||||
|
.filter(move => !originalTypes.includes(move.getMove().type) && move.getMove().category !== MoveCategory.STATUS)
|
||||||
|
.map(move => move.getMove().type);
|
||||||
|
if (priorityTypes?.length > 0) {
|
||||||
|
priorityTypes = [...new Set(priorityTypes)];
|
||||||
|
randSeedShuffle(priorityTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
let newTypes;
|
||||||
|
if (!originalTypes || originalTypes.length < 1) {
|
||||||
|
newTypes = priorityTypes?.length > 0 ? [priorityTypes.pop()] : [(randSeedInt(18) as Type)];
|
||||||
|
} else {
|
||||||
|
newTypes = originalTypes.map(m => {
|
||||||
|
if (priorityTypes?.length > 0) {
|
||||||
|
const ret = priorityTypes.pop();
|
||||||
|
randSeedShuffle(priorityTypes);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return randSeedInt(18) as Type;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pokemon.mysteryEncounterData) {
|
||||||
|
pokemon.mysteryEncounterData = new MysteryEncounterPokemonData(null, null, null, newTypes);
|
||||||
|
} else {
|
||||||
|
pokemon.mysteryEncounterData.types = newTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.withOptionPhase(async (scene: BattleScene) => {
|
||||||
|
leaveEncounterWithoutBattle(scene, true);
|
||||||
|
})
|
||||||
|
.withPostOptionPhase(async (scene: BattleScene) => {
|
||||||
|
// Play animations
|
||||||
|
const background = new EncounterBattleAnim(EncounterAnim.SMOKESCREEN, scene.getPlayerPokemon(), scene.getPlayerPokemon());
|
||||||
|
background.playWithoutTargets(scene, 230, 40, 2);
|
||||||
|
await transitionMysteryEncounterIntroVisuals(scene);
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.withOutroDialogue([
|
||||||
|
{
|
||||||
|
text: `${namespace}.outro`,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.build();
|
||||||
|
|
||||||
|
async function handleSwapAbility(scene: BattleScene) {
|
||||||
|
return new Promise<boolean>(async resolve => {
|
||||||
|
await showEncounterDialogue(scene, `${namespace}.option.1.apply_ability_dialogue`, `${namespace}.speaker`);
|
||||||
|
await showEncounterText(scene, `${namespace}.option.1.apply_ability_message`);
|
||||||
|
|
||||||
|
scene.ui.setMode(Mode.MESSAGE).then(() => {
|
||||||
|
displayYesNoOptions(scene, resolve);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayYesNoOptions(scene: BattleScene, resolve) {
|
||||||
|
showEncounterText(scene, `${namespace}.option.1.ability_prompt`, 500, false);
|
||||||
|
const fullOptions = [
|
||||||
|
{
|
||||||
|
label: i18next.t("menu:yes"),
|
||||||
|
handler: () => {
|
||||||
|
onYesAbilitySwap(scene, resolve);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: i18next.t("menu:no"),
|
||||||
|
handler: () => {
|
||||||
|
resolve(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const config: OptionSelectConfig = {
|
||||||
|
options: fullOptions,
|
||||||
|
maxOptions: 7,
|
||||||
|
yOffset: 0
|
||||||
|
};
|
||||||
|
scene.ui.setModeWithoutClear(Mode.OPTION_SELECT, config, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onYesAbilitySwap(scene: BattleScene, resolve) {
|
||||||
|
const onPokemonSelected = (pokemon: PlayerPokemon) => {
|
||||||
|
// Do ability swap
|
||||||
|
if (!pokemon.mysteryEncounterData) {
|
||||||
|
pokemon.mysteryEncounterData = new MysteryEncounterPokemonData(null, Abilities.AERILATE);
|
||||||
|
}
|
||||||
|
pokemon.mysteryEncounterData.ability = scene.currentBattle.mysteryEncounter.misc.ability;
|
||||||
|
scene.currentBattle.mysteryEncounter.setDialogueToken("chosenPokemon", pokemon.getNameToRender());
|
||||||
|
resolve(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPokemonNotSelected = () => {
|
||||||
|
scene.ui.setMode(Mode.MESSAGE).then(() => {
|
||||||
|
displayYesNoOptions(scene, resolve);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
selectPokemonForOption(scene, onPokemonSelected, onPokemonNotSelected);
|
||||||
|
}
|
@ -127,7 +127,7 @@ export const DarkDealEncounter: IMysteryEncounter =
|
|||||||
const removedPokemon = getRandomPlayerPokemon(scene, false, true);
|
const removedPokemon = getRandomPlayerPokemon(scene, false, true);
|
||||||
scene.removePokemonFromPlayerParty(removedPokemon);
|
scene.removePokemonFromPlayerParty(removedPokemon);
|
||||||
|
|
||||||
scene.currentBattle.mysteryEncounter.setDialogueToken("pokeName", removedPokemon.name);
|
scene.currentBattle.mysteryEncounter.setDialogueToken("pokeName", removedPokemon.getNameToRender());
|
||||||
|
|
||||||
// Store removed pokemon types
|
// Store removed pokemon types
|
||||||
scene.currentBattle.mysteryEncounter.misc = [
|
scene.currentBattle.mysteryEncounter.misc = [
|
||||||
|
@ -95,7 +95,7 @@ export const FieldTripEncounter: IMysteryEncounter =
|
|||||||
];
|
];
|
||||||
setEncounterExp(scene, scene.getParty().map((p) => p.id), 50);
|
setEncounterExp(scene, scene.getParty().map((p) => p.id), 50);
|
||||||
} else {
|
} else {
|
||||||
encounter.setDialogueToken("pokeName", pokemon.name);
|
encounter.setDialogueToken("pokeName", pokemon.getNameToRender());
|
||||||
encounter.setDialogueToken("move", move.getName());
|
encounter.setDialogueToken("move", move.getName());
|
||||||
encounter.options[0].dialogue.selected = [
|
encounter.options[0].dialogue.selected = [
|
||||||
{
|
{
|
||||||
@ -187,7 +187,7 @@ export const FieldTripEncounter: IMysteryEncounter =
|
|||||||
];
|
];
|
||||||
setEncounterExp(scene, scene.getParty().map((p) => p.id), 50);
|
setEncounterExp(scene, scene.getParty().map((p) => p.id), 50);
|
||||||
} else {
|
} else {
|
||||||
encounter.setDialogueToken("pokeName", pokemon.name);
|
encounter.setDialogueToken("pokeName", pokemon.getNameToRender());
|
||||||
encounter.setDialogueToken("move", move.getName());
|
encounter.setDialogueToken("move", move.getName());
|
||||||
encounter.options[1].dialogue.selected = [
|
encounter.options[1].dialogue.selected = [
|
||||||
{
|
{
|
||||||
@ -273,7 +273,7 @@ export const FieldTripEncounter: IMysteryEncounter =
|
|||||||
];
|
];
|
||||||
setEncounterExp(scene, scene.getParty().map((p) => p.id), 50);
|
setEncounterExp(scene, scene.getParty().map((p) => p.id), 50);
|
||||||
} else {
|
} else {
|
||||||
encounter.setDialogueToken("pokeName", pokemon.name);
|
encounter.setDialogueToken("pokeName", pokemon.getNameToRender());
|
||||||
encounter.setDialogueToken("move", move.getName());
|
encounter.setDialogueToken("move", move.getName());
|
||||||
encounter.options[2].dialogue.selected = [
|
encounter.options[2].dialogue.selected = [
|
||||||
{
|
{
|
||||||
|
@ -191,7 +191,7 @@ export const FieryFalloutEncounter: IMysteryEncounter =
|
|||||||
const chosenPokemon = burnable[roll];
|
const chosenPokemon = burnable[roll];
|
||||||
if (chosenPokemon.trySetStatus(StatusEffect.BURN)) {
|
if (chosenPokemon.trySetStatus(StatusEffect.BURN)) {
|
||||||
// Burn applied
|
// Burn applied
|
||||||
encounter.setDialogueToken("burnedPokemon", chosenPokemon.name);
|
encounter.setDialogueToken("burnedPokemon", chosenPokemon.getNameToRender());
|
||||||
queueEncounterMessage(scene, `${namespace}.option.2.target_burned`);
|
queueEncounterMessage(scene, `${namespace}.option.2.target_burned`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,7 +245,7 @@ function giveLeadPokemonCharcoal(scene: BattleScene) {
|
|||||||
if (leadPokemon) {
|
if (leadPokemon) {
|
||||||
const charcoal = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.FIRE]).type as AttackTypeBoosterModifierType;
|
const charcoal = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.FIRE]).type as AttackTypeBoosterModifierType;
|
||||||
applyModifierTypeToPlayerPokemon(scene, leadPokemon, charcoal);
|
applyModifierTypeToPlayerPokemon(scene, leadPokemon, charcoal);
|
||||||
scene.currentBattle.mysteryEncounter.setDialogueToken("leadPokemon", leadPokemon.name);
|
scene.currentBattle.mysteryEncounter.setDialogueToken("leadPokemon", leadPokemon.getNameToRender());
|
||||||
queueEncounterMessage(scene, `${namespace}.found_charcoal`);
|
queueEncounterMessage(scene, `${namespace}.found_charcoal`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ export const MysteriousChestEncounter: IMysteryEncounter =
|
|||||||
);
|
);
|
||||||
koPlayerPokemon(scene, highestLevelPokemon);
|
koPlayerPokemon(scene, highestLevelPokemon);
|
||||||
|
|
||||||
scene.currentBattle.mysteryEncounter.setDialogueToken("pokeName", highestLevelPokemon.name);
|
scene.currentBattle.mysteryEncounter.setDialogueToken("pokeName", highestLevelPokemon.getNameToRender());
|
||||||
// Show which Pokemon was KOed, then leave encounter with no rewards
|
// Show which Pokemon was KOed, then leave encounter with no rewards
|
||||||
// Does this synchronously so that game over doesn't happen over result message
|
// Does this synchronously so that game over doesn't happen over result message
|
||||||
await showEncounterText(scene, `${namespace}.option.1.bad`).then(() => {
|
await showEncounterText(scene, `${namespace}.option.1.bad`).then(() => {
|
||||||
|
@ -92,7 +92,7 @@ export const ThePokemonSalesmanEncounter: IMysteryEncounter =
|
|||||||
encounter.options[0].dialogue.buttonTooltip = `${namespace}.option.1.tooltip_shiny`;
|
encounter.options[0].dialogue.buttonTooltip = `${namespace}.option.1.tooltip_shiny`;
|
||||||
}
|
}
|
||||||
const price = scene.getWaveMoneyAmount(priceMultiplier);
|
const price = scene.getWaveMoneyAmount(priceMultiplier);
|
||||||
encounter.setDialogueToken("purchasePokemon", pokemon.name);
|
encounter.setDialogueToken("purchasePokemon", pokemon.getNameToRender());
|
||||||
encounter.setDialogueToken("price", price.toString());
|
encounter.setDialogueToken("price", price.toString());
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
price: price,
|
price: price,
|
||||||
|
@ -16,6 +16,7 @@ import { BattleStat } from "#app/data/battle-stat";
|
|||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { BerryType } from "#enums/berry-type";
|
import { BerryType } from "#enums/berry-type";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
|
import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/mystery-encounter-pokemon-data";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounter:theStrongStuff";
|
const namespace = "mysteryEncounter:theStrongStuff";
|
||||||
@ -70,7 +71,7 @@ export const TheStrongStuffEncounter: IMysteryEncounter =
|
|||||||
species: getPokemonSpecies(Species.SHUCKLE),
|
species: getPokemonSpecies(Species.SHUCKLE),
|
||||||
isBoss: true,
|
isBoss: true,
|
||||||
bossSegments: 5,
|
bossSegments: 5,
|
||||||
spriteScale: 1.5,
|
mysteryEncounterData: new MysteryEncounterPokemonData(1.5),
|
||||||
nature: Nature.BOLD,
|
nature: Nature.BOLD,
|
||||||
moveSet: [Moves.INFESTATION, Moves.SALT_CURE, Moves.GASTRO_ACID, Moves.HEAL_ORDER],
|
moveSet: [Moves.INFESTATION, Moves.SALT_CURE, Moves.GASTRO_ACID, Moves.HEAL_ORDER],
|
||||||
modifierTypes: [
|
modifierTypes: [
|
||||||
@ -147,7 +148,7 @@ export const TheStrongStuffEncounter: IMysteryEncounter =
|
|||||||
modifyPlayerPokemonBST(pokemon, 10);
|
modifyPlayerPokemonBST(pokemon, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
encounter.setDialogueToken("highBstPokemon", highestBst.name);
|
encounter.setDialogueToken("highBstPokemon", highestBst.getNameToRender());
|
||||||
await showEncounterText(scene, `${namespace}.option.1.selected_2`, null, true);
|
await showEncounterText(scene, `${namespace}.option.1.selected_2`, null, true);
|
||||||
|
|
||||||
setEncounterRewards(scene, { fillRemaining: true });
|
setEncounterRewards(scene, { fillRemaining: true });
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Type } from "#app/data/type";
|
||||||
|
|
||||||
|
export class MysteryEncounterPokemonData {
|
||||||
|
public spriteScale: number;
|
||||||
|
public ability: Abilities;
|
||||||
|
public passive: Abilities;
|
||||||
|
public types: Type[] = [];
|
||||||
|
|
||||||
|
constructor(spriteScale?: number, ability?: Abilities, passive?: Abilities, types?: Type[]) {
|
||||||
|
this.spriteScale = spriteScale;
|
||||||
|
this.ability = ability;
|
||||||
|
this.passive = passive;
|
||||||
|
this.types = types;
|
||||||
|
}
|
||||||
|
}
|
@ -305,7 +305,7 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.primaryPokemon?.length > 0) {
|
if (this.primaryPokemon?.length > 0) {
|
||||||
this.setDialogueToken("primaryName", this.primaryPokemon.name);
|
this.setDialogueToken("primaryName", this.primaryPokemon.getNameToRender());
|
||||||
for (const req of this.primaryPokemonRequirements) {
|
for (const req of this.primaryPokemonRequirements) {
|
||||||
if (!req.invertQuery) {
|
if (!req.invertQuery) {
|
||||||
const value = req.getDialogueToken(scene, this.primaryPokemon);
|
const value = req.getDialogueToken(scene, this.primaryPokemon);
|
||||||
@ -316,7 +316,7 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.secondaryPokemonRequirements?.length > 0 && this.secondaryPokemon?.length > 0) {
|
if (this.secondaryPokemonRequirements?.length > 0 && this.secondaryPokemon?.length > 0) {
|
||||||
this.setDialogueToken("secondaryName", this.secondaryPokemon[0].name);
|
this.setDialogueToken("secondaryName", this.secondaryPokemon[0].getNameToRender());
|
||||||
for (const req of this.secondaryPokemonRequirements) {
|
for (const req of this.secondaryPokemonRequirements) {
|
||||||
if (!req.invertQuery) {
|
if (!req.invertQuery) {
|
||||||
const value = req.getDialogueToken(scene, this.secondaryPokemon[0]);
|
const value = req.getDialogueToken(scene, this.secondaryPokemon[0]);
|
||||||
@ -342,7 +342,7 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (opt.primaryPokemonRequirements?.length > 0 && opt.primaryPokemon?.length > 0) {
|
if (opt.primaryPokemonRequirements?.length > 0 && opt.primaryPokemon?.length > 0) {
|
||||||
this.setDialogueToken("option" + j + "PrimaryName", opt.primaryPokemon.name);
|
this.setDialogueToken("option" + j + "PrimaryName", opt.primaryPokemon.getNameToRender());
|
||||||
for (const req of opt.primaryPokemonRequirements) {
|
for (const req of opt.primaryPokemonRequirements) {
|
||||||
if (!req.invertQuery) {
|
if (!req.invertQuery) {
|
||||||
const value = req.getDialogueToken(scene, opt.primaryPokemon);
|
const value = req.getDialogueToken(scene, opt.primaryPokemon);
|
||||||
@ -353,7 +353,7 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (opt.secondaryPokemonRequirements?.length > 0 && opt.secondaryPokemon?.length > 0) {
|
if (opt.secondaryPokemonRequirements?.length > 0 && opt.secondaryPokemon?.length > 0) {
|
||||||
this.setDialogueToken("option" + j + "SecondaryName", opt.secondaryPokemon[0].name);
|
this.setDialogueToken("option" + j + "SecondaryName", opt.secondaryPokemon[0].getNameToRender());
|
||||||
for (const req of opt.secondaryPokemonRequirements) {
|
for (const req of opt.secondaryPokemonRequirements) {
|
||||||
if (!req.invertQuery) {
|
if (!req.invertQuery) {
|
||||||
const value = req.getDialogueToken(scene, opt.secondaryPokemon[0]);
|
const value = req.getDialogueToken(scene, opt.secondaryPokemon[0]);
|
||||||
|
@ -21,7 +21,7 @@ import { AbsoluteAvariceEncounter } from "#app/data/mystery-encounters/encounter
|
|||||||
import { ATrainersTestEncounter } from "#app/data/mystery-encounters/encounters/a-trainers-test-encounter";
|
import { ATrainersTestEncounter } from "#app/data/mystery-encounters/encounters/a-trainers-test-encounter";
|
||||||
import { TrashToTreasureEncounter } from "#app/data/mystery-encounters/encounters/trash-to-treasure-encounter";
|
import { TrashToTreasureEncounter } from "#app/data/mystery-encounters/encounters/trash-to-treasure-encounter";
|
||||||
import { BerriesAboundEncounter } from "#app/data/mystery-encounters/encounters/berries-abound-encounter";
|
import { BerriesAboundEncounter } from "#app/data/mystery-encounters/encounters/berries-abound-encounter";
|
||||||
import { ClowningAroundEncounter } from "#app/data/mystery-encounters/encounters/clowing-around-encounter";
|
import { ClowningAroundEncounter } from "#app/data/mystery-encounters/encounters/clowning-around-encounter";
|
||||||
|
|
||||||
// Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * <number of missed spawns>) / 256
|
// Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * <number of missed spawns>) / 256
|
||||||
export const BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT = 1;
|
export const BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT = 1;
|
||||||
|
@ -30,6 +30,8 @@ import { TrainerConfig, trainerConfigs, TrainerSlot } from "#app/data/trainer-co
|
|||||||
import PokemonSpecies from "#app/data/pokemon-species";
|
import PokemonSpecies from "#app/data/pokemon-species";
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import { Egg, IEggOptions } from "#app/data/egg";
|
import { Egg, IEggOptions } from "#app/data/egg";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/mystery-encounter-pokemon-data";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Animates exclamation sprite over trainer's head at start of encounter
|
* Animates exclamation sprite over trainer's head at start of encounter
|
||||||
@ -63,7 +65,7 @@ export interface EnemyPokemonConfig {
|
|||||||
isBoss: boolean;
|
isBoss: boolean;
|
||||||
bossSegments?: number;
|
bossSegments?: number;
|
||||||
bossSegmentModifier?: number; // Additive to the determined segment number
|
bossSegmentModifier?: number; // Additive to the determined segment number
|
||||||
spriteScale?: number;
|
mysteryEncounterData?: MysteryEncounterPokemonData;
|
||||||
formIndex?: number;
|
formIndex?: number;
|
||||||
level?: number;
|
level?: number;
|
||||||
gender?: Gender;
|
gender?: Gender;
|
||||||
@ -71,6 +73,8 @@ export interface EnemyPokemonConfig {
|
|||||||
moveSet?: Moves[];
|
moveSet?: Moves[];
|
||||||
nature?: Nature;
|
nature?: Nature;
|
||||||
ivs?: [integer, integer, integer, integer, integer, integer];
|
ivs?: [integer, integer, integer, integer, integer, integer];
|
||||||
|
ability?: Abilities;
|
||||||
|
shiny?: boolean;
|
||||||
/** Can set just the status, or pass a timer on the status turns */
|
/** Can set just the status, or pass a timer on the status turns */
|
||||||
status?: StatusEffect | [StatusEffect, number];
|
status?: StatusEffect | [StatusEffect, number];
|
||||||
mysteryEncounterBattleEffects?: (pokemon: Pokemon) => void;
|
mysteryEncounterBattleEffects?: (pokemon: Pokemon) => void;
|
||||||
@ -210,11 +214,14 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
|||||||
enemyPokemon.formIndex = config.formIndex;
|
enemyPokemon.formIndex = config.formIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set scale
|
// Set shiny
|
||||||
if (!isNullOrUndefined(config.spriteScale)) {
|
if (!isNullOrUndefined(config.shiny)) {
|
||||||
enemyPokemon.mysteryEncounterData = {
|
enemyPokemon.shiny = config.shiny;
|
||||||
spriteScale: config.spriteScale
|
}
|
||||||
};
|
|
||||||
|
// Set custom mystery encounter data fields (such as sprite scale, custom abilities, types, etc.)
|
||||||
|
if (!isNullOrUndefined(config.mysteryEncounterData)) {
|
||||||
|
enemyPokemon.mysteryEncounterData = config.mysteryEncounterData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set Boss
|
// Set Boss
|
||||||
@ -252,6 +259,11 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
|||||||
|
|
||||||
// Set summon data fields
|
// Set summon data fields
|
||||||
|
|
||||||
|
// Set ability
|
||||||
|
if (!isNullOrUndefined(config.ability)) {
|
||||||
|
enemyPokemon.summonData.ability = config.ability;
|
||||||
|
}
|
||||||
|
|
||||||
// Set gender
|
// Set gender
|
||||||
if (!isNullOrUndefined(config.gender)) {
|
if (!isNullOrUndefined(config.gender)) {
|
||||||
enemyPokemon.gender = config.gender;
|
enemyPokemon.gender = config.gender;
|
||||||
@ -381,7 +393,7 @@ export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (p
|
|||||||
const pokemon = scene.getParty()[slotIndex];
|
const pokemon = scene.getParty()[slotIndex];
|
||||||
const secondaryOptions = onPokemonSelected(pokemon);
|
const secondaryOptions = onPokemonSelected(pokemon);
|
||||||
if (!secondaryOptions) {
|
if (!secondaryOptions) {
|
||||||
scene.currentBattle.mysteryEncounter.setDialogueToken("selectedPokemon", pokemon.name);
|
scene.currentBattle.mysteryEncounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
|
||||||
resolve(true);
|
resolve(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -395,7 +407,7 @@ export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (p
|
|||||||
const onSelect = option.handler;
|
const onSelect = option.handler;
|
||||||
option.handler = () => {
|
option.handler = () => {
|
||||||
onSelect();
|
onSelect();
|
||||||
scene.currentBattle.mysteryEncounter.setDialogueToken("selectedPokemon", pokemon.name);
|
scene.currentBattle.mysteryEncounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
|
||||||
resolve(true);
|
resolve(true);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -20,10 +20,6 @@ import { getPokemonNameWithAffix } from "#app/messages";
|
|||||||
import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||||
import { Gender } from "#app/data/gender";
|
import { Gender } from "#app/data/gender";
|
||||||
|
|
||||||
export interface MysteryEncounterPokemonData {
|
|
||||||
spriteScale?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getSpriteKeysFromSpecies(species: Species, female?: boolean, formIndex?: integer, shiny?: boolean, variant?: integer): { spriteKey: string, fileRoot: string } {
|
export function getSpriteKeysFromSpecies(species: Species, female?: boolean, formIndex?: integer, shiny?: boolean, variant?: integer): { spriteKey: string, fileRoot: string } {
|
||||||
const spriteKey = getPokemonSpecies(species).getSpriteKey(female ?? false, formIndex ?? 0, shiny ?? false, variant ?? 0);
|
const spriteKey = getPokemonSpecies(species).getSpriteKey(female ?? false, formIndex ?? 0, shiny ?? false, variant ?? 0);
|
||||||
const fileRoot = getPokemonSpecies(species).getSpriteAtlasPath(female ?? false, formIndex ?? 0, shiny ?? false, variant ?? 0);
|
const fileRoot = getPokemonSpecies(species).getSpriteAtlasPath(female ?? false, formIndex ?? 0, shiny ?? false, variant ?? 0);
|
||||||
@ -447,7 +443,7 @@ function failCatch(scene: BattleScene, pokemon: EnemyPokemon, originalY: number,
|
|||||||
scene.currentBattle.lastUsedPokeball = pokeballType;
|
scene.currentBattle.lastUsedPokeball = pokeballType;
|
||||||
removePb(scene, pokeball);
|
removePb(scene, pokeball);
|
||||||
|
|
||||||
scene.ui.showText(i18next.t("battle:pokemonBrokeFree", { pokemonName: pokemon.name }), null, () => resolve(), null, true);
|
scene.ui.showText(i18next.t("battle:pokemonBrokeFree", { pokemonName: pokemon.getNameToRender() }), null, () => resolve(), null, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,7 +512,7 @@ export async function catchPokemon(scene: BattleScene, pokemon: EnemyPokemon, po
|
|||||||
Promise.all([pokemon.hideInfo(), scene.gameData.setPokemonCaught(pokemon)]).then(() => {
|
Promise.all([pokemon.hideInfo(), scene.gameData.setPokemonCaught(pokemon)]).then(() => {
|
||||||
if (scene.getParty().length === 6) {
|
if (scene.getParty().length === 6) {
|
||||||
const promptRelease = () => {
|
const promptRelease = () => {
|
||||||
scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.name }), null, () => {
|
scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.getNameToRender() }), null, () => {
|
||||||
scene.pokemonInfoContainer.makeRoomForConfirmUi();
|
scene.pokemonInfoContainer.makeRoomForConfirmUi();
|
||||||
scene.ui.setMode(Mode.CONFIRM, () => {
|
scene.ui.setMode(Mode.CONFIRM, () => {
|
||||||
scene.ui.setMode(Mode.PARTY, PartyUiMode.RELEASE, 0, (slotIndex: integer, _option: PartyOption) => {
|
scene.ui.setMode(Mode.PARTY, PartyUiMode.RELEASE, 0, (slotIndex: integer, _option: PartyOption) => {
|
||||||
@ -544,7 +540,7 @@ export async function catchPokemon(scene: BattleScene, pokemon: EnemyPokemon, po
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (showCatchObtainMessage) {
|
if (showCatchObtainMessage) {
|
||||||
scene.ui.showText(i18next.t(isObtain ? "battle:pokemonObtained" : "battle:pokemonCaught", { pokemonName: pokemon.name }), null, doPokemonCatchMenu, 0, true);
|
scene.ui.showText(i18next.t(isObtain ? "battle:pokemonObtained" : "battle:pokemonCaught", { pokemonName: pokemon.getNameToRender() }), null, doPokemonCatchMenu, 0, true);
|
||||||
} else {
|
} else {
|
||||||
doPokemonCatchMenu();
|
doPokemonCatchMenu();
|
||||||
}
|
}
|
||||||
@ -581,7 +577,7 @@ export async function doPokemonFlee(scene: BattleScene, pokemon: EnemyPokemon):
|
|||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
pokemon.setVisible(false);
|
pokemon.setVisible(false);
|
||||||
scene.field.remove(pokemon, true);
|
scene.field.remove(pokemon, true);
|
||||||
showEncounterText(scene, i18next.t("battle:pokemonFled", { pokemonName: pokemon.name }), 600, false)
|
showEncounterText(scene, i18next.t("battle:pokemonFled", { pokemonName: pokemon.getNameToRender() }), 600, false)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
@ -604,7 +600,7 @@ export function doPlayerFlee(scene: BattleScene, pokemon: EnemyPokemon): Promise
|
|||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
pokemon.setVisible(false);
|
pokemon.setVisible(false);
|
||||||
scene.field.remove(pokemon, true);
|
scene.field.remove(pokemon, true);
|
||||||
showEncounterText(scene, i18next.t("battle:playerFled", { pokemonName: pokemon.name }), 600, false)
|
showEncounterText(scene, i18next.t("battle:playerFled", { pokemonName: pokemon.getNameToRender() }), 600, false)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
@ -64,5 +64,5 @@ export enum BattlerTagType {
|
|||||||
STOCKPILING = "STOCKPILING",
|
STOCKPILING = "STOCKPILING",
|
||||||
RECEIVE_DOUBLE_DAMAGE = "RECEIVE_DOUBLE_DAMAGE",
|
RECEIVE_DOUBLE_DAMAGE = "RECEIVE_DOUBLE_DAMAGE",
|
||||||
ALWAYS_GET_HIT = "ALWAYS_GET_HIT",
|
ALWAYS_GET_HIT = "ALWAYS_GET_HIT",
|
||||||
MYSTERY_ENCOUNTER_POST_SUMMON = "MYSTERY_ENCOUNTER_POST_SUMMON" // Provides effects on post-summon for MEs
|
MYSTERY_ENCOUNTER_POST_SUMMON = "MYSTERY_ENCOUNTER_POST_SUMMON", // Provides effects on post-summon for MEs
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ import { Biome } from "#enums/biome";
|
|||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages.js";
|
import { getPokemonNameWithAffix } from "#app/messages.js";
|
||||||
import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/mystery-encounter-pokemon-data";
|
||||||
|
|
||||||
export enum FieldPosition {
|
export enum FieldPosition {
|
||||||
CENTER,
|
CENTER,
|
||||||
@ -187,6 +187,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.fusionVariant = dataSource.fusionVariant || 0;
|
this.fusionVariant = dataSource.fusionVariant || 0;
|
||||||
this.fusionGender = dataSource.fusionGender;
|
this.fusionGender = dataSource.fusionGender;
|
||||||
this.fusionLuck = dataSource.fusionLuck;
|
this.fusionLuck = dataSource.fusionLuck;
|
||||||
|
this.mysteryEncounterData = dataSource.mysteryEncounterData;
|
||||||
} else {
|
} else {
|
||||||
this.id = Utils.randSeedInt(4294967296);
|
this.id = Utils.randSeedInt(4294967296);
|
||||||
this.ivs = ivs || Utils.getIvsFromId(this.id);
|
this.ivs = ivs || Utils.getIvsFromId(this.id);
|
||||||
@ -233,6 +234,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
this.luck = (this.shiny ? this.variant + 1 : 0) + (this.fusionShiny ? this.fusionVariant + 1 : 0);
|
this.luck = (this.shiny ? this.variant + 1 : 0) + (this.fusionShiny ? this.fusionVariant + 1 : 0);
|
||||||
this.fusionLuck = this.luck;
|
this.fusionLuck = this.luck;
|
||||||
|
this.mysteryEncounterData = new MysteryEncounterPokemonData();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.generateName();
|
this.generateName();
|
||||||
@ -927,7 +929,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!types.length || !includeTeraType) {
|
if (!types.length || !includeTeraType) {
|
||||||
if (!ignoreOverride && this.summonData?.types) {
|
if (this.mysteryEncounterData?.types?.length > 0) {
|
||||||
|
// "Permanent" override for a Pokemon's normal types, currently only used by Mystery Encounters
|
||||||
|
this.mysteryEncounterData.types.forEach(t => types.push(t));
|
||||||
|
} else if (!ignoreOverride && this.summonData?.types) {
|
||||||
this.summonData.types.forEach(t => types.push(t));
|
this.summonData.types.forEach(t => types.push(t));
|
||||||
} else {
|
} else {
|
||||||
const speciesForm = this.getSpeciesForm(ignoreOverride);
|
const speciesForm = this.getSpeciesForm(ignoreOverride);
|
||||||
@ -994,6 +999,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
if (Overrides.OPP_ABILITY_OVERRIDE && !this.isPlayer()) {
|
if (Overrides.OPP_ABILITY_OVERRIDE && !this.isPlayer()) {
|
||||||
return allAbilities[Overrides.OPP_ABILITY_OVERRIDE];
|
return allAbilities[Overrides.OPP_ABILITY_OVERRIDE];
|
||||||
}
|
}
|
||||||
|
if (this.mysteryEncounterData?.ability) {
|
||||||
|
return allAbilities[this.mysteryEncounterData.ability];
|
||||||
|
}
|
||||||
if (this.isFusion()) {
|
if (this.isFusion()) {
|
||||||
return allAbilities[this.getFusionSpeciesForm(ignoreOverride).getAbility(this.fusionAbilityIndex)];
|
return allAbilities[this.getFusionSpeciesForm(ignoreOverride).getAbility(this.fusionAbilityIndex)];
|
||||||
}
|
}
|
||||||
@ -1018,6 +1026,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
if (Overrides.OPP_PASSIVE_ABILITY_OVERRIDE && !this.isPlayer()) {
|
if (Overrides.OPP_PASSIVE_ABILITY_OVERRIDE && !this.isPlayer()) {
|
||||||
return allAbilities[Overrides.OPP_PASSIVE_ABILITY_OVERRIDE];
|
return allAbilities[Overrides.OPP_PASSIVE_ABILITY_OVERRIDE];
|
||||||
}
|
}
|
||||||
|
if (this.mysteryEncounterData?.passive) {
|
||||||
|
return allAbilities[this.mysteryEncounterData.passive];
|
||||||
|
}
|
||||||
|
|
||||||
let starterSpeciesId = this.species.speciesId;
|
let starterSpeciesId = this.species.speciesId;
|
||||||
while (pokemonPrevolutions.hasOwnProperty(starterSpeciesId)) {
|
while (pokemonPrevolutions.hasOwnProperty(starterSpeciesId)) {
|
||||||
@ -4059,6 +4070,7 @@ export class PokemonSummonData {
|
|||||||
public speciesForm: PokemonSpeciesForm;
|
public speciesForm: PokemonSpeciesForm;
|
||||||
public fusionSpeciesForm: PokemonSpeciesForm;
|
public fusionSpeciesForm: PokemonSpeciesForm;
|
||||||
public ability: Abilities = Abilities.NONE;
|
public ability: Abilities = Abilities.NONE;
|
||||||
|
public passiveAbility: Abilities = Abilities.NONE;
|
||||||
public gender: Gender;
|
public gender: Gender;
|
||||||
public fusionGender: Gender;
|
public fusionGender: Gender;
|
||||||
public stats: integer[];
|
public stats: integer[];
|
||||||
|
@ -1,31 +1,32 @@
|
|||||||
export const clowningAroundDialogue = {
|
export const clowningAroundDialogue = {
|
||||||
intro: "It's...@d{64} a clown?",
|
intro: "It's...@d{64} a clown?",
|
||||||
speaker: "Clown",
|
speaker: "Clown",
|
||||||
intro_dialogue: `Bumbling buffoon,\nbrace for a brilliant battle!
|
intro_dialogue: "Bumbling buffoon, brace for a brilliant battle!\nYou’ll be beaten by this brawling busker!",
|
||||||
$You’ll be beaten by this brawling busker!\nBring it!`,
|
|
||||||
title: "Clowning Around",
|
title: "Clowning Around",
|
||||||
description: "The clown seems eager to goad you into a battle, but to what end?\n\nSomething is off about this encounter.",
|
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.}",
|
||||||
query: "What will you do?",
|
query: "What will you do?",
|
||||||
option: {
|
option: {
|
||||||
1: {
|
1: {
|
||||||
label: "Battle the Clown",
|
label: "Battle the Clown",
|
||||||
tooltip: "(-) Strange Battle\n(?) Affects Pokémon Abilities",
|
tooltip: "(-) Strange Battle\n(?) Affects Pokémon Abilities",
|
||||||
selected: "Your pitiful Pokémon are poised for a pathetic performance!"
|
selected: "Your pitiful Pokémon are poised for a pathetic performance!",
|
||||||
|
apply_ability_dialogue: "A sensational showcase!\nYour savvy suits a sensational skill as spoils!",
|
||||||
|
apply_ability_message: "The clown is offering to permanently Skill Swap one of your Pokémon's ability to {{ability}}!",
|
||||||
|
ability_prompt: "Would you like to permanently teach a Pokémon the {{ability}} ability?",
|
||||||
|
ability_gained: "@s{level_up_fanfare}{{chosenPokemon}} gained the {{ability}} ability!"
|
||||||
},
|
},
|
||||||
2: {
|
2: {
|
||||||
label: "Remain Unprovoked",
|
label: "Remain Unprovoked",
|
||||||
tooltip: "(-) Upsets the Clown\n(?) Affects Pokémon Items",
|
tooltip: "(-) Upsets the Clown\n(?) Affects Pokémon Items",
|
||||||
selected: "Dismal dodger, you deny a delightful duel?\nFeel my fury!",
|
selected: "Dismal dodger, you deny a delightful duel?\nFeel my fury!",
|
||||||
selected_2: `The clown's Blacephalon uses Trick!
|
selected_2: "The clown's Blacephalon uses Trick!\nAll of your {{switchPokemon}}'s items were randomly swapped!",
|
||||||
All of your {{switchPokemon}}'s items were randomly swapped!`,
|
|
||||||
selected_3: "Flustered fool, fall for my flawless deception!",
|
selected_3: "Flustered fool, fall for my flawless deception!",
|
||||||
},
|
},
|
||||||
3: {
|
3: {
|
||||||
label: "Return the Insults",
|
label: "Return the Insults",
|
||||||
tooltip: "(-) Upsets the Clown\n(?) Affects Pokémon Types",
|
tooltip: "(-) Upsets the Clown\n(?) Affects Pokémon Types",
|
||||||
selected: "I'm appalled at your absurd antics!\nTaste my temper!",
|
selected: "Dismal dodger, you deny a delightful duel?\nFeel my fury!",
|
||||||
selected_2: `The clown's Blacephalon uses\na move you've never seen before!
|
selected_2: "The clown's Blacephalon uses a strange move!\nAll of your team's types were randomly swapped!",
|
||||||
All of your team's types were randomly swapped!`,
|
|
||||||
selected_3: "Flustered fool, fall for my flawless deception!",
|
selected_3: "Flustered fool, fall for my flawless deception!",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -127,9 +127,9 @@ class DefaultOverrides {
|
|||||||
// -------------------------
|
// -------------------------
|
||||||
|
|
||||||
// 1 to 256, set to null to ignore
|
// 1 to 256, set to null to ignore
|
||||||
readonly MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = 256;
|
readonly MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = null;
|
||||||
readonly MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier = null;
|
readonly MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier = null;
|
||||||
readonly MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = MysteryEncounterType.CLOWNING_AROUND;
|
readonly MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = null;
|
||||||
|
|
||||||
// -------------------------
|
// -------------------------
|
||||||
// MODIFIER / ITEM OVERRIDES
|
// MODIFIER / ITEM OVERRIDES
|
||||||
|
@ -1369,7 +1369,7 @@ export class PostSummonPhase extends PokemonPhase {
|
|||||||
}
|
}
|
||||||
this.scene.arena.applyTags(ArenaTrapTag, pokemon);
|
this.scene.arena.applyTags(ArenaTrapTag, pokemon);
|
||||||
|
|
||||||
// If this is fight or flight mystery encounter and is enemy pokemon summon phase, add enraged tag
|
// If this is mystery encounter and has post summon phase tag, apply post summon effects
|
||||||
if (pokemon.findTags(t => t instanceof MysteryEncounterPostSummonTag)) {
|
if (pokemon.findTags(t => t instanceof MysteryEncounterPostSummonTag)) {
|
||||||
pokemon.lapseTag(BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON);
|
pokemon.lapseTag(BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON);
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import { loadBattlerTag } from "../data/battler-tags";
|
|||||||
import { Biome } from "#enums/biome";
|
import { Biome } from "#enums/biome";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
|
import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/mystery-encounter-pokemon-data";
|
||||||
|
|
||||||
export default class PokemonData {
|
export default class PokemonData {
|
||||||
public id: integer;
|
public id: integer;
|
||||||
@ -54,6 +55,7 @@ export default class PokemonData {
|
|||||||
public bossSegments?: integer;
|
public bossSegments?: integer;
|
||||||
|
|
||||||
public summonData: PokemonSummonData;
|
public summonData: PokemonSummonData;
|
||||||
|
public mysteryEncounterData: MysteryEncounterPokemonData;
|
||||||
|
|
||||||
constructor(source: Pokemon | any, forHistory: boolean = false) {
|
constructor(source: Pokemon | any, forHistory: boolean = false) {
|
||||||
const sourcePokemon = source instanceof Pokemon ? source : null;
|
const sourcePokemon = source instanceof Pokemon ? source : null;
|
||||||
@ -108,6 +110,7 @@ export default class PokemonData {
|
|||||||
this.status = sourcePokemon.status;
|
this.status = sourcePokemon.status;
|
||||||
if (this.player) {
|
if (this.player) {
|
||||||
this.summonData = sourcePokemon.summonData;
|
this.summonData = sourcePokemon.summonData;
|
||||||
|
this.mysteryEncounterData = sourcePokemon.mysteryEncounterData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -137,6 +140,14 @@ export default class PokemonData {
|
|||||||
this.summonData.tags = [];
|
this.summonData.tags = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.mysteryEncounterData = new MysteryEncounterPokemonData();
|
||||||
|
if (!forHistory && source.mysteryEncounterData) {
|
||||||
|
this.mysteryEncounterData.spriteScale = source.mysteryEncounterData.spriteScale;
|
||||||
|
this.mysteryEncounterData.ability = source.mysteryEncounterData.ability;
|
||||||
|
this.mysteryEncounterData.passive = source.mysteryEncounterData.passive;
|
||||||
|
this.mysteryEncounterData.types = source.mysteryEncounterData.types;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user