diff --git a/src/data/mystery-encounters/encounters/juiced_shuckle-juice-encounter.ts b/src/data/mystery-encounters/encounters/juiced_shuckle-juice-encounter.ts new file mode 100644 index 00000000000..e30e3612761 --- /dev/null +++ b/src/data/mystery-encounters/encounters/juiced_shuckle-juice-encounter.ts @@ -0,0 +1,122 @@ +import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { modifierTypes, } from "#app/modifier/modifier-type"; +import { MysteryEncounterType } from "#enums/mystery-encounter-type"; +import BattleScene from "../../../battle-scene"; +import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter"; +import { getPokemonSpecies } from "#app/data/pokemon-species"; +import { Species } from "#enums/species"; +import { Nature } from "#app/data/nature"; + +/** the i18n namespace for the encounter */ +const namespace = "mysteryEncounter:oneForAll"; + +export const JuicedShuckleJuiceEncounter: IMysteryEncounter = + MysteryEncounterBuilder.withEncounterType( + MysteryEncounterType.JUICED_SHUCKLE_JUICE + ) + .withEncounterTier(MysteryEncounterTier.COMMON) + .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 + .withHideWildIntroMessage(true) + .withIntroSpriteConfigs([ + { + spriteKey: Species.SHUCKLE.toString(), + fileRoot: "pokemon", + hasShadow: true, + repeat: true, + scale: 2 + }, + { + spriteKey: "berry_juice", + fileRoot: "mystery-encounters", + hasShadow: true, + scale: 2 + }, + ]) // Set in onInit() + .withIntroDialogue([ + { + text: `${namespace}_intro_message`, + }, + ]) + .withOnInit((scene: BattleScene) => { + const encounter = scene.currentBattle.mysteryEncounter; + + // Calculate boss mon + const config: EnemyPartyConfig = { + levelAdditiveMultiplier: 1, + pokemonConfigs: [ + { + species: getPokemonSpecies(Species.SHUCKLE), + isBoss: true, + bossSegments: 5, + spriteScale: 2, + nature: Nature.BOLD, + // moves: [Moves.INFESTATION, Moves.SALT_CURE, Moves.STEALTH_ROCK, Moves.RECOVER] + } + ], + }; + encounter.enemyPartyConfigs = [config]; + + return true; + }) + .withTitle(`${namespace}_title`) + .withDescription(`${namespace}_description`) + .withQuery(`${namespace}_query`) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_1_label`, + buttonTooltip: `${namespace}_option_1_tooltip`, + selected: [ + { + text: `${namespace}_option_1_selected`, + }, + ], + }, + async (scene: BattleScene) => { + // Leave encounter with no rewards or exp + // const encounter = scene.currentBattle.mysteryEncounter; + + // Get highest BST mon + const party = scene.getParty(); + let highestBst = null; + let statTotal = 0; + for (const pokemon of party) { + if (!highestBst) { + highestBst = pokemon; + statTotal = pokemon.summonData.stats.reduce((i, n) => n + i); + continue; + } + + const total = pokemon.summonData.stats.reduce((i, n) => n + i); + if (total > statTotal) { + highestBst = pokemon; + statTotal = total; + } + } + + if (!highestBst) { + highestBst = party[0]; + } + + + + leaveEncounterWithoutBattle(scene, true); + return true; + } + ) + .withSimpleOption( + { + buttonLabel: `${namespace}_option_2_label`, + buttonTooltip: `${namespace}_option_2_tooltip`, + selected: [ + { + text: `${namespace}_option_2_selected_message`, + }, + ], + }, + async (scene: BattleScene) => { + // Pick battle + setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.SOUL_DEW], fillRemaining: true }); + await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]); + } + ) + .build(); diff --git a/src/data/mystery-encounters/encounters/one-for-all-encounter.ts b/src/data/mystery-encounters/encounters/one-for-all-encounter.ts deleted file mode 100644 index a07bec924a9..00000000000 --- a/src/data/mystery-encounters/encounters/one-for-all-encounter.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { BattleStat } from "#app/data/battle-stat"; -import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; -import { - EnemyPartyConfig, EnemyPokemonConfig, - initBattleWithEnemyConfig, - leaveEncounterWithoutBattle, - setEncounterRewards -} from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { STEALING_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups"; -import Pokemon from "#app/field/pokemon"; -import { ModifierTier } from "#app/modifier/modifier-tier"; -import { - getPartyLuckValue, - getPlayerModifierTypeOptions, - ModifierPoolType, - ModifierTypeOption, - regenerateModifierPoolThresholds, -} from "#app/modifier/modifier-type"; -import { StatChangePhase } from "#app/phases"; -import { randSeedInt } from "#app/utils"; -import { BattlerTagType } from "#enums/battler-tag-type"; -import { MysteryEncounterType } from "#enums/mystery-encounter-type"; -import BattleScene from "../../../battle-scene"; -import IMysteryEncounter, { - MysteryEncounterBuilder, - MysteryEncounterTier, -} from "../mystery-encounter"; -import { MoveRequirement } from "../mystery-encounter-requirements"; -import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; -import { getPokemonSpecies } from "#app/data/pokemon-species"; -import { Species } from "#enums/species"; -import { StatusEffect } from "#app/data/status-effect"; - -/** the i18n namespace for the encounter */ -const namespace = "mysteryEncounter:oneForAll"; - -export const OneForAllEncounter: IMysteryEncounter = - MysteryEncounterBuilder.withEncounterType( - MysteryEncounterType.FIGHT_OR_FLIGHT - ) - .withEncounterTier(MysteryEncounterTier.COMMON) - .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 - .withHideWildIntroMessage(true) - .withIntroSpriteConfigs([ - { - spriteKey: Species.SHUCKLE.toString(), - fileRoot: "pokemon", - hasShadow: true, - repeat: true, - scale: 2 - }, - { - spriteKey: "berry_juice", - fileRoot: "mystery-encounters", - hasShadow: true, - scale: 2 - }, - ]) // Set in onInit() - .withIntroDialogue([ - { - text: `${namespace}_intro_message`, - }, - ]) - .withOnInit((scene: BattleScene) => { - const encounter = scene.currentBattle.mysteryEncounter; - - // Calculate boss mon - const bossSpecies = scene.arena.randomSpecies(scene.currentBattle.waveIndex, scene.currentBattle.waveIndex, 0, getPartyLuckValue(scene.getParty()), true); - const config: EnemyPartyConfig = { - levelAdditiveMultiplier: 1, - pokemonConfigs: [{ species: bossSpecies, isBoss: true }], - }; - encounter.enemyPartyConfigs = [config]; - - // Calculate item - // 10-60 GREAT, 60-110 ULTRA, 110-160 ROGUE, 160-180 MASTER - const tier = - scene.currentBattle.waveIndex > 160 - ? ModifierTier.MASTER - : scene.currentBattle.waveIndex > 110 - ? ModifierTier.ROGUE - : scene.currentBattle.waveIndex > 60 - ? ModifierTier.ULTRA - : ModifierTier.GREAT; - regenerateModifierPoolThresholds(scene.getParty(), ModifierPoolType.PLAYER, 0); - const item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { guaranteedModifierTiers: [tier] })[0]; - encounter.setDialogueToken("itemName", item.type.name); - encounter.misc = item; - - const bossSpriteKey = bossSpecies.getSpriteId(false, bossSpecies.forms ? 0 : null, false, bossSpecies.hasVariants() ? 0 : null); - encounter.spriteConfigs = [ - { - spriteKey: item.type.iconImage, - fileRoot: "items", - hasShadow: false, - x: 35, - y: -5, - scale: 0.75, - isItem: true, - }, - { - spriteKey: bossSpriteKey, - fileRoot: "pokemon", - hasShadow: true, - tint: 0.25, - x: -5, - repeat: true, - }, - ]; - - // If player has a stealing move, they succeed automatically - encounter.options[1].meetsRequirements(scene); - const primaryPokemon = encounter.options[1].primaryPokemon; - if (primaryPokemon) { - // Use primaryPokemon to execute the thievery - encounter.options[1].dialogue.buttonTooltip = `${namespace}_option_2_steal_tooltip`; - } else { - encounter.options[1].dialogue.buttonTooltip = `${namespace}_option_2_tooltip`; - } - - return true; - }) - .withTitle(`${namespace}_title`) - .withDescription(`${namespace}_description`) - .withQuery(`${namespace}_query`) - .withSimpleOption( - { - buttonLabel: `${namespace}_option_1_label`, - buttonTooltip: `${namespace}_option_1_tooltip`, - selected: [ - { - text: `${namespace}_option_1_selected_message`, - }, - ], - }, - async (scene: BattleScene) => { - // Pick battle - const encounter = scene.currentBattle.mysteryEncounter; - const bossSpecies = getPokemonSpecies(Species.SNORLAX); - const pokemonConfig: EnemyPokemonConfig = { - species: bossSpecies, - isBoss: true, - status: StatusEffect.SLEEP, - }; - const config: EnemyPartyConfig = { - levelAdditiveMultiplier: 2, - pokemonConfigs: [pokemonConfig], - }; - encounter.enemyPartyConfigs = [config]; - - const item = scene.currentBattle.mysteryEncounter - .misc as ModifierTypeOption; - setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false }); - await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]); - } - ) - .withOption( - new MysteryEncounterOptionBuilder() - .withOptionMode(EncounterOptionMode.DEFAULT_OR_SPECIAL) - .withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically - .withDialogue({ - buttonLabel: `${namespace}_option_2_label`, - buttonTooltip: `${namespace}_option_2_tooltip`, - }) - .withOptionPhase(async (scene: BattleScene) => { - // Pick steal - const encounter = scene.currentBattle.mysteryEncounter; - const item = scene.currentBattle.mysteryEncounter.misc as ModifierTypeOption; - setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false }); - - // If player has a stealing move, they succeed automatically - const primaryPokemon = encounter.options[1].primaryPokemon; - if (primaryPokemon) { - // Use primaryPokemon to execute the thievery - await showEncounterText(scene, `${namespace}_option_2_steal_result`); - leaveEncounterWithoutBattle(scene); - return; - } - - const roll = randSeedInt(16); - if (roll > 6) { - // Noticed and attacked by boss, gets +1 to all stats at start of fight (62.5%) - const config = scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]; - config.pokemonConfigs[0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON]; - config.pokemonConfigs[0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => { - pokemon.scene.currentBattle.mysteryEncounter.setDialogueToken("enemyPokemon", pokemon.name); - queueEncounterMessage(pokemon.scene, `${namespace}_boss_enraged`); - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD], 1)); - }; - await showEncounterText(scene, `${namespace}_option_2_bad_result`); - await initBattleWithEnemyConfig(scene, config); - } else { - // Steal item (37.5%) - // Display result message then proceed to rewards - await showEncounterText(scene, `${namespace}_option_2_good_result`); - leaveEncounterWithoutBattle(scene); - } - }) - .build() - ) - .withSimpleOption( - { - buttonLabel: `${namespace}_option_3_label`, - buttonTooltip: `${namespace}_option_3_tooltip`, - selected: [ - { - text: `${namespace}_option_3_selected`, - }, - ], - }, - async (scene: BattleScene) => { - // Leave encounter with no rewards or exp - leaveEncounterWithoutBattle(scene, true); - return true; - } - ) - .build(); diff --git a/src/data/mystery-encounters/utils/encounter-phase-utils.ts b/src/data/mystery-encounters/utils/encounter-phase-utils.ts index 8ad022f881c..92acc65326c 100644 --- a/src/data/mystery-encounters/utils/encounter-phase-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-phase-utils.ts @@ -26,6 +26,7 @@ import PokemonSpecies from "../../pokemon-species"; import { Status, StatusEffect } from "../../status-effect"; import { TrainerConfig, trainerConfigs, TrainerSlot } from "../../trainer-config"; import { MysteryEncounterVariant } from "../mystery-encounter"; +import { Nature } from "#app/data/nature"; export class EnemyPokemonConfig { species: PokemonSpecies; @@ -34,6 +35,8 @@ export class EnemyPokemonConfig { bossSegmentModifier?: number; // Additive to the determined segment number formIndex?: number; level?: number; + nature?: Nature; + ivs?: [integer, integer, integer, integer, integer, integer]; modifierTypes?: PokemonHeldItemModifierType[]; dataSource?: PokemonData; tags?: BattlerTagType[]; @@ -180,15 +183,25 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: } // Set Passive - if (partyConfig.pokemonConfigs[e].passive) { + if (config.passive) { enemyPokemon.passive = true; } + // Set Nature + if (config.nature) { + enemyPokemon.nature = config.nature; + } + + // Set IVs + if (config.ivs) { + enemyPokemon.ivs = config.ivs; + } + // Set Status - if (partyConfig.pokemonConfigs[e].status) { + if (config.status) { // Default to cureturn 3 for sleep - const cureTurn = partyConfig.pokemonConfigs[e].status === StatusEffect.SLEEP ? 3 : null; - enemyPokemon.status = new Status(partyConfig.pokemonConfigs[e].status, 0, cureTurn); + const cureTurn = config.status === StatusEffect.SLEEP ? 3 : null; + enemyPokemon.status = new Status(config.status, 0, cureTurn); } // Set tags diff --git a/src/enums/mystery-encounter-type.ts b/src/enums/mystery-encounter-type.ts index 1f2711cd674..7a9938091c1 100644 --- a/src/enums/mystery-encounter-type.ts +++ b/src/enums/mystery-encounter-type.ts @@ -9,5 +9,6 @@ export enum MysteryEncounterType { SHADY_VITAMIN_DEALER, FIELD_TRIP, SAFARI_ZONE, - LOST_AT_SEA //might be generalized later on + LOST_AT_SEA, //might be generalized later on + JUICED_SHUCKLE_JUICE }