Merge pull request #150 from AsdarDevelops/winstrate-challenge
adds Winstrate Challenge mystery encounter
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 56 KiB |
BIN
public/images/items/macho_brace.png
Normal file
After Width: | Height: | Size: 372 B |
41
public/images/trainer/vicky.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "vicky.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 52,
|
||||
"h": 53
|
||||
},
|
||||
"scale": 1,
|
||||
"frames": [
|
||||
{
|
||||
"filename": "0001.png",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 80,
|
||||
"h": 80
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 13,
|
||||
"y": 27,
|
||||
"w": 52,
|
||||
"h": 53
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 52,
|
||||
"h": 53
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:bf9d2d417a1982282dd711456ac71206:101e07828e3d6e2a2a7a80aebfa802ad:cabe44a4410c334298b1984a219f8160$"
|
||||
}
|
||||
}
|
BIN
public/images/trainer/vicky.png
Normal file
After Width: | Height: | Size: 765 B |
41
public/images/trainer/victor.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "victor.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 55,
|
||||
"h": 53
|
||||
},
|
||||
"scale": 1,
|
||||
"frames": [
|
||||
{
|
||||
"filename": "0001.png",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 80,
|
||||
"h": 80
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 12,
|
||||
"y": 27,
|
||||
"w": 55,
|
||||
"h": 53
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 55,
|
||||
"h": 53
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:64eff0f697754cdf9552b46342c9292a:611e0e2cacbd90c1229ce5443b2414f0:0cc0f5a2c1b2eedb46dd8318e8feb1d8$"
|
||||
}
|
||||
}
|
BIN
public/images/trainer/victor.png
Normal file
After Width: | Height: | Size: 794 B |
41
public/images/trainer/victoria.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "victoria.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 52,
|
||||
"h": 54
|
||||
},
|
||||
"scale": 1,
|
||||
"frames": [
|
||||
{
|
||||
"filename": "0001.png",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 80,
|
||||
"h": 80
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 14,
|
||||
"y": 26,
|
||||
"w": 52,
|
||||
"h": 54
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 52,
|
||||
"h": 54
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:4dafeae3674d63b12cc4d8044f67b5a3:7834687d784c31169256927f419c7958:cf0eb39e0a3f2e42f23ca29747d73c40$"
|
||||
}
|
||||
}
|
BIN
public/images/trainer/victoria.png
Normal file
After Width: | Height: | Size: 813 B |
41
public/images/trainer/vito.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "vito.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 41,
|
||||
"h": 78
|
||||
},
|
||||
"scale": 1,
|
||||
"frames": [
|
||||
{
|
||||
"filename": "0001.png",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 80,
|
||||
"h": 80
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 20,
|
||||
"y": 2,
|
||||
"w": 41,
|
||||
"h": 78
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 41,
|
||||
"h": 78
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:cb988be58fcd5381174e9d120b051e38:4d4723dbbcd9713ee0ed3c2d84ef4bfb:1c7723b536b218346e3138016d865ce9$"
|
||||
}
|
||||
}
|
BIN
public/images/trainer/vito.png
Normal file
After Width: | Height: | Size: 765 B |
41
public/images/trainer/vivi.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "vivi.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 48,
|
||||
"h": 69
|
||||
},
|
||||
"scale": 1,
|
||||
"frames": [
|
||||
{
|
||||
"filename": "0001.png",
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"sourceSize": {
|
||||
"w": 80,
|
||||
"h": 80
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 13,
|
||||
"y": 11,
|
||||
"w": 48,
|
||||
"h": 69
|
||||
},
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 48,
|
||||
"h": 69
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"app": "https://www.codeandweb.com/texturepacker",
|
||||
"version": "3.0",
|
||||
"smartupdate": "$TexturePacker:SmartUpdate:0a51b4df0b2ed0fed7e3bdb5dffd9e28:af1f3b1480023b3e3761c49e49faf5f1:4fc6bf2bec74c4bb8809df38231deb01$"
|
||||
}
|
||||
}
|
BIN
public/images/trainer/vivi.png
Normal file
After Width: | Height: | Size: 713 B |
@ -14,7 +14,7 @@ import { Arena, ArenaBase } from "./field/arena";
|
||||
import { GameData } from "./system/game-data";
|
||||
import { addTextObject, getTextColor, TextStyle } from "./ui/text";
|
||||
import { allMoves } from "./data/move";
|
||||
import { getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getPartyLuckValue, ModifierPoolType, PokemonHeldItemModifierType } from "./modifier/modifier-type";
|
||||
import { getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getPartyLuckValue, ModifierPoolType } from "./modifier/modifier-type";
|
||||
import AbilityBar from "./ui/ability-bar";
|
||||
import { allAbilities, applyAbAttrs, applyPostBattleInitAbAttrs, BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, IncrementMovePriorityAbAttr, PostBattleInitAbAttr } from "./data/ability";
|
||||
import Battle, { BattleType, FixedBattleConfig } from "./battle";
|
||||
@ -67,12 +67,13 @@ import { UiTheme } from "#enums/ui-theme";
|
||||
import { TimedEventManager } from "#app/timed-event-manager.js";
|
||||
import i18next from "i18next";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import IMysteryEncounter from "./data/mystery-encounters/mystery-encounter";
|
||||
import MysteryEncounter from "./data/mystery-encounters/mystery-encounter";
|
||||
import { allMysteryEncounters, AVERAGE_ENCOUNTERS_PER_RUN_TARGET, BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT, mysteryEncountersByBiome, WEIGHT_INCREMENT_ON_SPAWN_MISS } from "./data/mystery-encounters/mystery-encounters";
|
||||
import { MysteryEncounterData } from "#app/data/mystery-encounters/mystery-encounter-data";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import HeldModifierConfig from "#app/interfaces/held-modifier-config";
|
||||
|
||||
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
|
||||
|
||||
@ -223,7 +224,7 @@ export default class BattleScene extends SceneBase {
|
||||
public pokemonInfoContainer: PokemonInfoContainer;
|
||||
private party: PlayerPokemon[];
|
||||
public mysteryEncounterData: MysteryEncounterData = new MysteryEncounterData(null);
|
||||
public lastMysteryEncounter: IMysteryEncounter;
|
||||
public lastMysteryEncounter: MysteryEncounter;
|
||||
/** Combined Biome and Wave count text */
|
||||
private biomeWaveText: Phaser.GameObjects.Text;
|
||||
private moneyText: Phaser.GameObjects.Text;
|
||||
@ -1036,7 +1037,7 @@ export default class BattleScene extends SceneBase {
|
||||
}
|
||||
}
|
||||
|
||||
newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean, mysteryEncounter?: IMysteryEncounter): Battle {
|
||||
newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean, mysteryEncounter?: MysteryEncounter): Battle {
|
||||
const _startingWave = Overrides.STARTING_WAVE_OVERRIDE || startingWave;
|
||||
const newWaveIndex = waveIndex || ((this.currentBattle?.waveIndex || (_startingWave - 1)) + 1);
|
||||
let newDouble: boolean;
|
||||
@ -2423,7 +2424,7 @@ export default class BattleScene extends SceneBase {
|
||||
});
|
||||
}
|
||||
|
||||
generateEnemyModifiers(customHeldModifiers?: PokemonHeldItemModifierType[][]): Promise<void> {
|
||||
generateEnemyModifiers(heldModifiersConfigs?: HeldModifierConfig[][]): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
if (this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
|
||||
return resolve();
|
||||
@ -2445,8 +2446,16 @@ export default class BattleScene extends SceneBase {
|
||||
}
|
||||
|
||||
party.every((enemyPokemon: EnemyPokemon, i: integer) => {
|
||||
if (customHeldModifiers && i < customHeldModifiers.length && customHeldModifiers[i] && customHeldModifiers[i].length > 0) {
|
||||
customHeldModifiers[i].forEach(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false, this));
|
||||
if (heldModifiersConfigs && i < heldModifiersConfigs.length && heldModifiersConfigs[i] && heldModifiersConfigs[i].length > 0) {
|
||||
heldModifiersConfigs[i].forEach(mt => {
|
||||
const stackCount = mt.stackCount ?? 1;
|
||||
// const isTransferable = mt.isTransferable ?? true;
|
||||
const modifier = mt.modifierType.newModifier(enemyPokemon);
|
||||
modifier.stackCount = stackCount;
|
||||
// TODO: set isTransferable
|
||||
// modifier.setIsTransferable(isTransferable);
|
||||
this.addEnemyModifier(modifier, false, true);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2702,9 +2711,9 @@ export default class BattleScene extends SceneBase {
|
||||
* @param override - used to load session encounter when restarting game, etc.
|
||||
* @returns
|
||||
*/
|
||||
getMysteryEncounter(override: IMysteryEncounter): IMysteryEncounter {
|
||||
getMysteryEncounter(override: MysteryEncounter): MysteryEncounter {
|
||||
// Loading override or session encounter
|
||||
let encounter: IMysteryEncounter;
|
||||
let encounter: MysteryEncounter;
|
||||
if (!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_OVERRIDE) && allMysteryEncounters.hasOwnProperty(Overrides.MYSTERY_ENCOUNTER_OVERRIDE)) {
|
||||
encounter = allMysteryEncounters[Overrides.MYSTERY_ENCOUNTER_OVERRIDE];
|
||||
} else {
|
||||
@ -2726,7 +2735,7 @@ export default class BattleScene extends SceneBase {
|
||||
}
|
||||
|
||||
if (encounter) {
|
||||
encounter = new IMysteryEncounter(encounter);
|
||||
encounter = new MysteryEncounter(encounter);
|
||||
encounter.populateDialogueTokensFromRequirements(this);
|
||||
return encounter;
|
||||
}
|
||||
@ -2755,7 +2764,7 @@ export default class BattleScene extends SceneBase {
|
||||
tier = Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE;
|
||||
}
|
||||
|
||||
let availableEncounters: IMysteryEncounter[] = [];
|
||||
let availableEncounters: MysteryEncounter[] = [];
|
||||
// New encounter will never be the same as the most recent encounter
|
||||
const previousEncounter = this.mysteryEncounterData.encounteredEvents?.length > 0 ? this.mysteryEncounterData.encounteredEvents[this.mysteryEncounterData.encounteredEvents.length - 1][0] : null;
|
||||
const biomeMysteryEncounters = mysteryEncountersByBiome.get(this.arena.biomeType) ?? [];
|
||||
@ -2802,7 +2811,7 @@ export default class BattleScene extends SceneBase {
|
||||
}
|
||||
encounter = availableEncounters[Utils.randSeedInt(availableEncounters.length)];
|
||||
// New encounter object to not dirty flags
|
||||
encounter = new IMysteryEncounter(encounter);
|
||||
encounter = new MysteryEncounter(encounter);
|
||||
encounter.populateDialogueTokensFromRequirements(this);
|
||||
return encounter;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import { PlayerGender } from "#enums/player-gender";
|
||||
import { Species } from "#enums/species";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import i18next from "#app/plugins/i18n";
|
||||
import IMysteryEncounter from "./data/mystery-encounters/mystery-encounter";
|
||||
import MysteryEncounter from "./data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
|
||||
export enum BattleType {
|
||||
@ -70,7 +70,7 @@ export default class Battle {
|
||||
public lastUsedPokeball: PokeballType;
|
||||
public playerFaints: number; // The amount of times pokemon on the players side have fainted
|
||||
public enemyFaints: number; // The amount of times pokemon on the enemies side have fainted
|
||||
public mysteryEncounter: IMysteryEncounter;
|
||||
public mysteryEncounter: MysteryEncounter;
|
||||
|
||||
private rngCounter: integer = 0;
|
||||
|
||||
|
@ -735,6 +735,56 @@ export const trainerTypeDialogue: TrainerTypeDialogue = {
|
||||
]
|
||||
}
|
||||
],
|
||||
[TrainerType.VICTOR]: [
|
||||
{
|
||||
encounter: [
|
||||
"dialogue:winstrates_victor.encounter.1",
|
||||
],
|
||||
victory: [
|
||||
"dialogue:winstrates_victor.victory.1"
|
||||
],
|
||||
}
|
||||
],
|
||||
[TrainerType.VICTORIA]: [
|
||||
{
|
||||
encounter: [
|
||||
"dialogue:winstrates_victoria.encounter.1",
|
||||
],
|
||||
victory: [
|
||||
"dialogue:winstrates_victoria.victory.1"
|
||||
],
|
||||
}
|
||||
],
|
||||
[TrainerType.VIVI]: [
|
||||
{
|
||||
encounter: [
|
||||
"dialogue:winstrates_vivi.encounter.1",
|
||||
],
|
||||
victory: [
|
||||
"dialogue:winstrates_vivi.victory.1"
|
||||
],
|
||||
}
|
||||
],
|
||||
[TrainerType.VICKY]: [
|
||||
{
|
||||
encounter: [
|
||||
"dialogue:winstrates_vicky.encounter.1",
|
||||
],
|
||||
victory: [
|
||||
"dialogue:winstrates_vicky.victory.1"
|
||||
],
|
||||
}
|
||||
],
|
||||
[TrainerType.VITO]: [
|
||||
{
|
||||
encounter: [
|
||||
"dialogue:winstrates_vito.encounter.1",
|
||||
],
|
||||
victory: [
|
||||
"dialogue:winstrates_vito.victory.1"
|
||||
],
|
||||
}
|
||||
],
|
||||
[TrainerType.BROCK]: {
|
||||
encounter: [
|
||||
"dialogue:brock.encounter.1",
|
||||
|
@ -2,7 +2,7 @@ import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattl
|
||||
import { trainerConfigs, } from "#app/data/trainer-config";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import { Species } from "#enums/species";
|
||||
@ -22,10 +22,10 @@ const namespace = "mysteryEncounter:aTrainersTest";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/115 | GitHub Issue #115}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const ATrainersTestEncounter: IMysteryEncounter =
|
||||
export const ATrainersTestEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.A_TRAINERS_TEST)
|
||||
.withEncounterTier(MysteryEncounterTier.ROGUE)
|
||||
.withSceneWaveRangeRequirement(10, 180) // waves 10 to 180
|
||||
.withSceneWaveRangeRequirement(100, 180)
|
||||
.withIntroSpriteConfigs([]) // These are set in onInit()
|
||||
.withIntroDialogue([
|
||||
{
|
||||
@ -139,13 +139,6 @@ export const ATrainersTestEncounter: IMysteryEncounter =
|
||||
// Spawn standard trainer battle with memory mushroom reward
|
||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
|
||||
|
||||
let eggTier;
|
||||
if (randSeedInt(64) >= 54) {
|
||||
eggTier = EggTier.MASTER;
|
||||
} else {
|
||||
eggTier = EggTier.ULTRA;
|
||||
}
|
||||
|
||||
await transitionMysteryEncounterIntroVisuals(scene);
|
||||
|
||||
const eggOptions: IEggOptions = {
|
||||
@ -153,9 +146,9 @@ export const ATrainersTestEncounter: IMysteryEncounter =
|
||||
pulled: false,
|
||||
sourceType: EggSourceType.EVENT,
|
||||
eventEggTypeDescriptor: encounter.misc.trainerEggDescription,
|
||||
tier: eggTier
|
||||
tier: EggTier.ULTRA
|
||||
};
|
||||
encounter.setDialogueToken("eggType", i18next.t(`${namespace}.eggTypes.${eggTier === EggTier.ULTRA ? "epic" : "legendary"}`));
|
||||
encounter.setDialogueToken("eggType", i18next.t(`${namespace}.eggTypes.epic`));
|
||||
setEncounterRewards(scene, { fillRemaining: true }, [eggOptions]);
|
||||
|
||||
return initBattleWithEnemyConfig(scene, config);
|
||||
@ -185,7 +178,7 @@ export const ATrainersTestEncounter: IMysteryEncounter =
|
||||
)
|
||||
.withOutroDialogue([
|
||||
{
|
||||
text: `${namespace}:outro`,
|
||||
text: `${namespace}.outro`,
|
||||
},
|
||||
])
|
||||
.build();
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { EnemyPartyConfig, generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import Pokemon, { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import { BerryModifierType, modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { PersistentModifierRequirement } from "../mystery-encounter-requirements";
|
||||
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
@ -21,6 +21,7 @@ import { BattlerIndex } from "#app/battle";
|
||||
import { applyModifierTypeToPlayerPokemon, catchPokemon, getHighestLevelPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { TrainerSlot } from "#app/data/trainer-config";
|
||||
import { PokeballType } from "#app/data/pokeball";
|
||||
import HeldModifierConfig from "#app/interfaces/held-modifier-config";
|
||||
|
||||
/** the i18n namespace for this encounter */
|
||||
const namespace = "mysteryEncounter:absoluteAvarice";
|
||||
@ -30,7 +31,7 @@ const namespace = "mysteryEncounter:absoluteAvarice";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/58 | GitHub Issue #58}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const AbsoluteAvariceEncounter: IMysteryEncounter =
|
||||
export const AbsoluteAvariceEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.ABSOLUTE_AVARICE)
|
||||
.withEncounterTier(MysteryEncounterTier.GREAT)
|
||||
.withSceneWaveRangeRequirement(10, 180)
|
||||
@ -191,13 +192,13 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
|
||||
encounter.misc = { berryItemsMap };
|
||||
|
||||
// Generates copies of the stolen berries to put on the Greedent
|
||||
const bossModifierTypes: PokemonHeldItemModifierType[] = [];
|
||||
const bossModifierConfigs: HeldModifierConfig[] = [];
|
||||
berryItems.forEach(berryMod => {
|
||||
// Can't define stack count on a ModifierType, have to just create separate instances for each stack
|
||||
// Overflow berries will be "lost" on the boss, but it's un-catchable anyway
|
||||
for (let i = 0; i < berryMod.stackCount; i++) {
|
||||
const modifierType = generateModifierTypeOption(scene, modifierTypes.BERRY, [berryMod.berryType]).type as PokemonHeldItemModifierType;
|
||||
bossModifierTypes.push(modifierType);
|
||||
const modifierType = generateModifierType(scene, modifierTypes.BERRY, [berryMod.berryType]) as PokemonHeldItemModifierType;
|
||||
bossModifierConfigs.push({ modifierType });
|
||||
}
|
||||
|
||||
scene.removeModifier(berryMod);
|
||||
@ -212,7 +213,7 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
|
||||
isBoss: true,
|
||||
bossSegments: 3,
|
||||
moveSet: [Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.SLACK_OFF],
|
||||
modifierTypes: bossModifierTypes,
|
||||
modifierConfigs: bossModifierConfigs,
|
||||
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
|
||||
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
||||
queueEncounterMessage(pokemon.scene, `${namespace}.option.1.boss_enraged`);
|
||||
@ -243,7 +244,7 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
|
||||
// Provides 1x Reviver Seed to each party member at end of battle
|
||||
const revSeed = generateModifierTypeOption(scene, modifierTypes.REVIVER_SEED).type;
|
||||
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED);
|
||||
const givePartyPokemonReviverSeeds = () => {
|
||||
const party = scene.getParty();
|
||||
party.forEach(p => {
|
||||
@ -296,7 +297,7 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
|
||||
Phaser.Math.RND.shuffle(berryTypesAsArray);
|
||||
const randBerryType = berryTypesAsArray.pop();
|
||||
|
||||
const berryModType = generateModifierTypeOption(scene, modifierTypes.BERRY, [randBerryType]).type as BerryModifierType;
|
||||
const berryModType = generateModifierType(scene, modifierTypes.BERRY, [randBerryType]) as BerryModifierType;
|
||||
applyModifierTypeToPlayerPokemon(scene, pokemon, berryModType);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { AbilityRequirement, CombinationPokemonRequirement, MoveRequirement } from "../mystery-encounter-requirements";
|
||||
import { getHighestStatTotalPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
@ -21,7 +21,7 @@ const namespace = "mysteryEncounter:offerYouCantRefuse";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/72 | GitHub Issue #72}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const AnOfferYouCantRefuseEncounter: IMysteryEncounter =
|
||||
export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.AN_OFFER_YOU_CANT_REFUSE)
|
||||
.withEncounterTier(MysteryEncounterTier.GREAT)
|
||||
.withSceneWaveRangeRequirement(10, 180)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { BattleStat } from "#app/data/battle-stat";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import {
|
||||
EnemyPartyConfig, generateModifierTypeOption,
|
||||
EnemyPartyConfig, generateModifierType, generateModifierTypeOption,
|
||||
initBattleWithEnemyConfig,
|
||||
leaveEncounterWithoutBattle, setEncounterExp,
|
||||
setEncounterRewards
|
||||
@ -19,7 +19,7 @@ import { randSeedInt } from "#app/utils";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
@ -40,7 +40,7 @@ const namespace = "mysteryEncounter:berriesAbound";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/24 | GitHub Issue #24}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const BerriesAboundEncounter: IMysteryEncounter =
|
||||
export const BerriesAboundEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.BERRIES_ABOUND)
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withSceneWaveRangeRequirement(10, 180) // waves 10 to 180
|
||||
@ -315,7 +315,7 @@ export const BerriesAboundEncounter: IMysteryEncounter =
|
||||
|
||||
async function tryGiveBerry(scene: BattleScene, prioritizedPokemon?: PlayerPokemon) {
|
||||
const berryType = randSeedInt(Object.keys(BerryType).filter(s => !isNaN(Number(s))).length) as BerryType;
|
||||
const berry = generateModifierTypeOption(scene, modifierTypes.BERRY, [berryType]).type as BerryModifierType;
|
||||
const berry = generateModifierType(scene, modifierTypes.BERRY, [berryType]) as BerryModifierType;
|
||||
|
||||
const party = scene.getParty();
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, loadCustomMovesForEncounter, selectPokemonForOption, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { EnemyPartyConfig, generateModifierType, 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 { 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 MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { Species } from "#enums/species";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
@ -56,7 +56,7 @@ const RANDOM_ABILITY_POOL = [
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/69 | GitHub Issue #69}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const ClowningAroundEncounter: IMysteryEncounter =
|
||||
export const ClowningAroundEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.CLOWNING_AROUND)
|
||||
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
||||
.withSceneWaveRangeRequirement(80, 180)
|
||||
@ -128,8 +128,7 @@ export const ClowningAroundEncounter: IMysteryEncounter =
|
||||
},
|
||||
{ // 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)]),
|
||||
mysteryEncounterData: new MysteryEncounterPokemonData(null, ability, null, [randSeedInt(18), randSeedInt(18)]),
|
||||
isBoss: true,
|
||||
moveSet: [Moves.TRICK, Moves.HYPNOSIS, Moves.SHADOW_BALL, Moves.MIND_BLOWN]
|
||||
},
|
||||
@ -483,9 +482,9 @@ function generateItemsOfTier(scene: BattleScene, pokemon: PlayerPokemon, numItem
|
||||
const newItemType = pool[randIndex];
|
||||
let newMod;
|
||||
if (tier === "Berries") {
|
||||
newMod = generateModifierTypeOption(scene, modifierTypes.BERRY, [newItemType[0]]).type as PokemonHeldItemModifierType;
|
||||
newMod = generateModifierType(scene, modifierTypes.BERRY, [newItemType[0]]) as PokemonHeldItemModifierType;
|
||||
} else {
|
||||
newMod = generateModifierTypeOption(scene, newItemType[0]).type as PokemonHeldItemModifierType;
|
||||
newMod = generateModifierType(scene, newItemType[0]) as PokemonHeldItemModifierType;
|
||||
}
|
||||
applyModifierTypeToPlayerPokemon(scene, pokemon, newMod);
|
||||
// Decrement max stacks and remove from pool if at max
|
||||
|
@ -3,7 +3,7 @@ import Pokemon, { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
@ -77,7 +77,7 @@ const SENSU_STYLE_BIOMES = [
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/130 | GitHub Issue #130}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const DancingLessonsEncounter: IMysteryEncounter =
|
||||
export const DancingLessonsEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.DANCING_LESSONS)
|
||||
.withEncounterTier(MysteryEncounterTier.GREAT)
|
||||
.withSceneWaveRangeRequirement(10, 180)
|
||||
|
@ -6,7 +6,7 @@ import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { EnemyPartyConfig, EnemyPokemonConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, } from "../utils/encounter-phase-utils";
|
||||
import { getRandomPlayerPokemon, getRandomSpeciesByStarterTier } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
@ -74,7 +74,7 @@ const excludedBosses = [
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/61 | GitHub Issue #61}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const DarkDealEncounter: IMysteryEncounter =
|
||||
export const DarkDealEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.DARK_DEAL)
|
||||
.withEncounterTier(MysteryEncounterTier.ROGUE)
|
||||
.withIntroSpriteConfigs([
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { generateModifierTypeOption, leaveEncounterWithoutBattle, selectPokemonForOption, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { generateModifierType, leaveEncounterWithoutBattle, selectPokemonForOption, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import Pokemon, { PlayerPokemon } from "#app/field/pokemon";
|
||||
import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { CombinationPokemonRequirement, HeldItemRequirement, MoneyRequirement } from "../mystery-encounter-requirements";
|
||||
import { getEncounterText, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
@ -36,7 +36,7 @@ const OPTION_3_DISALLOWED_MODIFIERS = [
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/57 | GitHub Issue #57}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const DelibirdyEncounter: IMysteryEncounter =
|
||||
export const DelibirdyEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.DELIBIRDY)
|
||||
.withEncounterTier(MysteryEncounterTier.GREAT)
|
||||
.withSceneWaveRangeRequirement(10, 180)
|
||||
@ -113,7 +113,7 @@ export const DelibirdyEncounter: IMysteryEncounter =
|
||||
|
||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) {
|
||||
// At max stacks, give the first party pokemon a Shell Bell instead
|
||||
const shellBell = generateModifierTypeOption(scene, modifierTypes.SHELL_BELL).type as PokemonHeldItemModifierType;
|
||||
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
|
||||
scene.playSound("item_fanfare");
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, true);
|
||||
@ -169,7 +169,7 @@ export const DelibirdyEncounter: IMysteryEncounter =
|
||||
// If pokemon meets primary pokemon reqs, it can be selected
|
||||
const meetsReqs = encounter.options[1].pokemonMeetsPrimaryRequirements(scene, pokemon);
|
||||
if (!meetsReqs) {
|
||||
return getEncounterText(scene, `${namespace}:invalid_selection`);
|
||||
return getEncounterText(scene, `${namespace}.invalid_selection`);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -188,7 +188,7 @@ export const DelibirdyEncounter: IMysteryEncounter =
|
||||
|
||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) {
|
||||
// At max stacks, give the first party pokemon a Shell Bell instead
|
||||
const shellBell = generateModifierTypeOption(scene, modifierTypes.SHELL_BELL).type as PokemonHeldItemModifierType;
|
||||
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
|
||||
scene.playSound("item_fanfare");
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, true);
|
||||
@ -201,7 +201,7 @@ export const DelibirdyEncounter: IMysteryEncounter =
|
||||
|
||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) {
|
||||
// At max stacks, give the first party pokemon a Shell Bell instead
|
||||
const shellBell = generateModifierTypeOption(scene, modifierTypes.SHELL_BELL).type as PokemonHeldItemModifierType;
|
||||
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
|
||||
scene.playSound("item_fanfare");
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, true);
|
||||
@ -281,7 +281,7 @@ export const DelibirdyEncounter: IMysteryEncounter =
|
||||
|
||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) {
|
||||
// At max stacks, give the first party pokemon a Shell Bell instead
|
||||
const shellBell = generateModifierTypeOption(scene, modifierTypes.SHELL_BELL).type as PokemonHeldItemModifierType;
|
||||
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
|
||||
scene.playSound("item_fanfare");
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, true);
|
||||
|
@ -7,7 +7,7 @@ import { randSeedInt } from "#app/utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, {
|
||||
import MysteryEncounter, {
|
||||
MysteryEncounterBuilder,
|
||||
} from "../mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
@ -20,7 +20,7 @@ const namespace = "mysteryEncounter:departmentStoreSale";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/33 | GitHub Issue #33}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const DepartmentStoreSaleEncounter: IMysteryEncounter =
|
||||
export const DepartmentStoreSaleEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.DEPARTMENT_STORE_SALE)
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withSceneWaveRangeRequirement(10, 100)
|
||||
|
@ -7,7 +7,7 @@ import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
@ -19,7 +19,7 @@ const namespace = "mysteryEncounter:fieldTrip";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/17 | GitHub Issue #17}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const FieldTripEncounter: IMysteryEncounter =
|
||||
export const FieldTripEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.FIELD_TRIP)
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withSceneWaveRangeRequirement(10, 180)
|
||||
|
@ -3,7 +3,7 @@ import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig
|
||||
import { AttackTypeBoosterModifierType, modifierTypes, } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { TypeRequirement } from "../mystery-encounter-requirements";
|
||||
import { Species } from "#enums/species";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
@ -36,7 +36,7 @@ const DAMAGE_PERCENTAGE: number = 20;
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/88 | GitHub Issue #88}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const FieryFalloutEncounter: IMysteryEncounter =
|
||||
export const FieryFalloutEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.FIERY_FALLOUT)
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withSceneWaveRangeRequirement(40, 180)
|
||||
|
@ -17,7 +17,7 @@ import {
|
||||
} from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MoveRequirement } from "../mystery-encounter-requirements";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
@ -33,7 +33,7 @@ const namespace = "mysteryEncounter:fightOrFlight";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/24 | GitHub Issue #24}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const FightOrFlightEncounter: IMysteryEncounter =
|
||||
export const FightOrFlightEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.FIGHT_OR_FLIGHT)
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withSceneWaveRangeRequirement(10, 180) // waves 10 to 180
|
||||
|
@ -127,7 +127,7 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
||||
* @param scene Battle scene
|
||||
* @param guidePokemon pokemon choosen as a guide
|
||||
*/
|
||||
function handlePokemonGuidingYouPhase(scene: BattleScene) {
|
||||
async function handlePokemonGuidingYouPhase(scene: BattleScene) {
|
||||
const laprasSpecies = getPokemonSpecies(Species.LAPRAS);
|
||||
const { mysteryEncounter } = scene.currentBattle;
|
||||
|
||||
|
@ -15,7 +15,7 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import * as Utils from "#app/utils";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
@ -26,7 +26,7 @@ const namespace = "mysteryEncounter:mysteriousChallengers";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/41 | GitHub Issue #41}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const MysteriousChallengersEncounter: IMysteryEncounter =
|
||||
export const MysteriousChallengersEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.MYSTERIOUS_CHALLENGERS)
|
||||
.withEncounterTier(MysteryEncounterTier.GREAT)
|
||||
.withSceneWaveRangeRequirement(10, 180) // waves 10 to 180
|
||||
|
@ -5,7 +5,7 @@ import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||
import { randSeedInt } from "#app/utils.js";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
@ -18,7 +18,7 @@ const namespace = "mysteryEncounter:mysteriousChest";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/32 | GitHub Issue #32}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const MysteriousChestEncounter: IMysteryEncounter =
|
||||
export const MysteriousChestEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.MYSTERIOUS_CHEST)
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withSceneWaveRangeRequirement(10, 180) // waves 2 to 180
|
||||
@ -116,9 +116,8 @@ export const MysteriousChestEncounter: IMysteryEncounter =
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("pokeName", highestLevelPokemon.getNameToRender());
|
||||
// Show which Pokemon was KOed, then leave encounter with no rewards
|
||||
// Does this synchronously so that game over doesn't happen over result message
|
||||
await showEncounterText(scene, `${namespace}.option.1.bad`).then(() => {
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
});
|
||||
await showEncounterText(scene, `${namespace}.option.1.bad`);
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
}
|
||||
})
|
||||
.build()
|
||||
|
@ -2,7 +2,7 @@ import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/myst
|
||||
import { leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterExp, setEncounterRewards, transitionMysteryEncounterIntroVisuals, updatePlayerMoney } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MoveRequirement } from "../mystery-encounter-requirements";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
@ -20,7 +20,7 @@ const namespace = "mysteryEncounter:partTimer";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/82 | GitHub Issue #82}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const PartTimerEncounter: IMysteryEncounter =
|
||||
export const PartTimerEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.PART_TIMER)
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withSceneWaveRangeRequirement(10, 180)
|
||||
@ -115,7 +115,7 @@ export const PartTimerEncounter: IMysteryEncounter =
|
||||
// Only Pokemon non-KOd pokemon can be selected
|
||||
const selectableFilter = (pokemon: Pokemon) => {
|
||||
if (!pokemon.isAllowedInBattle()) {
|
||||
return getEncounterText(scene, `${namespace}:invalid_selection`);
|
||||
return getEncounterText(scene, `${namespace}.invalid_selection`);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -194,7 +194,7 @@ export const PartTimerEncounter: IMysteryEncounter =
|
||||
// Only Pokemon non-KOd pokemon can be selected
|
||||
const selectableFilter = (pokemon: Pokemon) => {
|
||||
if (!pokemon.isAllowedInBattle()) {
|
||||
return getEncounterText(scene, `${namespace}:invalid_selection`);
|
||||
return getEncounterText(scene, `${namespace}.invalid_selection`);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { initSubsequentOptionSelect, leaveEncounterWithoutBattle, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounterOption, { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { TrainerSlot } from "#app/data/trainer-config";
|
||||
import { ScanIvsPhase, SummonPhase } from "#app/phases";
|
||||
@ -17,7 +17,6 @@ import { getEncounterText, showEncounterText } from "#app/data/mystery-encounter
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounter:safariZone";
|
||||
@ -29,7 +28,7 @@ const TRAINER_THROW_ANIMATION_TIMES = [512, 184, 768];
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/39 | GitHub Issue #39}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const SafariZoneEncounter: IMysteryEncounter =
|
||||
export const SafariZoneEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.SAFARI_ZONE)
|
||||
.withEncounterTier(MysteryEncounterTier.GREAT)
|
||||
.withSceneWaveRangeRequirement(10, 180)
|
||||
@ -66,7 +65,7 @@ export const SafariZoneEncounter: IMysteryEncounter =
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Start safari encounter
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
encounter.encounterMode = MysteryEncounterMode.CONTINUOUS_ENCOUNTER;
|
||||
encounter.continuousEncounter = true;
|
||||
encounter.misc = {
|
||||
safariPokemonRemaining: 3
|
||||
};
|
||||
@ -104,7 +103,7 @@ export const SafariZoneEncounter: IMysteryEncounter =
|
||||
/**
|
||||
* SAFARI ZONE MINIGAME OPTIONS
|
||||
*
|
||||
* Catch and flee rate **stages** are calculated in the same way stat changes are (they range from -6/+6)
|
||||
* Catch and flee rate stages are calculated in the same way stat changes are (they range from -6/+6)
|
||||
* https://bulbapedia.bulbagarden.net/wiki/Catch_rate#Great_Marsh_and_Johto_Safari_Zone
|
||||
*
|
||||
* Catch Rate calculation:
|
||||
@ -130,21 +129,23 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Throw a ball option
|
||||
const pokemon = scene.currentBattle.mysteryEncounter.misc.pokemon;
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const pokemon = encounter.misc.pokemon;
|
||||
const catchResult = await throwPokeball(scene, pokemon);
|
||||
|
||||
if (catchResult) {
|
||||
// You caught pokemon
|
||||
// Check how many safari pokemon left
|
||||
if (scene.currentBattle.mysteryEncounter.misc.safariPokemonRemaining > 0) {
|
||||
if (encounter.misc.safariPokemonRemaining > 0) {
|
||||
await summonSafariPokemon(scene);
|
||||
initSubsequentOptionSelect(scene, { overrideOptions: safariZoneGameOptions, startingCursorIndex: 0, hideDescription: true });
|
||||
} else {
|
||||
// End safari mode
|
||||
encounter.continuousEncounter = false;
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
}
|
||||
} else {
|
||||
// Pokemon failed to catch, end turn
|
||||
// Pokemon catch failed, end turn
|
||||
await doEndTurn(scene, 0);
|
||||
}
|
||||
return true;
|
||||
@ -217,14 +218,16 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Flee option
|
||||
const pokemon = scene.currentBattle.mysteryEncounter.misc.pokemon;
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const pokemon = encounter.misc.pokemon;
|
||||
await doPlayerFlee(scene, pokemon);
|
||||
// Check how many safari pokemon left
|
||||
if (scene.currentBattle.mysteryEncounter.misc.safariPokemonRemaining > 0) {
|
||||
if (encounter.misc.safariPokemonRemaining > 0) {
|
||||
await summonSafariPokemon(scene);
|
||||
initSubsequentOptionSelect(scene, { overrideOptions: safariZoneGameOptions, startingCursorIndex: 3, hideDescription: true });
|
||||
} else {
|
||||
// End safari mode
|
||||
encounter.continuousEncounter = false;
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
}
|
||||
return true;
|
||||
@ -487,6 +490,7 @@ async function doEndTurn(scene: BattleScene, cursorIndex: number) {
|
||||
initSubsequentOptionSelect(scene, { overrideOptions: safariZoneGameOptions, startingCursorIndex: cursorIndex, hideDescription: true });
|
||||
} else {
|
||||
// End safari mode
|
||||
encounter.continuousEncounter = false;
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
}
|
||||
} else {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { generateModifierTypeOption, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterExp, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { generateModifierType, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterExp, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { StatusEffect } from "#app/data/status-effect";
|
||||
import Pokemon, { PlayerPokemon } from "#app/field/pokemon";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
@ -6,7 +6,7 @@ import { randSeedInt } from "#app/utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { MoneyRequirement } from "../mystery-encounter-requirements";
|
||||
import { getEncounterText, queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
@ -22,7 +22,7 @@ const namespace = "mysteryEncounter:shadyVitaminDealer";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/34 | GitHub Issue #34}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const ShadyVitaminDealerEncounter: IMysteryEncounter =
|
||||
export const ShadyVitaminDealerEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.SHADY_VITAMIN_DEALER)
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withSceneWaveRangeRequirement(10, 180)
|
||||
@ -79,8 +79,8 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
|
||||
updatePlayerMoney(scene, -(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney);
|
||||
// Calculate modifiers and dialogue tokens
|
||||
const modifiers = [
|
||||
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type,
|
||||
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type,
|
||||
generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER),
|
||||
generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER),
|
||||
];
|
||||
encounter.setDialogueToken("boost1", modifiers[0].name);
|
||||
encounter.setDialogueToken("boost2", modifiers[1].name);
|
||||
@ -95,7 +95,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
|
||||
// If pokemon meets primary pokemon reqs, it can be selected
|
||||
const meetsReqs = encounter.pokemonMeetsPrimaryRequirements(scene, pokemon);
|
||||
if (!meetsReqs) {
|
||||
return getEncounterText(scene, `${namespace}:invalid_selection`);
|
||||
return getEncounterText(scene, `${namespace}.invalid_selection`);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -162,8 +162,8 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
|
||||
updatePlayerMoney(scene, -(encounter.options[1].requirements[0] as MoneyRequirement).requiredMoney);
|
||||
// Calculate modifiers and dialogue tokens
|
||||
const modifiers = [
|
||||
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type,
|
||||
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type,
|
||||
generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER),
|
||||
generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER),
|
||||
];
|
||||
encounter.setDialogueToken("boost1", modifiers[0].name);
|
||||
encounter.setDialogueToken("boost2", modifiers[1].name);
|
||||
|
@ -4,7 +4,7 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { StatusEffect } from "#app/data/status-effect";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { MoveRequirement } from "../mystery-encounter-requirements";
|
||||
import { EnemyPartyConfig, EnemyPokemonConfig, initBattleWithEnemyConfig, loadCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards, } from "../utils/encounter-phase-utils";
|
||||
@ -25,7 +25,7 @@ const namespace = "mysteryEncounter:slumberingSnorlax";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/103 | GitHub Issue #103}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const SlumberingSnorlaxEncounter: IMysteryEncounter =
|
||||
export const SlumberingSnorlaxEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.SLUMBERING_SNORLAX)
|
||||
.withEncounterTier(MysteryEncounterTier.GREAT)
|
||||
.withSceneWaveRangeRequirement(10, 180) // waves 10 to 180
|
||||
|
@ -2,7 +2,7 @@ import { leaveEncounterWithoutBattle, transitionMysteryEncounterIntroVisuals, up
|
||||
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MoneyRequirement } from "../mystery-encounter-requirements";
|
||||
import { catchPokemon, getRandomSpeciesByStarterTier, getSpriteKeysFromPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species";
|
||||
@ -25,7 +25,7 @@ const MAX_POKEMON_PRICE_MULTIPLIER = 6;
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/36 | GitHub Issue #36}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const ThePokemonSalesmanEncounter: IMysteryEncounter =
|
||||
export const ThePokemonSalesmanEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.THE_POKEMON_SALESMAN)
|
||||
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
||||
.withSceneWaveRangeRequirement(10, 180)
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig, loadCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { EnemyPartyConfig, initBattleWithEnemyConfig, loadCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals, generateModifierType } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { modifierTypes, PokemonHeldItemModifierType, } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { Species } from "#enums/species";
|
||||
import { Nature } from "#app/data/nature";
|
||||
@ -26,7 +26,7 @@ const namespace = "mysteryEncounter:theStrongStuff";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/54 | GitHub Issue #54}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const TheStrongStuffEncounter: IMysteryEncounter =
|
||||
export const TheStrongStuffEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.THE_STRONG_STUFF)
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withSceneWaveRangeRequirement(10, 180) // waves 10 to 180
|
||||
@ -74,12 +74,20 @@ export const TheStrongStuffEncounter: IMysteryEncounter =
|
||||
mysteryEncounterData: new MysteryEncounterPokemonData(1.5),
|
||||
nature: Nature.BOLD,
|
||||
moveSet: [Moves.INFESTATION, Moves.SALT_CURE, Moves.GASTRO_ACID, Moves.HEAL_ORDER],
|
||||
modifierTypes: [
|
||||
generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.SITRUS]).type as PokemonHeldItemModifierType,
|
||||
generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.APICOT]).type as PokemonHeldItemModifierType,
|
||||
generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.GANLON]).type as PokemonHeldItemModifierType,
|
||||
generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.LUM]).type as PokemonHeldItemModifierType,
|
||||
generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.LUM]).type as PokemonHeldItemModifierType
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.APICOT]) as PokemonHeldItemModifierType
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.GANLON]) as PokemonHeldItemModifierType
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2
|
||||
}
|
||||
],
|
||||
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
|
||||
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
||||
|
@ -0,0 +1,489 @@
|
||||
import { EnemyPartyConfig, generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import { Species } from "#enums/species";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Nature } from "#enums/nature";
|
||||
import { Type } from "#app/data/type";
|
||||
import { BerryType } from "#enums/berry-type";
|
||||
import { Stat } from "#enums/stat";
|
||||
import { PartyHealPhase, ReturnPhase, ShowTrainerPhase } from "#app/phases";
|
||||
import { SpeciesFormChangeManualTrigger } from "#app/data/pokemon-forms";
|
||||
import { applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "#app/data/ability";
|
||||
import { showEncounterDialogue } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounter:theWinstrateChallenge";
|
||||
|
||||
/**
|
||||
* The Winstrate Challenge encounter.
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/136 | GitHub Issue #136}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const TheWinstrateChallengeEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.THE_WINSTRATE_CHALLENGE)
|
||||
.withEncounterTier(MysteryEncounterTier.ROGUE)
|
||||
.withSceneWaveRangeRequirement(80, 180)
|
||||
.withIntroSpriteConfigs([
|
||||
{
|
||||
spriteKey: "vito",
|
||||
fileRoot: "trainer",
|
||||
hasShadow: false,
|
||||
x: 16,
|
||||
y: -4
|
||||
},
|
||||
{
|
||||
spriteKey: "vivi",
|
||||
fileRoot: "trainer",
|
||||
hasShadow: false,
|
||||
x: -14,
|
||||
y: -4
|
||||
},
|
||||
{
|
||||
spriteKey: "victor",
|
||||
fileRoot: "trainer",
|
||||
hasShadow: true,
|
||||
x: -32
|
||||
},
|
||||
{
|
||||
spriteKey: "victoria",
|
||||
fileRoot: "trainer",
|
||||
hasShadow: true,
|
||||
x: 40,
|
||||
},
|
||||
{
|
||||
spriteKey: "vicky",
|
||||
fileRoot: "trainer",
|
||||
hasShadow: true,
|
||||
x: 3,
|
||||
y: 5,
|
||||
yShadow: 5
|
||||
},
|
||||
])
|
||||
.withIntroDialogue([
|
||||
{
|
||||
text: `${namespace}.intro`,
|
||||
},
|
||||
{
|
||||
speaker: `${namespace}.speaker`,
|
||||
text: `${namespace}.intro_dialogue`,
|
||||
},
|
||||
])
|
||||
.withAutoHideIntroVisuals(false)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
|
||||
// Loaded back to front for pop() operations
|
||||
encounter.enemyPartyConfigs.push(getVitoTrainerConfig(scene));
|
||||
encounter.enemyPartyConfigs.push(getVickyTrainerConfig(scene));
|
||||
encounter.enemyPartyConfigs.push(getViviTrainerConfig(scene));
|
||||
encounter.enemyPartyConfigs.push(getVictoriaTrainerConfig(scene));
|
||||
encounter.enemyPartyConfigs.push(getVictorTrainerConfig(scene));
|
||||
|
||||
return true;
|
||||
})
|
||||
.withTitle(`${namespace}.title`)
|
||||
.withDescription(`${namespace}.description`)
|
||||
.withQuery(`${namespace}.query`)
|
||||
.withSimpleOption(
|
||||
{
|
||||
buttonLabel: `${namespace}.option.1.label`,
|
||||
buttonTooltip: `${namespace}.option.1.tooltip`,
|
||||
selected: [
|
||||
{
|
||||
speaker: "trainerNames:victor",
|
||||
text: `${namespace}.option.1.selected`,
|
||||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
// Spawn 5 trainer battles back to back with Macho Brace in rewards
|
||||
// scene.currentBattle.mysteryEncounter.continuousEncounter = true;
|
||||
scene.currentBattle.mysteryEncounter.doContinueEncounter = (scene: BattleScene) => {
|
||||
return endTrainerBattleAndShowDialogue(scene);
|
||||
};
|
||||
await transitionMysteryEncounterIntroVisuals(scene, true, false);
|
||||
await spawnNextTrainerOrEndEncounter(scene);
|
||||
}
|
||||
)
|
||||
.withSimpleOption(
|
||||
{
|
||||
buttonLabel: `${namespace}.option.2.label`,
|
||||
buttonTooltip: `${namespace}.option.2.tooltip`,
|
||||
selected: [
|
||||
{
|
||||
speaker: `${namespace}.speaker`,
|
||||
text: `${namespace}.option.2.selected`,
|
||||
},
|
||||
],
|
||||
},
|
||||
async (scene: BattleScene) => {
|
||||
// Refuse the challenge, they full heal the party and give the player a Rarer Candy
|
||||
scene.unshiftPhase(new PartyHealPhase(scene, true));
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.RARER_CANDY], fillRemaining: false });
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
}
|
||||
)
|
||||
.build();
|
||||
|
||||
async function spawnNextTrainerOrEndEncounter(scene: BattleScene) {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const nextConfig = encounter.enemyPartyConfigs.pop();
|
||||
if (!nextConfig) {
|
||||
await transitionMysteryEncounterIntroVisuals(scene, false, false);
|
||||
await showEncounterDialogue(scene, `${namespace}.victory`, `${namespace}.speaker`);
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.MYSTERY_ENCOUNTER_MACHO_BRACE], fillRemaining: false });
|
||||
encounter.doContinueEncounter = null;
|
||||
leaveEncounterWithoutBattle(scene, false, MysteryEncounterMode.TRAINER_BATTLE);
|
||||
} else {
|
||||
await initBattleWithEnemyConfig(scene, nextConfig);
|
||||
}
|
||||
}
|
||||
|
||||
function endTrainerBattleAndShowDialogue(scene: BattleScene): Promise<void> {
|
||||
return new Promise(async resolve => {
|
||||
if (scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length === 0) {
|
||||
// Battle is over
|
||||
scene.tweens.add({
|
||||
targets: scene.currentBattle.trainer,
|
||||
x: "+=16",
|
||||
y: "-=16",
|
||||
alpha: 0,
|
||||
ease: "Sine.easeInOut",
|
||||
duration: 750,
|
||||
onComplete: () => {
|
||||
scene.field.remove(scene.currentBattle.trainer, true);
|
||||
}
|
||||
});
|
||||
await spawnNextTrainerOrEndEncounter(scene);
|
||||
resolve(); // Wait for all dialogue/post battle stuff to complete before resolving
|
||||
} else {
|
||||
scene.arena.resetArenaEffects();
|
||||
const playerField = scene.getPlayerField();
|
||||
playerField.forEach((_, p) => scene.unshiftPhase(new ReturnPhase(scene, p)));
|
||||
|
||||
for (const pokemon of scene.getParty()) {
|
||||
// Only trigger form change when Eiscue is in Noice form
|
||||
// Hardcoded Eiscue for now in case it is fused with another pokemon
|
||||
if (pokemon.species.speciesId === Species.EISCUE && pokemon.hasAbility(Abilities.ICE_FACE) && pokemon.formIndex === 1) {
|
||||
scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
|
||||
}
|
||||
|
||||
pokemon.resetBattleData();
|
||||
applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon);
|
||||
}
|
||||
|
||||
scene.unshiftPhase(new ShowTrainerPhase(scene));
|
||||
// Hide the trainer and init next battle
|
||||
const trainer = scene.currentBattle.trainer;
|
||||
// Unassign previous trainer from battle so it isn't destroyed before animation completes
|
||||
scene.currentBattle.trainer = null;
|
||||
await spawnNextTrainerOrEndEncounter(scene);
|
||||
scene.tweens.add({
|
||||
targets: trainer,
|
||||
x: "+=16",
|
||||
y: "-=16",
|
||||
alpha: 0,
|
||||
ease: "Sine.easeInOut",
|
||||
duration: 750,
|
||||
onComplete: () => {
|
||||
scene.field.remove(trainer, true);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getVictorTrainerConfig(scene: BattleScene): EnemyPartyConfig {
|
||||
return {
|
||||
trainerType: TrainerType.VICTOR,
|
||||
pokemonConfigs: [
|
||||
{
|
||||
species: getPokemonSpecies(Species.SWELLOW),
|
||||
isBoss: false,
|
||||
abilityIndex: 0, // Guts
|
||||
nature: Nature.ADAMANT,
|
||||
moveSet: [Moves.FACADE, Moves.BRAVE_BIRD, Moves.PROTECT, Moves.QUICK_ATTACK],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType,
|
||||
isTransferable: false
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.FOCUS_BAND) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
isTransferable: false
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.OBSTAGOON),
|
||||
isBoss: false,
|
||||
abilityIndex: 1, // Guts
|
||||
nature: Nature.ADAMANT,
|
||||
moveSet: [Moves.FACADE, Moves.OBSTRUCT, Moves.NIGHT_SLASH, Moves.FIRE_PUNCH],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType,
|
||||
isTransferable: false
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.LEFTOVERS) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
isTransferable: false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
function getVictoriaTrainerConfig(scene: BattleScene): EnemyPartyConfig {
|
||||
return {
|
||||
trainerType: TrainerType.VICTORIA,
|
||||
pokemonConfigs: [
|
||||
{
|
||||
species: getPokemonSpecies(Species.ROSERADE),
|
||||
isBoss: false,
|
||||
abilityIndex: 0, // Natural Cure
|
||||
nature: Nature.CALM,
|
||||
moveSet: [Moves.SYNTHESIS, Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.SLEEP_POWDER],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.SOUL_DEW) as PokemonHeldItemModifierType,
|
||||
isTransferable: false
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
isTransferable: false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.GARDEVOIR),
|
||||
isBoss: false,
|
||||
formIndex: 1,
|
||||
nature: Nature.TIMID,
|
||||
moveSet: [Moves.PSYSHOCK, Moves.MOONBLAST, Moves.SHADOW_BALL, Moves.WILL_O_WISP],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.PSYCHIC]) as PokemonHeldItemModifierType,
|
||||
stackCount: 1,
|
||||
isTransferable: false
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.FAIRY]) as PokemonHeldItemModifierType,
|
||||
stackCount: 1,
|
||||
isTransferable: false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
function getViviTrainerConfig(scene: BattleScene): EnemyPartyConfig {
|
||||
return {
|
||||
trainerType: TrainerType.VIVI,
|
||||
pokemonConfigs: [
|
||||
{
|
||||
species: getPokemonSpecies(Species.SEAKING),
|
||||
isBoss: false,
|
||||
abilityIndex: 3, // Lightning Rod
|
||||
nature: Nature.ADAMANT,
|
||||
moveSet: [Moves.WATERFALL, Moves.MEGAHORN, Moves.KNOCK_OFF, Moves.REST],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
isTransferable: false
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType,
|
||||
stackCount: 4,
|
||||
isTransferable: false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.BRELOOM),
|
||||
isBoss: false,
|
||||
abilityIndex: 1, // Poison Heal
|
||||
nature: Nature.JOLLY,
|
||||
moveSet: [Moves.SPORE, Moves.SWORDS_DANCE, Moves.SEED_BOMB, Moves.DRAIN_PUNCH],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType,
|
||||
stackCount: 4,
|
||||
isTransferable: false
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.TOXIC_ORB) as PokemonHeldItemModifierType,
|
||||
isTransferable: false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.CAMERUPT),
|
||||
isBoss: false,
|
||||
formIndex: 1,
|
||||
nature: Nature.CALM,
|
||||
moveSet: [Moves.EARTH_POWER, Moves.FIRE_BLAST, Moves.YAWN, Moves.PROTECT],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType,
|
||||
stackCount: 3,
|
||||
isTransferable: false
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
function getVickyTrainerConfig(scene: BattleScene): EnemyPartyConfig {
|
||||
return {
|
||||
trainerType: TrainerType.VICKY,
|
||||
pokemonConfigs: [
|
||||
{
|
||||
species: getPokemonSpecies(Species.MEDICHAM),
|
||||
isBoss: false,
|
||||
formIndex: 1,
|
||||
nature: Nature.IMPISH,
|
||||
moveSet: [Moves.AXE_KICK, Moves.ICE_PUNCH, Moves.ZEN_HEADBUTT, Moves.BULLET_PUNCH],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType,
|
||||
isTransferable: false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
function getVitoTrainerConfig(scene: BattleScene): EnemyPartyConfig {
|
||||
return {
|
||||
trainerType: TrainerType.VITO,
|
||||
pokemonConfigs: [
|
||||
{
|
||||
species: getPokemonSpecies(Species.HISUI_ELECTRODE),
|
||||
isBoss: false,
|
||||
abilityIndex: 0, // Soundproof
|
||||
nature: Nature.MODEST,
|
||||
moveSet: [Moves.THUNDERBOLT, Moves.GIGA_DRAIN, Moves.FOUL_PLAY, Moves.THUNDER_WAVE],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [Stat.SPD]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
isTransferable: false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.SWALOT),
|
||||
isBoss: false,
|
||||
abilityIndex: 2, // Gluttony
|
||||
nature: Nature.QUIET,
|
||||
moveSet: [Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.ICE_BEAM, Moves.EARTHQUAKE],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.APICOT]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.GANLON]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.STARF]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SALAC]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LANSAT]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LIECHI]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.PETAYA]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
},
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LEPPA]) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.DODRIO),
|
||||
isBoss: false,
|
||||
abilityIndex: 2, // Tangled Feet
|
||||
nature: Nature.JOLLY,
|
||||
moveSet: [Moves.DRILL_PECK, Moves.QUICK_ATTACK, Moves.THRASH, Moves.KNOCK_OFF],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.KINGS_ROCK) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
isTransferable: false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.ALAKAZAM),
|
||||
isBoss: false,
|
||||
formIndex: 1,
|
||||
nature: Nature.BOLD,
|
||||
moveSet: [Moves.PSYCHIC, Moves.SHADOW_BALL, Moves.FOCUS_BLAST, Moves.THUNDERBOLT],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.WIDE_LENS) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
isTransferable: false
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.DARMANITAN),
|
||||
isBoss: false,
|
||||
abilityIndex: 0, // Sheer Force
|
||||
nature: Nature.IMPISH,
|
||||
moveSet: [Moves.EARTHQUAKE, Moves.U_TURN, Moves.FLARE_BLITZ, Moves.ROCK_SLIDE],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifierType: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType,
|
||||
stackCount: 2,
|
||||
isTransferable: false
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
@ -14,7 +14,7 @@ import { randSeedShuffle } from "#app/utils";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { getEncounterText, queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
@ -28,7 +28,7 @@ const namespace = "mysteryEncounter:trainingSession";
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/43 | GitHub Issue #43}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const TrainingSessionEncounter: IMysteryEncounter =
|
||||
export const TrainingSessionEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.TRAINING_SESSION)
|
||||
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
||||
.withSceneWaveRangeRequirement(10, 180) // waves 10 to 180
|
||||
@ -444,7 +444,7 @@ function getEnemyConfig(scene: BattleScene, playerPokemon: PlayerPokemon,segment
|
||||
formIndex: playerPokemon.formIndex,
|
||||
level: playerPokemon.level,
|
||||
dataSource: data,
|
||||
modifierTypes: modifierTypes,
|
||||
modifierConfigs: modifierTypes,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { EnemyPartyConfig, EnemyPokemonConfig, generateModifierTypeOption, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, loadCustomMovesForEncounter, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { EnemyPartyConfig, EnemyPokemonConfig, generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, loadCustomMovesForEncounter, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { ModifierRewardPhase } from "#app/phases";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
@ -28,7 +28,7 @@ const SOUND_EFFECT_WAIT_TIME = 700;
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/74 | GitHub Issue #74}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const TrashToTreasureEncounter: IMysteryEncounter =
|
||||
export const TrashToTreasureEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.TRASH_TO_TREASURE)
|
||||
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
||||
.withSceneWaveRangeRequirement(10, 180)
|
||||
@ -147,8 +147,8 @@ export const TrashToTreasureEncounter: IMysteryEncounter =
|
||||
.build();
|
||||
|
||||
async function tryApplyDigRewardItems(scene: BattleScene) {
|
||||
const shellBell = generateModifierTypeOption(scene, modifierTypes.SHELL_BELL).type as PokemonHeldItemModifierType;
|
||||
const leftovers = generateModifierTypeOption(scene, modifierTypes.LEFTOVERS).type as PokemonHeldItemModifierType;
|
||||
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||
const leftovers = generateModifierType(scene, modifierTypes.LEFTOVERS) as PokemonHeldItemModifierType;
|
||||
|
||||
const party = scene.getParty();
|
||||
|
||||
|
@ -2,7 +2,7 @@ import { Type } from "#app/data/type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { leaveEncounterWithoutBattle, setEncounterRewards, } from "../utils/encounter-phase-utils";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
@ -82,7 +82,7 @@ const excludedPokemon = [
|
||||
* @see {@link https://github.com/AsdarDevelops/PokeRogue-Events/issues/137 | GitHub Issue #137}
|
||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||
*/
|
||||
export const WeirdDreamEncounter: IMysteryEncounter =
|
||||
export const WeirdDreamEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.WEIRD_DREAM)
|
||||
.withEncounterTier(MysteryEncounterTier.ROGUE)
|
||||
.withIntroSpriteConfigs([
|
||||
@ -205,11 +205,6 @@ export const WeirdDreamEncounter: IMysteryEncounter =
|
||||
return true;
|
||||
}
|
||||
)
|
||||
.withOutroDialogue([
|
||||
{
|
||||
text: `${namespace}.outro`
|
||||
}
|
||||
])
|
||||
.build();
|
||||
|
||||
interface PokemonTransformation {
|
||||
|
@ -6,25 +6,16 @@ import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounterIntroVisuals, { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro";
|
||||
import * as Utils from "#app/utils";
|
||||
import { StatusEffect } from "../status-effect";
|
||||
import MysteryEncounterDialogue, {
|
||||
OptionTextDisplay
|
||||
} from "./mystery-encounter-dialogue";
|
||||
import MysteryEncounterDialogue, { OptionTextDisplay } from "./mystery-encounter-dialogue";
|
||||
import MysteryEncounterOption, { MysteryEncounterOptionBuilder, OptionPhaseCallback } from "./mystery-encounter-option";
|
||||
import {
|
||||
EncounterPokemonRequirement,
|
||||
EncounterSceneRequirement,
|
||||
HealthRatioRequirement,
|
||||
PartySizeRequirement,
|
||||
StatusEffectRequirement,
|
||||
WaveRangeRequirement
|
||||
} from "./mystery-encounter-requirements";
|
||||
import { EncounterPokemonRequirement, EncounterSceneRequirement, HealthRatioRequirement, PartySizeRequirement, StatusEffectRequirement, WaveRangeRequirement } from "./mystery-encounter-requirements";
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
import { EncounterAnim } from "#app/data/battle-anims";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
export interface StartOfBattleEffect {
|
||||
export interface EncounterStartOfBattleEffect {
|
||||
sourcePokemon?: Pokemon;
|
||||
sourceBattlerIndex?: BattlerIndex;
|
||||
targets: BattlerIndex[];
|
||||
@ -33,7 +24,7 @@ export interface StartOfBattleEffect {
|
||||
followUp?: boolean;
|
||||
}
|
||||
|
||||
export default interface IMysteryEncounter {
|
||||
export default interface MysteryEncounter {
|
||||
/**
|
||||
* Required params
|
||||
*/
|
||||
@ -44,13 +35,44 @@ export default interface IMysteryEncounter {
|
||||
* Optional params
|
||||
*/
|
||||
encounterTier?: MysteryEncounterTier;
|
||||
/**
|
||||
* Custom battle animations that are configured for encounter effects and visuals
|
||||
* Specify here so that assets are loaded on initialization of encounter
|
||||
*/
|
||||
encounterAnimations?: EncounterAnim[];
|
||||
/**
|
||||
* If true, hides "A Wild X Appeared" etc. messages
|
||||
* Default true
|
||||
*/
|
||||
hideBattleIntroMessage?: boolean;
|
||||
/**
|
||||
* If true, when an option is selected the field visuals will fade out automatically
|
||||
* Default false
|
||||
*/
|
||||
autoHideIntroVisuals?: boolean;
|
||||
/**
|
||||
* Intro visuals on the field will slide in from the right instead of the left
|
||||
* Default false
|
||||
*/
|
||||
enterIntroVisualsFromRight?: boolean;
|
||||
/**
|
||||
* If true, allows catching a wild pokemon during the encounter
|
||||
* Default false
|
||||
*/
|
||||
catchAllowed?: boolean;
|
||||
/**
|
||||
* If true, encounter will continuously run through multiple battles/puzzles/etc. instead of going to next wave
|
||||
* MUST EVENTUALLY BE DISABLED TO CONTINUE TO NEXT WAVE
|
||||
* Default false
|
||||
*/
|
||||
continuousEncounter?: boolean;
|
||||
/**
|
||||
* Maximum number of times the encounter can be seen per run
|
||||
* Rogue tier encounters default to 1, others default to 3
|
||||
*/
|
||||
maxAllowedEncounters?: number;
|
||||
|
||||
|
||||
/**
|
||||
* Event callback functions
|
||||
*/
|
||||
@ -62,6 +84,8 @@ export default interface IMysteryEncounter {
|
||||
doEncounterExp?: (scene: BattleScene) => boolean;
|
||||
/** Will provide the player a rewards shop for that wave */
|
||||
doEncounterRewards?: (scene: BattleScene) => boolean;
|
||||
/** Will execute callback during VictoryPhase of a continuousEncounter */
|
||||
doContinueEncounter?: (scene: BattleScene) => Promise<void>;
|
||||
|
||||
/**
|
||||
* Requirements
|
||||
@ -90,6 +114,7 @@ export default interface IMysteryEncounter {
|
||||
/**
|
||||
* Data used for setting up/initializing enemy party in battles
|
||||
* Can store multiple configs so that one can be chosen based on option selected
|
||||
* Should usually be defined in `onInit()` or `onPreOptionPhase()`
|
||||
*/
|
||||
enemyPartyConfigs?: EnemyPartyConfig[];
|
||||
/**
|
||||
@ -131,7 +156,7 @@ export default interface IMysteryEncounter {
|
||||
/**
|
||||
* Will be set by option select handlers automatically, and can be used to refer to which option was chosen by later phases
|
||||
*/
|
||||
startOfBattleEffects?: StartOfBattleEffect[];
|
||||
startOfBattleEffects?: EncounterStartOfBattleEffect[];
|
||||
/**
|
||||
* Can be set higher or lower based on the type of battle or exp gained for an option/encounter
|
||||
* Defaults to 1
|
||||
@ -149,14 +174,14 @@ export default interface IMysteryEncounter {
|
||||
* These objects will be saved as part of session data any time the player is on a floor with an encounter
|
||||
* Unless you know what you're doing, you should use MysteryEncounterBuilder to create an instance for this class
|
||||
*/
|
||||
export default class IMysteryEncounter implements IMysteryEncounter {
|
||||
export default class MysteryEncounter implements MysteryEncounter {
|
||||
/**
|
||||
* Used for keeping RNG consistent on session resets, but increments when cycling through multiple "Encounters" on the same wave
|
||||
* You should only need to interact via getter/update methods
|
||||
*/
|
||||
private seedOffset?: any;
|
||||
|
||||
constructor(encounter: IMysteryEncounter) {
|
||||
constructor(encounter: MysteryEncounter) {
|
||||
if (!isNullOrUndefined(encounter)) {
|
||||
Object.assign(this, encounter);
|
||||
}
|
||||
@ -170,6 +195,7 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
||||
this.hideBattleIntroMessage = this.hideBattleIntroMessage ?? false;
|
||||
this.autoHideIntroVisuals = this.autoHideIntroVisuals ?? true;
|
||||
this.enterIntroVisualsFromRight = this.enterIntroVisualsFromRight ?? false;
|
||||
this.continuousEncounter = this.continuousEncounter ?? false;
|
||||
|
||||
// Reset any dirty flags or encounter data
|
||||
this.startOfBattleEffectsComplete = false;
|
||||
@ -238,11 +264,11 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
||||
|
||||
}
|
||||
if (truePrimaryPool.length > 0) {
|
||||
// always choose from the non-overlapping pokemon first
|
||||
// Always choose from the non-overlapping pokemon first
|
||||
this.primaryPokemon = truePrimaryPool[Utils.randSeedInt(truePrimaryPool.length, 0)];
|
||||
return true;
|
||||
} else {
|
||||
// if there are multiple overlapping pokemon, we're okay - just choose one and take it out of the primary pokemon pool
|
||||
// If there are multiple overlapping pokemon, we're okay - just choose one and take it out of the primary pokemon pool
|
||||
if (overlap.length > 1 || (this.secondaryPokemon.length - overlap.length >= 1)) {
|
||||
// is this working?
|
||||
this.primaryPokemon = overlap[Utils.randSeedInt(overlap.length, 0)];
|
||||
@ -371,7 +397,7 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
||||
}
|
||||
|
||||
/**
|
||||
* If an encounter uses {@link MysteryEncounterMode.CONTINUOUS_ENCOUNTER},
|
||||
* If an encounter uses {@link MysteryEncounterMode.continuousEncounter},
|
||||
* should rely on this value for seed offset instead of wave index.
|
||||
*
|
||||
* This offset is incremented for each new {@link MysteryEncounterPhase} that occurs,
|
||||
@ -396,7 +422,11 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
||||
}
|
||||
}
|
||||
|
||||
export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
/**
|
||||
* Builder class for creating a MysteryEncounter
|
||||
* must call `build()` at the end after specifying all params for the MysteryEncounter
|
||||
*/
|
||||
export class MysteryEncounterBuilder implements Partial<MysteryEncounter> {
|
||||
encounterType?: MysteryEncounterType;
|
||||
options?: [MysteryEncounterOption, MysteryEncounterOption, ...MysteryEncounterOption[]] = [null, null];
|
||||
spriteConfigs?: MysteryEncounterSpriteConfig[];
|
||||
@ -418,7 +448,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
hideBattleIntroMessage?: boolean;
|
||||
hideIntroVisuals?: boolean;
|
||||
enterIntroVisualsFromRight?: boolean;
|
||||
enemyPartyConfigs?: EnemyPartyConfig[] = [];
|
||||
continuousEncounter?: boolean;
|
||||
|
||||
/**
|
||||
* REQUIRED
|
||||
@ -429,7 +459,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param encounterType
|
||||
* @returns this
|
||||
*/
|
||||
static withEncounterType(encounterType: MysteryEncounterType): MysteryEncounterBuilder & Pick<IMysteryEncounter, "encounterType"> {
|
||||
static withEncounterType(encounterType: MysteryEncounterType): MysteryEncounterBuilder & Pick<MysteryEncounter, "encounterType"> {
|
||||
return Object.assign(new MysteryEncounterBuilder(), { encounterType: encounterType });
|
||||
}
|
||||
|
||||
@ -442,7 +472,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param option - MysteryEncounterOption to add, can use MysteryEncounterOptionBuilder to create instance
|
||||
* @returns
|
||||
*/
|
||||
withOption(option: MysteryEncounterOption): this & Pick<IMysteryEncounter, "options"> {
|
||||
withOption(option: MysteryEncounterOption): this & Pick<MysteryEncounter, "options"> {
|
||||
if (this.options[0] === null) {
|
||||
return Object.assign(this, { options: [option, this.options[0]] });
|
||||
} else if (this.options[1] === null) {
|
||||
@ -464,7 +494,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param callback - {@linkcode OptionPhaseCallback}
|
||||
* @returns
|
||||
*/
|
||||
withSimpleOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback): this & Pick<IMysteryEncounter, "options"> {
|
||||
withSimpleOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback): this & Pick<MysteryEncounter, "options"> {
|
||||
return this.withOption(new MysteryEncounterOptionBuilder().withOptionMode(MysteryEncounterOptionMode.DEFAULT).withDialogue(dialogue).withOptionPhase(callback).build());
|
||||
}
|
||||
|
||||
@ -478,7 +508,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param callback - {@linkcode OptionPhaseCallback}
|
||||
* @returns
|
||||
*/
|
||||
withSimpleDexProgressOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback): this & Pick<IMysteryEncounter, "options"> {
|
||||
withSimpleDexProgressOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback): this & Pick<MysteryEncounter, "options"> {
|
||||
return this.withOption(new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withHasDexProgress(true)
|
||||
@ -492,7 +522,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param spriteConfigs
|
||||
* @returns
|
||||
*/
|
||||
withIntroSpriteConfigs(spriteConfigs: MysteryEncounterSpriteConfig[]): this & Pick<IMysteryEncounter, "spriteConfigs"> {
|
||||
withIntroSpriteConfigs(spriteConfigs: MysteryEncounterSpriteConfig[]): this & Pick<MysteryEncounter, "spriteConfigs"> {
|
||||
return Object.assign(this, { spriteConfigs: spriteConfigs });
|
||||
}
|
||||
|
||||
@ -521,28 +551,38 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param encounterTier
|
||||
* @returns
|
||||
*/
|
||||
withEncounterTier(encounterTier: MysteryEncounterTier): this & Required<Pick<IMysteryEncounter, "encounterTier">> {
|
||||
withEncounterTier(encounterTier: MysteryEncounterTier): this & Required<Pick<MysteryEncounter, "encounterTier">> {
|
||||
return Object.assign(this, { encounterTier: encounterTier });
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines any EncounterAnim animations that are intended to be used during the encounter
|
||||
* EncounterAnims can be played at any point during an encounter or callback
|
||||
* EncounterAnims are custom battle animations (think Ice Beam) that can be played at any point during an encounter or callback
|
||||
* They just need to be specified here so that resources are loaded on encounter init
|
||||
* @param encounterAnimations
|
||||
* @returns
|
||||
*/
|
||||
withAnimations(...encounterAnimations: EncounterAnim[]): this & Required<Pick<IMysteryEncounter, "encounterAnimations">> {
|
||||
withAnimations(...encounterAnimations: EncounterAnim[]): this & Required<Pick<MysteryEncounter, "encounterAnimations">> {
|
||||
const animations = Array.isArray(encounterAnimations) ? encounterAnimations : [encounterAnimations];
|
||||
return Object.assign(this, { encounterAnimations: animations });
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, encounter will continuously run through multiple battles/puzzles/etc. instead of going to next wave
|
||||
* MUST EVENTUALLY BE DISABLED TO CONTINUE TO NEXT WAVE
|
||||
* Default false
|
||||
* @param continuousEncounter
|
||||
*/
|
||||
withContinuousEncounter(continuousEncounter: boolean): this & Required<Pick<MysteryEncounter, "continuousEncounter">> {
|
||||
return Object.assign(this, { continuousEncounter: continuousEncounter });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of times that an encounter can spawn in a given Classic run
|
||||
* @param maxAllowedEncounters
|
||||
* @returns
|
||||
*/
|
||||
withMaxAllowedEncounters(maxAllowedEncounters: number): this & Required<Pick<IMysteryEncounter, "maxAllowedEncounters">> {
|
||||
withMaxAllowedEncounters(maxAllowedEncounters: number): this & Required<Pick<MysteryEncounter, "maxAllowedEncounters">> {
|
||||
return Object.assign(this, { maxAllowedEncounters: maxAllowedEncounters });
|
||||
}
|
||||
|
||||
@ -553,7 +593,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param requirement
|
||||
* @returns
|
||||
*/
|
||||
withSceneRequirement(requirement: EncounterSceneRequirement): this & Required<Pick<IMysteryEncounter, "requirements">> {
|
||||
withSceneRequirement(requirement: EncounterSceneRequirement): this & Required<Pick<MysteryEncounter, "requirements">> {
|
||||
if (requirement instanceof EncounterPokemonRequirement) {
|
||||
Error("Incorrectly added pokemon requirement as scene requirement.");
|
||||
}
|
||||
@ -568,7 +608,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param max optional max wave. If not given, defaults to min => exact wave
|
||||
* @returns
|
||||
*/
|
||||
withSceneWaveRangeRequirement(min: number, max?: number): this & Required<Pick<IMysteryEncounter, "requirements">> {
|
||||
withSceneWaveRangeRequirement(min: number, max?: number): this & Required<Pick<MysteryEncounter, "requirements">> {
|
||||
return this.withSceneRequirement(new WaveRangeRequirement([min, max ?? min]));
|
||||
}
|
||||
|
||||
@ -580,7 +620,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param excludeFainted - if true, only counts unfainted mons
|
||||
* @returns
|
||||
*/
|
||||
withScenePartySizeRequirement(min: number, max?: number, excludeFainted?: boolean): this & Required<Pick<IMysteryEncounter, "requirements">> {
|
||||
withScenePartySizeRequirement(min: number, max?: number, excludeFainted?: boolean): this & Required<Pick<MysteryEncounter, "requirements">> {
|
||||
return this.withSceneRequirement(new PartySizeRequirement([min, max ?? min], excludeFainted));
|
||||
}
|
||||
|
||||
@ -590,7 +630,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param requirement {@linkcode EncounterPokemonRequirement}
|
||||
* @returns
|
||||
*/
|
||||
withPrimaryPokemonRequirement(requirement: EncounterPokemonRequirement): this & Required<Pick<IMysteryEncounter, "primaryPokemonRequirements">> {
|
||||
withPrimaryPokemonRequirement(requirement: EncounterPokemonRequirement): this & Required<Pick<MysteryEncounter, "primaryPokemonRequirements">> {
|
||||
if (requirement instanceof EncounterSceneRequirement) {
|
||||
Error("Incorrectly added scene requirement as pokemon requirement.");
|
||||
}
|
||||
@ -607,7 +647,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param invertQuery if true will invert the query
|
||||
* @returns
|
||||
*/
|
||||
withPrimaryPokemonStatusEffectRequirement(statusEffect: StatusEffect | StatusEffect[], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required<Pick<IMysteryEncounter, "primaryPokemonRequirements">> {
|
||||
withPrimaryPokemonStatusEffectRequirement(statusEffect: StatusEffect | StatusEffect[], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required<Pick<MysteryEncounter, "primaryPokemonRequirements">> {
|
||||
return this.withPrimaryPokemonRequirement(new StatusEffectRequirement(statusEffect, minNumberOfPokemon, invertQuery));
|
||||
}
|
||||
|
||||
@ -619,14 +659,14 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param invertQuery if true will invert the query
|
||||
* @returns
|
||||
*/
|
||||
withPrimaryPokemonHealthRatioRequirement(requiredHealthRange: [number, number], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required<Pick<IMysteryEncounter, "primaryPokemonRequirements">> {
|
||||
withPrimaryPokemonHealthRatioRequirement(requiredHealthRange: [number, number], minNumberOfPokemon: number = 1, invertQuery: boolean = false): this & Required<Pick<MysteryEncounter, "primaryPokemonRequirements">> {
|
||||
return this.withPrimaryPokemonRequirement(new HealthRatioRequirement(requiredHealthRange, minNumberOfPokemon, invertQuery));
|
||||
}
|
||||
|
||||
// TODO: Maybe add an optional parameter for excluding primary pokemon from the support cast?
|
||||
// ex. if your only grass type pokemon, a snivy, is chosen as primary, if the support pokemon requires a grass type, the event won't trigger because
|
||||
// it's already been
|
||||
withSecondaryPokemonRequirement(requirement: EncounterPokemonRequirement, excludePrimaryFromSecondaryRequirements: boolean = false): this & Required<Pick<IMysteryEncounter, "secondaryPokemonRequirements">> {
|
||||
withSecondaryPokemonRequirement(requirement: EncounterPokemonRequirement, excludePrimaryFromSecondaryRequirements: boolean = false): this & Required<Pick<MysteryEncounter, "secondaryPokemonRequirements">> {
|
||||
if (requirement instanceof EncounterSceneRequirement) {
|
||||
Error("Incorrectly added scene requirement as pokemon requirement.");
|
||||
}
|
||||
@ -646,7 +686,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param doEncounterRewards - synchronous callback function to perform during rewards phase of the encounter
|
||||
* @returns
|
||||
*/
|
||||
withRewards(doEncounterRewards: (scene: BattleScene) => boolean): this & Required<Pick<IMysteryEncounter, "doEncounterRewards">> {
|
||||
withRewards(doEncounterRewards: (scene: BattleScene) => boolean): this & Required<Pick<MysteryEncounter, "doEncounterRewards">> {
|
||||
return Object.assign(this, { doEncounterRewards: doEncounterRewards });
|
||||
}
|
||||
|
||||
@ -660,7 +700,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param doEncounterExp - synchronous callback function to perform during rewards phase of the encounter
|
||||
* @returns
|
||||
*/
|
||||
withExp(doEncounterExp: (scene: BattleScene) => boolean): this & Required<Pick<IMysteryEncounter, "doEncounterExp">> {
|
||||
withExp(doEncounterExp: (scene: BattleScene) => boolean): this & Required<Pick<MysteryEncounter, "doEncounterExp">> {
|
||||
return Object.assign(this, { doEncounterExp: doEncounterExp });
|
||||
}
|
||||
|
||||
@ -671,7 +711,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param onInit - synchronous callback function to perform as soon as the encounter is selected for the next phase
|
||||
* @returns
|
||||
*/
|
||||
withOnInit(onInit: (scene: BattleScene) => boolean): this & Required<Pick<IMysteryEncounter, "onInit">> {
|
||||
withOnInit(onInit: (scene: BattleScene) => boolean): this & Required<Pick<MysteryEncounter, "onInit">> {
|
||||
return Object.assign(this, { onInit: onInit });
|
||||
}
|
||||
|
||||
@ -681,27 +721,17 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param onVisualsStart - synchronous callback function to perform as soon as the enemy field finishes sliding in
|
||||
* @returns
|
||||
*/
|
||||
withOnVisualsStart(onVisualsStart: (scene: BattleScene) => boolean): this & Required<Pick<IMysteryEncounter, "onVisualsStart">> {
|
||||
withOnVisualsStart(onVisualsStart: (scene: BattleScene) => boolean): this & Required<Pick<MysteryEncounter, "onVisualsStart">> {
|
||||
return Object.assign(this, { onVisualsStart: onVisualsStart });
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines any enemies to use for a battle from the mystery encounter
|
||||
* @param enemyPartyConfig
|
||||
* @returns
|
||||
*/
|
||||
withEnemyPartyConfig(enemyPartyConfig: EnemyPartyConfig): this & Required<Pick<IMysteryEncounter, "enemyPartyConfigs">> {
|
||||
this.enemyPartyConfigs.push(enemyPartyConfig);
|
||||
return Object.assign(this, { enemyPartyConfigs: this.enemyPartyConfigs });
|
||||
}
|
||||
|
||||
/**
|
||||
* Can set whether catching is allowed or not on the encounter
|
||||
* This flag can also be programmatically set inside option event functions or elsewhere
|
||||
* @param catchAllowed - if true, allows enemy pokemon to be caught during the encounter
|
||||
* @returns
|
||||
*/
|
||||
withCatchAllowed(catchAllowed: boolean): this & Required<Pick<IMysteryEncounter, "catchAllowed">> {
|
||||
withCatchAllowed(catchAllowed: boolean): this & Required<Pick<MysteryEncounter, "catchAllowed">> {
|
||||
return Object.assign(this, { catchAllowed: catchAllowed });
|
||||
}
|
||||
|
||||
@ -709,7 +739,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param hideBattleIntroMessage - if true, will not show the trainerAppeared/wildAppeared/bossAppeared message for an encounter
|
||||
* @returns
|
||||
*/
|
||||
withHideWildIntroMessage(hideBattleIntroMessage: boolean): this & Required<Pick<IMysteryEncounter, "hideBattleIntroMessage">> {
|
||||
withHideWildIntroMessage(hideBattleIntroMessage: boolean): this & Required<Pick<MysteryEncounter, "hideBattleIntroMessage">> {
|
||||
return Object.assign(this, { hideBattleIntroMessage: hideBattleIntroMessage });
|
||||
}
|
||||
|
||||
@ -717,7 +747,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* @param autoHideIntroVisuals - if false, will not hide the intro visuals that are displayed at the beginning of encounter
|
||||
* @returns
|
||||
*/
|
||||
withAutoHideIntroVisuals(autoHideIntroVisuals: boolean): this & Required<Pick<IMysteryEncounter, "autoHideIntroVisuals">> {
|
||||
withAutoHideIntroVisuals(autoHideIntroVisuals: boolean): this & Required<Pick<MysteryEncounter, "autoHideIntroVisuals">> {
|
||||
return Object.assign(this, { autoHideIntroVisuals: autoHideIntroVisuals });
|
||||
}
|
||||
|
||||
@ -726,7 +756,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
* Default false
|
||||
* @returns
|
||||
*/
|
||||
withEnterIntroVisualsFromRight(enterIntroVisualsFromRight: boolean): this & Required<Pick<IMysteryEncounter, "enterIntroVisualsFromRight">> {
|
||||
withEnterIntroVisualsFromRight(enterIntroVisualsFromRight: boolean): this & Required<Pick<MysteryEncounter, "enterIntroVisualsFromRight">> {
|
||||
return Object.assign(this, { enterIntroVisualsFromRight: enterIntroVisualsFromRight });
|
||||
}
|
||||
|
||||
@ -806,7 +836,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
build(this: IMysteryEncounter): IMysteryEncounter {
|
||||
return new IMysteryEncounter(this);
|
||||
build(this: MysteryEncounter): MysteryEncounter {
|
||||
return new MysteryEncounter(this);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import { MysteriousChestEncounter } from "./encounters/mysterious-chest-encounte
|
||||
import { ShadyVitaminDealerEncounter } from "./encounters/shady-vitamin-dealer-encounter";
|
||||
import { SlumberingSnorlaxEncounter } from "./encounters/slumbering-snorlax-encounter";
|
||||
import { TrainingSessionEncounter } from "./encounters/training-session-encounter";
|
||||
import IMysteryEncounter from "./mystery-encounter";
|
||||
import MysteryEncounter from "./mystery-encounter";
|
||||
import { SafariZoneEncounter } from "#app/data/mystery-encounters/encounters/safari-zone-encounter";
|
||||
import { FieryFalloutEncounter } from "#app/data/mystery-encounters/encounters/fiery-fallout-encounter";
|
||||
import { TheStrongStuffEncounter } from "#app/data/mystery-encounters/encounters/the-strong-stuff-encounter";
|
||||
@ -25,6 +25,7 @@ import { ClowningAroundEncounter } from "#app/data/mystery-encounters/encounters
|
||||
import { PartTimerEncounter } from "#app/data/mystery-encounters/encounters/part-timer-encounter";
|
||||
import { DancingLessonsEncounter } from "#app/data/mystery-encounters/encounters/dancing-lessons-encounter";
|
||||
import { WeirdDreamEncounter } from "#app/data/mystery-encounters/encounters/weird-dream-encounter";
|
||||
import { TheWinstrateChallengeEncounter } from "#app/data/mystery-encounters/encounters/the-winstrate-challenge-encounter";
|
||||
|
||||
// Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * <number of missed spawns>) / 256
|
||||
export const BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT = 1;
|
||||
@ -132,7 +133,7 @@ export const CIVILIZATION_ENCOUNTER_BIOMES = [
|
||||
Biome.ISLAND
|
||||
];
|
||||
|
||||
export const allMysteryEncounters: { [encounterType: number]: IMysteryEncounter } = {};
|
||||
export const allMysteryEncounters: { [encounterType: number]: MysteryEncounter } = {};
|
||||
|
||||
|
||||
const extremeBiomeEncounters: MysteryEncounterType[] = [];
|
||||
@ -147,6 +148,7 @@ const humanTransitableBiomeEncounters: MysteryEncounterType[] = [
|
||||
MysteryEncounterType.SHADY_VITAMIN_DEALER,
|
||||
MysteryEncounterType.THE_POKEMON_SALESMAN,
|
||||
MysteryEncounterType.AN_OFFER_YOU_CANT_REFUSE,
|
||||
MysteryEncounterType.THE_WINSTRATE_CHALLENGE
|
||||
];
|
||||
|
||||
const civilizationBiomeEncounters: MysteryEncounterType[] = [
|
||||
@ -270,6 +272,7 @@ export function initMysteryEncounters() {
|
||||
allMysteryEncounters[MysteryEncounterType.PART_TIMER] = PartTimerEncounter;
|
||||
allMysteryEncounters[MysteryEncounterType.DANCING_LESSONS] = DancingLessonsEncounter;
|
||||
allMysteryEncounters[MysteryEncounterType.WEIRD_DREAM] = WeirdDreamEncounter;
|
||||
allMysteryEncounters[MysteryEncounterType.THE_WINSTRATE_CHALLENGE] = TheWinstrateChallengeEncounter;
|
||||
|
||||
// Add extreme encounters to biome map
|
||||
extremeBiomeEncounters.forEach(encounter => {
|
||||
|
@ -3,9 +3,9 @@ import { biomeLinks, BiomePoolTier } from "#app/data/biomes";
|
||||
import MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { WEIGHT_INCREMENT_ON_SPAWN_MISS } from "#app/data/mystery-encounters/mystery-encounters";
|
||||
import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import Pokemon, { FieldPosition, PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import Pokemon, { FieldPosition, PlayerPokemon, PokemonMove, PokemonSummonData } from "#app/field/pokemon";
|
||||
import { ExpBalanceModifier, ExpShareModifier, MultipleParticipantExpBonusModifier, PokemonExpBoosterModifier } from "#app/modifier/modifier";
|
||||
import { CustomModifierSettings, ModifierPoolType, ModifierType, ModifierTypeGenerator, ModifierTypeOption, modifierTypes, PokemonHeldItemModifierType, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
||||
import { CustomModifierSettings, ModifierPoolType, ModifierType, ModifierTypeGenerator, ModifierTypeOption, modifierTypes, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
||||
import { BattleEndPhase, EggLapsePhase, ExpPhase, GameOverPhase, MovePhase, SelectModifierPhase, ShowPartyExpBarPhase, TrainerVictoryPhase } from "#app/phases";
|
||||
import { MysteryEncounterBattlePhase, MysteryEncounterBattleStartCleanupPhase, MysteryEncounterPhase, MysteryEncounterRewardsPhase } from "#app/phases/mystery-encounter-phases";
|
||||
import PokemonData from "#app/system/pokemon-data";
|
||||
@ -30,8 +30,8 @@ import { TrainerConfig, trainerConfigs, TrainerSlot } from "#app/data/trainer-co
|
||||
import PokemonSpecies from "#app/data/pokemon-species";
|
||||
import Overrides from "#app/overrides";
|
||||
import { Egg, IEggOptions } from "#app/data/egg";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/mystery-encounter-pokemon-data";
|
||||
import HeldModifierConfig from "#app/interfaces/held-modifier-config";
|
||||
|
||||
/**
|
||||
* Animates exclamation sprite over trainer's head at start of encounter
|
||||
@ -67,18 +67,18 @@ export interface EnemyPokemonConfig {
|
||||
bossSegmentModifier?: number; // Additive to the determined segment number
|
||||
mysteryEncounterData?: MysteryEncounterPokemonData;
|
||||
formIndex?: number;
|
||||
abilityIndex?: number;
|
||||
level?: number;
|
||||
gender?: Gender;
|
||||
passive?: boolean;
|
||||
moveSet?: Moves[];
|
||||
nature?: Nature;
|
||||
ivs?: [integer, integer, integer, integer, integer, integer];
|
||||
ability?: Abilities;
|
||||
shiny?: boolean;
|
||||
/** Can set just the status, or pass a timer on the status turns */
|
||||
status?: StatusEffect | [StatusEffect, number];
|
||||
mysteryEncounterBattleEffects?: (pokemon: Pokemon) => void;
|
||||
modifierTypes?: PokemonHeldItemModifierType[];
|
||||
modifierConfigs?: HeldModifierConfig[];
|
||||
tags?: BattlerTagType[];
|
||||
dataSource?: PokemonData;
|
||||
}
|
||||
@ -258,10 +258,13 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
||||
}
|
||||
|
||||
// Set summon data fields
|
||||
if (!enemyPokemon.summonData) {
|
||||
enemyPokemon.summonData = new PokemonSummonData();
|
||||
}
|
||||
|
||||
// Set ability
|
||||
if (!isNullOrUndefined(config.ability)) {
|
||||
enemyPokemon.summonData.ability = config.ability;
|
||||
if (!isNullOrUndefined(config.abilityIndex)) {
|
||||
enemyPokemon.abilityIndex = config.abilityIndex;
|
||||
}
|
||||
|
||||
// Set gender
|
||||
@ -293,6 +296,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
||||
|
||||
enemyPokemon.initBattleInfo();
|
||||
enemyPokemon.getBattleInfo().initInfo(enemyPokemon);
|
||||
enemyPokemon.generateName();
|
||||
}
|
||||
|
||||
loadEnemyAssets.push(enemyPokemon.loadAssets());
|
||||
@ -315,8 +319,8 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
||||
});
|
||||
if (!loaded) {
|
||||
regenerateModifierPoolThresholds(scene.getEnemyField(), battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD);
|
||||
const customModifiers = partyConfig?.pokemonConfigs?.map(config => config?.modifierTypes);
|
||||
scene.generateEnemyModifiers(customModifiers);
|
||||
const customModifierTypes = partyConfig?.pokemonConfigs?.map(config => config?.modifierConfigs);
|
||||
scene.generateEnemyModifiers(customModifierTypes);
|
||||
}
|
||||
}
|
||||
|
||||
@ -363,7 +367,7 @@ export function updatePlayerMoney(scene: BattleScene, changeValue: number, playS
|
||||
* @param modifier
|
||||
* @param pregenArgs - can specify BerryType for berries, TM for TMs, AttackBoostType for item, etc.
|
||||
*/
|
||||
export function generateModifierTypeOption(scene: BattleScene, modifier: () => ModifierType, pregenArgs?: any[]): ModifierTypeOption {
|
||||
export function generateModifierType(scene: BattleScene, modifier: () => ModifierType, pregenArgs?: any[]): ModifierType {
|
||||
const modifierId = Object.keys(modifierTypes).find(k => modifierTypes[k] === modifier);
|
||||
let result: ModifierType = modifierTypes[modifierId]?.();
|
||||
|
||||
@ -373,6 +377,17 @@ export function generateModifierTypeOption(scene: BattleScene, modifier: () => M
|
||||
.withTierFromPool();
|
||||
|
||||
result = result instanceof ModifierTypeGenerator ? result.generateType(scene.getParty(), pregenArgs) : result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts modifier bullshit to an actual item
|
||||
* @param scene - Battle Scene
|
||||
* @param modifier
|
||||
* @param pregenArgs - can specify BerryType for berries, TM for TMs, AttackBoostType for item, etc.
|
||||
*/
|
||||
export function generateModifierTypeOption(scene: BattleScene, modifier: () => ModifierType, pregenArgs?: any[]): ModifierTypeOption {
|
||||
const result = generateModifierType(scene, modifier, pregenArgs);
|
||||
return new ModifierTypeOption(result, 0);
|
||||
}
|
||||
|
||||
@ -619,9 +634,10 @@ export function initSubsequentOptionSelect(scene: BattleScene, optionSelectSetti
|
||||
* Will skip any shops and rewards, and queue the next encounter phase as normal
|
||||
* @param scene
|
||||
* @param addHealPhase - when true, will add a shop phase to end of encounter with 0 rewards but healing items are available
|
||||
* @param encounterMode - Can set custom encounter mode if necessary (may be required for forcing Pokemon to return before next phase)
|
||||
*/
|
||||
export function leaveEncounterWithoutBattle(scene: BattleScene, addHealPhase: boolean = false) {
|
||||
scene.currentBattle.mysteryEncounter.encounterMode = MysteryEncounterMode.NO_BATTLE;
|
||||
export function leaveEncounterWithoutBattle(scene: BattleScene, addHealPhase: boolean = false, encounterMode: MysteryEncounterMode = MysteryEncounterMode.NO_BATTLE) {
|
||||
scene.currentBattle.mysteryEncounter.encounterMode = encounterMode;
|
||||
scene.clearPhaseQueue();
|
||||
scene.clearPhaseQueueSplice();
|
||||
handleMysteryEncounterVictory(scene, addHealPhase);
|
||||
@ -644,18 +660,22 @@ export function handleMysteryEncounterVictory(scene: BattleScene, addHealPhase:
|
||||
|
||||
// If in repeated encounter variant, do nothing
|
||||
// Variant must eventually be swapped in order to handle "true" end of the encounter
|
||||
if (scene.currentBattle.mysteryEncounter.encounterMode === MysteryEncounterMode.CONTINUOUS_ENCOUNTER || doNotContinue) {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
if (encounter.continuousEncounter || doNotContinue) {
|
||||
return;
|
||||
} else if (scene.currentBattle.mysteryEncounter.encounterMode === MysteryEncounterMode.NO_BATTLE) {
|
||||
} else if (encounter.encounterMode === MysteryEncounterMode.NO_BATTLE) {
|
||||
scene.pushPhase(new EggLapsePhase(scene));
|
||||
scene.pushPhase(new MysteryEncounterRewardsPhase(scene, addHealPhase));
|
||||
} else if (!scene.getEnemyParty().find(p => scene.currentBattle.mysteryEncounter.encounterMode !== MysteryEncounterMode.TRAINER_BATTLE ? p.isOnField() : !p?.isFainted(true))) {
|
||||
} else if (!scene.getEnemyParty().find(p => encounter.encounterMode !== MysteryEncounterMode.TRAINER_BATTLE ? p.isOnField() : !p?.isFainted(true))) {
|
||||
scene.pushPhase(new BattleEndPhase(scene));
|
||||
if (scene.currentBattle.mysteryEncounter.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
||||
if (encounter.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
||||
scene.pushPhase(new TrainerVictoryPhase(scene));
|
||||
}
|
||||
if (scene.gameMode.isEndless || !scene.gameMode.isWaveFinal(scene.currentBattle.waveIndex)) {
|
||||
scene.pushPhase(new EggLapsePhase(scene));
|
||||
if (!encounter.doContinueEncounter) {
|
||||
// Only lapse eggs once for multi-battle encounters
|
||||
scene.pushPhase(new EggLapsePhase(scene));
|
||||
}
|
||||
scene.pushPhase(new MysteryEncounterRewardsPhase(scene, addHealPhase));
|
||||
}
|
||||
}
|
||||
|
@ -11,13 +11,13 @@ export enum TransformationScreenPosition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates an "evolution-like" animation to transform a pokemon (presumably from the player's party) into a new one, not necessarily an evolution species.
|
||||
* Initiates an "evolution-like" animation to transform a previousPokemon (presumably from the player's party) into a new one, not necessarily an evolution species.
|
||||
* @param scene
|
||||
* @param pokemon
|
||||
* @param transformedPokemon
|
||||
* @param previousPokemon
|
||||
* @param transformPokemon
|
||||
* @param screenPosition
|
||||
*/
|
||||
export function doPokemonTransformationSequence(scene: BattleScene, pokemon: PlayerPokemon, transformedPokemon: PlayerPokemon, screenPosition: TransformationScreenPosition) {
|
||||
export function doPokemonTransformationSequence(scene: BattleScene, previousPokemon: PlayerPokemon, transformPokemon: PlayerPokemon, screenPosition: TransformationScreenPosition) {
|
||||
return new Promise<void>(resolve => {
|
||||
const transformationContainer = scene.fieldUI.getByName("Dream Background") as Phaser.GameObjects.Container;
|
||||
const transformationBaseBg = scene.add.image(0, 0, "default_bg");
|
||||
@ -36,7 +36,7 @@ export function doPokemonTransformationSequence(scene: BattleScene, pokemon: Pla
|
||||
const yOffset = screenPosition !== TransformationScreenPosition.CENTER ? -15 : 0;
|
||||
|
||||
const getPokemonSprite = () => {
|
||||
const ret = scene.addPokemonSprite(pokemon, transformationBaseBg.displayWidth / 2 + xOffset, transformationBaseBg.displayHeight / 2 + yOffset, "pkmn__sub");
|
||||
const ret = scene.addPokemonSprite(previousPokemon, transformationBaseBg.displayWidth / 2 + xOffset, transformationBaseBg.displayHeight / 2 + yOffset, "pkmn__sub");
|
||||
ret.setPipeline(scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true });
|
||||
return ret;
|
||||
};
|
||||
@ -54,31 +54,31 @@ export function doPokemonTransformationSequence(scene: BattleScene, pokemon: Pla
|
||||
pokemonEvoTintSprite.setTintFill(0xFFFFFF);
|
||||
|
||||
[ pokemonSprite, pokemonTintSprite, pokemonEvoSprite, pokemonEvoTintSprite ].map(sprite => {
|
||||
sprite.play(pokemon.getSpriteKey(true));
|
||||
sprite.setPipeline(scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(pokemon.getTeraType()) });
|
||||
sprite.play(previousPokemon.getSpriteKey(true));
|
||||
sprite.setPipeline(scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(previousPokemon.getTeraType()) });
|
||||
sprite.setPipelineData("ignoreTimeTint", true);
|
||||
sprite.setPipelineData("spriteKey", pokemon.getSpriteKey());
|
||||
sprite.setPipelineData("shiny", pokemon.shiny);
|
||||
sprite.setPipelineData("variant", pokemon.variant);
|
||||
sprite.setPipelineData("spriteKey", previousPokemon.getSpriteKey());
|
||||
sprite.setPipelineData("shiny", previousPokemon.shiny);
|
||||
sprite.setPipelineData("variant", previousPokemon.variant);
|
||||
[ "spriteColors", "fusionSpriteColors" ].map(k => {
|
||||
if (pokemon.summonData?.speciesForm) {
|
||||
if (previousPokemon.summonData?.speciesForm) {
|
||||
k += "Base";
|
||||
}
|
||||
sprite.pipelineData[k] = pokemon.getSprite().pipelineData[k];
|
||||
sprite.pipelineData[k] = previousPokemon.getSprite().pipelineData[k];
|
||||
});
|
||||
});
|
||||
|
||||
[ pokemonEvoSprite, pokemonEvoTintSprite ].map(sprite => {
|
||||
sprite.play(transformedPokemon.getSpriteKey(true));
|
||||
sprite.play(transformPokemon.getSpriteKey(true));
|
||||
sprite.setPipelineData("ignoreTimeTint", true);
|
||||
sprite.setPipelineData("spriteKey", transformedPokemon.getSpriteKey());
|
||||
sprite.setPipelineData("shiny", transformedPokemon.shiny);
|
||||
sprite.setPipelineData("variant", transformedPokemon.variant);
|
||||
sprite.setPipelineData("spriteKey", transformPokemon.getSpriteKey());
|
||||
sprite.setPipelineData("shiny", transformPokemon.shiny);
|
||||
sprite.setPipelineData("variant", transformPokemon.variant);
|
||||
[ "spriteColors", "fusionSpriteColors" ].map(k => {
|
||||
if (transformedPokemon.summonData?.speciesForm) {
|
||||
if (transformPokemon.summonData?.speciesForm) {
|
||||
k += "Base";
|
||||
}
|
||||
sprite.pipelineData[k] = transformedPokemon.getSprite().pipelineData[k];
|
||||
sprite.pipelineData[k] = transformPokemon.getSprite().pipelineData[k];
|
||||
});
|
||||
});
|
||||
|
||||
@ -123,9 +123,11 @@ export function doPokemonTransformationSequence(scene: BattleScene, pokemon: Pla
|
||||
duration: 2000,
|
||||
delay: 150,
|
||||
easing: "Sine.easeIn",
|
||||
// onComplete: () => {
|
||||
// transformedPokemon.destroy();
|
||||
// }
|
||||
onComplete: () => {
|
||||
previousPokemon.destroy();
|
||||
transformPokemon.setVisible(false);
|
||||
transformPokemon.setAlpha(1);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1958,4 +1958,19 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
}
|
||||
p.pokeball = PokeballType.MASTER_BALL;
|
||||
})),
|
||||
[TrainerType.VICTOR]: new TrainerConfig(++t).setName("Victor").setTitle("The Winstrates")
|
||||
.setMoneyMultiplier(1) // The Winstrate trainers have total money multiplier of 6
|
||||
.setPartyTemplates(trainerPartyTemplates.ONE_AVG_ONE_STRONG),
|
||||
[TrainerType.VICTORIA]: new TrainerConfig(++t).setName("Victoria").setTitle("The Winstrates")
|
||||
.setMoneyMultiplier(1)
|
||||
.setPartyTemplates(trainerPartyTemplates.ONE_AVG_ONE_STRONG),
|
||||
[TrainerType.VIVI]: new TrainerConfig(++t).setName("Vivi").setTitle("The Winstrates")
|
||||
.setMoneyMultiplier(1)
|
||||
.setPartyTemplates(trainerPartyTemplates.TWO_AVG_ONE_STRONG),
|
||||
[TrainerType.VICKY]: new TrainerConfig(++t).setName("Vicky").setTitle("The Winstrates")
|
||||
.setMoneyMultiplier(1)
|
||||
.setPartyTemplates(trainerPartyTemplates.ONE_AVG),
|
||||
[TrainerType.VITO]: new TrainerConfig(++t).setName("Vito").setTitle("The Winstrates")
|
||||
.setMoneyMultiplier(2)
|
||||
.setPartyTemplates(new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.STRONG)))
|
||||
};
|
||||
|
@ -2,8 +2,7 @@ export enum MysteryEncounterMode {
|
||||
DEFAULT,
|
||||
TRAINER_BATTLE,
|
||||
WILD_BATTLE,
|
||||
/** Enables wild boss music during encounter */
|
||||
BOSS_BATTLE,
|
||||
NO_BATTLE,
|
||||
/** For spawning new encounter queries instead of continuing to next wave */
|
||||
CONTINUOUS_ENCOUNTER
|
||||
NO_BATTLE
|
||||
}
|
||||
|
@ -22,5 +22,6 @@ export enum MysteryEncounterType {
|
||||
CLOWNING_AROUND,
|
||||
PART_TIMER,
|
||||
DANCING_LESSONS,
|
||||
WEIRD_DREAM
|
||||
WEIRD_DREAM,
|
||||
THE_WINSTRATE_CHALLENGE
|
||||
}
|
||||
|
@ -75,6 +75,11 @@ export enum TrainerType {
|
||||
MARLEY,
|
||||
MIRA,
|
||||
RILEY,
|
||||
VICTOR,
|
||||
VICTORIA,
|
||||
VIVI,
|
||||
VICKY,
|
||||
VITO,
|
||||
|
||||
BROCK = 200,
|
||||
MISTY,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { GameObjects } from "phaser";
|
||||
import BattleScene from "../battle-scene";
|
||||
import IMysteryEncounter from "../data/mystery-encounters/mystery-encounter";
|
||||
import MysteryEncounter from "../data/mystery-encounters/mystery-encounter";
|
||||
import { Species } from "#enums/species";
|
||||
import { isNullOrUndefined } from "#app/utils";
|
||||
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
@ -70,11 +70,11 @@ export class MysteryEncounterSpriteConfig {
|
||||
* Note: intro visuals are not "Trainers" or any other specific game object, though they may contain trainer sprites
|
||||
*/
|
||||
export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Container {
|
||||
public encounter: IMysteryEncounter;
|
||||
public encounter: MysteryEncounter;
|
||||
public spriteConfigs: MysteryEncounterSpriteConfig[];
|
||||
public enterFromRight: boolean;
|
||||
|
||||
constructor(scene: BattleScene, encounter: IMysteryEncounter) {
|
||||
constructor(scene: BattleScene, encounter: MysteryEncounter) {
|
||||
super(scene, -72, 76);
|
||||
this.encounter = encounter;
|
||||
this.enterFromRight = encounter.enterIntroVisualsFromRight ?? false;
|
||||
|
@ -10,7 +10,7 @@ import * as Utils from "../utils";
|
||||
import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from "../data/type";
|
||||
import { getLevelTotalExp } from "../data/exp";
|
||||
import { Stat } from "../data/pokemon-stat";
|
||||
import { DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, PokemonBaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempBattleStatBoosterModifier, StatBoosterModifier, CritBoosterModifier, TerastallizeModifier, PokemonBaseStatTotalModifier } from "../modifier/modifier";
|
||||
import { DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, PokemonBaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempBattleStatBoosterModifier, StatBoosterModifier, CritBoosterModifier, TerastallizeModifier, PokemonBaseStatTotalModifier, PokemonIncrementingStatModifier } from "../modifier/modifier";
|
||||
import { PokeballType } from "../data/pokeball";
|
||||
import { Gender } from "../data/gender";
|
||||
import { initMoveAnim, loadMoveAnimAssets } from "../data/battle-anims";
|
||||
@ -804,6 +804,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
}
|
||||
this.stats[s] = value;
|
||||
}
|
||||
this.scene.applyModifier(PokemonIncrementingStatModifier, this.isPlayer(), this, this.stats);
|
||||
}
|
||||
|
||||
getNature(): Nature {
|
||||
|
7
src/interfaces/held-modifier-config.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
|
||||
export default interface HeldModifierConfig {
|
||||
modifierType: PokemonHeldItemModifierType;
|
||||
stackCount?: number;
|
||||
isTransferable?: boolean;
|
||||
}
|
@ -627,6 +627,51 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
1: "You put up quite the display.\nBetter luck next time."
|
||||
}
|
||||
},
|
||||
"winstrates_victor": {
|
||||
"encounter": {
|
||||
1: "That's the spirit! I like you!",
|
||||
},
|
||||
"victory": {
|
||||
1: "A-ha! You're stronger than I thought!"
|
||||
}
|
||||
},
|
||||
"winstrates_victoria": {
|
||||
"encounter": {
|
||||
1: `My goodness! Aren't you young?
|
||||
$You must be quite the trainer to beat my husband, though.
|
||||
$Now I suppose it's my turn to battle!`,
|
||||
},
|
||||
"victory": {
|
||||
1: "Uwah! Just how strong are you?!"
|
||||
}
|
||||
},
|
||||
"winstrates_vivi": {
|
||||
"encounter": {
|
||||
1: `You're stronger than Mom? Wow!
|
||||
$But I'm strong, too!\nReally! Honestly!`,
|
||||
},
|
||||
"victory": {
|
||||
1: "Huh? Did I really lose?\nSnivel... Grandmaaa!"
|
||||
}
|
||||
},
|
||||
"winstrates_vicky": {
|
||||
"encounter": {
|
||||
1: `How dare you make my precious\ngranddaughter cry!
|
||||
$I see I need to teach you a lesson.\nPrepare to feel the sting of defeat!`,
|
||||
},
|
||||
"victory": {
|
||||
1: "Whoa! So strong!\nMy granddaughter wasn't lying."
|
||||
}
|
||||
},
|
||||
"winstrates_vito": {
|
||||
"encounter": {
|
||||
1: `I trained together with my whole family,\nevery one of us!
|
||||
$I'm not losing to anyone!`,
|
||||
},
|
||||
"victory": {
|
||||
1: "I was better than everyone in my family.\nI've never lost before..."
|
||||
}
|
||||
},
|
||||
"brock": {
|
||||
"encounter": {
|
||||
1: "My expertise on Rock-type Pokémon will take you down! Come on!",
|
||||
|
@ -262,6 +262,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
|
||||
|
||||
"MYSTERY_ENCOUNTER_SHUCKLE_JUICE": { name: "Shuckle Juice" },
|
||||
"MYSTERY_ENCOUNTER_BLACK_SLUDGE": { name: "Black Sludge", description: "The stench is so powerful that healing items are no longer available to purchase in shops." },
|
||||
"MYSTERY_ENCOUNTER_MACHO_BRACE": { name: "Macho Brace", description: "Defeating a Pokémon grants the holder a Macho Brace stack. Each stack slightly boosts stats, with an extra bonus at max stacks." },
|
||||
"MYSTERY_ENCOUNTER_OLD_GATEAU": { name: "Old Gateau", description: "Increases the holder's {{stats}} stats by {{statValue}}." },
|
||||
},
|
||||
SpeciesBoosterItem: {
|
||||
|
@ -22,6 +22,7 @@ import { clowningAroundDialogue } from "#app/locales/en/mystery-encounters/clown
|
||||
import { partTimerDialogue } from "#app/locales/en/mystery-encounters/part-timer-dialogue";
|
||||
import { dancingLessonsDialogue } from "#app/locales/en/mystery-encounters/dancing-lessons-dialogue";
|
||||
import { weirdDreamDialogue } from "#app/locales/en/mystery-encounters/weird-dream-dialogue";
|
||||
import { theWinstrateChallengeDialogue } from "#app/locales/en/mystery-encounters/the-winstrate-challenge-dialogue";
|
||||
|
||||
/**
|
||||
* Injection patterns that can be used:
|
||||
@ -71,5 +72,6 @@ export const mysteryEncounter = {
|
||||
clowningAround: clowningAroundDialogue,
|
||||
partTimer: partTimerDialogue,
|
||||
dancingLessons: dancingLessonsDialogue,
|
||||
weirdDream: weirdDreamDialogue
|
||||
weirdDream: weirdDreamDialogue,
|
||||
theWinstrateChallenge: theWinstrateChallengeDialogue
|
||||
} as const;
|
||||
|
@ -0,0 +1,24 @@
|
||||
export const theWinstrateChallengeDialogue = {
|
||||
intro: "It's a family standing outside their house!",
|
||||
speaker: "The Winstrates",
|
||||
intro_dialogue: `We're the Winstrates!
|
||||
$What do you say to taking on our family in a series of Pokémon battles?`,
|
||||
title: "The Winstrate Challenge",
|
||||
description: "The Winstrates are a family of 5 trainers, and they want to battle! If you beat all of them back-to-back, they'll give you a grand prize. But can you handle the heat?",
|
||||
query: "What will you do?",
|
||||
option: {
|
||||
1: {
|
||||
label: "Accept the Challenge",
|
||||
tooltip: "(-) Brutal Battle\n(+) Special Item Reward",
|
||||
selected: "That's the spirit! I like you!",
|
||||
},
|
||||
2: {
|
||||
label: "Refuse the Challenge",
|
||||
tooltip: "(+) Full Heal Party\n(+) Gain a Rarer Candy",
|
||||
selected: "That's too bad. Say, your team looks worn out, why don't you stay awhile and rest?"
|
||||
},
|
||||
},
|
||||
victory: `Congratulations on beating our challenge!
|
||||
$Our family uses this Macho Brace to strengthen our Pokémon more effectively during their training.
|
||||
$You may not need it, considering that you beat the whole lot of us, but we hope you'll accept it anyway!`,
|
||||
};
|
@ -19,6 +19,7 @@ export const titles: SimpleTranslationEntries = {
|
||||
"galactic_boss": "Team Galactic Boss",
|
||||
"plasma_boss": "Team Plasma Boss",
|
||||
"flare_boss": "Team Flare Boss",
|
||||
"the_winstrates": "The Winstrates'"
|
||||
// Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc.
|
||||
} as const;
|
||||
|
||||
@ -275,6 +276,11 @@ export const trainerNames: SimpleTranslationEntries = {
|
||||
"marley": "Marley",
|
||||
"mira": "Mira",
|
||||
"riley": "Riley",
|
||||
"victor": "Victor",
|
||||
"victoria": "Victoria",
|
||||
"vivi": "Vivi",
|
||||
"vicky": "Vicky",
|
||||
"vito": "Vito",
|
||||
|
||||
// Double Names
|
||||
"blue_red_double": "Blue & Red",
|
||||
|
@ -1506,6 +1506,7 @@ export const modifierTypes = {
|
||||
return new PokemonBaseStatFlatModifierType(Utils.randSeedInt(20), [Stat.HP, Stat.ATK, Stat.DEF]);
|
||||
}),
|
||||
MYSTERY_ENCOUNTER_BLACK_SLUDGE: () => new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_BLACK_SLUDGE", "black_sludge", (type, _args) => new Modifiers.RemoveHealShopModifier(type)),
|
||||
MYSTERY_ENCOUNTER_MACHO_BRACE: () => new PokemonHeldItemModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_MACHO_BRACE", "macho_brace", (type, args) => new Modifiers.PokemonIncrementingStatModifier(type, (args[0] as Pokemon).id)),
|
||||
};
|
||||
|
||||
interface ModifierPool {
|
||||
|
@ -793,6 +793,54 @@ export class PokemonBaseStatFlatModifier extends PokemonHeldItemModifier {
|
||||
}
|
||||
}
|
||||
|
||||
export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier {
|
||||
readonly isTransferrable: boolean = false;
|
||||
|
||||
constructor (type: ModifierType, pokemonId: integer, stackCount?: integer) {
|
||||
super(type, pokemonId, stackCount);
|
||||
}
|
||||
|
||||
matchType(modifier: Modifier): boolean {
|
||||
return modifier instanceof PokemonIncrementingStatModifier;
|
||||
}
|
||||
|
||||
clone(): PersistentModifier {
|
||||
return new PokemonIncrementingStatModifier(this.type, this.pokemonId);
|
||||
}
|
||||
|
||||
getArgs(): any[] {
|
||||
return super.getArgs();
|
||||
}
|
||||
|
||||
shouldApply(args: any[]): boolean {
|
||||
return super.shouldApply(args) && args.length === 2 && args[1] instanceof Array;
|
||||
}
|
||||
|
||||
apply(args: any[]): boolean {
|
||||
// Modifies the passed in stats[] array by +1 per stack for HP, +2 per stack for other stats
|
||||
// If the Macho Brace is at max stacks (50), adds additional 5% to total HP and 10% to other stats
|
||||
args[1].forEach((v, i) => {
|
||||
const isHp = i === 0;
|
||||
let mult = 1;
|
||||
if (this.stackCount === this.getMaxHeldItemCount(null)) {
|
||||
mult = isHp ? 1.05 : 1.1;
|
||||
}
|
||||
const newVal = Math.floor((v + this.stackCount * (isHp ? 1 : 2)) * mult);
|
||||
args[1][i] = Math.min(Math.max(newVal, 1), 999999);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
getScoreMultiplier(): number {
|
||||
return 1.2;
|
||||
}
|
||||
|
||||
getMaxHeldItemCount(pokemon: Pokemon): integer {
|
||||
return 50;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifier used for held items that apply {@linkcode Stat} boost(s)
|
||||
* using a multiplier.
|
||||
|
@ -6,7 +6,7 @@ import { allMoves, applyFilteredMoveAttrs, applyMoveAttrs, AttackMove, BypassRed
|
||||
import { Mode } from "./ui/ui";
|
||||
import { Command } from "./ui/command-ui-handler";
|
||||
import { Stat } from "./data/pokemon-stat";
|
||||
import { BerryModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, IvScannerModifier, LapsingPersistentModifier, LapsingPokemonHeldItemModifier, MapModifier, Modifier, MoneyInterestModifier, MoneyMultiplierModifier, MultipleParticipantExpBonusModifier, overrideHeldItems, overrideModifiers, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, PokemonMultiHitModifier, PokemonResetNegativeStatStageModifier, SwitchEffectTransferModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier } from "./modifier/modifier";
|
||||
import { BerryModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, IvScannerModifier, LapsingPersistentModifier, LapsingPokemonHeldItemModifier, MapModifier, Modifier, MoneyInterestModifier, MoneyMultiplierModifier, MultipleParticipantExpBonusModifier, overrideHeldItems, overrideModifiers, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonIncrementingStatModifier, PokemonInstantReviveModifier, PokemonMultiHitModifier, PokemonResetNegativeStatStageModifier, SwitchEffectTransferModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier } from "./modifier/modifier";
|
||||
import PartyUiHandler, { PartyOption, PartyUiMode } from "./ui/party-ui-handler";
|
||||
import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor, PokeballType } from "./data/pokeball";
|
||||
import { CommonAnim, CommonBattleAnim, initEncounterAnims, initMoveAnim, loadEncounterAnimAssets, loadMoveAnimAssets, MoveAnim } from "./data/battle-anims";
|
||||
@ -1302,8 +1302,7 @@ export class NextEncounterPhase extends EncounterPhase {
|
||||
this.scene.lastEnemyTrainer.destroy();
|
||||
}
|
||||
if (lastEncounterVisuals) {
|
||||
this.scene.field.remove(lastEncounterVisuals);
|
||||
lastEncounterVisuals.destroy();
|
||||
this.scene.field.remove(lastEncounterVisuals, true);
|
||||
this.scene.lastMysteryEncounter.introVisuals = null;
|
||||
}
|
||||
|
||||
@ -1583,7 +1582,7 @@ export class SummonPhase extends PartyMemberPokemonPhase {
|
||||
onComplete: () => this.scene.trainer.setVisible(false)
|
||||
});
|
||||
this.scene.time.delayedCall(750, () => this.summon());
|
||||
} else if (this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene?.currentBattle?.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
||||
} else if (this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene.currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
||||
const trainerName = this.scene.currentBattle.trainer.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER);
|
||||
const pokemonName = getPokemonNameWithAffix(this.getPokemon());
|
||||
const message = i18next.t("battle:trainerSendOut", { trainerName, pokemonName });
|
||||
@ -2287,7 +2286,7 @@ export class CommandPhase extends FieldPhase {
|
||||
this.scene.ui.showText(null, 0);
|
||||
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
|
||||
}, null, true);
|
||||
} else if (!isSwitch && this.scene.currentBattle.battleType === BattleType.TRAINER) {
|
||||
} else if (!isSwitch && (this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene.currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE)) {
|
||||
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
|
||||
this.scene.ui.setMode(Mode.MESSAGE);
|
||||
this.scene.ui.showText(i18next.t("battle:noEscapeTrainer"), null, () => {
|
||||
@ -4138,6 +4137,12 @@ export class VictoryPhase extends PokemonPhase {
|
||||
const participated = participantIds.has(pId);
|
||||
if (participated) {
|
||||
partyMember.addFriendship(2);
|
||||
const machoBraceModifier = partyMember.getHeldItems().find(m => m instanceof PokemonIncrementingStatModifier);
|
||||
if (!isNullOrUndefined(machoBraceModifier) && machoBraceModifier.stackCount < machoBraceModifier.getMaxStackCount(this.scene)) {
|
||||
machoBraceModifier.stackCount++;
|
||||
this.scene.updateModifiers(true, true);
|
||||
partyMember.updateInfo();
|
||||
}
|
||||
}
|
||||
if (!expPartyMembers.includes(partyMember)) {
|
||||
continue;
|
||||
|
@ -381,6 +381,10 @@ export class MysteryEncounterBattlePhase extends Phase {
|
||||
|
||||
/**
|
||||
* Will handle (in order):
|
||||
* - doContinueEncounter() callback for continuous encounters with back-to-back battles (this should push/shift its own phases as needed)
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* - Any encounter reward logic that is set within MysteryEncounter doEncounterExp
|
||||
* - Any encounter reward logic that is set within MysteryEncounter doEncounterRewards
|
||||
* - Otherwise, can add a no-reward-item shop with only Potions, etc. if addHealPhase is true
|
||||
@ -396,23 +400,30 @@ export class MysteryEncounterRewardsPhase extends Phase {
|
||||
|
||||
start() {
|
||||
super.start();
|
||||
const encounter = this.scene.currentBattle.mysteryEncounter;
|
||||
|
||||
this.scene.executeWithSeedOffset(() => {
|
||||
if (this.scene.currentBattle.mysteryEncounter.doEncounterExp) {
|
||||
this.scene.currentBattle.mysteryEncounter.doEncounterExp(this.scene);
|
||||
}
|
||||
if (encounter.doContinueEncounter) {
|
||||
encounter.doContinueEncounter(this.scene).then(() => {
|
||||
this.end();
|
||||
});
|
||||
} else {
|
||||
this.scene.executeWithSeedOffset(() => {
|
||||
if (this.scene.currentBattle.mysteryEncounter.doEncounterExp) {
|
||||
this.scene.currentBattle.mysteryEncounter.doEncounterExp(this.scene);
|
||||
}
|
||||
|
||||
if (this.scene.currentBattle.mysteryEncounter.doEncounterRewards) {
|
||||
this.scene.currentBattle.mysteryEncounter.doEncounterRewards(this.scene);
|
||||
} else if (this.addHealPhase) {
|
||||
this.scene.tryRemovePhase(p => p instanceof SelectModifierPhase);
|
||||
this.scene.unshiftPhase(new SelectModifierPhase(this.scene, 0, null, { fillRemaining: false, rerollMultiplier: 0 }));
|
||||
}
|
||||
// Do not use ME's seedOffset for rewards, these should always be consistent with waveIndex (once per wave)
|
||||
}, this.scene.currentBattle.waveIndex * 1000);
|
||||
if (this.scene.currentBattle.mysteryEncounter.doEncounterRewards) {
|
||||
this.scene.currentBattle.mysteryEncounter.doEncounterRewards(this.scene);
|
||||
} else if (this.addHealPhase) {
|
||||
this.scene.tryRemovePhase(p => p instanceof SelectModifierPhase);
|
||||
this.scene.unshiftPhase(new SelectModifierPhase(this.scene, 0, null, { fillRemaining: false, rerollMultiplier: 0 }));
|
||||
}
|
||||
// Do not use ME's seedOffset for rewards, these should always be consistent with waveIndex (once per wave)
|
||||
}, this.scene.currentBattle.waveIndex * 1000);
|
||||
|
||||
this.scene.pushPhase(new PostMysteryEncounterPhase(this.scene));
|
||||
this.end();
|
||||
this.scene.pushPhase(new PostMysteryEncounterPhase(this.scene));
|
||||
this.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ import { Species } from "#enums/species";
|
||||
import { applyChallenges, ChallengeType } from "#app/data/challenge.js";
|
||||
import { Abilities } from "#app/enums/abilities.js";
|
||||
import { MysteryEncounterData } from "../data/mystery-encounters/mystery-encounter-data";
|
||||
import IMysteryEncounter from "../data/mystery-encounters/mystery-encounter";
|
||||
import MysteryEncounter from "../data/mystery-encounters/mystery-encounter";
|
||||
|
||||
export const defaultStarterSpecies: Species[] = [
|
||||
Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE,
|
||||
@ -126,7 +126,7 @@ export interface SessionSaveData {
|
||||
gameVersion: string;
|
||||
timestamp: integer;
|
||||
challenges: ChallengeData[];
|
||||
mysteryEncounter: IMysteryEncounter;
|
||||
mysteryEncounter: MysteryEncounter;
|
||||
mysteryEncounterData: MysteryEncounterData;
|
||||
}
|
||||
|
||||
@ -1167,7 +1167,7 @@ export class GameData {
|
||||
}
|
||||
|
||||
if (k === "mysteryEncounter") {
|
||||
return new IMysteryEncounter(v);
|
||||
return new MysteryEncounter(v);
|
||||
}
|
||||
|
||||
if (k === "mysteryEncounterData") {
|
||||
|
@ -7,7 +7,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import * as BattleAnims from "#app/data/battle-anims";
|
||||
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { generateModifierTypeOption } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { generateModifierType } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
|
||||
import { CommandPhase, MovePhase, NewBattlePhase, SelectModifierPhase } from "#app/phases";
|
||||
import { Moves } from "#enums/moves";
|
||||
@ -123,7 +123,6 @@ describe("Clowning Around - Mystery Encounter", () => {
|
||||
});
|
||||
expect(config.pokemonConfigs[1]).toEqual({
|
||||
species: getPokemonSpecies(Species.BLACEPHALON),
|
||||
ability: expect.any(Number),
|
||||
mysteryEncounterData: expect.anything(),
|
||||
isBoss: true,
|
||||
moveSet: [Moves.TRICK, Moves.HYPNOSIS, Moves.SHADOW_BALL, Moves.MIND_BLOWN]
|
||||
@ -145,8 +144,8 @@ describe("Clowning Around - Mystery Encounter", () => {
|
||||
Abilities.MAGICIAN,
|
||||
Abilities.SHEER_FORCE,
|
||||
Abilities.PRANKSTER
|
||||
]).toContain(config.pokemonConfigs[1].ability);
|
||||
expect(ClowningAroundEncounter.misc.ability).toBe(config.pokemonConfigs[1].ability);
|
||||
]).toContain(config.pokemonConfigs[1].mysteryEncounterData.ability);
|
||||
expect(ClowningAroundEncounter.misc.ability).toBe(config.pokemonConfigs[1].mysteryEncounterData.ability);
|
||||
await vi.waitFor(() => expect(moveInitSpy).toHaveBeenCalled());
|
||||
await vi.waitFor(() => expect(moveLoadSpy).toHaveBeenCalled());
|
||||
expect(onInitResult).toBe(true);
|
||||
@ -258,26 +257,26 @@ describe("Clowning Around - Mystery Encounter", () => {
|
||||
|
||||
// 2 Sitrus Berries on lead
|
||||
scene.modifiers = [];
|
||||
let itemType = generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.SITRUS]).type as PokemonHeldItemModifierType;
|
||||
let itemType = generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType;
|
||||
await addItemToPokemon(scene, scene.getParty()[0], 2, itemType);
|
||||
// 2 Ganlon Berries on lead
|
||||
itemType = generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.GANLON]).type as PokemonHeldItemModifierType;
|
||||
itemType = generateModifierType(scene, modifierTypes.BERRY, [BerryType.GANLON]) as PokemonHeldItemModifierType;
|
||||
await addItemToPokemon(scene, scene.getParty()[0], 2, itemType);
|
||||
// 5 Golden Punch on lead (ultra)
|
||||
itemType = generateModifierTypeOption(scene, modifierTypes.GOLDEN_PUNCH).type as PokemonHeldItemModifierType;
|
||||
itemType = generateModifierType(scene, modifierTypes.GOLDEN_PUNCH) as PokemonHeldItemModifierType;
|
||||
await addItemToPokemon(scene, scene.getParty()[0], 5, itemType);
|
||||
// 5 Lucky Egg on lead (ultra)
|
||||
itemType = generateModifierTypeOption(scene, modifierTypes.LUCKY_EGG).type as PokemonHeldItemModifierType;
|
||||
itemType = generateModifierType(scene, modifierTypes.LUCKY_EGG) as PokemonHeldItemModifierType;
|
||||
await addItemToPokemon(scene, scene.getParty()[0], 5, itemType);
|
||||
// 5 Soul Dew on lead (rogue)
|
||||
itemType = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type as PokemonHeldItemModifierType;
|
||||
itemType = generateModifierType(scene, modifierTypes.SOUL_DEW) as PokemonHeldItemModifierType;
|
||||
await addItemToPokemon(scene, scene.getParty()[0], 5, itemType);
|
||||
// 2 Golden Egg on lead (rogue)
|
||||
itemType = generateModifierTypeOption(scene, modifierTypes.GOLDEN_EGG).type as PokemonHeldItemModifierType;
|
||||
itemType = generateModifierType(scene, modifierTypes.GOLDEN_EGG) as PokemonHeldItemModifierType;
|
||||
await addItemToPokemon(scene, scene.getParty()[0], 2, itemType);
|
||||
|
||||
// 5 Soul Dew on second party pokemon (these should not change)
|
||||
itemType = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type as PokemonHeldItemModifierType;
|
||||
itemType = generateModifierType(scene, modifierTypes.SOUL_DEW) as PokemonHeldItemModifierType;
|
||||
await addItemToPokemon(scene, scene.getParty()[1], 5, itemType);
|
||||
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
@ -13,7 +13,7 @@ import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encount
|
||||
import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||
import { BerryModifier, HealingBoosterModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, LevelIncrementBoosterModifier, PokemonInstantReviveModifier, PokemonNatureWeightModifier, PreserveBerryModifier } from "#app/modifier/modifier";
|
||||
import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases";
|
||||
import { generateModifierTypeOption } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { generateModifierType } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { BerryType } from "#enums/berry-type";
|
||||
|
||||
@ -137,7 +137,7 @@ describe("Delibird-y - Mystery Encounter", () => {
|
||||
|
||||
// 5 Healing Charms
|
||||
scene.modifiers = [];
|
||||
const abilityCharm = generateModifierTypeOption(scene, modifierTypes.ABILITY_CHARM).type.newModifier() as HiddenAbilityRateBoosterModifier;
|
||||
const abilityCharm = generateModifierType(scene, modifierTypes.ABILITY_CHARM).newModifier() as HiddenAbilityRateBoosterModifier;
|
||||
abilityCharm.stackCount = 4;
|
||||
await scene.addModifier(abilityCharm, true, false, false, true);
|
||||
await scene.updateModifiers(true);
|
||||
@ -206,7 +206,7 @@ describe("Delibird-y - Mystery Encounter", () => {
|
||||
|
||||
// Set 2 Sitrus berries on party lead
|
||||
scene.modifiers = [];
|
||||
const sitrus = generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.SITRUS]).type;
|
||||
const sitrus = generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]);
|
||||
const sitrusMod = sitrus.newModifier(scene.getParty()[0]) as BerryModifier;
|
||||
sitrusMod.stackCount = 2;
|
||||
await scene.addModifier(sitrusMod, true, false, false, true);
|
||||
@ -227,7 +227,7 @@ describe("Delibird-y - Mystery Encounter", () => {
|
||||
|
||||
// Set 1 Reviver Seed on party lead
|
||||
scene.modifiers = [];
|
||||
const revSeed = generateModifierTypeOption(scene, modifierTypes.REVIVER_SEED).type;
|
||||
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED);
|
||||
const modifier = revSeed.newModifier(scene.getParty()[0]) as PokemonInstantReviveModifier;
|
||||
modifier.stackCount = 1;
|
||||
await scene.addModifier(modifier, true, false, false, true);
|
||||
@ -248,10 +248,10 @@ describe("Delibird-y - Mystery Encounter", () => {
|
||||
|
||||
// 99 Candy Jars
|
||||
scene.modifiers = [];
|
||||
const candyJar = generateModifierTypeOption(scene, modifierTypes.CANDY_JAR).type.newModifier() as LevelIncrementBoosterModifier;
|
||||
const candyJar = generateModifierType(scene, modifierTypes.CANDY_JAR).newModifier() as LevelIncrementBoosterModifier;
|
||||
candyJar.stackCount = 99;
|
||||
await scene.addModifier(candyJar, true, false, false, true);
|
||||
const sitrus = generateModifierTypeOption(scene, modifierTypes.BERRY, [BerryType.SITRUS]).type;
|
||||
const sitrus = generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]);
|
||||
|
||||
// Sitrus berries on party
|
||||
const sitrusMod = sitrus.newModifier(scene.getParty()[0]) as BerryModifier;
|
||||
@ -277,12 +277,12 @@ describe("Delibird-y - Mystery Encounter", () => {
|
||||
|
||||
// 5 Healing Charms
|
||||
scene.modifiers = [];
|
||||
const healingCharm = generateModifierTypeOption(scene, modifierTypes.HEALING_CHARM).type.newModifier() as HealingBoosterModifier;
|
||||
const healingCharm = generateModifierType(scene, modifierTypes.HEALING_CHARM).newModifier() as HealingBoosterModifier;
|
||||
healingCharm.stackCount = 5;
|
||||
await scene.addModifier(healingCharm, true, false, false, true);
|
||||
|
||||
// Set 1 Reviver Seed on party lead
|
||||
const revSeed = generateModifierTypeOption(scene, modifierTypes.REVIVER_SEED).type;
|
||||
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED);
|
||||
const modifier = revSeed.newModifier(scene.getParty()[0]) as PokemonInstantReviveModifier;
|
||||
modifier.stackCount = 1;
|
||||
await scene.addModifier(modifier, true, false, false, true);
|
||||
@ -306,7 +306,7 @@ describe("Delibird-y - Mystery Encounter", () => {
|
||||
|
||||
// Set 1 Soul Dew on party lead
|
||||
scene.modifiers = [];
|
||||
const soulDew = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type;
|
||||
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW);
|
||||
const modifier = soulDew.newModifier(scene.getParty()[0]);
|
||||
await scene.addModifier(modifier, true, false, false, true);
|
||||
await scene.updateModifiers(true);
|
||||
@ -334,7 +334,7 @@ describe("Delibird-y - Mystery Encounter", () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.DELIBIRDY, defaultParty);
|
||||
|
||||
// Set 1 Reviver Seed on party lead
|
||||
const revSeed = generateModifierTypeOption(scene, modifierTypes.REVIVER_SEED).type;
|
||||
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED);
|
||||
const modifier = revSeed.newModifier(scene.getParty()[0]) as PokemonInstantReviveModifier;
|
||||
modifier.stackCount = 1;
|
||||
await scene.addModifier(modifier, true, false, false, true);
|
||||
@ -368,7 +368,7 @@ describe("Delibird-y - Mystery Encounter", () => {
|
||||
|
||||
// Set 2 Soul Dew on party lead
|
||||
scene.modifiers = [];
|
||||
const soulDew = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type;
|
||||
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW);
|
||||
const modifier = soulDew.newModifier(scene.getParty()[0]) as PokemonNatureWeightModifier;
|
||||
modifier.stackCount = 2;
|
||||
await scene.addModifier(modifier, true, false, false, true);
|
||||
@ -389,7 +389,7 @@ describe("Delibird-y - Mystery Encounter", () => {
|
||||
|
||||
// Set 1 Soul Dew on party lead
|
||||
scene.modifiers = [];
|
||||
const soulDew = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type;
|
||||
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW);
|
||||
const modifier = soulDew.newModifier(scene.getParty()[0]) as PokemonNatureWeightModifier;
|
||||
modifier.stackCount = 1;
|
||||
await scene.addModifier(modifier, true, false, false, true);
|
||||
@ -410,12 +410,12 @@ describe("Delibird-y - Mystery Encounter", () => {
|
||||
|
||||
// 5 Healing Charms
|
||||
scene.modifiers = [];
|
||||
const healingCharm = generateModifierTypeOption(scene, modifierTypes.BERRY_POUCH).type.newModifier() as PreserveBerryModifier;
|
||||
const healingCharm = generateModifierType(scene, modifierTypes.BERRY_POUCH).newModifier() as PreserveBerryModifier;
|
||||
healingCharm.stackCount = 3;
|
||||
await scene.addModifier(healingCharm, true, false, false, true);
|
||||
|
||||
// Set 1 Soul Dew on party lead
|
||||
const soulDew = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type;
|
||||
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW);
|
||||
const modifier = soulDew.newModifier(scene.getParty()[0]) as PokemonNatureWeightModifier;
|
||||
modifier.stackCount = 1;
|
||||
await scene.addModifier(modifier, true, false, false, true);
|
||||
@ -439,7 +439,7 @@ describe("Delibird-y - Mystery Encounter", () => {
|
||||
|
||||
// Set 1 Reviver Seed on party lead
|
||||
scene.modifiers = [];
|
||||
const revSeed = generateModifierTypeOption(scene, modifierTypes.REVIVER_SEED).type;
|
||||
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED);
|
||||
const modifier = revSeed.newModifier(scene.getParty()[0]);
|
||||
await scene.addModifier(modifier, true, false, false, true);
|
||||
await scene.updateModifiers(true);
|
||||
@ -468,7 +468,7 @@ describe("Delibird-y - Mystery Encounter", () => {
|
||||
|
||||
// Set 1 Soul Dew on party lead
|
||||
scene.modifiers = [];
|
||||
const soulDew = generateModifierTypeOption(scene, modifierTypes.SOUL_DEW).type;
|
||||
const soulDew = generateModifierType(scene, modifierTypes.SOUL_DEW);
|
||||
const modifier = soulDew.newModifier(scene.getParty()[0]) as PokemonNatureWeightModifier;
|
||||
modifier.stackCount = 1;
|
||||
await scene.addModifier(modifier, true, false, false, true);
|
||||
|
@ -18,7 +18,7 @@ import { TrainerConfig, TrainerPartyCompoundTemplate, TrainerPartyTemplate } fro
|
||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
|
||||
import IMysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
|
||||
const namespace = "mysteryEncounter:mysteriousChallengers";
|
||||
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA];
|
||||
@ -96,7 +96,7 @@ describe("Mysterious Challengers - Mystery Encounter", () => {
|
||||
|
||||
it("should initialize fully", async () => {
|
||||
initSceneWithoutEncounterPhase(scene, defaultParty);
|
||||
scene.currentBattle.mysteryEncounter = new IMysteryEncounter(MysteriousChallengersEncounter);
|
||||
scene.currentBattle.mysteryEncounter = new MysteryEncounter(MysteriousChallengersEncounter);
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
scene.currentBattle.waveIndex = defaultWave;
|
||||
|
||||
|
@ -123,7 +123,7 @@ describe("The Strong Stuff - Mystery Encounter", () => {
|
||||
mysteryEncounterData: new MysteryEncounterPokemonData(1.5),
|
||||
nature: Nature.BOLD,
|
||||
moveSet: [Moves.INFESTATION, Moves.SALT_CURE, Moves.GASTRO_ACID, Moves.HEAL_ORDER],
|
||||
modifierTypes: expect.any(Array),
|
||||
modifierConfigs: expect.any(Array),
|
||||
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
|
||||
mysteryEncounterBattleEffects: expect.any(Function)
|
||||
}
|
||||
|
@ -0,0 +1,385 @@
|
||||
import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters";
|
||||
import { HUMAN_TRANSITABLE_BIOMES } from "#app/data/mystery-encounters/mystery-encounters";
|
||||
import { Biome } from "#app/enums/biome";
|
||||
import { MysteryEncounterType } from "#app/enums/mystery-encounter-type";
|
||||
import { Species } from "#app/enums/species";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounterTestUtils";
|
||||
import { CommandPhase, PartyHealPhase, SelectModifierPhase, VictoryPhase } from "#app/phases";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { Mode } from "#app/ui/ui";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
|
||||
import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import { Nature } from "#enums/nature";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { TheWinstrateChallengeEncounter } from "#app/data/mystery-encounters/encounters/the-winstrate-challenge-encounter";
|
||||
import { Status, StatusEffect } from "#app/data/status-effect";
|
||||
import { MysteryEncounterRewardsPhase } from "#app/phases/mystery-encounter-phases";
|
||||
|
||||
const namespace = "mysteryEncounter:theWinstrateChallenge";
|
||||
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA];
|
||||
const defaultBiome = Biome.CAVE;
|
||||
const defaultWave = 45;
|
||||
|
||||
describe("The Winstrate Challenge - Mystery Encounter", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
let scene: BattleScene;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({ type: Phaser.HEADLESS });
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
game = new GameManager(phaserGame);
|
||||
scene = game.scene;
|
||||
game.override.mysteryEncounterChance(100);
|
||||
game.override.startingWave(defaultWave);
|
||||
game.override.startingBiome(defaultBiome);
|
||||
game.override.disableTrainerWaves(true);
|
||||
|
||||
const biomeMap = new Map<Biome, MysteryEncounterType[]>([
|
||||
[Biome.VOLCANO, [MysteryEncounterType.FIGHT_OR_FLIGHT]],
|
||||
]);
|
||||
HUMAN_TRANSITABLE_BIOMES.forEach(biome => {
|
||||
biomeMap.set(biome, [MysteryEncounterType.THE_WINSTRATE_CHALLENGE]);
|
||||
});
|
||||
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(biomeMap);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
vi.clearAllMocks();
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it("should have the correct properties", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.THE_WINSTRATE_CHALLENGE, defaultParty);
|
||||
|
||||
expect(TheWinstrateChallengeEncounter.encounterType).toBe(MysteryEncounterType.THE_WINSTRATE_CHALLENGE);
|
||||
expect(TheWinstrateChallengeEncounter.encounterTier).toBe(MysteryEncounterTier.ROGUE);
|
||||
expect(TheWinstrateChallengeEncounter.dialogue).toBeDefined();
|
||||
expect(TheWinstrateChallengeEncounter.dialogue.intro).toStrictEqual([
|
||||
{ text: `${namespace}.intro` },
|
||||
{
|
||||
speaker: `${namespace}.speaker`,
|
||||
text: `${namespace}.intro_dialogue`,
|
||||
}
|
||||
]);
|
||||
expect(TheWinstrateChallengeEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}.title`);
|
||||
expect(TheWinstrateChallengeEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}.description`);
|
||||
expect(TheWinstrateChallengeEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}.query`);
|
||||
expect(TheWinstrateChallengeEncounter.options.length).toBe(2);
|
||||
});
|
||||
|
||||
it("should not spawn outside of HUMAN_TRANSITABLE_BIOMES", async () => {
|
||||
game.override.mysteryEncounterTier(MysteryEncounterTier.GREAT);
|
||||
game.override.startingBiome(Biome.VOLCANO);
|
||||
await game.runToMysteryEncounter();
|
||||
|
||||
expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.THE_WINSTRATE_CHALLENGE);
|
||||
});
|
||||
|
||||
it("should not run below wave 10", async () => {
|
||||
game.override.startingWave(9);
|
||||
|
||||
await game.runToMysteryEncounter();
|
||||
|
||||
expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.THE_WINSTRATE_CHALLENGE);
|
||||
});
|
||||
|
||||
it("should not run above wave 179", async () => {
|
||||
game.override.startingWave(181);
|
||||
|
||||
await game.runToMysteryEncounter();
|
||||
|
||||
expect(scene.currentBattle.mysteryEncounter).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should initialize fully", async () => {
|
||||
initSceneWithoutEncounterPhase(scene, defaultParty);
|
||||
scene.currentBattle.mysteryEncounter = new MysteryEncounter(TheWinstrateChallengeEncounter);
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
scene.currentBattle.waveIndex = defaultWave;
|
||||
|
||||
const { onInit } = encounter;
|
||||
|
||||
expect(encounter.onInit).toBeDefined();
|
||||
|
||||
encounter.populateDialogueTokensFromRequirements(scene);
|
||||
const onInitResult = onInit(scene);
|
||||
|
||||
expect(encounter.enemyPartyConfigs).toBeDefined();
|
||||
expect(encounter.enemyPartyConfigs.length).toBe(5);
|
||||
expect(encounter.enemyPartyConfigs).toEqual([
|
||||
{
|
||||
trainerType: TrainerType.VITO,
|
||||
pokemonConfigs: [
|
||||
{
|
||||
species: getPokemonSpecies(Species.HISUI_ELECTRODE),
|
||||
isBoss: false,
|
||||
abilityIndex: 0, // Soundproof
|
||||
nature: Nature.MODEST,
|
||||
moveSet: [Moves.THUNDERBOLT, Moves.GIGA_DRAIN, Moves.FOUL_PLAY, Moves.THUNDER_WAVE],
|
||||
modifierConfigs: expect.any(Array)
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.SWALOT),
|
||||
isBoss: false,
|
||||
abilityIndex: 2, // Gluttony
|
||||
nature: Nature.QUIET,
|
||||
moveSet: [Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.ICE_BEAM, Moves.EARTHQUAKE],
|
||||
modifierConfigs: expect.any(Array)
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.DODRIO),
|
||||
isBoss: false,
|
||||
abilityIndex: 2, // Tangled Feet
|
||||
nature: Nature.JOLLY,
|
||||
moveSet: [Moves.DRILL_PECK, Moves.QUICK_ATTACK, Moves.THRASH, Moves.KNOCK_OFF],
|
||||
modifierConfigs: expect.any(Array)
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.ALAKAZAM),
|
||||
isBoss: false,
|
||||
formIndex: 1,
|
||||
nature: Nature.BOLD,
|
||||
moveSet: [Moves.PSYCHIC, Moves.SHADOW_BALL, Moves.FOCUS_BLAST, Moves.THUNDERBOLT],
|
||||
modifierConfigs: expect.any(Array)
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.DARMANITAN),
|
||||
isBoss: false,
|
||||
abilityIndex: 0, // Sheer Force
|
||||
nature: Nature.IMPISH,
|
||||
moveSet: [Moves.EARTHQUAKE, Moves.U_TURN, Moves.FLARE_BLITZ, Moves.ROCK_SLIDE],
|
||||
modifierConfigs: expect.any(Array)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
trainerType: TrainerType.VICKY,
|
||||
pokemonConfigs: [
|
||||
{
|
||||
species: getPokemonSpecies(Species.MEDICHAM),
|
||||
isBoss: false,
|
||||
formIndex: 1,
|
||||
nature: Nature.IMPISH,
|
||||
moveSet: [Moves.AXE_KICK, Moves.ICE_PUNCH, Moves.ZEN_HEADBUTT, Moves.BULLET_PUNCH],
|
||||
modifierConfigs: expect.any(Array)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
trainerType: TrainerType.VIVI,
|
||||
pokemonConfigs: [
|
||||
{
|
||||
species: getPokemonSpecies(Species.SEAKING),
|
||||
isBoss: false,
|
||||
abilityIndex: 3, // Lightning Rod
|
||||
nature: Nature.ADAMANT,
|
||||
moveSet: [Moves.WATERFALL, Moves.MEGAHORN, Moves.KNOCK_OFF, Moves.REST],
|
||||
modifierConfigs: expect.any(Array)
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.BRELOOM),
|
||||
isBoss: false,
|
||||
abilityIndex: 1, // Poison Heal
|
||||
nature: Nature.JOLLY,
|
||||
moveSet: [Moves.SPORE, Moves.SWORDS_DANCE, Moves.SEED_BOMB, Moves.DRAIN_PUNCH],
|
||||
modifierConfigs: expect.any(Array)
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.CAMERUPT),
|
||||
isBoss: false,
|
||||
formIndex: 1,
|
||||
nature: Nature.CALM,
|
||||
moveSet: [Moves.EARTH_POWER, Moves.FIRE_BLAST, Moves.YAWN, Moves.PROTECT],
|
||||
modifierConfigs: expect.any(Array)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
trainerType: TrainerType.VICTORIA,
|
||||
pokemonConfigs: [
|
||||
{
|
||||
species: getPokemonSpecies(Species.ROSERADE),
|
||||
isBoss: false,
|
||||
abilityIndex: 0, // Natural Cure
|
||||
nature: Nature.CALM,
|
||||
moveSet: [Moves.SYNTHESIS, Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.SLEEP_POWDER],
|
||||
modifierConfigs: expect.any(Array)
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.GARDEVOIR),
|
||||
isBoss: false,
|
||||
formIndex: 1,
|
||||
nature: Nature.TIMID,
|
||||
moveSet: [Moves.PSYSHOCK, Moves.MOONBLAST, Moves.SHADOW_BALL, Moves.WILL_O_WISP],
|
||||
modifierConfigs: expect.any(Array)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
trainerType: TrainerType.VICTOR,
|
||||
pokemonConfigs: [
|
||||
{
|
||||
species: getPokemonSpecies(Species.SWELLOW),
|
||||
isBoss: false,
|
||||
abilityIndex: 0, // Guts
|
||||
nature: Nature.ADAMANT,
|
||||
moveSet: [Moves.FACADE, Moves.BRAVE_BIRD, Moves.PROTECT, Moves.QUICK_ATTACK],
|
||||
modifierConfigs: expect.any(Array)
|
||||
},
|
||||
{
|
||||
species: getPokemonSpecies(Species.OBSTAGOON),
|
||||
isBoss: false,
|
||||
abilityIndex: 1, // Guts
|
||||
nature: Nature.ADAMANT,
|
||||
moveSet: [Moves.FACADE, Moves.OBSTRUCT, Moves.NIGHT_SLASH, Moves.FIRE_PUNCH],
|
||||
modifierConfigs: expect.any(Array)
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
expect(encounter.spriteConfigs).toBeDefined();
|
||||
expect(encounter.spriteConfigs.length).toBe(5);
|
||||
expect(onInitResult).toBe(true);
|
||||
});
|
||||
|
||||
describe("Option 1 - Normal Battle", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option = TheWinstrateChallengeEncounter.options[0];
|
||||
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||
expect(option.dialogue).toBeDefined();
|
||||
expect(option.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}.option.1.label`,
|
||||
buttonTooltip: `${namespace}.option.1.tooltip`,
|
||||
selected: [
|
||||
{
|
||||
speaker: "trainerNames:victor",
|
||||
text: `${namespace}.option.1.selected`,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should battle all 5 trainers for a Macho Brace reward", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.THE_WINSTRATE_CHALLENGE, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 1, null, true);
|
||||
|
||||
expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
|
||||
expect(scene.currentBattle.trainer).toBeDefined();
|
||||
expect(scene.currentBattle.trainer.config.trainerType).toBe(TrainerType.VICTOR);
|
||||
expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(4);
|
||||
expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
|
||||
await skipBattleToNextBattle(game);
|
||||
expect(scene.currentBattle.trainer).toBeDefined();
|
||||
expect(scene.currentBattle.trainer.config.trainerType).toBe(TrainerType.VICTORIA);
|
||||
expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(3);
|
||||
expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
|
||||
await skipBattleToNextBattle(game);
|
||||
expect(scene.currentBattle.trainer).toBeDefined();
|
||||
expect(scene.currentBattle.trainer.config.trainerType).toBe(TrainerType.VIVI);
|
||||
expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(2);
|
||||
expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
|
||||
await skipBattleToNextBattle(game);
|
||||
expect(scene.currentBattle.trainer).toBeDefined();
|
||||
expect(scene.currentBattle.trainer.config.trainerType).toBe(TrainerType.VICKY);
|
||||
expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(1);
|
||||
expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
|
||||
await skipBattleToNextBattle(game);
|
||||
expect(scene.currentBattle.trainer).toBeDefined();
|
||||
expect(scene.currentBattle.trainer.config.trainerType).toBe(TrainerType.VITO);
|
||||
expect(scene.currentBattle.mysteryEncounter.enemyPartyConfigs.length).toBe(0);
|
||||
expect(scene.currentBattle.mysteryEncounter.encounterMode).toBe(MysteryEncounterMode.TRAINER_BATTLE);
|
||||
|
||||
// Should have Macho Brace in the rewards
|
||||
await skipBattleToNextBattle(game, true);
|
||||
await game.phaseInterceptor.to(SelectModifierPhase, false);
|
||||
expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name);
|
||||
await game.phaseInterceptor.run(SelectModifierPhase);
|
||||
|
||||
expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
|
||||
const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
|
||||
expect(modifierSelectHandler.options.length).toEqual(1);
|
||||
expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toBe("MYSTERY_ENCOUNTER_MACHO_BRACE");
|
||||
}, 15000);
|
||||
});
|
||||
|
||||
describe("Option 2 - Refuse the Challenge", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option = TheWinstrateChallengeEncounter.options[1];
|
||||
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||
expect(option.dialogue).toBeDefined();
|
||||
expect(option.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}.option.2.label`,
|
||||
buttonTooltip: `${namespace}.option.2.tooltip`,
|
||||
selected: [
|
||||
{
|
||||
speaker: `${namespace}.speaker`,
|
||||
text: `${namespace}.option.2.selected`,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("Should fully heal the party", async () => {
|
||||
const phaseSpy = vi.spyOn(scene, "unshiftPhase");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.THE_WINSTRATE_CHALLENGE, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
const partyHealPhases = phaseSpy.mock.calls.filter(p => p[0] instanceof PartyHealPhase).map(p => p[0]);
|
||||
expect(partyHealPhases.length).toBe(1);
|
||||
});
|
||||
|
||||
it("should have a Rarer Candy in the rewards", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.THE_WINSTRATE_CHALLENGE, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name);
|
||||
await game.phaseInterceptor.run(SelectModifierPhase);
|
||||
|
||||
expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
|
||||
const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
|
||||
expect(modifierSelectHandler.options.length).toEqual(1);
|
||||
expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toBe("RARER_CANDY");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* For any MysteryEncounter that has a battle, can call this to skip battle and proceed to MysteryEncounterRewardsPhase
|
||||
* @param game
|
||||
* @param isFinalBattle
|
||||
*/
|
||||
async function skipBattleToNextBattle(game: GameManager, isFinalBattle: boolean = false) {
|
||||
game.scene.clearPhaseQueue();
|
||||
game.scene.clearPhaseQueueSplice();
|
||||
const commandUiHandler = game.scene.ui.handlers[Mode.COMMAND];
|
||||
commandUiHandler.clear();
|
||||
game.scene.getEnemyParty().forEach(p => {
|
||||
p.hp = 0;
|
||||
p.status = new Status(StatusEffect.FAINT);
|
||||
game.scene.field.remove(p);
|
||||
});
|
||||
game.phaseInterceptor["onHold"] = [];
|
||||
game.scene.pushPhase(new VictoryPhase(game.scene, 0));
|
||||
game.phaseInterceptor.superEndPhase();
|
||||
if (isFinalBattle) {
|
||||
await game.phaseInterceptor.to(MysteryEncounterRewardsPhase);
|
||||
} else {
|
||||
await game.phaseInterceptor.to(CommandPhase);
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { StatusEffect } from "#app/data/status-effect";
|
||||
import IMysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MessagePhase } from "#app/phases";
|
||||
import { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species";
|
||||
import { Type } from "#app/data/type";
|
||||
@ -250,7 +250,7 @@ describe("Mystery Encounter Utils", () => {
|
||||
|
||||
describe("getTextWithEncounterDialogueTokens", () => {
|
||||
it("injects dialogue tokens and color styling", () => {
|
||||
scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null);
|
||||
scene.currentBattle.mysteryEncounter = new MysteryEncounter(null);
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value");
|
||||
|
||||
const result = getEncounterText(scene, "mysteryEncounter:unit_test_dialogue");
|
||||
@ -258,7 +258,7 @@ describe("Mystery Encounter Utils", () => {
|
||||
});
|
||||
|
||||
it("can perform nested dialogue token injection", () => {
|
||||
scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null);
|
||||
scene.currentBattle.mysteryEncounter = new MysteryEncounter(null);
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value");
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("testvalue", "new");
|
||||
|
||||
@ -269,7 +269,7 @@ describe("Mystery Encounter Utils", () => {
|
||||
|
||||
describe("queueEncounterMessage", () => {
|
||||
it("queues a message with encounter dialogue tokens", async () => {
|
||||
scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null);
|
||||
scene.currentBattle.mysteryEncounter = new MysteryEncounter(null);
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value");
|
||||
const spy = vi.spyOn(game.scene, "queueMessage");
|
||||
const phaseSpy = vi.spyOn(game.scene, "unshiftPhase");
|
||||
@ -282,7 +282,7 @@ describe("Mystery Encounter Utils", () => {
|
||||
|
||||
describe("showEncounterText", () => {
|
||||
it("showText with dialogue tokens", async () => {
|
||||
scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null);
|
||||
scene.currentBattle.mysteryEncounter = new MysteryEncounter(null);
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value");
|
||||
const spy = vi.spyOn(game.scene.ui, "showText");
|
||||
|
||||
@ -293,7 +293,7 @@ describe("Mystery Encounter Utils", () => {
|
||||
|
||||
describe("showEncounterDialogue", () => {
|
||||
it("showText with dialogue tokens", async () => {
|
||||
scene.currentBattle.mysteryEncounter = new IMysteryEncounter(null);
|
||||
scene.currentBattle.mysteryEncounter = new MysteryEncounter(null);
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value");
|
||||
const spy = vi.spyOn(game.scene.ui, "showDialogue");
|
||||
|
||||
|
@ -127,6 +127,7 @@ export default class GameWrapper {
|
||||
manager: {
|
||||
game: this.game,
|
||||
},
|
||||
destroy: () => null,
|
||||
setVolume: () => null,
|
||||
stopByKey: () => null,
|
||||
on: (evt, callback) => callback(),
|
||||
|