[Balance] [Mystery] Salesman ME offers mons from event encounter pool (#5674)

* Initial event commit

* Salesman odds

* Clean up imports

* globalScene shiny rate getter, fix reroll, remove placeholder event

* Rerolling shiny also tries rerolling for better variant

* Shiny reroll affects 'trainer' mons too

---------

Co-authored-by: damocleas <damocleas25@gmail.com>
Co-authored-by: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com>
This commit is contained in:
AJ Fontaine 2025-04-22 20:03:49 -04:00 committed by GitHub
parent be6a117b1e
commit aadb57ab75
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 61 additions and 24 deletions

View File

@ -3,7 +3,7 @@ import {
transitionMysteryEncounterIntroVisuals, transitionMysteryEncounterIntroVisuals,
updatePlayerMoney, updatePlayerMoney,
} from "#app/data/mystery-encounters/utils/encounter-phase-utils"; } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { isNullOrUndefined, randSeedInt } from "#app/utils/common"; import { isNullOrUndefined, NumberHolder, randSeedInt, randSeedItem } from "#app/utils/common";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
@ -28,7 +28,8 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups"; import { NON_LEGEND_PARADOX_POKEMON, NON_LEGEND_ULTRA_BEASTS } from "#app/data/balance/special-species-groups";
import { timedEventManager } from "#app/global-event-manager";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounters/thePokemonSalesman"; const namespace = "mysteryEncounters/thePokemonSalesman";
@ -38,6 +39,9 @@ const MAX_POKEMON_PRICE_MULTIPLIER = 4;
/** Odds of shiny magikarp will be 1/value */ /** Odds of shiny magikarp will be 1/value */
const SHINY_MAGIKARP_WEIGHT = 100; const SHINY_MAGIKARP_WEIGHT = 100;
/** Odds of event sale will be value/100 */
const EVENT_THRESHOLD = 50;
/** /**
* Pokemon Salesman encounter. * Pokemon Salesman encounter.
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3799 | GitHub Issue #3799} * @see {@link https://github.com/pagefaultgames/pokerogue/issues/3799 | GitHub Issue #3799}
@ -82,15 +86,46 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui
tries++; tries++;
} }
const r = randSeedInt(SHINY_MAGIKARP_WEIGHT);
const validEventEncounters = timedEventManager
.getEventEncounters()
.filter(
s =>
!getPokemonSpecies(s.species).legendary &&
!getPokemonSpecies(s.species).subLegendary &&
!getPokemonSpecies(s.species).mythical &&
!NON_LEGEND_PARADOX_POKEMON.includes(s.species) &&
!NON_LEGEND_ULTRA_BEASTS.includes(s.species),
);
let pokemon: PlayerPokemon; let pokemon: PlayerPokemon;
/**
* Mon is determined as follows:
* If you roll the 1% for Shiny Magikarp, you get Magikarp with a random variant
* If an event with more than 1 valid event encounter species is active, you have 20% chance to get one of those
* If the rolled species has no HA, and there are valid event encounters, you will get one of those
* If the rolled species has no HA and there are no valid event encounters, you will get Shiny Magikarp
* Mons rolled from the event encounter pool get 2 extra shiny rolls
*/
if ( if (
randSeedInt(SHINY_MAGIKARP_WEIGHT) === 0 || r === 0 ||
isNullOrUndefined(species.abilityHidden) || ((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE) &&
species.abilityHidden === Abilities.NONE (validEventEncounters.length === 0))
) { ) {
// If no HA mon found or you roll 1%, give shiny Magikarp with random variant // If you roll 1%, give shiny Magikarp with random variant
species = getPokemonSpecies(Species.MAGIKARP); species = getPokemonSpecies(Species.MAGIKARP);
pokemon = new PlayerPokemon(species, 5, 2, species.formIndex, undefined, true); pokemon = new PlayerPokemon(species, 5, 2, undefined, undefined, true);
} else if (
(validEventEncounters.length > 0 && (r <= EVENT_THRESHOLD ||
(isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE)))
) {
// If you roll 20%, give event encounter with 2 extra shiny rolls and its HA, if it has one
const enc = randSeedItem(validEventEncounters);
species = getPokemonSpecies(enc.species);
pokemon = new PlayerPokemon(species, 5, species.abilityHidden === Abilities.NONE ? undefined : 2, enc.formIndex);
pokemon.trySetShinySeed();
pokemon.trySetShinySeed();
} else { } else {
pokemon = new PlayerPokemon(species, 5, 2, species.formIndex); pokemon = new PlayerPokemon(species, 5, 2, species.formIndex);
} }

View File

@ -1075,8 +1075,8 @@ export function getRandomEncounterSpecies(level: number, isBoss = false, rerollH
ret.formIndex = formIndex; ret.formIndex = formIndex;
} }
//Reroll shiny for event encounters //Reroll shiny or variant for event encounters
if (isEventEncounter && !ret.shiny) { if (isEventEncounter) {
ret.trySetShinySeed(); ret.trySetShinySeed();
} }
//Reroll hidden ability //Reroll hidden ability

View File

@ -3170,7 +3170,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
/** /**
* Function that tries to set a Pokemon shiny based on seed. * Function that tries to set a Pokemon shiny based on seed.
* For manual use only, usually to roll a Pokemon's shiny chance a second time. * For manual use only, usually to roll a Pokemon's shiny chance a second time.
* If it rolls shiny, also sets a random variant and give the Pokemon the associated luck. * If it rolls shiny, or if it's already shiny, also sets a random variant and give the Pokemon the associated luck.
* *
* The base shiny odds are {@linkcode BASE_SHINY_CHANCE} / `65536` * The base shiny odds are {@linkcode BASE_SHINY_CHANCE} / `65536`
* @param thresholdOverride number that is divided by `2^16` (`65536`) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm) * @param thresholdOverride number that is divided by `2^16` (`65536`) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm)
@ -3181,29 +3181,31 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
thresholdOverride?: number, thresholdOverride?: number,
applyModifiersToOverride?: boolean, applyModifiersToOverride?: boolean,
): boolean { ): boolean {
const shinyThreshold = new NumberHolder(BASE_SHINY_CHANCE); if (!this.shiny) {
if (thresholdOverride === undefined || applyModifiersToOverride) { const shinyThreshold = new NumberHolder(BASE_SHINY_CHANCE);
if (thresholdOverride !== undefined && applyModifiersToOverride) { if (thresholdOverride === undefined || applyModifiersToOverride) {
shinyThreshold.value = thresholdOverride; if (thresholdOverride !== undefined && applyModifiersToOverride) {
} shinyThreshold.value = thresholdOverride;
if (timedEventManager.isEventActive()) { }
shinyThreshold.value *= timedEventManager.getShinyMultiplier(); if (timedEventManager.isEventActive()) {
} shinyThreshold.value *= timedEventManager.getShinyMultiplier();
if (!this.hasTrainer()) { }
globalScene.applyModifiers( globalScene.applyModifiers(
ShinyRateBoosterModifier, ShinyRateBoosterModifier,
true, true,
shinyThreshold, shinyThreshold,
); );
} }
} else { else {
shinyThreshold.value = thresholdOverride; shinyThreshold.value = thresholdOverride;
}
this.shiny = randSeedInt(65536) < shinyThreshold.value;
} }
this.shiny = randSeedInt(65536) < shinyThreshold.value;
if (this.shiny) { if (this.shiny) {
this.variant = this.generateShinyVariant(); this.variant = this.variant ?? 0;
this.variant = Math.max(this.generateShinyVariant(), this.variant) as Variant; // Don't set a variant lower than the current one
this.luck = this.luck =
this.variant + 1 + (this.fusionShiny ? this.fusionVariant + 1 : 0); this.variant + 1 + (this.fusionShiny ? this.fusionVariant + 1 : 0);
this.initShinySparkle(); this.initShinySparkle();