mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-11-04 18:31:20 +01:00
* Replace various `scene` pass-arounds with global scene variable * Modify tests * Add scene back to `fade[in|out]()` calls Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com> * Fix Bug Superfan ME test Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com> * Re-enable fixed test Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com> * Rename `gScene` to `globalScene` * Move `globalScene` to its own file to fix import/async issues * Fix `SelectModifierPhase` tests * Fix ME tests by removing `scene` from `expect()`s * Resolve merge issues * Remove tsdocs referencing `scene` params Remove missed instances of `.scene` * Remove unnecessary `globalScene` usage in `loading-scene.ts` * Fix merge conflicts * Attempt to fix circular import issue * Found the source of the import issue * Fix merge issues --------- Co-authored-by: Moka <54149968+MokaStitcher@users.noreply.github.com>
224 lines
7.9 KiB
TypeScript
224 lines
7.9 KiB
TypeScript
import type { Type } from "#enums/type";
|
|
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
|
import { Species } from "#enums/species";
|
|
import { globalScene } from "#app/global-scene";
|
|
import { modifierTypes } from "#app/modifier/modifier-type";
|
|
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
|
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
|
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
|
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
|
import type { EnemyPartyConfig, EnemyPokemonConfig } from "../utils/encounter-phase-utils";
|
|
import { initBattleWithEnemyConfig, leaveEncounterWithoutBattle, } from "../utils/encounter-phase-utils";
|
|
import { getRandomPlayerPokemon, getRandomSpeciesByStarterCost } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
|
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
|
|
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
|
import { PokemonFormChangeItemModifier } from "#app/modifier/modifier";
|
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
|
import { Challenges } from "#enums/challenges";
|
|
|
|
/** i18n namespace for encounter */
|
|
const namespace = "mysteryEncounters/darkDeal";
|
|
|
|
/** Exclude Ultra Beasts (inludes Cosmog/Solgaleo/Lunala/Necrozma), Paradox (includes Miraidon/Koraidon), Eternatus, and Mythicals */
|
|
const excludedBosses = [
|
|
Species.NECROZMA,
|
|
Species.COSMOG,
|
|
Species.COSMOEM,
|
|
Species.SOLGALEO,
|
|
Species.LUNALA,
|
|
Species.ETERNATUS,
|
|
Species.NIHILEGO,
|
|
Species.BUZZWOLE,
|
|
Species.PHEROMOSA,
|
|
Species.XURKITREE,
|
|
Species.CELESTEELA,
|
|
Species.KARTANA,
|
|
Species.GUZZLORD,
|
|
Species.POIPOLE,
|
|
Species.NAGANADEL,
|
|
Species.STAKATAKA,
|
|
Species.BLACEPHALON,
|
|
Species.GREAT_TUSK,
|
|
Species.SCREAM_TAIL,
|
|
Species.BRUTE_BONNET,
|
|
Species.FLUTTER_MANE,
|
|
Species.SLITHER_WING,
|
|
Species.SANDY_SHOCKS,
|
|
Species.ROARING_MOON,
|
|
Species.KORAIDON,
|
|
Species.WALKING_WAKE,
|
|
Species.GOUGING_FIRE,
|
|
Species.RAGING_BOLT,
|
|
Species.IRON_TREADS,
|
|
Species.IRON_BUNDLE,
|
|
Species.IRON_HANDS,
|
|
Species.IRON_JUGULIS,
|
|
Species.IRON_MOTH,
|
|
Species.IRON_THORNS,
|
|
Species.IRON_VALIANT,
|
|
Species.MIRAIDON,
|
|
Species.IRON_LEAVES,
|
|
Species.IRON_BOULDER,
|
|
Species.IRON_CROWN,
|
|
Species.MEW,
|
|
Species.CELEBI,
|
|
Species.DEOXYS,
|
|
Species.JIRACHI,
|
|
Species.DARKRAI,
|
|
Species.PHIONE,
|
|
Species.MANAPHY,
|
|
Species.ARCEUS,
|
|
Species.SHAYMIN,
|
|
Species.VICTINI,
|
|
Species.MELOETTA,
|
|
Species.KELDEO,
|
|
Species.GENESECT,
|
|
Species.DIANCIE,
|
|
Species.HOOPA,
|
|
Species.VOLCANION,
|
|
Species.MAGEARNA,
|
|
Species.MARSHADOW,
|
|
Species.ZERAORA,
|
|
Species.ZARUDE,
|
|
Species.MELTAN,
|
|
Species.MELMETAL,
|
|
Species.PECHARUNT,
|
|
];
|
|
|
|
/**
|
|
* Dark Deal encounter.
|
|
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3806 | GitHub Issue #3806}
|
|
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
|
*/
|
|
export const DarkDealEncounter: MysteryEncounter =
|
|
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.DARK_DEAL)
|
|
.withEncounterTier(MysteryEncounterTier.ROGUE)
|
|
.withIntroSpriteConfigs([
|
|
{
|
|
spriteKey: "dark_deal_scientist",
|
|
fileRoot: "mystery-encounters",
|
|
hasShadow: true,
|
|
},
|
|
{
|
|
spriteKey: "dark_deal_porygon",
|
|
fileRoot: "mystery-encounters",
|
|
hasShadow: true,
|
|
repeat: true,
|
|
},
|
|
])
|
|
.withIntroDialogue([
|
|
{
|
|
text: `${namespace}:intro`,
|
|
},
|
|
{
|
|
speaker: `${namespace}:speaker`,
|
|
text: `${namespace}:intro_dialogue`,
|
|
},
|
|
])
|
|
.withSceneWaveRangeRequirement(30, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES[1])
|
|
.withScenePartySizeRequirement(2, 6, true) // Must have at least 2 pokemon in party
|
|
.withCatchAllowed(true)
|
|
.setLocalizationKey(`${namespace}`)
|
|
.withTitle(`${namespace}:title`)
|
|
.withDescription(`${namespace}:description`)
|
|
.withQuery(`${namespace}:query`)
|
|
.withOption(
|
|
MysteryEncounterOptionBuilder
|
|
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
|
|
.withDialogue({
|
|
buttonLabel: `${namespace}:option.1.label`,
|
|
buttonTooltip: `${namespace}:option.1.tooltip`,
|
|
selected: [
|
|
{
|
|
speaker: `${namespace}:speaker`,
|
|
text: `${namespace}:option.1.selected_dialogue`,
|
|
},
|
|
{
|
|
text: `${namespace}:option.1.selected_message`,
|
|
},
|
|
],
|
|
})
|
|
.withPreOptionPhase(async () => {
|
|
// Removes random pokemon (including fainted) from party and adds name to dialogue data tokens
|
|
// Will never return last battle able mon and instead pick fainted/unable to battle
|
|
const removedPokemon = getRandomPlayerPokemon(true, false, true);
|
|
|
|
// Get all the pokemon's held items
|
|
const modifiers = removedPokemon.getHeldItems().filter(m => !(m instanceof PokemonFormChangeItemModifier));
|
|
globalScene.removePokemonFromPlayerParty(removedPokemon);
|
|
|
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
|
encounter.setDialogueToken("pokeName", removedPokemon.getNameToRender());
|
|
|
|
// Store removed pokemon types
|
|
encounter.misc = {
|
|
removedTypes: removedPokemon.getTypes(),
|
|
modifiers
|
|
};
|
|
})
|
|
.withOptionPhase(async () => {
|
|
// Give the player 5 Rogue Balls
|
|
const encounter = globalScene.currentBattle.mysteryEncounter!;
|
|
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.ROGUE_BALL));
|
|
|
|
// Start encounter with random legendary (7-10 starter strength) that has level additive
|
|
// If this is a mono-type challenge, always ensure the required type is filtered for
|
|
let bossTypes: Type[] = encounter.misc.removedTypes;
|
|
const singleTypeChallenges = globalScene.gameMode.challenges.filter(c => c.value && c.id === Challenges.SINGLE_TYPE);
|
|
if (globalScene.gameMode.isChallenge && singleTypeChallenges.length > 0) {
|
|
bossTypes = singleTypeChallenges.map(c => (c.value - 1) as Type);
|
|
}
|
|
|
|
const bossModifiers: PokemonHeldItemModifier[] = encounter.misc.modifiers;
|
|
// Starter egg tier, 35/50/10/5 %odds for tiers 6/7/8/9+
|
|
const roll = randSeedInt(100);
|
|
const starterTier: number | [number, number] =
|
|
roll >= 65 ? 6 : roll >= 15 ? 7 : roll >= 5 ? 8 : [ 9, 10 ];
|
|
const bossSpecies = getPokemonSpecies(getRandomSpeciesByStarterCost(starterTier, excludedBosses, bossTypes));
|
|
const pokemonConfig: EnemyPokemonConfig = {
|
|
species: bossSpecies,
|
|
isBoss: true,
|
|
modifierConfigs: bossModifiers.map(m => {
|
|
return {
|
|
modifier: m,
|
|
stackCount: m.getStackCount(),
|
|
};
|
|
})
|
|
};
|
|
if (!isNullOrUndefined(bossSpecies.forms) && bossSpecies.forms.length > 0) {
|
|
pokemonConfig.formIndex = 0;
|
|
}
|
|
const config: EnemyPartyConfig = {
|
|
pokemonConfigs: [ pokemonConfig ],
|
|
};
|
|
await initBattleWithEnemyConfig(config);
|
|
})
|
|
.build()
|
|
)
|
|
.withSimpleOption(
|
|
{
|
|
buttonLabel: `${namespace}:option.2.label`,
|
|
buttonTooltip: `${namespace}:option.2.tooltip`,
|
|
selected: [
|
|
{
|
|
speaker: `${namespace}:speaker`,
|
|
text: `${namespace}:option.2.selected`,
|
|
},
|
|
],
|
|
},
|
|
async () => {
|
|
// Leave encounter with no rewards or exp
|
|
leaveEncounterWithoutBattle(true);
|
|
return true;
|
|
}
|
|
)
|
|
.withOutroDialogue([
|
|
{
|
|
text: `${namespace}:outro`
|
|
}
|
|
])
|
|
.build();
|