diff --git a/src/data/balance/rates.ts b/src/data/balance/rates.ts index 06f3ee78efd..83dd7cfac02 100644 --- a/src/data/balance/rates.ts +++ b/src/data/balance/rates.ts @@ -51,3 +51,6 @@ export const BOOSTED_RARE_EGGMOVE_RATES: readonly number[] = [16, 12, 6, 3]; // The chance x/10 of a shiny being a variant, then of being specifically an epic variant export const SHINY_VARIANT_CHANCE = 4; export const SHINY_EPIC_CHANCE = 1; + +// The catch rate bonus for shiny mons, introduced in Z-A. Can be boosted in events. +export const SHINY_CATCH_RATE_MULTIPLIER = 2; diff --git a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts index 8e901002aa9..700cee3d323 100644 --- a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts @@ -1,3 +1,4 @@ +import { timedEventManager } from "#app/global-event-manager"; import { globalScene } from "#app/global-scene"; import { getPokemonNameWithAffix } from "#app/messages"; import { speciesStarterCosts } from "#balance/starters"; @@ -452,7 +453,8 @@ export function trainerThrowPokeball( const catchRate = pokemon.species.catchRate; const pokeballMultiplier = getPokeballCatchMultiplier(pokeballType); const statusMultiplier = pokemon.status ? getStatusEffectCatchRateMultiplier(pokemon.status.effect) : 1; - const x = Math.round((((_3m - _2h) * catchRate * pokeballMultiplier) / _3m) * statusMultiplier); + const shinyMultiplier = pokemon.isShiny() ? timedEventManager.getShinyCatchMultiplier() : 1; + const x = Math.round((((_3m - _2h) * catchRate * pokeballMultiplier) / _3m) * statusMultiplier * shinyMultiplier); ballTwitchRate = Math.round(65536 / Math.sqrt(Math.sqrt(255 / x))); } diff --git a/src/phases/attempt-capture-phase.ts b/src/phases/attempt-capture-phase.ts index 2eadae244d5..2660dd6294d 100644 --- a/src/phases/attempt-capture-phase.ts +++ b/src/phases/attempt-capture-phase.ts @@ -1,6 +1,8 @@ import { PLAYER_PARTY_MAX_SIZE } from "#app/constants"; +import { timedEventManager } from "#app/global-event-manager"; import { globalScene } from "#app/global-scene"; import { getPokemonNameWithAffix } from "#app/messages"; +import { isBeta, isDev } from "#constants/app-constants"; import { SubstituteTag } from "#data/battler-tags"; import { Gender } from "#data/gender"; import { @@ -64,9 +66,26 @@ export class AttemptCapturePhase extends PokemonPhase { const catchRate = pokemon.species.catchRate; const pokeballMultiplier = getPokeballCatchMultiplier(this.pokeballType); const statusMultiplier = pokemon.status ? getStatusEffectCatchRateMultiplier(pokemon.status.effect) : 1; - const modifiedCatchRate = Math.round((((_3m - _2h) * catchRate * pokeballMultiplier) / _3m) * statusMultiplier); + const shinyMultiplier = pokemon.isShiny() ? timedEventManager.getShinyCatchMultiplier() : 1; + const modifiedCatchRate = Math.round( + (((_3m - _2h) * catchRate * pokeballMultiplier) / _3m) * statusMultiplier * shinyMultiplier, + ); const shakeProbability = Math.round(65536 / Math.pow(255 / modifiedCatchRate, 0.1875)); // Formula taken from gen 6 const criticalCaptureChance = getCriticalCaptureChance(modifiedCatchRate); + + if ((isBeta || isDev) && import.meta.env.NODE_ENV !== "test") { + console.log( + "Base Catch Rate: %d\nBall Mult: %d\nStatus Mult: %d\nShiny Bonus: %d\nModified Catch Rate: %d\nShake Probability: %d\nCritical Catch Chance: %d", + catchRate, + pokeballMultiplier, + statusMultiplier, + shinyMultiplier, + modifiedCatchRate, + shakeProbability, + criticalCaptureChance, + ); + } + const isCritical = pokemon.randBattleSeedInt(256) < criticalCaptureChance; const fpOffset = pokemon.getFieldPositionOffset(); diff --git a/src/timed-event-manager.ts b/src/timed-event-manager.ts index 76398b5df8d..926a65837cb 100644 --- a/src/timed-event-manager.ts +++ b/src/timed-event-manager.ts @@ -1,4 +1,5 @@ import { globalScene } from "#app/global-scene"; +import { SHINY_CATCH_RATE_MULTIPLIER } from "#balance/rates"; import { CLASSIC_CANDY_FRIENDSHIP_MULTIPLIER } from "#balance/starters"; import type { WeatherPoolEntry } from "#data/weather"; import { Challenges } from "#enums/challenges"; @@ -432,7 +433,7 @@ export class TimedEventManager { * @returns the shiny catch multiplier */ getShinyCatchMultiplier(): number { - return this.activeEvent()?.shinyCatchMultiplier ?? 1; + return this.activeEvent()?.shinyCatchMultiplier ?? SHINY_CATCH_RATE_MULTIPLIER; } getEventBannerFilename(): string {