mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-03 23:12:20 +02:00
Merge 489295f2c0
into a54cd953a6
This commit is contained in:
commit
52d89cc428
18
src/@types/enum-types.ts
Normal file
18
src/@types/enum-types.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/** Union type accepting any TS Enum or `const object`, with or without reverse mapping. */
|
||||||
|
export type EnumOrObject = Record<string | number, string | number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility type to extract the enum values from a `const object`,
|
||||||
|
* or convert an `enum` interface produced by `typeof Enum` into the union type representing its values.
|
||||||
|
*/
|
||||||
|
export type EnumValues<E> = E[keyof E];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic type constraint representing a TS numeric enum with reverse mappings.
|
||||||
|
* @example
|
||||||
|
* TSNumericEnum<typeof WeatherType>
|
||||||
|
*/
|
||||||
|
export type TSNumericEnum<T extends EnumOrObject> = number extends EnumValues<T> ? T : never;
|
||||||
|
|
||||||
|
/** Generic type constraint representing a non reverse-mapped TS enum or `const object`. */
|
||||||
|
export type NormalEnum<T extends EnumOrObject> = Exclude<T, TSNumericEnum<T>>;
|
@ -2,8 +2,10 @@
|
|||||||
* A collection of custom utility types that aid in type checking and ensuring strict type conformity
|
* A collection of custom utility types that aid in type checking and ensuring strict type conformity
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// biome-ignore lint/correctness/noUnusedImports: Used in a tsdoc comment
|
// biome-ignore-start lint/correctness/noUnusedImports: Used in a tsdoc comment
|
||||||
|
import type { EnumValues } from "#app/@types/enum-types";
|
||||||
import type { AbAttr } from "./ability-types";
|
import type { AbAttr } from "./ability-types";
|
||||||
|
// biome-ignore-end lint/correctness/noUnusedImports: Used in a tsdoc comment
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exactly matches the type of the argument, preventing adding additional properties.
|
* Exactly matches the type of the argument, preventing adding additional properties.
|
||||||
@ -11,7 +13,7 @@ import type { AbAttr } from "./ability-types";
|
|||||||
* ⚠️ Should never be used with `extends`, as this will nullify the exactness of the type.
|
* ⚠️ Should never be used with `extends`, as this will nullify the exactness of the type.
|
||||||
*
|
*
|
||||||
* As an example, used to ensure that the parameters of {@linkcode AbAttr.canApply} and {@linkcode AbAttr.getTriggerMessage} are compatible with
|
* As an example, used to ensure that the parameters of {@linkcode AbAttr.canApply} and {@linkcode AbAttr.getTriggerMessage} are compatible with
|
||||||
* the type of the apply method
|
* the type of its {@linkcode AbAttr.apply | apply} method.
|
||||||
*
|
*
|
||||||
* @typeParam T - The type to match exactly
|
* @typeParam T - The type to match exactly
|
||||||
*/
|
*/
|
||||||
@ -26,9 +28,18 @@ export type Exact<T> = {
|
|||||||
export type Closed<X> = X;
|
export type Closed<X> = X;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove `readonly` from all properties of the provided type
|
* Remove `readonly` from all properties of the provided type.
|
||||||
* @typeParam T - The type to make mutable
|
* @typeParam T - The type to make mutable.
|
||||||
*/
|
*/
|
||||||
export type Mutable<T> = {
|
export type Mutable<T> = {
|
||||||
-readonly [P in keyof T]: T[P];
|
-readonly [P in keyof T]: T[P];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type helper to obtain the keys associated with a given value inside a `const object`.
|
||||||
|
* @typeParam O - The type of the object
|
||||||
|
* @typeParam V - The type of one of O's values
|
||||||
|
*/
|
||||||
|
export type InferKeys<O extends Record<keyof any, unknown>, V extends EnumValues<O>> = {
|
||||||
|
[K in keyof O]: O[K] extends V ? K : never;
|
||||||
|
}[keyof O];
|
||||||
|
@ -10,7 +10,6 @@ import {
|
|||||||
fixedInt,
|
fixedInt,
|
||||||
getIvsFromId,
|
getIvsFromId,
|
||||||
randSeedInt,
|
randSeedInt,
|
||||||
getEnumValues,
|
|
||||||
randomString,
|
randomString,
|
||||||
NumberHolder,
|
NumberHolder,
|
||||||
shiftCharCodes,
|
shiftCharCodes,
|
||||||
@ -20,6 +19,7 @@ import {
|
|||||||
type Constructor,
|
type Constructor,
|
||||||
isBetween,
|
isBetween,
|
||||||
} from "#app/utils/common";
|
} from "#app/utils/common";
|
||||||
|
import { getEnumValues } from "./utils/enums";
|
||||||
import { deepMergeSpriteData } from "#app/utils/data";
|
import { deepMergeSpriteData } from "#app/utils/data";
|
||||||
import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier";
|
import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier";
|
||||||
import {
|
import {
|
||||||
@ -2182,6 +2182,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
: allSpecies.filter(s => s.isCatchable());
|
: allSpecies.filter(s => s.isCatchable());
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
return filteredSpecies[randSeedInt(filteredSpecies.length)];
|
return filteredSpecies[randSeedInt(filteredSpecies.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2207,6 +2208,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
return biomes[randSeedInt(biomes.length)];
|
return biomes[randSeedInt(biomes.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3726,6 +3728,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
console.log("No Mystery Encounters found, falling back to Mysterious Challengers.");
|
console.log("No Mystery Encounters found, falling back to Mysterious Challengers.");
|
||||||
return allMysteryEncounters[MysteryEncounterType.MYSTERIOUS_CHALLENGERS];
|
return allMysteryEncounters[MysteryEncounterType.MYSTERIOUS_CHALLENGERS];
|
||||||
}
|
}
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
encounter = availableEncounters[randSeedInt(availableEncounters.length)];
|
encounter = availableEncounters[randSeedInt(availableEncounters.length)];
|
||||||
// New encounter object to not dirty flags
|
// New encounter object to not dirty flags
|
||||||
encounter = new MysteryEncounter(encounter);
|
encounter = new MysteryEncounter(encounter);
|
||||||
|
@ -2,7 +2,6 @@ import { globalScene } from "#app/global-scene";
|
|||||||
import type { Command } from "#enums/command";
|
import type { Command } from "#enums/command";
|
||||||
import {
|
import {
|
||||||
randomString,
|
randomString,
|
||||||
getEnumValues,
|
|
||||||
NumberHolder,
|
NumberHolder,
|
||||||
randSeedInt,
|
randSeedInt,
|
||||||
shiftCharCodes,
|
shiftCharCodes,
|
||||||
@ -10,6 +9,7 @@ import {
|
|||||||
randInt,
|
randInt,
|
||||||
randSeedFloat,
|
randSeedFloat,
|
||||||
} from "#app/utils/common";
|
} from "#app/utils/common";
|
||||||
|
import { getEnumValues } from "./utils/enums";
|
||||||
import Trainer from "./field/trainer";
|
import Trainer from "./field/trainer";
|
||||||
import { TrainerVariant } from "#enums/trainer-variant";
|
import { TrainerVariant } from "#enums/trainer-variant";
|
||||||
import type { GameMode } from "./game-mode";
|
import type { GameMode } from "./game-mode";
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import { randSeedInt, getEnumValues } from "#app/utils/common";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
|
import { getEnumValues } from "#app/utils/enums";
|
||||||
import type { SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions";
|
import type { SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions";
|
||||||
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
@ -7708,10 +7709,10 @@ export function initBiomes() {
|
|||||||
|
|
||||||
const traverseBiome = (biome: BiomeId, depth: number) => {
|
const traverseBiome = (biome: BiomeId, depth: number) => {
|
||||||
if (biome === BiomeId.END) {
|
if (biome === BiomeId.END) {
|
||||||
const biomeList = Object.keys(BiomeId).filter(key => !Number.isNaN(Number(key)));
|
const biomeList = getEnumValues(BiomeId)
|
||||||
biomeList.pop(); // Removes BiomeId.END from the list
|
biomeList.pop(); // Removes BiomeId.END from the list
|
||||||
const randIndex = randSeedInt(biomeList.length, 1); // Will never be BiomeId.TOWN
|
const randIndex = randSeedInt(biomeList.length, 1); // Will never be BiomeId.TOWN
|
||||||
biome = BiomeId[biomeList[randIndex]];
|
biome = biomeList[randIndex];
|
||||||
}
|
}
|
||||||
const linkedBiomes: (BiomeId | [ BiomeId, number ])[] = Array.isArray(biomeLinks[biome])
|
const linkedBiomes: (BiomeId | [ BiomeId, number ])[] = Array.isArray(biomeLinks[biome])
|
||||||
? biomeLinks[biome] as (BiomeId | [ BiomeId, number ])[]
|
? biomeLinks[biome] as (BiomeId | [ BiomeId, number ])[]
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { allMoves } from "../data-lists";
|
import { allMoves } from "../data-lists";
|
||||||
import { getEnumKeys, getEnumValues } from "#app/utils/common";
|
import { getEnumKeys, getEnumValues } from "#app/utils/enums";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
|
import { toReadableString } from "#app/utils/common";
|
||||||
|
|
||||||
export const speciesEggMoves = {
|
export const speciesEggMoves = {
|
||||||
[SpeciesId.BULBASAUR]: [ MoveId.SAPPY_SEED, MoveId.MALIGNANT_CHAIN, MoveId.EARTH_POWER, MoveId.MATCHA_GOTCHA ],
|
[SpeciesId.BULBASAUR]: [ MoveId.SAPPY_SEED, MoveId.MALIGNANT_CHAIN, MoveId.EARTH_POWER, MoveId.MATCHA_GOTCHA ],
|
||||||
@ -584,17 +584,24 @@ export const speciesEggMoves = {
|
|||||||
[SpeciesId.BLOODMOON_URSALUNA]: [ MoveId.NASTY_PLOT, MoveId.ROCK_POLISH, MoveId.SANDSEAR_STORM, MoveId.BOOMBURST ]
|
[SpeciesId.BLOODMOON_URSALUNA]: [ MoveId.NASTY_PLOT, MoveId.ROCK_POLISH, MoveId.SANDSEAR_STORM, MoveId.BOOMBURST ]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a CSV-separated list of Egg Moves (such as one sourced from a Google Sheets)
|
||||||
|
* into code able to form the `speciesEggMoves` const object as above.
|
||||||
|
* @param content - The CSV-formatted string to convert into code.
|
||||||
|
*/
|
||||||
|
// TODO: Move this into the scripts folder and stop running it on initialization
|
||||||
function parseEggMoves(content: string): void {
|
function parseEggMoves(content: string): void {
|
||||||
let output = "";
|
let output = "";
|
||||||
|
|
||||||
const speciesNames = getEnumKeys(SpeciesId);
|
const speciesNames = getEnumKeys(SpeciesId);
|
||||||
const speciesValues = getEnumValues(SpeciesId);
|
const speciesValues = getEnumValues(SpeciesId);
|
||||||
|
const moveNames = allMoves.map(m => m.name.replace(/ \([A-Z]\)$/, "").toLowerCase());
|
||||||
const lines = content.split(/\n/g);
|
const lines = content.split(/\n/g);
|
||||||
|
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
const cols = line.split(",").slice(0, 5);
|
const cols = line.split(",").slice(0, 5);
|
||||||
const moveNames = allMoves.map(m => m.name.replace(/ \([A-Z]\)$/, "").toLowerCase());
|
const enumSpeciesName = cols[0].toUpperCase().replace(/[ -]/g, "_") as keyof typeof SpeciesId;
|
||||||
const enumSpeciesName = cols[0].toUpperCase().replace(/[ -]/g, "_");
|
// TODO: This should use reverse mapping instead of `indexOf`
|
||||||
const species = speciesValues[speciesNames.indexOf(enumSpeciesName)];
|
const species = speciesValues[speciesNames.indexOf(enumSpeciesName)];
|
||||||
|
|
||||||
const eggMoves: MoveId[] = [];
|
const eggMoves: MoveId[] = [];
|
||||||
@ -602,14 +609,16 @@ function parseEggMoves(content: string): void {
|
|||||||
for (let m = 0; m < 4; m++) {
|
for (let m = 0; m < 4; m++) {
|
||||||
const moveName = cols[m + 1].trim();
|
const moveName = cols[m + 1].trim();
|
||||||
const moveIndex = moveName !== "N/A" ? moveNames.indexOf(moveName.toLowerCase()) : -1;
|
const moveIndex = moveName !== "N/A" ? moveNames.indexOf(moveName.toLowerCase()) : -1;
|
||||||
eggMoves.push(moveIndex > -1 ? moveIndex as MoveId : MoveId.NONE);
|
|
||||||
|
|
||||||
if (moveIndex === -1) {
|
if (moveIndex === -1) {
|
||||||
console.warn(moveName, "could not be parsed");
|
console.warn(moveName, "could not be parsed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eggMoves.push(moveIndex > -1 ? moveIndex as MoveId : MoveId.NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eggMoves.find(m => m !== MoveId.NONE)) {
|
if (eggMoves.every(m => m === MoveId.NONE)) {
|
||||||
|
console.warn(`Species ${toReadableString(SpeciesId[species])} could not be parsed, excluding from output...`)
|
||||||
|
} else {
|
||||||
output += `[SpeciesId.${SpeciesId[species]}]: [ ${eggMoves.map(m => `MoveId.${MoveId[m]}`).join(", ")} ],\n`;
|
output += `[SpeciesId.${SpeciesId[species]}]: [ ${eggMoves.map(m => `MoveId.${MoveId[m]}`).join(", ")} ],\n`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,8 @@ import { globalScene } from "#app/global-scene";
|
|||||||
import { allMoves } from "#app/data/data-lists";
|
import { allMoves } from "#app/data/data-lists";
|
||||||
import { MoveFlags } from "#enums/MoveFlags";
|
import { MoveFlags } from "#enums/MoveFlags";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import {
|
import { type nil, getFrameMs, animationFileName, coerceArray, isNullOrUndefined } from "#app/utils/common";
|
||||||
type nil,
|
import { getEnumKeys, getEnumValues } from "#app/utils/enums";
|
||||||
getFrameMs,
|
|
||||||
getEnumKeys,
|
|
||||||
getEnumValues,
|
|
||||||
animationFileName,
|
|
||||||
coerceArray,
|
|
||||||
isNullOrUndefined,
|
|
||||||
} from "#app/utils/common";
|
|
||||||
import type { BattlerIndex } from "#enums/battler-index";
|
import type { BattlerIndex } from "#enums/battler-index";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
@ -1402,10 +1395,10 @@ export class EncounterBattleAnim extends BattleAnim {
|
|||||||
export async function populateAnims() {
|
export async function populateAnims() {
|
||||||
const commonAnimNames = getEnumKeys(CommonAnim).map(k => k.toLowerCase());
|
const commonAnimNames = getEnumKeys(CommonAnim).map(k => k.toLowerCase());
|
||||||
const commonAnimMatchNames = commonAnimNames.map(k => k.replace(/_/g, ""));
|
const commonAnimMatchNames = commonAnimNames.map(k => k.replace(/_/g, ""));
|
||||||
const commonAnimIds = getEnumValues(CommonAnim) as CommonAnim[];
|
const commonAnimIds = getEnumValues(CommonAnim);
|
||||||
const chargeAnimNames = getEnumKeys(ChargeAnim).map(k => k.toLowerCase());
|
const chargeAnimNames = getEnumKeys(ChargeAnim).map(k => k.toLowerCase());
|
||||||
const chargeAnimMatchNames = chargeAnimNames.map(k => k.replace(/_/g, " "));
|
const chargeAnimMatchNames = chargeAnimNames.map(k => k.replace(/_/g, " "));
|
||||||
const chargeAnimIds = getEnumValues(ChargeAnim) as ChargeAnim[];
|
const chargeAnimIds = getEnumValues(ChargeAnim);
|
||||||
const commonNamePattern = /name: (?:Common:)?(Opp )?(.*)/;
|
const commonNamePattern = /name: (?:Common:)?(Opp )?(.*)/;
|
||||||
const moveNameToId = {};
|
const moveNameToId = {};
|
||||||
for (const move of getEnumValues(MoveId).slice(1)) {
|
for (const move of getEnumValues(MoveId).slice(1)) {
|
||||||
|
@ -3,7 +3,8 @@ import type { SpeciesId } from "#enums/species-id";
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { PlayerPokemon } from "#app/field/pokemon";
|
import { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type { Starter } from "#app/ui/starter-select-ui-handler";
|
import type { Starter } from "#app/ui/starter-select-ui-handler";
|
||||||
import { randSeedGauss, randSeedInt, randSeedItem, getEnumValues } from "#app/utils/common";
|
import { randSeedGauss, randSeedInt, randSeedItem } from "#app/utils/common";
|
||||||
|
import { getEnumValues } from "#app/utils/enums";
|
||||||
import type { PokemonSpeciesForm } from "#app/data/pokemon-species";
|
import type { PokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||||
import PokemonSpecies, { getPokemonSpeciesForm } from "#app/data/pokemon-species";
|
import PokemonSpecies, { getPokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||||
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
||||||
@ -165,5 +166,6 @@ export function getDailyStartingBiome(): BiomeId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fallback in case something went wrong
|
// Fallback in case something went wrong
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
return biomes[randSeedInt(biomes.length)];
|
return biomes[randSeedInt(biomes.length)];
|
||||||
}
|
}
|
||||||
|
@ -1744,6 +1744,7 @@ export function getCharVariantFromDialogue(message: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function initTrainerTypeDialogue(): void {
|
export function initTrainerTypeDialogue(): void {
|
||||||
|
// TODO: this should not be using `Object.Keys`
|
||||||
const trainerTypes = Object.keys(trainerTypeDialogue).map(t => Number.parseInt(t) as TrainerType);
|
const trainerTypes = Object.keys(trainerTypeDialogue).map(t => Number.parseInt(t) as TrainerType);
|
||||||
for (const trainerType of trainerTypes) {
|
for (const trainerType of trainerTypes) {
|
||||||
const messages = trainerTypeDialogue[trainerType];
|
const messages = trainerTypeDialogue[trainerType];
|
||||||
|
@ -28,7 +28,8 @@ import {
|
|||||||
} from "../status-effect";
|
} from "../status-effect";
|
||||||
import { getTypeDamageMultiplier } from "../type";
|
import { getTypeDamageMultiplier } from "../type";
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import { BooleanHolder, NumberHolder, isNullOrUndefined, toDmgValue, randSeedItem, randSeedInt, getEnumValues, toReadableString, type Constructor, randSeedFloat } from "#app/utils/common";
|
import { BooleanHolder, NumberHolder, isNullOrUndefined, toDmgValue, randSeedItem, randSeedInt, toReadableString, type Constructor, randSeedFloat } from "#app/utils/common";
|
||||||
|
import { getEnumValues } from "#app/utils/enums";
|
||||||
import { WeatherType } from "#enums/weather-type";
|
import { WeatherType } from "#enums/weather-type";
|
||||||
import type { ArenaTrapTag } from "../arena-tag";
|
import type { ArenaTrapTag } from "../arena-tag";
|
||||||
import { WeakenMoveTypeTag } from "../arena-tag";
|
import { WeakenMoveTypeTag } from "../arena-tag";
|
||||||
|
@ -15,7 +15,7 @@ import type { BerryModifierType, ModifierTypeOption } from "#app/modifier/modifi
|
|||||||
import { regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
import { regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
||||||
import { modifierTypes } from "#app/data/data-lists";
|
import { modifierTypes } from "#app/data/data-lists";
|
||||||
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
import { ModifierPoolType } from "#enums/modifier-pool-type";
|
||||||
import { randSeedInt } from "#app/utils/common";
|
import { randSeedItem } from "#app/utils/common";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
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";
|
||||||
@ -38,6 +38,7 @@ import i18next from "#app/plugins/i18n";
|
|||||||
import { BerryType } from "#enums/berry-type";
|
import { BerryType } from "#enums/berry-type";
|
||||||
import { PERMANENT_STATS, Stat } from "#enums/stat";
|
import { PERMANENT_STATS, Stat } from "#enums/stat";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
|
import { getEnumValues } from "#app/utils/enums";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/berriesAbound";
|
const namespace = "mysteryEncounters/berriesAbound";
|
||||||
@ -311,7 +312,7 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
function tryGiveBerry(prioritizedPokemon?: PlayerPokemon) {
|
function tryGiveBerry(prioritizedPokemon?: PlayerPokemon) {
|
||||||
const berryType = randSeedInt(Object.keys(BerryType).filter(s => !Number.isNaN(Number(s))).length) as BerryType;
|
const berryType = randSeedItem(getEnumValues(BerryType));
|
||||||
const berry = generateModifierType(modifierTypes.BERRY, [berryType]) as BerryModifierType;
|
const berry = generateModifierType(modifierTypes.BERRY, [berryType]) as BerryModifierType;
|
||||||
|
|
||||||
const party = globalScene.getPlayerParty();
|
const party = globalScene.getPlayerParty();
|
||||||
|
@ -292,6 +292,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
|
|
||||||
// Init the moves available for tutor
|
// Init the moves available for tutor
|
||||||
const moveTutorOptions: PokemonMove[] = [];
|
const moveTutorOptions: PokemonMove[] = [];
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
moveTutorOptions.push(new PokemonMove(PHYSICAL_TUTOR_MOVES[randSeedInt(PHYSICAL_TUTOR_MOVES.length)]));
|
moveTutorOptions.push(new PokemonMove(PHYSICAL_TUTOR_MOVES[randSeedInt(PHYSICAL_TUTOR_MOVES.length)]));
|
||||||
moveTutorOptions.push(new PokemonMove(SPECIAL_TUTOR_MOVES[randSeedInt(SPECIAL_TUTOR_MOVES.length)]));
|
moveTutorOptions.push(new PokemonMove(SPECIAL_TUTOR_MOVES[randSeedInt(SPECIAL_TUTOR_MOVES.length)]));
|
||||||
moveTutorOptions.push(new PokemonMove(STATUS_TUTOR_MOVES[randSeedInt(STATUS_TUTOR_MOVES.length)]));
|
moveTutorOptions.push(new PokemonMove(STATUS_TUTOR_MOVES[randSeedInt(STATUS_TUTOR_MOVES.length)]));
|
||||||
@ -389,6 +390,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
|
|||||||
specialOptions.push(rareFormChangeModifier);
|
specialOptions.push(rareFormChangeModifier);
|
||||||
}
|
}
|
||||||
if (specialOptions.length > 0) {
|
if (specialOptions.length > 0) {
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
modifierOptions.push(specialOptions[randSeedInt(specialOptions.length)]);
|
modifierOptions.push(specialOptions[randSeedInt(specialOptions.length)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +139,7 @@ export const ClowningAroundEncounter: MysteryEncounter = MysteryEncounterBuilder
|
|||||||
clownConfig.partyTemplateFunc = null; // Overrides party template func if it exists
|
clownConfig.partyTemplateFunc = null; // Overrides party template func if it exists
|
||||||
|
|
||||||
// Generate random ability for Blacephalon from pool
|
// Generate random ability for Blacephalon from pool
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
const ability = RANDOM_ABILITY_POOL[randSeedInt(RANDOM_ABILITY_POOL.length)];
|
const ability = RANDOM_ABILITY_POOL[randSeedInt(RANDOM_ABILITY_POOL.length)];
|
||||||
encounter.setDialogueToken("ability", allAbilities[ability].name);
|
encounter.setDialogueToken("ability", allAbilities[ability].name);
|
||||||
encounter.misc = { ability };
|
encounter.misc = { ability };
|
||||||
|
@ -190,6 +190,7 @@ async function doBiomeTransitionDialogueAndBattleInit() {
|
|||||||
|
|
||||||
// Calculate new biome (cannot be current biome)
|
// Calculate new biome (cannot be current biome)
|
||||||
const filteredBiomes = BIOME_CANDIDATES.filter(b => globalScene.arena.biomeType !== b);
|
const filteredBiomes = BIOME_CANDIDATES.filter(b => globalScene.arena.biomeType !== b);
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
const newBiome = filteredBiomes[randSeedInt(filteredBiomes.length)];
|
const newBiome = filteredBiomes[randSeedInt(filteredBiomes.length)];
|
||||||
|
|
||||||
// Show dialogue and transition biome
|
// Show dialogue and transition biome
|
||||||
|
@ -314,6 +314,7 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
|
|||||||
// One random pokemon will get its passive unlocked
|
// One random pokemon will get its passive unlocked
|
||||||
const passiveDisabledPokemon = globalScene.getPlayerParty().filter(p => !p.passive);
|
const passiveDisabledPokemon = globalScene.getPlayerParty().filter(p => !p.passive);
|
||||||
if (passiveDisabledPokemon?.length > 0) {
|
if (passiveDisabledPokemon?.length > 0) {
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
const enablePassiveMon = passiveDisabledPokemon[randSeedInt(passiveDisabledPokemon.length)];
|
const enablePassiveMon = passiveDisabledPokemon[randSeedInt(passiveDisabledPokemon.length)];
|
||||||
enablePassiveMon.passive = true;
|
enablePassiveMon.passive = true;
|
||||||
enablePassiveMon.updateInfo(true);
|
enablePassiveMon.updateInfo(true);
|
||||||
@ -479,6 +480,7 @@ async function doNewTeamPostProcess(transformations: PokemonTransformation[]) {
|
|||||||
// One random pokemon will get its passive unlocked
|
// One random pokemon will get its passive unlocked
|
||||||
const passiveDisabledPokemon = globalScene.getPlayerParty().filter(p => !p.passive);
|
const passiveDisabledPokemon = globalScene.getPlayerParty().filter(p => !p.passive);
|
||||||
if (passiveDisabledPokemon?.length > 0) {
|
if (passiveDisabledPokemon?.length > 0) {
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
const enablePassiveMon = passiveDisabledPokemon[randSeedInt(passiveDisabledPokemon.length)];
|
const enablePassiveMon = passiveDisabledPokemon[randSeedInt(passiveDisabledPokemon.length)];
|
||||||
enablePassiveMon.passive = true;
|
enablePassiveMon.passive = true;
|
||||||
await enablePassiveMon.updateInfo(true);
|
await enablePassiveMon.updateInfo(true);
|
||||||
|
@ -145,11 +145,13 @@ export default class MysteryEncounterOption implements IMysteryEncounterOption {
|
|||||||
}
|
}
|
||||||
if (truePrimaryPool.length > 0) {
|
if (truePrimaryPool.length > 0) {
|
||||||
// always choose from the non-overlapping pokemon first
|
// always choose from the non-overlapping pokemon first
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
this.primaryPokemon = truePrimaryPool[randSeedInt(truePrimaryPool.length)];
|
this.primaryPokemon = truePrimaryPool[randSeedInt(truePrimaryPool.length)];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// if there are multiple overlapping pokemon, we're okay - just choose one and take it out of the supporting pokemon pool
|
// if there are multiple overlapping pokemon, we're okay - just choose one and take it out of the supporting pokemon pool
|
||||||
if (overlap.length > 1 || this.secondaryPokemon.length - overlap.length >= 1) {
|
if (overlap.length > 1 || this.secondaryPokemon.length - overlap.length >= 1) {
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
this.primaryPokemon = overlap[randSeedInt(overlap.length)];
|
this.primaryPokemon = overlap[randSeedInt(overlap.length)];
|
||||||
this.secondaryPokemon = this.secondaryPokemon.filter(supp => supp !== this.primaryPokemon);
|
this.secondaryPokemon = this.secondaryPokemon.filter(supp => supp !== this.primaryPokemon);
|
||||||
return true;
|
return true;
|
||||||
|
@ -385,6 +385,7 @@ export default class MysteryEncounter implements IMysteryEncounter {
|
|||||||
// If there are multiple overlapping pokemon, we're okay - just choose one and take it out of the primary pokemon pool
|
// If there are multiple overlapping pokemon, we're okay - just choose one and take it out of the primary pokemon pool
|
||||||
if (overlap.length > 1 || this.secondaryPokemon.length - overlap.length >= 1) {
|
if (overlap.length > 1 || this.secondaryPokemon.length - overlap.length >= 1) {
|
||||||
// is this working?
|
// is this working?
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
this.primaryPokemon = overlap[randSeedInt(overlap.length, 0)];
|
this.primaryPokemon = overlap[randSeedInt(overlap.length, 0)];
|
||||||
this.secondaryPokemon = this.secondaryPokemon.filter(supp => supp !== this.primaryPokemon);
|
this.secondaryPokemon = this.secondaryPokemon.filter(supp => supp !== this.primaryPokemon);
|
||||||
return true;
|
return true;
|
||||||
@ -395,6 +396,7 @@ export default class MysteryEncounter implements IMysteryEncounter {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// this means we CAN have the same pokemon be a primary and secondary pokemon, so just choose any qualifying one randomly.
|
// this means we CAN have the same pokemon be a primary and secondary pokemon, so just choose any qualifying one randomly.
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
this.primaryPokemon = qualified[randSeedInt(qualified.length, 0)];
|
this.primaryPokemon = qualified[randSeedInt(qualified.length, 0)];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1099,8 +1099,10 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) {
|
|||||||
if (biomes! && biomes.length > 0) {
|
if (biomes! && biomes.length > 0) {
|
||||||
const specialBiomes = biomes.filter(b => alwaysPickTheseBiomes.includes(b));
|
const specialBiomes = biomes.filter(b => alwaysPickTheseBiomes.includes(b));
|
||||||
if (specialBiomes.length > 0) {
|
if (specialBiomes.length > 0) {
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
currentBiome = specialBiomes[randSeedInt(specialBiomes.length)];
|
currentBiome = specialBiomes[randSeedInt(specialBiomes.length)];
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
currentBiome = biomes[randSeedInt(biomes.length)];
|
currentBiome = biomes[randSeedInt(biomes.length)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,20 +111,24 @@ export function getRandomPlayerPokemon(
|
|||||||
// If there is only 1 legal/unfainted mon left, select from fainted legal mons
|
// If there is only 1 legal/unfainted mon left, select from fainted legal mons
|
||||||
const faintedLegalMons = party.filter(p => (!isAllowed || p.isAllowedInChallenge()) && p.isFainted());
|
const faintedLegalMons = party.filter(p => (!isAllowed || p.isAllowedInChallenge()) && p.isFainted());
|
||||||
if (faintedLegalMons.length > 0) {
|
if (faintedLegalMons.length > 0) {
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
chosenIndex = randSeedInt(faintedLegalMons.length);
|
chosenIndex = randSeedInt(faintedLegalMons.length);
|
||||||
chosenPokemon = faintedLegalMons[chosenIndex];
|
chosenPokemon = faintedLegalMons[chosenIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!chosenPokemon && fullyLegalMons.length > 0) {
|
if (!chosenPokemon && fullyLegalMons.length > 0) {
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
chosenIndex = randSeedInt(fullyLegalMons.length);
|
chosenIndex = randSeedInt(fullyLegalMons.length);
|
||||||
chosenPokemon = fullyLegalMons[chosenIndex];
|
chosenPokemon = fullyLegalMons[chosenIndex];
|
||||||
}
|
}
|
||||||
if (!chosenPokemon && isAllowed && allowedOnlyMons.length > 0) {
|
if (!chosenPokemon && isAllowed && allowedOnlyMons.length > 0) {
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
chosenIndex = randSeedInt(allowedOnlyMons.length);
|
chosenIndex = randSeedInt(allowedOnlyMons.length);
|
||||||
chosenPokemon = allowedOnlyMons[chosenIndex];
|
chosenPokemon = allowedOnlyMons[chosenIndex];
|
||||||
}
|
}
|
||||||
if (!chosenPokemon) {
|
if (!chosenPokemon) {
|
||||||
// If no other options worked, returns fully random
|
// If no other options worked, returns fully random
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
chosenIndex = randSeedInt(party.length);
|
chosenIndex = randSeedInt(party.length);
|
||||||
chosenPokemon = party[chosenIndex];
|
chosenPokemon = party[chosenIndex];
|
||||||
}
|
}
|
||||||
|
@ -146,6 +146,7 @@ export class Arena {
|
|||||||
if (!tierPool.length) {
|
if (!tierPool.length) {
|
||||||
ret = globalScene.randomSpecies(waveIndex, level);
|
ret = globalScene.randomSpecies(waveIndex, level);
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
const entry = tierPool[randSeedInt(tierPool.length)];
|
const entry = tierPool[randSeedInt(tierPool.length)];
|
||||||
let species: SpeciesId;
|
let species: SpeciesId;
|
||||||
if (typeof entry === "number") {
|
if (typeof entry === "number") {
|
||||||
@ -157,6 +158,7 @@ export class Arena {
|
|||||||
if (level >= levelThreshold) {
|
if (level >= levelThreshold) {
|
||||||
const speciesIds = entry[levelThreshold];
|
const speciesIds = entry[levelThreshold];
|
||||||
if (speciesIds.length > 1) {
|
if (speciesIds.length > 1) {
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
species = speciesIds[randSeedInt(speciesIds.length)];
|
species = speciesIds[randSeedInt(speciesIds.length)];
|
||||||
} else {
|
} else {
|
||||||
species = speciesIds[0];
|
species = speciesIds[0];
|
||||||
|
@ -25,7 +25,6 @@ import {
|
|||||||
BooleanHolder,
|
BooleanHolder,
|
||||||
randSeedItem,
|
randSeedItem,
|
||||||
isNullOrUndefined,
|
isNullOrUndefined,
|
||||||
getEnumValues,
|
|
||||||
toDmgValue,
|
toDmgValue,
|
||||||
fixedInt,
|
fixedInt,
|
||||||
rgbaToInt,
|
rgbaToInt,
|
||||||
@ -38,6 +37,7 @@ import {
|
|||||||
randSeedIntRange,
|
randSeedIntRange,
|
||||||
coerceArray,
|
coerceArray,
|
||||||
} from "#app/utils/common";
|
} from "#app/utils/common";
|
||||||
|
import { getEnumValues } from "#app/utils/enums";
|
||||||
import type { TypeDamageMultiplier } from "#app/data/type";
|
import type { TypeDamageMultiplier } from "#app/data/type";
|
||||||
import { getTypeDamageMultiplier, getTypeRgb } from "#app/data/type";
|
import { getTypeDamageMultiplier, getTypeRgb } from "#app/data/type";
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
|
@ -421,7 +421,8 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
// If useNewSpeciesPool is true, we need to generate a new species from the new species pool, otherwise we generate a random species
|
// If useNewSpeciesPool is true, we need to generate a new species from the new species pool, otherwise we generate a random species
|
||||||
let species = useNewSpeciesPool
|
let species = useNewSpeciesPool
|
||||||
? getPokemonSpecies(newSpeciesPool[Math.floor(randSeedInt(newSpeciesPool.length))])
|
? // TODO: should this use `randSeedItem`?
|
||||||
|
getPokemonSpecies(newSpeciesPool[Math.floor(randSeedInt(newSpeciesPool.length))])
|
||||||
: template.isSameSpecies(index) && index > offset
|
: template.isSameSpecies(index) && index > offset
|
||||||
? getPokemonSpecies(
|
? getPokemonSpecies(
|
||||||
battle.enemyParty[offset].species.getTrainerSpeciesForLevel(
|
battle.enemyParty[offset].species.getTrainerSpeciesForLevel(
|
||||||
@ -619,6 +620,8 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
if (maxScorePartyMemberIndexes.length > 1) {
|
if (maxScorePartyMemberIndexes.length > 1) {
|
||||||
let rand: number;
|
let rand: number;
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
|
|
||||||
globalScene.executeWithSeedOffset(
|
globalScene.executeWithSeedOffset(
|
||||||
() => (rand = randSeedInt(maxScorePartyMemberIndexes.length)),
|
() => (rand = randSeedInt(maxScorePartyMemberIndexes.length)),
|
||||||
globalScene.currentBattle.turn << 2,
|
globalScene.currentBattle.turn << 2,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { getEnumValues } from "#app/utils/common";
|
import { getEnumValues } from "./utils/enums";
|
||||||
import { deepCopy } from "#app/utils/data";
|
import { deepCopy } from "#app/utils/data";
|
||||||
import pad_generic from "./configs/inputs/pad_generic";
|
import pad_generic from "./configs/inputs/pad_generic";
|
||||||
import pad_unlicensedSNES from "./configs/inputs/pad_unlicensedSNES";
|
import pad_unlicensedSNES from "./configs/inputs/pad_unlicensedSNES";
|
||||||
|
@ -4,7 +4,8 @@ import CacheBustedLoaderPlugin from "#app/plugins/cache-busted-loader-plugin";
|
|||||||
import { SceneBase } from "#app/scene-base";
|
import { SceneBase } from "#app/scene-base";
|
||||||
import { WindowVariant, getWindowVariantSuffix } from "#app/ui/ui-theme";
|
import { WindowVariant, getWindowVariantSuffix } from "#app/ui/ui-theme";
|
||||||
import { isMobile } from "#app/touch-controls";
|
import { isMobile } from "#app/touch-controls";
|
||||||
import { localPing, getEnumValues, hasAllLocalizedSprites, getEnumKeys } from "#app/utils/common";
|
import { localPing, hasAllLocalizedSprites } from "#app/utils/common";
|
||||||
|
import { getEnumValues, getEnumKeys } from "./utils/enums";
|
||||||
import { initPokemonPrevolutions, initPokemonStarters } from "#app/data/balance/pokemon-evolutions";
|
import { initPokemonPrevolutions, initPokemonStarters } from "#app/data/balance/pokemon-evolutions";
|
||||||
import { initBiomes } from "#app/data/balance/biomes";
|
import { initBiomes } from "#app/data/balance/biomes";
|
||||||
import { initEggMoves } from "#app/data/balance/egg-moves";
|
import { initEggMoves } from "#app/data/balance/egg-moves";
|
||||||
|
@ -103,15 +103,8 @@ import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "#app/system
|
|||||||
import type { PokemonMoveSelectFilter, PokemonSelectFilter } from "#app/ui/party-ui-handler";
|
import type { PokemonMoveSelectFilter, PokemonSelectFilter } from "#app/ui/party-ui-handler";
|
||||||
import PartyUiHandler from "#app/ui/party-ui-handler";
|
import PartyUiHandler from "#app/ui/party-ui-handler";
|
||||||
import { getModifierTierTextTint } from "#app/ui/text";
|
import { getModifierTierTextTint } from "#app/ui/text";
|
||||||
import {
|
import { formatMoney, isNullOrUndefined, NumberHolder, padInt, randSeedInt, randSeedItem } from "#app/utils/common";
|
||||||
formatMoney,
|
import { getEnumKeys, getEnumValues } from "#app/utils/enums";
|
||||||
getEnumKeys,
|
|
||||||
getEnumValues,
|
|
||||||
isNullOrUndefined,
|
|
||||||
NumberHolder,
|
|
||||||
padInt,
|
|
||||||
randSeedInt,
|
|
||||||
} from "#app/utils/common";
|
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { BerryType } from "#enums/berry-type";
|
import { BerryType } from "#enums/berry-type";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
@ -1565,6 +1558,7 @@ class TmModifierTypeGenerator extends ModifierTypeGenerator {
|
|||||||
if (!tierUniqueCompatibleTms.length) {
|
if (!tierUniqueCompatibleTms.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
const randTmIndex = randSeedInt(tierUniqueCompatibleTms.length);
|
const randTmIndex = randSeedInt(tierUniqueCompatibleTms.length);
|
||||||
return new TmModifierType(tierUniqueCompatibleTms[randTmIndex]);
|
return new TmModifierType(tierUniqueCompatibleTms[randTmIndex]);
|
||||||
});
|
});
|
||||||
@ -1618,6 +1612,7 @@ class EvolutionItemModifierTypeGenerator extends ModifierTypeGenerator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
return new EvolutionItemModifierType(evolutionItemPool[randSeedInt(evolutionItemPool.length)]!); // TODO: is the bang correct?
|
return new EvolutionItemModifierType(evolutionItemPool[randSeedInt(evolutionItemPool.length)]!); // TODO: is the bang correct?
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1703,6 +1698,7 @@ export class FormChangeItemModifierTypeGenerator extends ModifierTypeGenerator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
return new FormChangeItemModifierType(formChangeItemPool[randSeedInt(formChangeItemPool.length)]);
|
return new FormChangeItemModifierType(formChangeItemPool[randSeedInt(formChangeItemPool.length)]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1973,7 +1969,7 @@ const modifierTypeInitObj = Object.freeze({
|
|||||||
if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in Nature) {
|
if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in Nature) {
|
||||||
return new PokemonNatureChangeModifierType(pregenArgs[0] as Nature);
|
return new PokemonNatureChangeModifierType(pregenArgs[0] as Nature);
|
||||||
}
|
}
|
||||||
return new PokemonNatureChangeModifierType(randSeedInt(getEnumValues(Nature).length) as Nature);
|
return new PokemonNatureChangeModifierType(randSeedItem(getEnumValues(Nature)));
|
||||||
}),
|
}),
|
||||||
|
|
||||||
MYSTICAL_ROCK: () =>
|
MYSTICAL_ROCK: () =>
|
||||||
|
@ -19,7 +19,8 @@ import { MoveResult } from "#enums/move-result";
|
|||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import { BattlePhase } from "#app/phases/battle-phase";
|
import { BattlePhase } from "#app/phases/battle-phase";
|
||||||
import { enumValueToKey, NumberHolder } from "#app/utils/common";
|
import { NumberHolder } from "#app/utils/common";
|
||||||
|
import { enumValueToKey } from "#app/utils/enums";
|
||||||
import { AbilityId } from "#enums/ability-id";
|
import { AbilityId } from "#enums/ability-id";
|
||||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
|
@ -56,6 +56,7 @@ export class SelectBiomePhase extends BattlePhase {
|
|||||||
delay: 1000,
|
delay: 1000,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: should this use `randSeedItem`?
|
||||||
setNextBiome(biomes[randSeedInt(biomes.length)]);
|
setNextBiome(biomes[randSeedInt(biomes.length)]);
|
||||||
}
|
}
|
||||||
} else if (biomeLinks.hasOwnProperty(currentBiome)) {
|
} else if (biomeLinks.hasOwnProperty(currentBiome)) {
|
||||||
|
@ -9,7 +9,8 @@ import type PokemonSpecies from "#app/data/pokemon-species";
|
|||||||
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
||||||
import { allSpecies } from "#app/data/data-lists";
|
import { allSpecies } from "#app/data/data-lists";
|
||||||
import { speciesStarterCosts } from "#app/data/balance/starters";
|
import { speciesStarterCosts } from "#app/data/balance/starters";
|
||||||
import { randInt, getEnumKeys, isLocal, executeIf, fixedInt, randSeedItem, NumberHolder } from "#app/utils/common";
|
import { randInt, isLocal, executeIf, fixedInt, randSeedItem, NumberHolder } from "#app/utils/common";
|
||||||
|
import { getEnumKeys } from "#app/utils/enums";
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import PokemonData from "#app/system/pokemon-data";
|
import PokemonData from "#app/system/pokemon-data";
|
||||||
import PersistentModifierData from "#app/system/modifier-data";
|
import PersistentModifierData from "#app/system/modifier-data";
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { getEnumKeys, executeIf } from "#app/utils/common";
|
import { executeIf } from "#app/utils/common";
|
||||||
|
import { getEnumKeys } from "#app/utils/enums";
|
||||||
import { TextStyle, addTextObject } from "./text";
|
import { TextStyle, addTextObject } from "./text";
|
||||||
import { WindowVariant, addWindow } from "./ui-theme";
|
import { WindowVariant, addWindow } from "./ui-theme";
|
||||||
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
|
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { UiMode } from "#enums/ui-mode";
|
import { UiMode } from "#enums/ui-mode";
|
||||||
import { TextStyle, addTextObject, getEggTierTextTint, getTextStyleOptions } from "./text";
|
import { TextStyle, addTextObject, getEggTierTextTint, getTextStyleOptions } from "./text";
|
||||||
import MessageUiHandler from "./message-ui-handler";
|
import MessageUiHandler from "./message-ui-handler";
|
||||||
import { getEnumValues, getEnumKeys, fixedInt, randSeedShuffle } from "#app/utils/common";
|
import { fixedInt, randSeedShuffle } from "#app/utils/common";
|
||||||
|
import { getEnumValues, getEnumKeys } from "#app/utils/enums";
|
||||||
import type { IEggOptions } from "../data/egg";
|
import type { IEggOptions } from "../data/egg";
|
||||||
import { Egg, getLegendaryGachaSpeciesForTimestamp } from "../data/egg";
|
import { Egg, getLegendaryGachaSpeciesForTimestamp } from "../data/egg";
|
||||||
import { VoucherType, getVoucherTypeIcon } from "../system/voucher";
|
import { VoucherType, getVoucherTypeIcon } from "../system/voucher";
|
||||||
@ -299,7 +300,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
this.eggGachaContainer.add(this.eggGachaOptionsContainer);
|
this.eggGachaContainer.add(this.eggGachaOptionsContainer);
|
||||||
|
|
||||||
new Array(getEnumKeys(VoucherType).length).fill(null).map((_, i) => {
|
getEnumValues(VoucherType).forEach((voucher, i) => {
|
||||||
const container = globalScene.add.container(globalScene.game.canvas.width / 6 - 56 * i, 0);
|
const container = globalScene.add.container(globalScene.game.canvas.width / 6 - 56 * i, 0);
|
||||||
|
|
||||||
const bg = addWindow(0, 0, 56, 22);
|
const bg = addWindow(0, 0, 56, 22);
|
||||||
@ -312,7 +313,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
this.voucherCountLabels.push(countLabel);
|
this.voucherCountLabels.push(countLabel);
|
||||||
|
|
||||||
const iconImage = getVoucherTypeIcon(i as VoucherType);
|
const iconImage = getVoucherTypeIcon(voucher);
|
||||||
|
|
||||||
const icon = globalScene.add.sprite(-19, 2, "items", iconImage);
|
const icon = globalScene.add.sprite(-19, 2, "items", iconImage);
|
||||||
icon.setOrigin(0, 0);
|
icon.setOrigin(0, 0);
|
||||||
|
@ -2,7 +2,8 @@ import { bypassLogin } from "#app/global-vars/bypass-login";
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { TextStyle, addTextObject, getTextStyleOptions } from "./text";
|
import { TextStyle, addTextObject, getTextStyleOptions } from "./text";
|
||||||
import { UiMode } from "#enums/ui-mode";
|
import { UiMode } from "#enums/ui-mode";
|
||||||
import { getEnumKeys, isLocal, fixedInt, sessionIdKey } from "#app/utils/common";
|
import { isLocal, fixedInt, sessionIdKey } from "#app/utils/common";
|
||||||
|
import { getEnumValues } from "#app/utils/enums";
|
||||||
import { isBeta } from "#app/utils/utility-vars";
|
import { isBeta } from "#app/utils/utility-vars";
|
||||||
import { getCookie } from "#app/utils/cookies";
|
import { getCookie } from "#app/utils/cookies";
|
||||||
import { addWindow, WindowVariant } from "./ui-theme";
|
import { addWindow, WindowVariant } from "./ui-theme";
|
||||||
@ -76,11 +77,9 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
{ condition: bypassLogin, options: [MenuOptions.LOG_OUT] },
|
{ condition: bypassLogin, options: [MenuOptions.LOG_OUT] },
|
||||||
];
|
];
|
||||||
|
|
||||||
this.menuOptions = getEnumKeys(MenuOptions)
|
this.menuOptions = getEnumValues(MenuOptions).filter(m => {
|
||||||
.map(m => Number.parseInt(MenuOptions[m]) as MenuOptions)
|
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
|
||||||
.filter(m => {
|
});
|
||||||
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setup(): void {
|
setup(): void {
|
||||||
@ -131,11 +130,9 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
{ condition: bypassLogin, options: [MenuOptions.LOG_OUT] },
|
{ condition: bypassLogin, options: [MenuOptions.LOG_OUT] },
|
||||||
];
|
];
|
||||||
|
|
||||||
this.menuOptions = getEnumKeys(MenuOptions)
|
this.menuOptions = getEnumValues(MenuOptions).filter(m => {
|
||||||
.map(m => Number.parseInt(MenuOptions[m]) as MenuOptions)
|
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
|
||||||
.filter(m => {
|
});
|
||||||
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.optionSelectText = addTextObject(
|
this.optionSelectText = addTextObject(
|
||||||
0,
|
0,
|
||||||
@ -511,11 +508,9 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||||||
this.render();
|
this.render();
|
||||||
super.show(args);
|
super.show(args);
|
||||||
|
|
||||||
this.menuOptions = getEnumKeys(MenuOptions)
|
this.menuOptions = getEnumValues(MenuOptions).filter(m => {
|
||||||
.map(m => Number.parseInt(MenuOptions[m]) as MenuOptions)
|
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
|
||||||
.filter(m => {
|
});
|
||||||
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.menuContainer.setVisible(true);
|
this.menuContainer.setVisible(true);
|
||||||
this.setCursor(0);
|
this.setCursor(0);
|
||||||
|
@ -58,7 +58,7 @@ import {
|
|||||||
toReadableString,
|
toReadableString,
|
||||||
} from "#app/utils/common";
|
} from "#app/utils/common";
|
||||||
import type { Nature } from "#enums/nature";
|
import type { Nature } from "#enums/nature";
|
||||||
import { getEnumKeys } from "#app/utils/common";
|
import { getEnumValues } from "#app/utils/enums";
|
||||||
import { speciesTmMoves } from "#app/data/balance/tms";
|
import { speciesTmMoves } from "#app/data/balance/tms";
|
||||||
import type { BiomeTierTod } from "#app/data/balance/biomes";
|
import type { BiomeTierTod } from "#app/data/balance/biomes";
|
||||||
import { BiomePoolTier, catchableSpecies } from "#app/data/balance/biomes";
|
import { BiomePoolTier, catchableSpecies } from "#app/data/balance/biomes";
|
||||||
@ -603,7 +603,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
this.menuContainer.setVisible(false);
|
this.menuContainer.setVisible(false);
|
||||||
|
|
||||||
this.menuOptions = getEnumKeys(MenuOptions).map(m => Number.parseInt(MenuOptions[m]) as MenuOptions);
|
this.menuOptions = getEnumValues(MenuOptions);
|
||||||
|
|
||||||
this.optionSelectText = addBBCodeTextObject(
|
this.optionSelectText = addBBCodeTextObject(
|
||||||
0,
|
0,
|
||||||
@ -707,7 +707,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
this.starterAttributes = this.initStarterPrefs();
|
this.starterAttributes = this.initStarterPrefs();
|
||||||
|
|
||||||
this.menuOptions = getEnumKeys(MenuOptions).map(m => Number.parseInt(MenuOptions[m]) as MenuOptions);
|
this.menuOptions = getEnumValues(MenuOptions);
|
||||||
|
|
||||||
this.menuContainer.setVisible(true);
|
this.menuContainer.setVisible(true);
|
||||||
|
|
||||||
|
@ -6,13 +6,13 @@ import {
|
|||||||
getLocalizedSpriteKey,
|
getLocalizedSpriteKey,
|
||||||
rgbHexToRgba,
|
rgbHexToRgba,
|
||||||
padInt,
|
padInt,
|
||||||
getEnumValues,
|
|
||||||
fixedInt,
|
fixedInt,
|
||||||
isNullOrUndefined,
|
isNullOrUndefined,
|
||||||
toReadableString,
|
toReadableString,
|
||||||
formatStat,
|
formatStat,
|
||||||
getShinyDescriptor,
|
getShinyDescriptor,
|
||||||
} from "#app/utils/common";
|
} from "#app/utils/common";
|
||||||
|
import { getEnumValues } from "#app/utils/enums";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type { PokemonMove } from "#app/data/moves/pokemon-move";
|
import type { PokemonMove } from "#app/data/moves/pokemon-move";
|
||||||
import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters";
|
import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters";
|
||||||
|
@ -8,11 +8,19 @@ export type nil = null | undefined;
|
|||||||
|
|
||||||
export const MissingTextureKey = "__MISSING";
|
export const MissingTextureKey = "__MISSING";
|
||||||
|
|
||||||
|
// TODO: Draft tests for these utility functions
|
||||||
|
// TODO: Break up this file
|
||||||
|
/**
|
||||||
|
* Convert a `snake_case` string in any capitalization (such as one from an enum reverse mapping)
|
||||||
|
* into a readable `Title Case` version.
|
||||||
|
* @param str - The snake case string to be converted.
|
||||||
|
* @returns The result of converting `str` into title case.
|
||||||
|
*/
|
||||||
export function toReadableString(str: string): string {
|
export function toReadableString(str: string): string {
|
||||||
return str
|
return str
|
||||||
.replace(/_/g, " ")
|
.replace(/_/g, " ")
|
||||||
.split(" ")
|
.split(" ")
|
||||||
.map(s => `${s.slice(0, 1)}${s.slice(1).toLowerCase()}`)
|
.map(s => capitalizeFirstLetter(s.toLowerCase()))
|
||||||
.join(" ");
|
.join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,18 +281,6 @@ export function formatStat(stat: number, forHp = false): string {
|
|||||||
return formatLargeNumber(stat, forHp ? 100000 : 1000000);
|
return formatLargeNumber(stat, forHp ? 100000 : 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getEnumKeys(enumType: any): string[] {
|
|
||||||
return Object.values(enumType)
|
|
||||||
.filter(v => Number.isNaN(Number.parseInt(v!.toString())))
|
|
||||||
.map(v => v!.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getEnumValues(enumType: any): number[] {
|
|
||||||
return Object.values(enumType)
|
|
||||||
.filter(v => !Number.isNaN(Number.parseInt(v!.toString())))
|
|
||||||
.map(v => Number.parseInt(v!.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function executeIf<T>(condition: boolean, promiseFunc: () => Promise<T>): Promise<T | null> {
|
export function executeIf<T>(condition: boolean, promiseFunc: () => Promise<T>): Promise<T | null> {
|
||||||
return condition ? promiseFunc() : new Promise<T | null>(resolve => resolve(null));
|
return condition ? promiseFunc() : new Promise<T | null>(resolve => resolve(null));
|
||||||
}
|
}
|
||||||
@ -636,25 +632,3 @@ export function coerceArray<T>(input: T): T extends any[] ? T : [T];
|
|||||||
export function coerceArray<T>(input: T): T | [T] {
|
export function coerceArray<T>(input: T): T | [T] {
|
||||||
return Array.isArray(input) ? input : [input];
|
return Array.isArray(input) ? input : [input];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the key that matches the enum [object] value.
|
|
||||||
* @param input - The enum [object] to check
|
|
||||||
* @param val - The value to get the key of
|
|
||||||
* @returns The name of the key with the specified value
|
|
||||||
* @example
|
|
||||||
* const thing = {
|
|
||||||
* one: 1,
|
|
||||||
* two: 2,
|
|
||||||
* } as const;
|
|
||||||
* console.log(enumValueToKey(thing, thing.two)); // output: "two"
|
|
||||||
* @throws An `Error` if an invalid enum value is passed to the function
|
|
||||||
*/
|
|
||||||
export function enumValueToKey<T extends Record<string, string | number>>(input: T, val: T[keyof T]): keyof T {
|
|
||||||
for (const [key, value] of Object.entries(input)) {
|
|
||||||
if (val === value) {
|
|
||||||
return key as keyof T;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new Error(`Invalid value passed to \`enumValueToKey\`! Value: ${val}`);
|
|
||||||
}
|
|
||||||
|
74
src/utils/enums.ts
Normal file
74
src/utils/enums.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import type { EnumOrObject, EnumValues, TSNumericEnum, NormalEnum } from "#app/@types/enum-types";
|
||||||
|
import type { InferKeys } from "#app/@types/type-helpers";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the string keys of an Enum object, excluding reverse-mapped numbers.
|
||||||
|
* @param enumType - The numeric enum to retrieve keys for
|
||||||
|
* @returns An ordered array of all of `enumType`'s string keys
|
||||||
|
* @example
|
||||||
|
* enum fruit {
|
||||||
|
* apple = 1,
|
||||||
|
* banana = 2,
|
||||||
|
* cherry = 3,
|
||||||
|
* orange = 12,
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* console.log(getEnumKeys<typeof fruit>(fruit)); // output: ["apple", "banana", "cherry", "orange"]
|
||||||
|
* @remarks
|
||||||
|
* To retrieve the keys of a {@linkcode NormalEnum}, use {@linkcode Object.keys} instead.
|
||||||
|
*/
|
||||||
|
export function getEnumKeys<E extends EnumOrObject>(enumType: TSNumericEnum<E>): (keyof E)[] {
|
||||||
|
// All enum values are either normal numbers or reverse mapped strings, so we can retrieve the keys by filtering out numbers.
|
||||||
|
return Object.values(enumType).filter(v => typeof v === "string");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the numeric values of a numeric Enum object, excluding reverse-mapped strings.
|
||||||
|
* @param enumType - The enum object to retrieve keys for
|
||||||
|
* @returns An ordered array of all of `enumType`'s number values
|
||||||
|
* @example
|
||||||
|
* enum fruit {
|
||||||
|
* apple = 1,
|
||||||
|
* banana = 2,
|
||||||
|
* cherry = 3,
|
||||||
|
* orange = 12,
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* console.log(getEnumValues<typeof fruit>(fruit)); // output: [1, 2, 3, 12]
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* To retrieve the keys of a {@linkcode NormalEnum}, use {@linkcode Object.values} instead.
|
||||||
|
*/
|
||||||
|
// NB: This intentionally does not use `EnumValues<E>` as using `E[keyof E]` leads to improved variable highlighting in IDEs.
|
||||||
|
export function getEnumValues<E extends EnumOrObject>(enumType: TSNumericEnum<E>): E[keyof E][] {
|
||||||
|
return Object.values(enumType).filter(v => typeof v !== "string") as E[keyof E][];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name of the key that matches the given Enum value.
|
||||||
|
* Can be used to emulate Typescript reverse mapping for `const object`s or string enums.
|
||||||
|
* @param object - The {@linkcode NormalEnum} to check
|
||||||
|
* @param val - The value to get the key of
|
||||||
|
* @returns The name of the key with the specified value
|
||||||
|
* @example
|
||||||
|
* const thing = {
|
||||||
|
* one: 1,
|
||||||
|
* two: 2,
|
||||||
|
* } as const;
|
||||||
|
* console.log(enumValueToKey(thing, 2)); // output: "two"
|
||||||
|
* @throws Error if an invalid enum value is passed to the function
|
||||||
|
* @remarks
|
||||||
|
* If multiple keys map to the same value, the first one (in insertion order) will be retrieved,
|
||||||
|
* but the return type will be the union of ALL their corresponding keys.
|
||||||
|
*/
|
||||||
|
export function enumValueToKey<T extends EnumOrObject, V extends EnumValues<T>>(
|
||||||
|
object: NormalEnum<T>,
|
||||||
|
val: V,
|
||||||
|
): InferKeys<T, V> {
|
||||||
|
for (const [key, value] of Object.entries(object)) {
|
||||||
|
if (val === value) {
|
||||||
|
return key as InferKeys<T, V>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error(`Invalid value passed to \`enumValueToKey\`! Value: ${val}`);
|
||||||
|
}
|
107
test/types/enum-types.test-d.ts
Normal file
107
test/types/enum-types.test-d.ts
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import type { EnumOrObject, EnumValues, TSNumericEnum, NormalEnum } from "#app/@types/enum-types";
|
||||||
|
|
||||||
|
import type { getEnumKeys, getEnumValues } from "#app/utils/enums";
|
||||||
|
import type { enumValueToKey } from "#app/utils/enums";
|
||||||
|
|
||||||
|
import { expectTypeOf, describe, it } from "vitest";
|
||||||
|
|
||||||
|
enum testEnumNum {
|
||||||
|
testN1 = 1,
|
||||||
|
testN2 = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum testEnumString {
|
||||||
|
testS1 = "apple",
|
||||||
|
testS2 = "banana",
|
||||||
|
}
|
||||||
|
|
||||||
|
const testObjNum = { testON1: 1, testON2: 2 } as const;
|
||||||
|
|
||||||
|
const testObjString = { testOS1: "apple", testOS2: "banana" } as const;
|
||||||
|
|
||||||
|
describe("Enum Type Helpers", () => {
|
||||||
|
describe("EnumValues", () => {
|
||||||
|
it("should go from enum object type to value type", () => {
|
||||||
|
expectTypeOf<EnumValues<typeof testEnumNum>>().toEqualTypeOf<testEnumNum>();
|
||||||
|
expectTypeOf<EnumValues<typeof testEnumNum>>().branded.toEqualTypeOf<1 | 2>();
|
||||||
|
|
||||||
|
expectTypeOf<EnumValues<typeof testEnumString>>().toEqualTypeOf<testEnumString>();
|
||||||
|
expectTypeOf<EnumValues<typeof testEnumString>>().toEqualTypeOf<testEnumString.testS1 | testEnumString.testS2>();
|
||||||
|
expectTypeOf<EnumValues<typeof testEnumString>>().toMatchTypeOf<"apple" | "banana">();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should produce union of const object values as type", () => {
|
||||||
|
expectTypeOf<EnumValues<typeof testObjNum>>().toEqualTypeOf<1 | 2>();
|
||||||
|
|
||||||
|
expectTypeOf<EnumValues<typeof testObjString>>().toEqualTypeOf<"apple" | "banana">();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("TSNumericEnum", () => {
|
||||||
|
it("should match numeric enums", () => {
|
||||||
|
expectTypeOf<TSNumericEnum<typeof testEnumNum>>().toEqualTypeOf<typeof testEnumNum>();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not match string enums or const objects", () => {
|
||||||
|
expectTypeOf<TSNumericEnum<typeof testEnumString>>().toBeNever();
|
||||||
|
expectTypeOf<TSNumericEnum<typeof testObjNum>>().toBeNever();
|
||||||
|
expectTypeOf<TSNumericEnum<typeof testObjString>>().toBeNever();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("NormalEnum", () => {
|
||||||
|
it("should match string enums or const objects", () => {
|
||||||
|
expectTypeOf<NormalEnum<typeof testEnumString>>().toEqualTypeOf<typeof testEnumString>();
|
||||||
|
expectTypeOf<NormalEnum<typeof testObjNum>>().toEqualTypeOf<typeof testObjNum>();
|
||||||
|
expectTypeOf<NormalEnum<typeof testObjString>>().toEqualTypeOf<typeof testObjString>();
|
||||||
|
});
|
||||||
|
it("should not match numeric enums", () => {
|
||||||
|
expectTypeOf<NormalEnum<typeof testEnumNum>>().toBeNever();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("EnumOrObject", () => {
|
||||||
|
it("should match any enum or const object", () => {
|
||||||
|
expectTypeOf<typeof testEnumNum>().toMatchTypeOf<EnumOrObject>();
|
||||||
|
expectTypeOf<typeof testEnumString>().toMatchTypeOf<EnumOrObject>();
|
||||||
|
expectTypeOf<typeof testObjNum>().toMatchTypeOf<EnumOrObject>();
|
||||||
|
expectTypeOf<typeof testObjString>().toMatchTypeOf<EnumOrObject>();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not match an enum value union w/o typeof", () => {
|
||||||
|
expectTypeOf<testEnumNum>().not.toMatchTypeOf<EnumOrObject>();
|
||||||
|
expectTypeOf<testEnumString>().not.toMatchTypeOf<EnumOrObject>();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be equivalent to `TSNumericEnum | NormalEnum`", () => {
|
||||||
|
expectTypeOf<EnumOrObject>().branded.toEqualTypeOf<TSNumericEnum<EnumOrObject> | NormalEnum<EnumOrObject>>();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Enum Functions", () => {
|
||||||
|
describe("getEnumKeys", () => {
|
||||||
|
it("should retrieve keys of numeric enum", () => {
|
||||||
|
expectTypeOf<typeof getEnumKeys<typeof testEnumNum>>().returns.toEqualTypeOf<("testN1" | "testN2")[]>();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getEnumValues", () => {
|
||||||
|
it("should retrieve values of numeric enum", () => {
|
||||||
|
expectTypeOf<typeof getEnumValues<typeof testEnumNum>>().returns.branded.toEqualTypeOf<(1 | 2)[]>();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("enumValueToKey", () => {
|
||||||
|
it("should retrieve values for a given key", () => {
|
||||||
|
expectTypeOf<
|
||||||
|
typeof enumValueToKey<typeof testEnumString, testEnumString.testS1>
|
||||||
|
>().returns.toEqualTypeOf<"testS1">();
|
||||||
|
expectTypeOf<typeof enumValueToKey<typeof testEnumString, testEnumString>>().returns.toEqualTypeOf<
|
||||||
|
"testS1" | "testS2"
|
||||||
|
>();
|
||||||
|
expectTypeOf<typeof enumValueToKey<typeof testObjNum, 1>>().returns.toEqualTypeOf<"testON1">();
|
||||||
|
expectTypeOf<typeof enumValueToKey<typeof testObjNum, 1 | 2>>().returns.toEqualTypeOf<"testON1" | "testON2">();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -28,19 +28,23 @@ export default defineProject(({ mode }) => ({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
environment: "jsdom" as const,
|
environment: "jsdom",
|
||||||
environmentOptions: {
|
environmentOptions: {
|
||||||
jsdom: {
|
jsdom: {
|
||||||
resources: "usable",
|
resources: "usable",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
typecheck: {
|
||||||
|
tsconfig: "tsconfig.json",
|
||||||
|
include: ["./test/types/**/*.{test,spec}{-|.}d.ts"],
|
||||||
|
},
|
||||||
threads: false,
|
threads: false,
|
||||||
trace: true,
|
trace: true,
|
||||||
restoreMocks: true,
|
restoreMocks: true,
|
||||||
watch: false,
|
watch: false,
|
||||||
coverage: {
|
coverage: {
|
||||||
provider: "istanbul" as const,
|
provider: "istanbul",
|
||||||
reportsDirectory: "coverage" as const,
|
reportsDirectory: "coverage",
|
||||||
reporters: ["text-summary", "html"],
|
reporters: ["text-summary", "html"],
|
||||||
},
|
},
|
||||||
name: "main",
|
name: "main",
|
||||||
|
Loading…
Reference in New Issue
Block a user