more ME balance changes and bug fixes

This commit is contained in:
ImperialSympathizer 2024-09-24 11:32:22 -04:00
parent b2b88c37cf
commit 1513f2a57d
21 changed files with 122 additions and 62 deletions

View File

@ -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([
{

View File

@ -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[];

View File

@ -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());

View File

@ -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);

View File

@ -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",

View File

@ -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);
}
}
}
}

View File

@ -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)

View File

@ -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()

View File

@ -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);

View File

@ -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 * <number of missed spawns>) / 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);
}

View File

@ -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",

View File

@ -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!"

View File

@ -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?",

View File

@ -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",

View File

@ -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": {

View File

@ -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}}!"
},

View File

@ -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": {

View File

@ -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)),
};

View File

@ -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);
}

View File

@ -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);
});

View File

@ -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`);