[Refactor] Only use first active timedEvent (#6679)

* rename `getShinyMultiplier`

* simplify methods to use first active event instead of sometimes using all active events

* change remaining methods to use first event

* use `ModifierTypeKeys` instead of `string` for wave rewards

* rename `shinyMultiplier` to `shinyEncounterMultiplier` and add `shinyCatchMultiplier`

* update comments

* add comment

* Fix capitalization of variable, remove comment

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
This commit is contained in:
Fabi 2025-10-23 10:27:38 +02:00 committed by GitHub
parent 170e996358
commit 08e6bba2db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 69 additions and 117 deletions

View File

@ -279,7 +279,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
if (!tradePokemon.shiny) { if (!tradePokemon.shiny) {
const shinyThreshold = new NumberHolder(WONDER_TRADE_SHINY_CHANCE); const shinyThreshold = new NumberHolder(WONDER_TRADE_SHINY_CHANCE);
if (timedEventManager.isEventActive()) { if (timedEventManager.isEventActive()) {
shinyThreshold.value *= timedEventManager.getShinyMultiplier(); shinyThreshold.value *= timedEventManager.getShinyEncounterMultiplier();
} }
globalScene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold); globalScene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold);

View File

@ -2904,7 +2904,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
if (thresholdOverride === undefined) { if (thresholdOverride === undefined) {
if (timedEventManager.isEventActive()) { if (timedEventManager.isEventActive()) {
const tchance = timedEventManager.getClassicTrainerShinyChance(); const tchance = timedEventManager.getClassicTrainerShinyChance();
shinyThreshold.value *= timedEventManager.getShinyMultiplier(); shinyThreshold.value *= timedEventManager.getShinyEncounterMultiplier();
if (this.hasTrainer() && tchance > 0) { if (this.hasTrainer() && tchance > 0) {
shinyThreshold.value = Math.max(tchance, shinyThreshold.value); // Choose the higher boost shinyThreshold.value = Math.max(tchance, shinyThreshold.value); // Choose the higher boost
} }
@ -2942,7 +2942,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
const shinyThreshold = new NumberHolder(thresholdOverride ?? BASE_SHINY_CHANCE); const shinyThreshold = new NumberHolder(thresholdOverride ?? BASE_SHINY_CHANCE);
if (applyModifiersToOverride) { if (applyModifiersToOverride) {
if (timedEventManager.isEventActive()) { if (timedEventManager.isEventActive()) {
shinyThreshold.value *= timedEventManager.getShinyMultiplier(); shinyThreshold.value *= timedEventManager.getShinyEncounterMultiplier();
} }
globalScene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold); globalScene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold);
} }

View File

@ -7,6 +7,7 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
import { TextStyle } from "#enums/text-style"; import { TextStyle } from "#enums/text-style";
import { WeatherType } from "#enums/weather-type"; import { WeatherType } from "#enums/weather-type";
import type { ModifierTypeKeys } from "#modifiers/modifier-type";
import type { nil } from "#types/common"; import type { nil } from "#types/common";
import { addTextObject } from "#ui/text"; import { addTextObject } from "#ui/text";
import i18next from "i18next"; import i18next from "i18next";
@ -38,8 +39,12 @@ interface EventMysteryEncounterTier {
} }
interface EventWaveReward { interface EventWaveReward {
/**
* The wave at which the reward should be given.
* {@linkcode ClassicFixedBossWaves.RIVAL1} and {@linkcode ClassicFixedBossWaves.RIVAL2} are currently the only waves that give fixed rewards.
*/
readonly wave: number; readonly wave: number;
readonly type: string; readonly type: ModifierTypeKeys;
} }
type EventMusicReplacement = readonly [string, string]; type EventMusicReplacement = readonly [string, string];
@ -52,7 +57,8 @@ interface EventChallenge {
interface TimedEvent extends EventBanner { interface TimedEvent extends EventBanner {
readonly name: string; readonly name: string;
readonly eventType: EventType; readonly eventType: EventType;
readonly shinyMultiplier?: number; readonly shinyEncounterMultiplier?: number;
readonly shinyCatchMultiplier?: number;
readonly classicFriendshipMultiplier?: number; readonly classicFriendshipMultiplier?: number;
readonly luckBoost?: number; readonly luckBoost?: number;
readonly upgradeUnlockedVouchers?: boolean; readonly upgradeUnlockedVouchers?: boolean;
@ -74,7 +80,7 @@ const timedEvents: readonly TimedEvent[] = [
{ {
name: "Winter Holiday Update", name: "Winter Holiday Update",
eventType: EventType.SHINY, eventType: EventType.SHINY,
shinyMultiplier: 2, shinyEncounterMultiplier: 2,
upgradeUnlockedVouchers: true, upgradeUnlockedVouchers: true,
startDate: new Date(Date.UTC(2024, 11, 21, 0)), startDate: new Date(Date.UTC(2024, 11, 21, 0)),
endDate: new Date(Date.UTC(2025, 0, 4, 0)), endDate: new Date(Date.UTC(2025, 0, 4, 0)),
@ -205,7 +211,7 @@ const timedEvents: readonly TimedEvent[] = [
startDate: new Date(Date.UTC(2025, 1, 10)), startDate: new Date(Date.UTC(2025, 1, 10)),
endDate: new Date(Date.UTC(2025, 1, 21)), endDate: new Date(Date.UTC(2025, 1, 21)),
boostFusions: true, boostFusions: true,
shinyMultiplier: 2, shinyEncounterMultiplier: 2,
bannerKey: "valentines2025event", bannerKey: "valentines2025event",
scale: 0.21, scale: 0.21,
availableLangs: ["en", "de", "it", "fr", "ja", "ko", "es-ES", "pt-BR", "zh-Hans"], availableLangs: ["en", "de", "it", "fr", "ja", "ko", "es-ES", "pt-BR", "zh-Hans"],
@ -318,7 +324,7 @@ const timedEvents: readonly TimedEvent[] = [
bannerKey: "spr25event", bannerKey: "spr25event",
scale: 0.21, scale: 0.21,
availableLangs: ["en", "de", "it", "fr", "ja", "ko", "es-ES", "es-419", "pt-BR", "zh-Hans"], availableLangs: ["en", "de", "it", "fr", "ja", "ko", "es-ES", "es-419", "pt-BR", "zh-Hans"],
shinyMultiplier: 2, shinyEncounterMultiplier: 2,
upgradeUnlockedVouchers: true, upgradeUnlockedVouchers: true,
eventEncounters: [ eventEncounters: [
{ species: SpeciesId.HOPPIP }, { species: SpeciesId.HOPPIP },
@ -359,7 +365,7 @@ const timedEvents: readonly TimedEvent[] = [
bannerKey: "pride2025", bannerKey: "pride2025",
scale: 0.105, scale: 0.105,
availableLangs: ["en", "de", "it", "fr", "ja", "ko", "es-ES", "es-419", "pt-BR", "zh-Hans", "zh-Hant"], availableLangs: ["en", "de", "it", "fr", "ja", "ko", "es-ES", "es-419", "pt-BR", "zh-Hans", "zh-Hant"],
shinyMultiplier: 2, shinyEncounterMultiplier: 2,
eventEncounters: [ eventEncounters: [
{ species: SpeciesId.CHARMANDER }, { species: SpeciesId.CHARMANDER },
{ species: SpeciesId.SANDILE }, { species: SpeciesId.SANDILE },
@ -389,6 +395,10 @@ export class TimedEventManager {
return event.startDate < now && now < event.endDate; return event.startDate < now && now < event.endDate;
} }
/**
* For getting the active event
* @returns The first active {@linkcode TimedEvent} or `undefined` if there are no active events
*/
activeEvent(): TimedEvent | undefined { activeEvent(): TimedEvent | undefined {
return timedEvents.find((te: TimedEvent) => this.isActive(te)); return timedEvents.find((te: TimedEvent) => this.isActive(te));
} }
@ -398,63 +408,51 @@ export class TimedEventManager {
} }
/** /**
* Check whether the current event is active and for April Fools. * Check whether the current {@linkcode TimedEvent} is active and for April Fools.
* @returns Whether the April Fools event is currently active. * @returns Whether the April Fools event is currently active.
*/ */
isAprilFoolsActive(): boolean { isAprilFoolsActive(): boolean {
return timedEvents.some( return this.activeEvent()?.bannerKey?.startsWith("aprf") ?? false;
te => this.isActive(te) && te.hasOwnProperty("bannerKey") && te.bannerKey!.startsWith("aprf"),
);
} }
activeEventHasBanner(): boolean { activeEventHasBanner(): boolean {
const activeEvents = timedEvents.filter(te => this.isActive(te) && te.hasOwnProperty("bannerKey")); return this.activeEvent()?.bannerKey != null;
return activeEvents.length > 0;
} }
getShinyMultiplier(): number { /**
let multiplier = 1; * Get the multiplier for shiny encounters during a shiny {@linkcode TimedEvent}
const shinyEvents = timedEvents.filter(te => te.eventType === EventType.SHINY && this.isActive(te)); * @returns the shiny encounter multiplier
for (const se of shinyEvents) { */
multiplier *= se.shinyMultiplier ?? 1; getShinyEncounterMultiplier(): number {
return this.activeEvent()?.shinyEncounterMultiplier ?? 1;
} }
return multiplier; /**
* Get the multiplier for shiny catches during a shiny {@linkcode TimedEvent}
* @returns the shiny catch multiplier
*/
getShinyCatchMultiplier(): number {
return this.activeEvent()?.shinyCatchMultiplier ?? 1;
} }
getEventBannerFilename(): string { getEventBannerFilename(): string {
return timedEvents.find((te: TimedEvent) => this.isActive(te))?.bannerKey ?? ""; return this.activeEvent()?.bannerKey ?? "";
} }
getEventBannerLangs(): string[] { getEventBannerLangs(): string[] {
const ret: string[] = []; return [...(this.activeEvent()?.availableLangs ?? [])];
ret.push(...(timedEvents.find(te => this.isActive(te) && te.availableLangs != null)?.availableLangs ?? []));
return ret;
} }
getEventEncounters(): EventEncounter[] { getEventEncounters(): EventEncounter[] {
const ret: EventEncounter[] = []; return [...(this.activeEvent()?.eventEncounters ?? [])];
for (const te of timedEvents) {
if (this.isActive(te) && te.eventEncounters != null) {
ret.push(...te.eventEncounters);
}
}
return ret;
} }
/** /**
* For events that change the classic candy friendship multiplier * For events that change the classic candy friendship multiplier
* @returns The highest classic friendship multiplier among the active events, or the default CLASSIC_CANDY_FRIENDSHIP_MULTIPLIER * @returns The classic friendship multiplier of the active {@linkcode TimedEvent}, or the default {@linkcode CLASSIC_CANDY_FRIENDSHIP_MULTIPLIER}
*/ */
getClassicFriendshipMultiplier(): number { getClassicFriendshipMultiplier(): number {
let multiplier = CLASSIC_CANDY_FRIENDSHIP_MULTIPLIER; return this.activeEvent()?.classicFriendshipMultiplier ?? CLASSIC_CANDY_FRIENDSHIP_MULTIPLIER;
const classicFriendshipEvents = timedEvents.filter(te => this.isActive(te));
for (const fe of classicFriendshipEvents) {
if (fe.classicFriendshipMultiplier != null && fe.classicFriendshipMultiplier > multiplier) {
multiplier = fe.classicFriendshipMultiplier;
}
}
return multiplier;
} }
/** /**
@ -462,7 +460,7 @@ export class TimedEventManager {
* @returns Whether vouchers should be upgraded * @returns Whether vouchers should be upgraded
*/ */
getUpgradeUnlockedVouchers(): boolean { getUpgradeUnlockedVouchers(): boolean {
return timedEvents.some(te => this.isActive(te) && (te.upgradeUnlockedVouchers ?? false)); return this.activeEvent()?.upgradeUnlockedVouchers ?? false;
} }
/** /**
@ -470,13 +468,7 @@ export class TimedEventManager {
* @returns list of ids of {@linkcode ModifierType}s that Delibirdy hands out as a bonus * @returns list of ids of {@linkcode ModifierType}s that Delibirdy hands out as a bonus
*/ */
getDelibirdyBuff(): string[] { getDelibirdyBuff(): string[] {
const ret: string[] = []; return [...(this.activeEvent()?.delibirdyBuff ?? [])];
for (const te of timedEvents) {
if (this.isActive(te) && te.delibirdyBuff != null) {
ret.push(...te.delibirdyBuff);
}
}
return ret;
} }
/** /**
@ -484,13 +476,7 @@ export class TimedEventManager {
* @returns Event weathers for town * @returns Event weathers for town
*/ */
getWeather(): WeatherPoolEntry[] { getWeather(): WeatherPoolEntry[] {
const ret: WeatherPoolEntry[] = []; return [...(this.activeEvent()?.weather ?? [])];
for (const te of timedEvents) {
if (this.isActive(te) && te.weather != null) {
ret.push(...te.weather);
}
}
return ret;
} }
getAllMysteryEncounterChanges(): EventMysteryEncounterTier[] { getAllMysteryEncounterChanges(): EventMysteryEncounterTier[] {
@ -505,15 +491,12 @@ export class TimedEventManager {
getEventMysteryEncountersDisabled(): MysteryEncounterType[] { getEventMysteryEncountersDisabled(): MysteryEncounterType[] {
const ret: MysteryEncounterType[] = []; const ret: MysteryEncounterType[] = [];
for (const te of timedEvents) { const metChanges = this.activeEvent()?.mysteryEncounterTierChanges ?? [];
if (this.isActive(te) && te.mysteryEncounterTierChanges != null) { for (const metc of metChanges) {
for (const metc of te.mysteryEncounterTierChanges) {
if (metc.disable) { if (metc.disable) {
ret.push(metc.mysteryEncounter); ret.push(metc.mysteryEncounter);
} }
} }
}
}
return ret; return ret;
} }
@ -521,43 +504,25 @@ export class TimedEventManager {
encounterType: MysteryEncounterType, encounterType: MysteryEncounterType,
normal: MysteryEncounterTier, normal: MysteryEncounterTier,
): MysteryEncounterTier { ): MysteryEncounterTier {
let ret = normal; const metChanges = this.activeEvent()?.mysteryEncounterTierChanges ?? [];
for (const te of timedEvents) { for (const metc of metChanges) {
if (this.isActive(te) && te.mysteryEncounterTierChanges != null) {
for (const metc of te.mysteryEncounterTierChanges) {
if (metc.mysteryEncounter === encounterType) { if (metc.mysteryEncounter === encounterType) {
ret = metc.tier ?? normal; return metc.tier ?? normal;
} }
} }
} return normal;
}
return ret;
} }
getEventLuckBoost(): number { getEventLuckBoost(): number {
let ret = 0; return this.activeEvent()?.luckBoost ?? 0;
const luckEvents = timedEvents.filter(te => this.isActive(te) && te.luckBoost != null);
for (const le of luckEvents) {
ret += le.luckBoost!;
}
return ret;
} }
getEventLuckBoostedSpecies(): SpeciesId[] { getEventLuckBoostedSpecies(): SpeciesId[] {
const ret = new Set<SpeciesId>(); return [...(this.activeEvent()?.luckBoostedSpecies ?? [])];
for (const te of timedEvents) {
if (this.isActive(te) && te.luckBoostedSpecies != null) {
for (const s of te.luckBoostedSpecies) {
ret.add(s);
}
}
}
return Array.from(ret);
} }
areFusionsBoosted(): boolean { areFusionsBoosted(): boolean {
return timedEvents.some(te => this.isActive(te) && te.boostFusions); return this.activeEvent()?.boostFusions ?? false;
} }
/** /**
@ -566,43 +531,30 @@ export class TimedEventManager {
* @param wave the wave to check for associated rewards * @param wave the wave to check for associated rewards
* @returns array of strings of the event modifier reward types * @returns array of strings of the event modifier reward types
*/ */
getFixedBattleEventRewards(wave: number): string[] { getFixedBattleEventRewards(wave: number): ModifierTypeKeys[] {
const ret: string[] = []; return (
for (const te of timedEvents) { this.activeEvent()
if (this.isActive(te) && te.classicWaveRewards != null) { ?.classicWaveRewards?.filter(cwr => cwr.wave === wave)
ret.push(...te.classicWaveRewards.filter(cwr => cwr.wave === wave).map(cwr => cwr.type)); .map(cwr => cwr.type) ?? []
} );
}
return ret;
} }
/** /**
* Get the extra shiny chance for trainers due to event * Get the extra shiny chance for trainers due to event
*/ */
getClassicTrainerShinyChance(): number { getClassicTrainerShinyChance(): number {
let ret = 0; return this.activeEvent()?.trainerShinyChance ?? 0;
for (const te of timedEvents) {
const shinyChance = te.trainerShinyChance;
if (shinyChance && this.isActive(te)) {
ret += shinyChance;
}
}
return ret;
} }
getEventBgmReplacement(bgm: string): string { getEventBgmReplacement(bgm: string): string {
let ret = bgm; const eventMusicReplacements = this.activeEvent()?.music ?? [];
for (const te of timedEvents) { for (const emr of eventMusicReplacements) {
if (this.isActive(te) && te.music != null) { if (emr[0] === bgm) {
for (const mr of te.music) { console.log(`it is ${this.activeEvent()?.name} so instead of ${emr[0]} we play ${emr[1]}`);
if (mr[0] === bgm) { return emr[1];
console.log(`it is ${te.name} so instead of ${mr[0]} we play ${mr[1]}`);
ret = mr[1];
} }
} }
} return bgm;
}
return ret;
} }
/** /**

View File

@ -13,7 +13,7 @@ export class MockTimedEventManager extends TimedEventManager {
override getClassicFriendshipMultiplier(): number { override getClassicFriendshipMultiplier(): number {
return CLASSIC_CANDY_FRIENDSHIP_MULTIPLIER; return CLASSIC_CANDY_FRIENDSHIP_MULTIPLIER;
} }
override getShinyMultiplier(): number { override getShinyEncounterMultiplier(): number {
return 1; return 1;
} }
} }