commit latest beta merge updates
This commit is contained in:
parent
8899fce571
commit
0b698a04a2
|
@ -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());
|
||||
|
|
|
@ -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!?");
|
||||
|
|
|
@ -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<void | boolean>;
|
||||
|
@ -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<T> = Exclude<{ [K in Keys<T>]: T extends Record<K, T[K]> ? K : never; }[Keys<T>], undefined>;
|
||||
// type NonFunctionFieldsKeys<T> = { [K in Keys<T>]: T[K] extends Function ? never : K; }[Keys<T>];
|
||||
// type FunctionPropertyKeys<T> = { [K in Keys<T>]: T[K] extends Function ? K : never; }[Keys<T>];
|
||||
/* Extracts keys from T */
|
||||
type Keys<T> = keyof T;
|
||||
/* Filters out all optional fields from an "object" type alias, and all function fields */
|
||||
type PickNonOptionalFields<T> = Pick<T, PickNonOptionalFieldsKeys<T>>;
|
||||
/* Omits keys that exist in the base object and optional keys on MysteryEncounter, as well as functions on MysteryEncounter */
|
||||
type OmitBaseAndOptionalKeys<T, B> = Omit<PickNonOptionalFields<T>, Keys<B>>;
|
||||
|
||||
export class MysteryEncounterOptionBuilder implements Partial<MysteryEncounterOption> {
|
||||
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<MysteryEncounterOption, typeof baseOption> & Pick<MysteryEncounterOption, "optionMode"> {
|
||||
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<MysteryEncounterOption, "optionMode"> {
|
||||
return Object.assign(new MysteryEncounterOptionBuilder(), { optionMode });
|
||||
}
|
||||
|
||||
withHasDexProgress(hasDexProgress: boolean): this & Required<Pick<MysteryEncounterOption, "hasDexProgress">> {
|
||||
|
|
|
@ -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 ?? [];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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", ""];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<string, string>(),
|
||||
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<T> = Exclude<{ [K in Keys<T>]: T extends Record<K, T[K]> ? K : never; }[Keys<T>], undefined>;
|
||||
// type NonFunctionFieldsKeys<T> = { [K in Keys<T>]: T[K] extends Function ? never : K; }[Keys<T>];
|
||||
// type FunctionPropertyKeys<T> = { [K in Keys<T>]: T[K] extends Function ? K : never; }[Keys<T>];
|
||||
/* Extracts keys from T */
|
||||
type Keys<T> = keyof T;
|
||||
/* Filters out all optional fields from an "object" type alias, and all function fields */
|
||||
type PickNonOptionalFields<T> = Pick<T, PickNonOptionalFieldsKeys<T>>;
|
||||
/* Omits keys that exist in the base object and optional keys on MysteryEncounter, as well as functions on MysteryEncounter */
|
||||
type OmitBaseAndOptionalKeys<T, B> = Omit<PickNonOptionalFields<T>, Keys<B>>;
|
||||
// type OmitBaseSuppliedAndOptionalKeys<T, B, S> = Omit<OmitBaseAndOptionalKeys<T, B>, Keys<S>>;
|
||||
|
||||
/**
|
||||
* 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<T, B> = Omit<PickNonOptionalFields<T>, Keys<B>>;
|
|||
export class MysteryEncounterBuilder implements Partial<MysteryEncounter> {
|
||||
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<MysteryEncounter> {
|
|||
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<MysteryEncounter> {
|
|||
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<MysteryEncounter> {
|
|||
* @param encounterType
|
||||
* @returns this
|
||||
*/
|
||||
static withEncounterType(encounterType: MysteryEncounterType): MysteryEncounterBuilder & OmitBaseAndOptionalKeys<MysteryEncounter, typeof baseMysteryEncounter> & Pick<MysteryEncounter, "encounterType"> {
|
||||
return Object.assign(new MysteryEncounterBuilder(), { ...baseMysteryEncounter, encounterType });
|
||||
static withEncounterType(encounterType: MysteryEncounterType): MysteryEncounterBuilder & Pick<MysteryEncounter, "encounterType"> {
|
||||
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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue