From 1513f2a57ddec2409b5be208e38bae5e4be1d462 Mon Sep 17 00:00:00 2001 From: ImperialSympathizer Date: Tue, 24 Sep 2024 11:32:22 -0400 Subject: [PATCH] more ME balance changes and bug fixes --- .../encounters/a-trainers-test-encounter.ts | 3 +- .../encounters/absolute-avarice-encounter.ts | 9 ++-- .../an-offer-you-cant-refuse-encounter.ts | 11 ++++- .../encounters/delibirdy-encounter.ts | 10 ++-- .../encounters/field-trip-encounter.ts | 2 +- .../global-trade-system-encounter.ts | 46 +++++++++++++++---- .../encounters/the-strong-stuff-encounter.ts | 2 +- .../encounters/trash-to-treasure-encounter.ts | 16 +++++-- .../encounters/weird-dream-encounter.ts | 2 +- .../mystery-encounters/mystery-encounters.ts | 8 +++- .../a-trainers-test-dialogue.json | 2 +- .../clowning-around-dialogue.json | 6 +-- .../delibirdy-dialogue.json | 2 +- .../global-trade-system-dialogue.json | 4 +- .../the-pokemon-salesman-dialogue.json | 4 +- .../training-session-dialogue.json | 8 ++-- .../trash-to-treasure-dialogue.json | 2 +- src/modifier/modifier-type.ts | 11 +++-- src/modifier/modifier.ts | 12 +++-- .../encounters/delibirdy-encounter.test.ts | 22 ++++----- .../the-strong-stuff-encounter.test.ts | 2 +- 21 files changed, 122 insertions(+), 62 deletions(-) diff --git a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts index f7666fa1b37..88fdadf8588 100644 --- a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts +++ b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts @@ -15,6 +15,7 @@ import { EggTier } from "#enums/egg-type"; import { PartyHealPhase } from "#app/phases/party-heal-phase"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { modifierTypes } from "#app/modifier/modifier-type"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounter:aTrainersTest"; @@ -27,7 +28,7 @@ const namespace = "mysteryEncounter:aTrainersTest"; export const ATrainersTestEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.A_TRAINERS_TEST) .withEncounterTier(MysteryEncounterTier.ROGUE) - .withSceneWaveRangeRequirement(100, 180) + .withSceneWaveRangeRequirement(100, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES[1]) .withIntroSpriteConfigs([]) // These are set in onInit() .withIntroDialogue([ { diff --git a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts index 7a3de0a5bbb..efcd41054ea 100644 --- a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts +++ b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts @@ -159,12 +159,6 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = ]) .withHideWildIntroMessage(true) .withAutoHideIntroVisuals(false) - .withOnVisualsStart((scene: BattleScene) => { - doGreedentSpriteSteal(scene); - doBerrySpritePile(scene); - - return true; - }) .withIntroDialogue([ { text: `${namespace}.intro`, @@ -236,6 +230,9 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = return true; }) .withOnVisualsStart((scene: BattleScene) => { + doGreedentSpriteSteal(scene); + doBerrySpritePile(scene); + // Remove the berries from the party // Session has been safely saved at this point, so data won't be lost const berryItems = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[]; diff --git a/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts b/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts index 62025957abe..013feb6e5a4 100644 --- a/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts +++ b/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts @@ -8,7 +8,7 @@ import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/myst import { AbilityRequirement, CombinationPokemonRequirement, MoveRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; import { getHighestStatTotalPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { EXTORTION_ABILITIES, EXTORTION_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups"; -import { getPokemonSpecies } from "#app/data/pokemon-species"; +import { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; @@ -61,7 +61,14 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter = .withOnInit((scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter!; const pokemon = getHighestStatTotalPlayerPokemon(scene, true, true); - const price = scene.getWaveMoneyAmount(10); + + // Base value of Relic Gold, increased linearly up to 3x Relic Gold based on the starter tier of the Pokemon being purchased + // Starter value 1-3 -> 10x + // Starter value 10 -> 30x + const baseSpecies = pokemon.getSpeciesForm().getRootSpeciesId(true); + const starterValue: number = speciesStarters[baseSpecies] ?? 1; + const multiplier = Math.max(3 * starterValue, 10); + const price = scene.getWaveMoneyAmount(multiplier); encounter.setDialogueToken("strongestPokemon", pokemon.getNameToRender()); encounter.setDialogueToken("price", price.toString()); diff --git a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts index 90ed486efd7..2b0f7b0722e 100644 --- a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts +++ b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts @@ -10,7 +10,7 @@ import { CombinationPokemonRequirement, HeldItemRequirement, MoneyRequirement } import { getEncounterText, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; -import { BerryModifier, HealingBoosterModifier, HiddenAbilityRateBoosterModifier, LevelIncrementBoosterModifier, PokemonHeldItemModifier, PreserveBerryModifier } from "#app/modifier/modifier"; +import { BerryModifier, HealingBoosterModifier, LevelIncrementBoosterModifier, MoneyMultiplierModifier, PokemonHeldItemModifier, PreserveBerryModifier } from "#app/modifier/modifier"; import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import { applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import i18next from "#app/plugins/i18n"; @@ -33,7 +33,7 @@ const OPTION_3_DISALLOWED_MODIFIERS = [ "PokemonBaseStatTotalModifier" ]; -const DELIBIRDY_MONEY_PRICE_MULTIPLIER = 1.5; +const DELIBIRDY_MONEY_PRICE_MULTIPLIER = 2; /** * Delibird-y encounter. @@ -122,9 +122,9 @@ export const DelibirdyEncounter: MysteryEncounter = return true; }) .withOptionPhase(async (scene: BattleScene) => { - // Give the player an Ability Charm + // Give the player an Amulet Coin // Check if the player has max stacks of that item already - const existing = scene.findModifier(m => m instanceof HiddenAbilityRateBoosterModifier) as HiddenAbilityRateBoosterModifier; + const existing = scene.findModifier(m => m instanceof MoneyMultiplierModifier) as MoneyMultiplierModifier; if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) { // At max stacks, give the first party pokemon a Shell Bell instead @@ -133,7 +133,7 @@ export const DelibirdyEncounter: MysteryEncounter = scene.playSound("item_fanfare"); await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true); } else { - scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.ABILITY_CHARM)); + scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.AMULET_COIN)); } leaveEncounterWithoutBattle(scene, true); diff --git a/src/data/mystery-encounters/encounters/field-trip-encounter.ts b/src/data/mystery-encounters/encounters/field-trip-encounter.ts index 82f27c5e59b..49936b67efe 100644 --- a/src/data/mystery-encounters/encounters/field-trip-encounter.ts +++ b/src/data/mystery-encounters/encounters/field-trip-encounter.ts @@ -24,7 +24,7 @@ const namespace = "mysteryEncounter:fieldTrip"; export const FieldTripEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.FIELD_TRIP) .withEncounterTier(MysteryEncounterTier.COMMON) - .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) + .withSceneWaveRangeRequirement(CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES[0], 100) .withIntroSpriteConfigs([ { spriteKey: "preschooler_m", diff --git a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts index 18b913f80ce..71e9a71a554 100644 --- a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts +++ b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts @@ -11,9 +11,10 @@ import PokemonSpecies, { allSpecies, getPokemonSpecies } from "#app/data/pokemon import { getTypeRgb } from "#app/data/type"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; +import * as Utils from "#app/utils"; import { IntegerHolder, isNullOrUndefined, randInt, randSeedInt, randSeedShuffle } from "#app/utils"; -import Pokemon, { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; -import { HiddenAbilityRateBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, SpeciesStatBoosterModifier } from "#app/modifier/modifier"; +import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon"; +import { HiddenAbilityRateBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, ShinyRateBoosterModifier, SpeciesStatBoosterModifier } from "#app/modifier/modifier"; import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import PokemonData from "#app/system/pokemon-data"; import i18next from "i18next"; @@ -24,6 +25,8 @@ import { getEncounterText, showEncounterText } from "#app/data/mystery-encounter import { trainerNamePools } from "#app/data/trainer-names"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { addPokemonDataToDexAndValidateAchievements } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import { Moves } from "#enums/moves"; +import { speciesEggMoves } from "#app/data/egg-moves"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounter:globalTradeSystem"; @@ -222,21 +225,48 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = const tradePokemon = new EnemyPokemon(scene, randomTradeOption, pokemon.level, TrainerSlot.NONE, false); // Extra shiny roll at 1/128 odds (boosted by events and charms) if (!tradePokemon.shiny) { - // 512/65536 -> 1/128 - tradePokemon.trySetShinySeed(512, true); + const baseShinyChance = 512; + const shinyThreshold = new Utils.IntegerHolder(baseShinyChance); + if (scene.eventManager.isEventActive()) { + shinyThreshold.value *= scene.eventManager.getShinyMultiplier(); + } + scene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold); + + // Base shiny chance of 512/65536 -> 1/128, affected by events and Shiny Charms + // Maximum shiny chance of 4090/65536 -> 1/16, cannot improve further after that + const shinyChance = Math.min(shinyThreshold.value, 4090); + + tradePokemon.trySetShinySeed(shinyChance, false); } // Extra HA roll at base 1/64 odds (boosted by events and charms) - if (pokemon.species.abilityHidden) { - const hiddenIndex = pokemon.species.ability2 ? 2 : 1; - if (pokemon.abilityIndex < hiddenIndex) { + const hiddenIndex = tradePokemon.species.ability2 ? 2 : 1; + if (tradePokemon.species.abilityHidden) { + if (tradePokemon.abilityIndex < hiddenIndex) { const hiddenAbilityChance = new IntegerHolder(64); scene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance); const hasHiddenAbility = !randSeedInt(hiddenAbilityChance.value); if (hasHiddenAbility) { - pokemon.abilityIndex = hiddenIndex; + tradePokemon.abilityIndex = hiddenIndex; + } + } + } + + // If Pokemon is still not shiny or with HA, give the Pokemon a random Common egg move in its moveset + if (!tradePokemon.shiny && (!tradePokemon.species.abilityHidden || tradePokemon.abilityIndex < hiddenIndex)) { + const eggMoves: Moves[] = speciesEggMoves[tradePokemon.getSpeciesForm().getRootSpeciesId()]; + if (eggMoves) { + // Cannot gen the rare egg move, only 1 of the first 3 common moves + const eggMove = eggMoves[randSeedInt(3)]; + if (!tradePokemon.moveset.some(m => m?.moveId === eggMove)) { + if (tradePokemon.moveset.length < 4) { + tradePokemon.moveset.push(new PokemonMove(eggMove)); + } else { + const eggMoveIndex = randSeedInt(4); + tradePokemon.moveset[eggMoveIndex] = new PokemonMove(eggMove); + } } } } diff --git a/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts b/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts index 55cb10644e8..56328695128 100644 --- a/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts @@ -33,7 +33,7 @@ const BST_INCREASE_VALUE = 10; */ export const TheStrongStuffEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.THE_STRONG_STUFF) - .withEncounterTier(MysteryEncounterTier.GREAT) + .withEncounterTier(MysteryEncounterTier.COMMON) .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) .withScenePartySizeRequirement(3, 6) // Must have at least 3 pokemon in party .withMaxAllowedEncounters(1) diff --git a/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts b/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts index d295c8ab548..985984e73e8 100644 --- a/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts +++ b/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts @@ -16,7 +16,6 @@ import { getPokemonSpecies } from "#app/data/pokemon-species"; import { Moves } from "#enums/moves"; import { BattlerIndex } from "#app/battle"; import { PokemonMove } from "#app/field/pokemon"; -import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; /** the i18n namespace for this encounter */ @@ -24,6 +23,9 @@ const namespace = "mysteryEncounter:trashToTreasure"; const SOUND_EFFECT_WAIT_TIME = 700; +// Items will cost 2.5x as much for remainder of the run +const SHOP_ITEM_COST_MULTIPLIER = 2.5; + /** * Trash to Treasure encounter. * @see {@link https://github.com/pagefaultgames/pokerogue/issues/3809 | GitHub Issue #3809} @@ -79,6 +81,8 @@ export const TrashToTreasureEncounter: MysteryEncounter = scene.loadSe("PRSFX- Dig2", "battle_anims", "PRSFX- Dig2.wav"); scene.loadSe("PRSFX- Venom Drench", "battle_anims", "PRSFX- Venom Drench.wav"); + encounter.setDialogueToken("costMultiplier", SHOP_ITEM_COST_MULTIPLIER.toString()); + return true; }) .withOption( @@ -102,8 +106,14 @@ export const TrashToTreasureEncounter: MysteryEncounter = transitionMysteryEncounterIntroVisuals(scene); await tryApplyDigRewardItems(scene); - // Give the player the Black Sludge curse - scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.MYSTERY_ENCOUNTER_BLACK_SLUDGE)); + const blackSludge = generateModifierType(scene, modifierTypes.MYSTERY_ENCOUNTER_BLACK_SLUDGE, [SHOP_ITEM_COST_MULTIPLIER]); + const modifier = blackSludge?.newModifier(); + if (modifier) { + await scene.addModifier(modifier, false, false, false, true); + scene.playSound("battle_anims/PRSFX- Venom Drench", { volume: 2 }); + await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: modifier.type.name }), null, undefined, true); + } + leaveEncounterWithoutBattle(scene, true); }) .build() diff --git a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts index 7ddafc7732e..43a3bfd8d3b 100644 --- a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts +++ b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts @@ -429,7 +429,7 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon } function getTransformedSpecies(originalBst: number, bstSearchRange: [number, number], hasPokemonBstHigherThan600: boolean, hasPokemonBstBetween570And600: boolean, alreadyUsedSpecies: PokemonSpecies[]): PokemonSpecies { - let newSpecies: PokemonSpecies | undefined = undefined; + let newSpecies: PokemonSpecies | undefined; while (isNullOrUndefined(newSpecies)) { const bstCap = originalBst + bstSearchRange[1]; const bstMin = Math.max(originalBst + bstSearchRange[0], 0); diff --git a/src/data/mystery-encounters/mystery-encounters.ts b/src/data/mystery-encounters/mystery-encounters.ts index cc2eaf234c4..0ce4a5c2506 100644 --- a/src/data/mystery-encounters/mystery-encounters.ts +++ b/src/data/mystery-encounters/mystery-encounters.ts @@ -32,6 +32,7 @@ import { FunAndGamesEncounter } from "#app/data/mystery-encounters/encounters/fu import { UncommonBreedEncounter } from "#app/data/mystery-encounters/encounters/uncommon-breed-encounter"; import { GlobalTradeSystemEncounter } from "#app/data/mystery-encounters/encounters/global-trade-system-encounter"; import { TheExpertPokemonBreederEncounter } from "#app/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter"; +import { getBiomeName } from "#app/data/biomes"; /** * Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * ) / MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT @@ -362,11 +363,16 @@ export function initMysteryEncounters() { }); // Add ANY biome encounters to biome map - mysteryEncountersByBiome.forEach(biomeEncounters => { + let encounterBiomeTableLog = ""; + mysteryEncountersByBiome.forEach((biomeEncounters, biome) => { anyBiomeEncounters.forEach(encounter => { if (!biomeEncounters.includes(encounter)) { biomeEncounters.push(encounter); } }); + + encounterBiomeTableLog += `${getBiomeName(biome).toUpperCase()}: [${biomeEncounters.map(type => MysteryEncounterType[type].toString().toLowerCase()).sort().join(", ")}]\n`; }); + + console.debug("All Mystery Encounters by Biome:\n" + encounterBiomeTableLog); } diff --git a/src/locales/en/mystery-encounters/a-trainers-test-dialogue.json b/src/locales/en/mystery-encounters/a-trainers-test-dialogue.json index c96c0d5f327..553f4822f07 100644 --- a/src/locales/en/mystery-encounters/a-trainers-test-dialogue.json +++ b/src/locales/en/mystery-encounters/a-trainers-test-dialogue.json @@ -31,7 +31,7 @@ "option": { "1": { "label": "Accept the Challenge", - "tooltip": "(-) Tough Battle\n(+) Gain a @[TOOLTIP_TITLE]{Very Rare Egg}" + "tooltip": "(-) Extremely Tough Battle\n(+) Gain a @[TOOLTIP_TITLE]{Very Rare Egg}" }, "2": { "label": "Refuse the Challenge", diff --git a/src/locales/en/mystery-encounters/clowning-around-dialogue.json b/src/locales/en/mystery-encounters/clowning-around-dialogue.json index 743358b4f29..c60a5eb0c01 100644 --- a/src/locales/en/mystery-encounters/clowning-around-dialogue.json +++ b/src/locales/en/mystery-encounters/clowning-around-dialogue.json @@ -8,7 +8,7 @@ "option": { "1": { "label": "Battle the Clown", - "tooltip": "(-) Strange Battle\n(?) Affects Pokémon Abilities", + "tooltip": "(-) Strange Battle\n(?) Affects One Pokémon's Ability", "selected": "Your pitiful Pokémon are poised for a pathetic performance!", "apply_ability_dialogue": "A sensational showcase!\nYour savvy suits a special skill as spoils!", "apply_ability_message": "The clown is offering to permanently Skill Swap one of your Pokémon's ability to {{ability}}!", @@ -17,14 +17,14 @@ }, "2": { "label": "Remain Unprovoked", - "tooltip": "(-) Upsets the Clown\n(?) Affects Pokémon Items", + "tooltip": "(?) Affects One Pokémon's Items", "selected": "Dismal dodger, you deny a delightful duel?\nFeel my fury!", "selected_2": "The clown's {{blacephalonName}} uses Trick!\nAll of your {{switchPokemon}}'s items were randomly swapped!", "selected_3": "Flustered fool, fall for my flawless deception!" }, "3": { "label": "Return the Insults", - "tooltip": "(-) Upsets the Clown\n(?) Affects Pokémon Types", + "tooltip": "(?) Affects Your Pokémons' Types", "selected": "Dismal dodger, you deny a delightful duel?\nFeel my fury!", "selected_2": "The clown's {{blacephalonName}} uses a strange move!\nAll of your team's types were randomly swapped!", "selected_3": "Flustered fool, fall for my flawless deception!" diff --git a/src/locales/en/mystery-encounters/delibirdy-dialogue.json b/src/locales/en/mystery-encounters/delibirdy-dialogue.json index eb9e02f1312..0a16c424f5a 100644 --- a/src/locales/en/mystery-encounters/delibirdy-dialogue.json +++ b/src/locales/en/mystery-encounters/delibirdy-dialogue.json @@ -1,7 +1,7 @@ { - "intro": "A pack of {{delibirdName}} have appeared!", + "intro": "A flock of {{delibirdName}} have appeared!", "title": "Delibir-dy", "description": "The {{delibirdName}}s are looking at you expectantly, as if they want something. Perhaps giving them an item or some money would satisfy them?", "query": "What will you give them?", diff --git a/src/locales/en/mystery-encounters/global-trade-system-dialogue.json b/src/locales/en/mystery-encounters/global-trade-system-dialogue.json index 1cc420355b7..84abebd4cbb 100644 --- a/src/locales/en/mystery-encounters/global-trade-system-dialogue.json +++ b/src/locales/en/mystery-encounters/global-trade-system-dialogue.json @@ -11,13 +11,13 @@ }, "2": { "label": "Wonder Trade", - "tooltip": "(+) Send one of your Pokémon to the GTS and get a random Pokémon in return" + "tooltip": "(+) Send one of your Pokémon to the GTS and get a random special Pokémon in return" }, "3": { "label": "Trade an Item", "trade_options_prompt": "Select an item to send.", "invalid_selection": "This Pokémon doesn't have legal items to trade.", - "tooltip": "(+) Send one of your Items to the GTS and get a random new Item" + "tooltip": "(+) Send one of your Items to the GTS and get a random improved Item" }, "4": { "label": "Leave", diff --git a/src/locales/en/mystery-encounters/the-pokemon-salesman-dialogue.json b/src/locales/en/mystery-encounters/the-pokemon-salesman-dialogue.json index 7e8091bbfff..0dc22574686 100644 --- a/src/locales/en/mystery-encounters/the-pokemon-salesman-dialogue.json +++ b/src/locales/en/mystery-encounters/the-pokemon-salesman-dialogue.json @@ -3,8 +3,8 @@ "speaker": "Gentleman", "intro_dialogue": "Hello there! Have I got a deal just for YOU!", "title": "The Pokémon Salesman", - "description": "\"This {{purchasePokemon}} is extremely unique and carries an ability not normally found in its species! I'll let you have this swell {{purchasePokemon}} for just {{price, money}}!\"\n\n\"What do you say?\"", - "description_shiny": "\"This {{purchasePokemon}} is extremely unique and has a pigment not normally found in its species! I'll let you have this swell {{purchasePokemon}} for just {{price, money}}!\"\n\n\"What do you say?\"", + "description": "\"This {{purchasePokemon}} is extremely unique and @[TOOLTIP_TITLE]{carries an ability not normally found in its species}! I'll let you have this swell {{purchasePokemon}} for just {{price, money}}!\"\n\n\"What do you say?\"", + "description_shiny": "\"This {{purchasePokemon}} is extremely unique and @[TOOLTIP_TITLE]{has a pigment not normally found in its species}! I'll let you have this swell {{purchasePokemon}} for just {{price, money}}!\"\n\n\"What do you say?\"", "query": "What will you do?", "option": { "1": { diff --git a/src/locales/en/mystery-encounters/training-session-dialogue.json b/src/locales/en/mystery-encounters/training-session-dialogue.json index f018018fe4e..61597dc7c89 100644 --- a/src/locales/en/mystery-encounters/training-session-dialogue.json +++ b/src/locales/en/mystery-encounters/training-session-dialogue.json @@ -1,24 +1,24 @@ { "intro": "You've come across some\ntraining tools and supplies.", "title": "Training Session", - "description": "These supplies look like they could be used to train a member of your party! There are a few ways you could train your Pokémon, by battling against it with the rest of your team.", + "description": "These supplies look like they could be used to train a member of your party! There are a few ways you could train your Pokémon, by @[TOOLTIP_TITLE]{battling and defeating it with the rest of your team}.", "query": "How should you train?", "invalid_selection": "Pokémon must be healthy enough.", "option": { "1": { "label": "Light Training", - "tooltip": "(-) Light Battle\n(+) Improve 2 Random IVs of Pokémon", + "tooltip": "(-) Light Battle with Chosen Pokémon\n(+) Permanently Improve 2 Random IVs of Chosen Pokémon", "finished": "{{selectedPokemon}} returns, feeling\nworn out but accomplished!$Its {{stat1}} and {{stat2}} IVs were improved!" }, "2": { "label": "Moderate Training", - "tooltip": "(-) Moderate Battle\n(+) Change Pokémon's Nature", + "tooltip": "(-) Moderate Battle with Chosen Pokémon\n(+) Permanently Change Chosen Pokémon's Nature", "select_prompt": "Select a new nature\nto train your Pokémon in.", "finished": "{{selectedPokemon}} returns, feeling\nworn out but accomplished!$Its nature was changed to {{nature}}!" }, "3": { "label": "Heavy Training", - "tooltip": "(-) Harsh Battle\n(+) Change Pokémon's Ability", + "tooltip": "(-) Harsh Battle with Chosen Pokémon\n(+) Permanently Change Chosen Pokémon's Ability", "select_prompt": "Select a new ability\nto train your Pokémon in.", "finished": "{{selectedPokemon}} returns, feeling\nworn out but accomplished!$Its ability was changed to {{ability}}!" }, diff --git a/src/locales/en/mystery-encounters/trash-to-treasure-dialogue.json b/src/locales/en/mystery-encounters/trash-to-treasure-dialogue.json index fe2cb54f5b1..da35082248c 100644 --- a/src/locales/en/mystery-encounters/trash-to-treasure-dialogue.json +++ b/src/locales/en/mystery-encounters/trash-to-treasure-dialogue.json @@ -6,7 +6,7 @@ "option": { "1": { "label": "Dig for Valuables", - "tooltip": "(-) Items in Shops Cost 3x\n(+) Gain Amazing Items", + "tooltip": "(-) Items in Shops Will Cost {{costMultiplier}}x\n(+) Gain Amazing Items", "selected": "You wade through the garbage pile, becoming mired in filth.$There's no way any respectable shopkeeper would\nsell you items at the normal rate in your grimy state!$You'll have to pay extra for items now.$However, you found some incredible items in the garbage!" }, "2": { diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 2b4f910034b..6503aaafbc5 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1577,17 +1577,22 @@ export const modifierTypes = { MYSTERY_ENCOUNTER_SHUCKLE_JUICE: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs) { - return new PokemonBaseStatTotalModifierType(pregenArgs[0] as integer); + return new PokemonBaseStatTotalModifierType(pregenArgs[0] as number); } return new PokemonBaseStatTotalModifierType(Utils.randSeedInt(20)); }), MYSTERY_ENCOUNTER_OLD_GATEAU: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs) { - return new PokemonBaseStatFlatModifierType(pregenArgs[0] as integer, pregenArgs[1] as Stat[]); + return new PokemonBaseStatFlatModifierType(pregenArgs[0] as number, pregenArgs[1] as Stat[]); } 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.HealShopCostModifier(type)), + MYSTERY_ENCOUNTER_BLACK_SLUDGE: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => { + if (pregenArgs) { + return new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_BLACK_SLUDGE", "black_sludge", (type, _args) => new Modifiers.HealShopCostModifier(type, pregenArgs[0] as number)); + } + return new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_BLACK_SLUDGE", "black_sludge", (type, _args) => new Modifiers.HealShopCostModifier(type, 2.5)); + }), 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)), MYSTERY_ENCOUNTER_GOLDEN_BUG_NET: () => new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET", "golden_net", (type, _args) => new Modifiers.BoostBugSpawnModifier(type)), }; diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index d091648b1b0..6c998105c1d 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -2576,8 +2576,12 @@ export class LockModifierTiersModifier extends PersistentModifier { * Black Sludge item */ export class HealShopCostModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + public readonly shopMultiplier: number; + + constructor(type: ModifierType, shopMultiplier: number, stackCount?: integer) { super(type, stackCount); + + this.shopMultiplier = shopMultiplier; } match(modifier: Modifier): boolean { @@ -2585,11 +2589,11 @@ export class HealShopCostModifier extends PersistentModifier { } clone(): HealShopCostModifier { - return new HealShopCostModifier(this.type, this.stackCount); + return new HealShopCostModifier(this.type, this.shopMultiplier, this.stackCount); } apply(args: any[]): boolean { - (args[0] as Utils.IntegerHolder).value *= Math.pow(3, this.getStackCount()); + (args[0] as Utils.IntegerHolder).value *= this.shopMultiplier; return true; } @@ -2608,7 +2612,7 @@ export class BoostBugSpawnModifier extends PersistentModifier { return modifier instanceof BoostBugSpawnModifier; } - clone(): HealShopCostModifier { + clone(): BoostBugSpawnModifier { return new BoostBugSpawnModifier(this.type, this.stackCount); } diff --git a/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts b/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts index 7e452fd90c7..dfa793fe7b5 100644 --- a/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/delibirdy-encounter.test.ts @@ -11,7 +11,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { DelibirdyEncounter } from "#app/data/mystery-encounters/encounters/delibirdy-encounter"; import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters"; import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; -import { BerryModifier, HealingBoosterModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, LevelIncrementBoosterModifier, PokemonInstantReviveModifier, PokemonNatureWeightModifier, PreserveBerryModifier } from "#app/modifier/modifier"; +import { BerryModifier, HealingBoosterModifier, HitHealModifier, LevelIncrementBoosterModifier, MoneyMultiplierModifier, PokemonInstantReviveModifier, PokemonNatureWeightModifier, PreserveBerryModifier } from "#app/modifier/modifier"; import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases"; import { generateModifierType } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { modifierTypes } from "#app/modifier/modifier-type"; @@ -104,35 +104,35 @@ describe("Delibird-y - Mystery Encounter", () => { expect(scene.money).toBe(initialMoney - price); }); - it("Should give the player a Hidden Ability Charm", async () => { + it("Should give the player an Amulet Coin", async () => { scene.money = 200000; await game.runToMysteryEncounter(MysteryEncounterType.DELIBIRDY, defaultParty); await runMysteryEncounterToEnd(game, 1); - const itemModifier = scene.findModifier(m => m instanceof HiddenAbilityRateBoosterModifier) as HiddenAbilityRateBoosterModifier; + const itemModifier = scene.findModifier(m => m instanceof MoneyMultiplierModifier) as MoneyMultiplierModifier; expect(itemModifier).toBeDefined(); expect(itemModifier?.stackCount).toBe(1); }); - it("Should give the player a Shell Bell if they have max stacks of Berry Pouches", async () => { + it("Should give the player a Shell Bell if they have max stacks of Amulet Coins", async () => { scene.money = 200000; await game.runToMysteryEncounter(MysteryEncounterType.DELIBIRDY, defaultParty); - // 5 Healing Charms + // Max Amulet Coins scene.modifiers = []; - const abilityCharm = generateModifierType(scene, modifierTypes.ABILITY_CHARM)!.newModifier() as HiddenAbilityRateBoosterModifier; - abilityCharm.stackCount = 4; - await scene.addModifier(abilityCharm, true, false, false, true); + const amuletCoin = generateModifierType(scene, modifierTypes.AMULET_COIN)!.newModifier() as MoneyMultiplierModifier; + amuletCoin.stackCount = 5; + await scene.addModifier(amuletCoin, true, false, false, true); await scene.updateModifiers(true); await runMysteryEncounterToEnd(game, 1); - const abilityCharmAfter = scene.findModifier(m => m instanceof HiddenAbilityRateBoosterModifier); + const amuletCoinAfter = scene.findModifier(m => m instanceof MoneyMultiplierModifier); const shellBellAfter = scene.findModifier(m => m instanceof HitHealModifier); - expect(abilityCharmAfter).toBeDefined(); - expect(abilityCharmAfter?.stackCount).toBe(4); + expect(amuletCoinAfter).toBeDefined(); + expect(amuletCoinAfter?.stackCount).toBe(5); expect(shellBellAfter).toBeDefined(); expect(shellBellAfter?.stackCount).toBe(1); }); diff --git a/src/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts b/src/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts index 4bcb063fff0..6930195b6cb 100644 --- a/src/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts @@ -70,7 +70,7 @@ describe("The Strong Stuff - Mystery Encounter", () => { await game.runToMysteryEncounter(MysteryEncounterType.THE_STRONG_STUFF, defaultParty); expect(TheStrongStuffEncounter.encounterType).toBe(MysteryEncounterType.THE_STRONG_STUFF); - expect(TheStrongStuffEncounter.encounterTier).toBe(MysteryEncounterTier.GREAT); + expect(TheStrongStuffEncounter.encounterTier).toBe(MysteryEncounterTier.COMMON); expect(TheStrongStuffEncounter.dialogue).toBeDefined(); expect(TheStrongStuffEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}.intro` }]); expect(TheStrongStuffEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`);