From 0b698a04a21e1ca590c252b55fe02a816bab427f Mon Sep 17 00:00:00 2001 From: ImperialSympathizer Date: Tue, 20 Aug 2024 18:01:47 -0400 Subject: [PATCH] commit latest beta merge updates --- .../encounters/clowning-around-encounter.ts | 3 +- .../encounters/lost-at-sea-encounter.ts | 6 +- .../mystery-encounter-option.ts | 41 +++------ .../mystery-encounter-pokemon-data.ts | 10 +-- .../mystery-encounter-requirements.ts | 60 ++++++------- .../mystery-encounters/mystery-encounter.ts | 85 ++++++------------- src/ui/mystery-encounter-ui-handler.ts | 2 +- src/utils.ts | 4 + 8 files changed, 85 insertions(+), 126 deletions(-) diff --git a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts index d8dcfa503c7..85fbc2d2f18 100644 --- a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts +++ b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts @@ -111,6 +111,7 @@ export const ClowningAroundEncounter: MysteryEncounter = new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)); clownConfig.setPartyTemplates(clownPartyTemplate); clownConfig.setDoubleOnly(); + // @ts-ignore clownConfig.partyTemplateFunc = null; // Overrides party template func if it exists // Generate random ability for Blacephalon from pool @@ -415,7 +416,7 @@ function onYesAbilitySwap(scene: BattleScene, resolve) { const onPokemonSelected = (pokemon: PlayerPokemon) => { // Do ability swap if (!pokemon.mysteryEncounterData) { - pokemon.mysteryEncounterData = new MysteryEncounterPokemonData(null, Abilities.AERILATE); + pokemon.mysteryEncounterData = new MysteryEncounterPokemonData(undefined, Abilities.AERILATE); } pokemon.mysteryEncounterData.ability = scene.currentBattle.mysteryEncounter.misc.ability; scene.currentBattle.mysteryEncounter.setDialogueToken("chosenPokemon", pokemon.getNameToRender()); diff --git a/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts b/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts index a0be4314e28..db8168e7bd7 100644 --- a/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts +++ b/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts @@ -54,8 +54,8 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with .withOption( // Option 1: Use a (non fainted) pokemon that can learn Surf to guide you back/ MysteryEncounterOptionBuilder - .withPokemonCanLearnMoveRequirement(OPTION_1_REQUIRED_MOVE) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) + .withPokemonCanLearnMoveRequirement(OPTION_1_REQUIRED_MOVE) .withDialogue({ buttonLabel: `${namespace}.option.1.label`, disabledButtonLabel: `${namespace}.option.1.label_disabled`, @@ -73,8 +73,8 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with .withOption( //Option 2: Use a (non fainted) pokemon that can learn fly to guide you back. MysteryEncounterOptionBuilder - .withPokemonCanLearnMoveRequirement(OPTION_2_REQUIRED_MOVE) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) + .withPokemonCanLearnMoveRequirement(OPTION_2_REQUIRED_MOVE) .withDialogue({ buttonLabel: `${namespace}.option.2.label`, disabledButtonLabel: `${namespace}.option.2.label_disabled`, @@ -131,7 +131,7 @@ async function handlePokemonGuidingYouPhase(scene: BattleScene) { const laprasSpecies = getPokemonSpecies(Species.LAPRAS); const { mysteryEncounter } = scene.currentBattle; - if (mysteryEncounter.selectedOption) { + if (mysteryEncounter.selectedOption?.primaryPokemon?.id) { setEncounterExp(scene, mysteryEncounter.selectedOption.primaryPokemon.id, laprasSpecies.baseExp, true); } else { console.warn("Lost at sea: No guide pokemon found but pokemon guides player. huh!?"); diff --git a/src/data/mystery-encounters/mystery-encounter-option.ts b/src/data/mystery-encounters/mystery-encounter-option.ts index f0932472571..d4cf56ae17c 100644 --- a/src/data/mystery-encounters/mystery-encounter-option.ts +++ b/src/data/mystery-encounters/mystery-encounter-option.ts @@ -8,6 +8,7 @@ import { EncounterPokemonRequirement, EncounterSceneRequirement, MoneyRequiremen import { CanLearnMoveRequirement, CanLearnMoveRequirementOptions } from "./requirements/can-learn-move-requirement"; import { isNullOrUndefined } from "#app/utils"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; +import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; export type OptionPhaseCallback = (scene: BattleScene) => Promise; @@ -39,7 +40,7 @@ export default class MysteryEncounterOption { /** Executes after the encounter is over. Usually this will be for calculating dialogueTokens or performing data updates */ onPostOptionPhase?: OptionPhaseCallback; - constructor(option: MysteryEncounterOption) { + constructor(option: MysteryEncounterOption | null) { Object.assign(this, option); this.hasDexProgress = !isNullOrUndefined(this.hasDexProgress) ? this.hasDexProgress : false; this.requirements = this.requirements ? this.requirements : []; @@ -137,41 +138,27 @@ export default class MysteryEncounterOption { } } -const baseOption = { - optionMode: MysteryEncounterOptionMode.DEFAULT, - hasDexProgress: false, - requirements: [], - primaryPokemonRequirements: [], - secondaryPokemonRequirements: [], - excludePrimaryFromSecondaryRequirements: true, -}; - -/* Picks non-optional fields from an "object" type alias and returns a union of literal types (keys) */ -type PickNonOptionalFieldsKeys = Exclude<{ [K in Keys]: T extends Record ? K : never; }[Keys], undefined>; -// type NonFunctionFieldsKeys = { [K in Keys]: T[K] extends Function ? never : K; }[Keys]; -// type FunctionPropertyKeys = { [K in Keys]: T[K] extends Function ? K : never; }[Keys]; -/* Extracts keys from T */ -type Keys = keyof T; -/* Filters out all optional fields from an "object" type alias, and all function fields */ -type PickNonOptionalFields = Pick>; -/* Omits keys that exist in the base object and optional keys on MysteryEncounter, as well as functions on MysteryEncounter */ -type OmitBaseAndOptionalKeys = Omit, Keys>; - export class MysteryEncounterOptionBuilder implements Partial { - optionMode: MysteryEncounterOptionMode; + optionMode: MysteryEncounterOptionMode = MysteryEncounterOptionMode.DEFAULT; requirements: EncounterSceneRequirement[] = []; primaryPokemonRequirements: EncounterPokemonRequirement[] = []; secondaryPokemonRequirements: EncounterPokemonRequirement[] = []; - excludePrimaryFromSecondaryRequirements: boolean; - isDisabledOnRequirementsNotMet: boolean; - hasDexProgress: boolean; + excludePrimaryFromSecondaryRequirements: boolean = false; + isDisabledOnRequirementsNotMet: boolean = true; + hasDexProgress: boolean = false; onPreOptionPhase?: OptionPhaseCallback; onOptionPhase: OptionPhaseCallback; onPostOptionPhase?: OptionPhaseCallback; dialogue: OptionTextDisplay; - static newOptionWithMode(optionMode: MysteryEncounterOptionMode): MysteryEncounterOptionBuilder & OmitBaseAndOptionalKeys & Pick { - return Object.assign(new MysteryEncounterOptionBuilder(), { ...baseOption, optionMode }); + hasRequirements = MysteryEncounter.prototype["hasRequirements"]; + meetsRequirements = MysteryEncounter.prototype["meetsRequirements"]; + pokemonMeetsPrimaryRequirements = MysteryEncounter.prototype["pokemonMeetsPrimaryRequirements"]; + meetsPrimaryRequirementAndPrimaryPokemonSelected = MysteryEncounter.prototype["meetsPrimaryRequirementAndPrimaryPokemonSelected"]; + meetsSupportingRequirementAndSupportingPokemonSelected = MysteryEncounter.prototype["meetsSupportingRequirementAndSupportingPokemonSelected"]; + + static newOptionWithMode(optionMode: MysteryEncounterOptionMode): MysteryEncounterOptionBuilder & Pick { + return Object.assign(new MysteryEncounterOptionBuilder(), { optionMode }); } withHasDexProgress(hasDexProgress: boolean): this & Required> { diff --git a/src/data/mystery-encounters/mystery-encounter-pokemon-data.ts b/src/data/mystery-encounters/mystery-encounter-pokemon-data.ts index cab6d1ce82f..4e933304c5e 100644 --- a/src/data/mystery-encounters/mystery-encounter-pokemon-data.ts +++ b/src/data/mystery-encounters/mystery-encounter-pokemon-data.ts @@ -2,15 +2,15 @@ import { Abilities } from "#enums/abilities"; import { Type } from "#app/data/type"; export class MysteryEncounterPokemonData { - public spriteScale: number; - public ability: Abilities; - public passive: Abilities; - public types: Type[] = []; + public spriteScale: number | undefined; + public ability: Abilities | undefined; + public passive: Abilities | undefined; + public types: Type[]; constructor(spriteScale?: number, ability?: Abilities, passive?: Abilities, types?: Type[]) { this.spriteScale = spriteScale; this.ability = ability; this.passive = passive; - this.types = types; + this.types = types ?? []; } } diff --git a/src/data/mystery-encounters/mystery-encounter-requirements.ts b/src/data/mystery-encounters/mystery-encounter-requirements.ts index 1596cb6b549..24e5f02b6f4 100644 --- a/src/data/mystery-encounters/mystery-encounter-requirements.ts +++ b/src/data/mystery-encounters/mystery-encounter-requirements.ts @@ -48,7 +48,7 @@ export class CombinationSceneRequirement extends EncounterSceneRequirement { } } - return null; + return this.orRequirements[0].getDialogueToken(scene, pokemon); } } @@ -104,7 +104,7 @@ export class CombinationPokemonRequirement extends EncounterPokemonRequirement { } } - return null; + return this.orRequirements[0].getDialogueToken(scene, pokemon); } } @@ -125,7 +125,7 @@ export class PreviousEncounterRequirement extends EncounterSceneRequirement { } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - return ["previousEncounter", scene.mysteryEncounterData.encounteredEvents.find(e => e[0] === this.previousEncounterRequirement)[0].toString()]; + return ["previousEncounter", scene.mysteryEncounterData.encounteredEvents.find(e => e[0] === this.previousEncounterRequirement)?.[0].toString() ?? ""]; } } @@ -158,7 +158,7 @@ export class WaveRangeRequirement extends EncounterSceneRequirement { } export class TimeOfDayRequirement extends EncounterSceneRequirement { - requiredTimeOfDay?: TimeOfDay[]; + requiredTimeOfDay: TimeOfDay[]; constructor(timeOfDay: TimeOfDay | TimeOfDay[]) { super(); @@ -180,7 +180,7 @@ export class TimeOfDayRequirement extends EncounterSceneRequirement { } export class WeatherRequirement extends EncounterSceneRequirement { - requiredWeather?: WeatherType[]; + requiredWeather: WeatherType[]; constructor(weather: WeatherType | WeatherType[]) { super(); @@ -188,8 +188,8 @@ export class WeatherRequirement extends EncounterSceneRequirement { } meetsRequirement(scene: BattleScene): boolean { - const currentWeather = scene.arena?.weather?.weatherType; - if (!isNullOrUndefined(currentWeather) && this?.requiredWeather?.length > 0 && !this.requiredWeather.includes(currentWeather)) { + const currentWeather = scene.arena.weather?.weatherType; + if (!isNullOrUndefined(currentWeather) && this?.requiredWeather?.length > 0 && !this.requiredWeather.includes(currentWeather!)) { return false; } @@ -197,7 +197,12 @@ export class WeatherRequirement extends EncounterSceneRequirement { } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - return ["weather", WeatherType[scene.arena?.weather?.weatherType].replace("_", " ").toLocaleLowerCase()]; + const currentWeather = scene.arena.weather?.weatherType; + let token = ""; + if (!isNullOrUndefined(currentWeather)) { + token = WeatherType[currentWeather!].replace("_", " ").toLocaleLowerCase(); + } + return ["weather", token]; } } @@ -262,10 +267,7 @@ export class PersistentModifierRequirement extends EncounterSceneRequirement { } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - if (this.requiredHeldItemModifiers.length > 0) { - return ["requiredItem", this.requiredHeldItemModifiers[0]]; - } - return null; + return ["requiredItem", this.requiredHeldItemModifiers[0]]; } } @@ -327,10 +329,10 @@ export class SpeciesRequirement extends EncounterPokemonRequirement { } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - if (this.requiredSpecies.includes(pokemon.species.speciesId)) { + if (pokemon?.species.speciesId && this.requiredSpecies.includes(pokemon.species.speciesId)) { return ["species", Species[pokemon.species.speciesId]]; } - return null; + return ["species", ""]; } } @@ -410,11 +412,11 @@ export class TypeRequirement extends EncounterPokemonRequirement { } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - const includedTypes = this.requiredType.filter((ty) => pokemon.getTypes().includes(ty)); + const includedTypes = this.requiredType.filter((ty) => pokemon?.getTypes().includes(ty)); if (includedTypes.length > 0) { return ["type", Type[includedTypes[0]]]; } - return null; + return ["type", ""]; } } @@ -441,19 +443,19 @@ export class MoveRequirement extends EncounterPokemonRequirement { queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] { if (!this.invertQuery) { - return partyPokemon.filter((pokemon) => this.requiredMoves.filter((reqMove) => pokemon.moveset.filter((move) => move.moveId === reqMove).length > 0).length > 0); + return partyPokemon.filter((pokemon) => this.requiredMoves.filter((reqMove) => pokemon.moveset.filter((move) => move?.moveId === reqMove).length > 0).length > 0); } else { // for an inverted query, we only want to get the pokemon that don't have ANY of the listed moves - return partyPokemon.filter((pokemon) => this.requiredMoves.filter((reqMove) => pokemon.moveset.filter((move) => move.moveId === reqMove).length === 0).length === 0); + return partyPokemon.filter((pokemon) => this.requiredMoves.filter((reqMove) => pokemon.moveset.filter((move) => move?.moveId === reqMove).length === 0).length === 0); } } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - const includedMoves = pokemon.moveset.filter((move) => this.requiredMoves.includes(move.moveId)); - if (includedMoves.length > 0) { + const includedMoves = pokemon?.moveset.filter((move) => move?.moveId && this.requiredMoves.includes(move.moveId)); + if (includedMoves && includedMoves.length > 0 && includedMoves[0]) { return ["move", includedMoves[0].getName()]; } - return null; + return ["move", ""]; } } @@ -485,19 +487,19 @@ export class CompatibleMoveRequirement extends EncounterPokemonRequirement { queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] { if (!this.invertQuery) { - return partyPokemon.filter((pokemon) => this.requiredMoves.filter((learnableMove) => pokemon.compatibleTms.filter(tm => !pokemon.moveset.find(m => m.moveId === tm)).includes(learnableMove)).length > 0); + return partyPokemon.filter((pokemon) => this.requiredMoves.filter((learnableMove) => pokemon.compatibleTms.filter(tm => !pokemon.moveset.find(m => m?.moveId === tm)).includes(learnableMove)).length > 0); } else { // for an inverted query, we only want to get the pokemon that don't have ANY of the listed learnableMoves - return partyPokemon.filter((pokemon) => this.requiredMoves.filter((learnableMove) => pokemon.compatibleTms.filter(tm => !pokemon.moveset.find(m => m.moveId === tm)).includes(learnableMove)).length === 0); + return partyPokemon.filter((pokemon) => this.requiredMoves.filter((learnableMove) => pokemon.compatibleTms.filter(tm => !pokemon.moveset.find(m => m?.moveId === tm)).includes(learnableMove)).length === 0); } } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - const includedCompatMoves = this.requiredMoves.filter((reqMove) => pokemon.compatibleTms.filter((tm) => !pokemon.moveset.find(m => m.moveId === tm)).includes(reqMove)); + const includedCompatMoves = this.requiredMoves.filter((reqMove) => pokemon?.compatibleTms.filter((tm) => !pokemon.moveset.find(m => m?.moveId === tm)).includes(reqMove)); if (includedCompatMoves.length > 0) { return ["compatibleMove", Moves[includedCompatMoves[0]]]; } - return null; + return ["compatibleMove", ""]; } } @@ -572,10 +574,10 @@ export class AbilityRequirement extends EncounterPokemonRequirement { } getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { - if (this.requiredAbilities.some(a => pokemon.getAbility().id === a)) { + if (pokemon?.getAbility().id && this.requiredAbilities.some(a => pokemon.getAbility().id === a)) { return ["ability", pokemon.getAbility().name]; } - return null; + return ["ability", ""]; } } @@ -607,7 +609,7 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement { return this.requiredStatusEffect.some((statusEffect) => { if (statusEffect === StatusEffect.NONE) { // StatusEffect.NONE also checks for null or undefined status - return isNullOrUndefined(pokemon.status) || isNullOrUndefined(pokemon.status.effect) || pokemon.status?.effect === statusEffect; + return isNullOrUndefined(pokemon.status) || isNullOrUndefined(pokemon.status!.effect) || pokemon.status?.effect === statusEffect; } else { return pokemon.status?.effect === statusEffect; } @@ -639,7 +641,7 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement { if (reqStatus.length > 0) { return ["status", StatusEffect[reqStatus[0]]]; } - return null; + return ["status", ""]; } } diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts index 866f19d925f..cae68150255 100644 --- a/src/data/mystery-encounters/mystery-encounter.ts +++ b/src/data/mystery-encounters/mystery-encounter.ts @@ -1,6 +1,6 @@ import { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import Pokemon, { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; -import { isNullOrUndefined } from "#app/utils"; +import { capitalizeFirstLetter, isNullOrUndefined } from "#app/utils"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; import MysteryEncounterIntroVisuals, { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro"; @@ -125,17 +125,17 @@ export default class MysteryEncounter implements IMysteryEncounter { /** * Dialogue object containing all the dialogue, messages, tooltips, etc. for an encounter */ - dialogue?: MysteryEncounterDialogue; + dialogue: MysteryEncounterDialogue; /** * Data used for setting up/initializing enemy party in battles * Can store multiple configs so that one can be chosen based on option selected * Should usually be defined in `onInit()` or `onPreOptionPhase()` */ - enemyPartyConfigs?: EnemyPartyConfig[]; + enemyPartyConfigs: EnemyPartyConfig[]; /** * Object instance containing sprite data for an encounter when it is being spawned * Otherwise, will be undefined - * You probably shouldn't do anything with this unless you have a very specific need + * You probably shouldn't do anything directly with this unless you have a very specific need */ introVisuals?: MysteryEncounterIntroVisuals; @@ -233,7 +233,7 @@ export default class MysteryEncounter implements IMysteryEncounter { return !this.primaryPokemonRequirements.some(req => !req.queryParty(scene.getParty()).map(p => p.id).includes(pokemon.id)); } - private meetsPrimaryRequirementAndPrimaryPokemonSelected(scene: BattleScene): boolean { + meetsPrimaryRequirementAndPrimaryPokemonSelected(scene: BattleScene): boolean { if (this.primaryPokemonRequirements.length === 0) { const activeMon = scene.getParty().filter(p => p.isActive(true)); if (activeMon.length > 0) { @@ -290,7 +290,7 @@ export default class MysteryEncounter implements IMysteryEncounter { } } - private meetsSecondaryRequirementAndSecondaryPokemonSelected(scene: BattleScene): boolean { + meetsSecondaryRequirementAndSecondaryPokemonSelected(scene: BattleScene): boolean { if (!this.secondaryPokemonRequirements) { this.secondaryPokemon = []; return true; @@ -338,7 +338,7 @@ export default class MysteryEncounter implements IMysteryEncounter { if (!req.invertQuery) { const value = req.getDialogueToken(scene, this.primaryPokemon); if (value?.length === 2) { - this.setDialogueToken("primary" + this.capitalizeFirstLetter(value[0]), value[1]); + this.setDialogueToken("primary" + capitalizeFirstLetter(value[0]), value[1]); } } } @@ -349,9 +349,9 @@ export default class MysteryEncounter implements IMysteryEncounter { if (!req.invertQuery) { const value = req.getDialogueToken(scene, this.secondaryPokemon[0]); if (value?.length === 2) { - this.setDialogueToken("primary" + this.capitalizeFirstLetter(value[0]), value[1]); + this.setDialogueToken("primary" + capitalizeFirstLetter(value[0]), value[1]); } - this.setDialogueToken("secondary" + this.capitalizeFirstLetter(value[0]), value[1]); + this.setDialogueToken("secondary" + capitalizeFirstLetter(value[0]), value[1]); } } } @@ -365,7 +365,7 @@ export default class MysteryEncounter implements IMysteryEncounter { for (const req of opt.requirements) { const dialogueToken = req.getDialogueToken(scene); if (dialogueToken?.length === 2) { - this.setDialogueToken("option" + j + this.capitalizeFirstLetter(dialogueToken[0]), dialogueToken[1]); + this.setDialogueToken("option" + j + capitalizeFirstLetter(dialogueToken[0]), dialogueToken[1]); } } } @@ -375,7 +375,7 @@ export default class MysteryEncounter implements IMysteryEncounter { if (!req.invertQuery) { const value = req.getDialogueToken(scene, opt.primaryPokemon); if (value?.length === 2) { - this.setDialogueToken("option" + j + "Primary" + this.capitalizeFirstLetter(value[0]), value[1]); + this.setDialogueToken("option" + j + "Primary" + capitalizeFirstLetter(value[0]), value[1]); } } } @@ -386,7 +386,7 @@ export default class MysteryEncounter implements IMysteryEncounter { if (!req.invertQuery) { const value = req.getDialogueToken(scene, opt.secondaryPokemon[0]); if (value?.length === 2) { - this.setDialogueToken("option" + j + "Secondary" + this.capitalizeFirstLetter(value[0]), value[1]); + this.setDialogueToken("option" + j + "Secondary" + capitalizeFirstLetter(value[0]), value[1]); } } } @@ -418,42 +418,8 @@ export default class MysteryEncounter implements IMysteryEncounter { const currentOffset = this.seedOffset ?? scene.currentBattle.waveIndex * 1000; this.seedOffset = currentOffset + 512; } - - private capitalizeFirstLetter(str: string) { - return str.charAt(0).toUpperCase() + str.slice(1); - } } -const baseMysteryEncounter = { - hideBattleIntroMessage: false, - autoHideIntroVisuals: true, - enterIntroVisualsFromRight: false, - catchAllowed: false, - continuousEncounter: false, - maxAllowedEncounters: 3, - requirements: [], - primaryPokemonRequirements: [], - secondaryPokemonRequirements: [], - excludePrimaryFromSupportRequirements: true, - dialogueTokens: new Map(), - encounterMode: MysteryEncounterMode.DEFAULT, - lockEncounterRewardTiers: false, - startOfBattleEffectsComplete: false, - expMultiplier: 1, -}; - -/* Picks non-optional fields from an "object" type alias and returns a union of literal types (keys) */ -type PickNonOptionalFieldsKeys = Exclude<{ [K in Keys]: T extends Record ? K : never; }[Keys], undefined>; -// type NonFunctionFieldsKeys = { [K in Keys]: T[K] extends Function ? never : K; }[Keys]; -// type FunctionPropertyKeys = { [K in Keys]: T[K] extends Function ? K : never; }[Keys]; -/* Extracts keys from T */ -type Keys = keyof T; -/* Filters out all optional fields from an "object" type alias, and all function fields */ -type PickNonOptionalFields = Pick>; -/* Omits keys that exist in the base object and optional keys on MysteryEncounter, as well as functions on MysteryEncounter */ -type OmitBaseAndOptionalKeys = Omit, Keys>; -// type OmitBaseSuppliedAndOptionalKeys = Omit, Keys>; - /** * Builder class for creating a MysteryEncounter * must call `build()` at the end after specifying all params for the MysteryEncounter @@ -461,8 +427,9 @@ type OmitBaseAndOptionalKeys = Omit, Keys>; export class MysteryEncounterBuilder implements Partial { encounterType: MysteryEncounterType; encounterMode: MysteryEncounterMode; - options: [MysteryEncounterOption, MysteryEncounterOption, ...MysteryEncounterOption[]]; + options: [MysteryEncounterOption, MysteryEncounterOption, ...MysteryEncounterOption[]] = [new MysteryEncounterOption(null), new MysteryEncounterOption(null)]; spriteConfigs: MysteryEncounterSpriteConfig[]; + enemyPartyConfigs: EnemyPartyConfig[] = []; dialogue: MysteryEncounterDialogue = {}; encounterTier: MysteryEncounterTier; @@ -478,15 +445,15 @@ export class MysteryEncounterBuilder implements Partial { onInit?: (scene: BattleScene) => boolean; onVisualsStart?: (scene: BattleScene) => boolean; - hideBattleIntroMessage: boolean; - hideIntroVisuals: boolean; - enterIntroVisualsFromRight: boolean; - continuousEncounter: boolean; - catchAllowed: boolean; - lockEncounterRewardTiers: boolean; - startOfBattleEffectsComplete: boolean; - maxAllowedEncounters: number; - expMultiplier: number; + hideBattleIntroMessage: boolean = false; + autoHideIntroVisuals: boolean = true; + enterIntroVisualsFromRight: boolean = false; + continuousEncounter: boolean = false; + catchAllowed: boolean = false; + lockEncounterRewardTiers: boolean = false; + startOfBattleEffectsComplete: boolean = false; + maxAllowedEncounters: number = 3; + expMultiplier: number = 1; /** * Builder class has to re-declare the {@link MysteryEncounter} class functions so @@ -502,7 +469,6 @@ export class MysteryEncounterBuilder implements Partial { updateSeedOffset = MysteryEncounter.prototype["updateSeedOffset"]; meetsPrimaryRequirementAndPrimaryPokemonSelected = MysteryEncounter.prototype["meetsPrimaryRequirementAndPrimaryPokemonSelected"]; meetsSecondaryRequirementAndSecondaryPokemonSelected = MysteryEncounter.prototype["meetsSecondaryRequirementAndSecondaryPokemonSelected"]; - capitalizeFirstLetter = MysteryEncounter.prototype["capitalizeFirstLetter"]; /** * REQUIRED @@ -514,15 +480,14 @@ export class MysteryEncounterBuilder implements Partial { * @param encounterType * @returns this */ - static withEncounterType(encounterType: MysteryEncounterType): MysteryEncounterBuilder & OmitBaseAndOptionalKeys & Pick { - return Object.assign(new MysteryEncounterBuilder(), { ...baseMysteryEncounter, encounterType }); + static withEncounterType(encounterType: MysteryEncounterType): MysteryEncounterBuilder & Pick { + return Object.assign(new MysteryEncounterBuilder(), { encounterType }); } /** * Defines an option for the encounter. * Use for complex options. * There should be at least 2 options defined and no more than 4. - * If easy/streamlined use {@linkcode MysteryEncounterBuilder.withOptionPhase} * * @param option - MysteryEncounterOption to add, can use MysteryEncounterOptionBuilder to create instance * @returns diff --git a/src/ui/mystery-encounter-ui-handler.ts b/src/ui/mystery-encounter-ui-handler.ts index 78eac8a3982..d5bae208629 100644 --- a/src/ui/mystery-encounter-ui-handler.ts +++ b/src/ui/mystery-encounter-ui-handler.ts @@ -552,7 +552,7 @@ export default class MysteryEncounterUiHandler extends UiHandler { duration: 750, onComplete: () => { this.dexProgressContainer.on("pointerover", () => { - (this.scene as BattleScene).ui.showTooltip(null, i18next.t("mysteryEncounter:affects_pokedex"), true); + (this.scene as BattleScene).ui.showTooltip("", i18next.t("mysteryEncounter:affects_pokedex"), true); }); this.dexProgressContainer.on("pointerout", () => { (this.scene as BattleScene).ui.hideTooltip(); diff --git a/src/utils.ts b/src/utils.ts index c51ac2b5b0b..52e817bc2b7 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -560,3 +560,7 @@ export function capitalizeString(str: string, sep: string, lowerFirstChar: boole export function isNullOrUndefined(object: any): boolean { return null === object || undefined === object; } + +export function capitalizeFirstLetter(str: string) { + return str.charAt(0).toUpperCase() + str.slice(1); +}