mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-03 23:12:20 +02:00
Moved Enum functions to own file; added type helpers for enums
This commit is contained in:
parent
9c0c163257
commit
925ddeaae4
54
src/@types/enum-types.ts
Normal file
54
src/@types/enum-types.ts
Normal file
@ -0,0 +1,54 @@
|
||||
/** 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` object produced by `typeof Enum` into its literal value union.
|
||||
*/
|
||||
export type EnumValues<E> = E[keyof E];
|
||||
|
||||
/**
|
||||
* Generic type constraint representing a TS numeric enum with reverse mappings.
|
||||
* @example
|
||||
* TSNumericEnum<typeof WeatherType>
|
||||
*/
|
||||
// NB: this works because `EnumValues<typeof Enum>` returns the underlying Enum union type.
|
||||
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>>;
|
||||
|
||||
// ### Type check tests
|
||||
|
||||
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;
|
||||
|
||||
testEnumNum satisfies EnumOrObject;
|
||||
testEnumString satisfies EnumOrObject;
|
||||
testObjNum satisfies EnumOrObject;
|
||||
testObjString satisfies EnumOrObject;
|
||||
|
||||
// @ts-expect-error - This is intentionally supposed to fail as an example
|
||||
testEnumNum satisfies NormalEnum<typeof testEnumNum>;
|
||||
testEnumString satisfies NormalEnum<typeof testEnumString>;
|
||||
testObjNum satisfies NormalEnum<typeof testObjNum>;
|
||||
testObjString satisfies NormalEnum<typeof testObjString>;
|
||||
|
||||
testEnumNum satisfies TSNumericEnum<typeof testEnumNum>;
|
||||
// @ts-expect-error - This is intentionally supposed to fail as an example
|
||||
testEnumString satisfies TSNumericEnum<typeof testEnumString>;
|
||||
// @ts-expect-error - This is intentionally supposed to fail as an example
|
||||
testObjNum satisfies TSNumericEnum<typeof testObjNum>;
|
||||
// @ts-expect-error - This is intentionally supposed to fail as an example
|
||||
testObjString satisfies TSNumericEnum<typeof testObjString>;
|
@ -10,7 +10,6 @@ import {
|
||||
fixedInt,
|
||||
getIvsFromId,
|
||||
randSeedInt,
|
||||
getEnumValues,
|
||||
randomString,
|
||||
NumberHolder,
|
||||
shiftCharCodes,
|
||||
@ -19,6 +18,7 @@ import {
|
||||
BooleanHolder,
|
||||
type Constructor,
|
||||
} from "#app/utils/common";
|
||||
import { getEnumValues } from "./utils/enums";
|
||||
import { deepMergeSpriteData } from "#app/utils/data";
|
||||
import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier";
|
||||
import {
|
||||
|
@ -2,7 +2,6 @@ import { globalScene } from "#app/global-scene";
|
||||
import type { Command } from "#enums/command";
|
||||
import {
|
||||
randomString,
|
||||
getEnumValues,
|
||||
NumberHolder,
|
||||
randSeedInt,
|
||||
shiftCharCodes,
|
||||
@ -10,6 +9,7 @@ import {
|
||||
randInt,
|
||||
randSeedFloat,
|
||||
} from "#app/utils/common";
|
||||
import { getEnumValues } from "./utils/enums";
|
||||
import Trainer from "./field/trainer";
|
||||
import { TrainerVariant } from "#enums/trainer-variant";
|
||||
import type { GameMode } from "./game-mode";
|
||||
|
@ -1,5 +1,6 @@
|
||||
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 { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
||||
import i18next from "i18next";
|
||||
@ -7708,10 +7709,10 @@ export function initBiomes() {
|
||||
|
||||
const traverseBiome = (biome: BiomeId, depth: number) => {
|
||||
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
|
||||
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])
|
||||
? biomeLinks[biome] as (BiomeId | [ BiomeId, number ])[]
|
||||
|
@ -1,8 +1,8 @@
|
||||
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 { SpeciesId } from "#enums/species-id";
|
||||
|
||||
import { toReadableString } from "#app/utils/common";
|
||||
|
||||
export const speciesEggMoves = {
|
||||
[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 ]
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
let output = "";
|
||||
|
||||
const speciesNames = getEnumKeys(SpeciesId);
|
||||
const speciesValues = getEnumValues(SpeciesId);
|
||||
const moveNames = allMoves.map(m => m.name.replace(/ \([A-Z]\)$/, "").toLowerCase());
|
||||
const lines = content.split(/\n/g);
|
||||
|
||||
for (const line of lines) {
|
||||
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, "_");
|
||||
const enumSpeciesName = cols[0].toUpperCase().replace(/[ -]/g, "_") as keyof typeof SpeciesId;
|
||||
// TODO: This should use reverse mapping instead of `indexOf`
|
||||
const species = speciesValues[speciesNames.indexOf(enumSpeciesName)];
|
||||
|
||||
const eggMoves: MoveId[] = [];
|
||||
@ -602,14 +609,16 @@ function parseEggMoves(content: string): void {
|
||||
for (let m = 0; m < 4; m++) {
|
||||
const moveName = cols[m + 1].trim();
|
||||
const moveIndex = moveName !== "N/A" ? moveNames.indexOf(moveName.toLowerCase()) : -1;
|
||||
eggMoves.push(moveIndex > -1 ? moveIndex as MoveId : MoveId.NONE);
|
||||
|
||||
if (moveIndex === -1) {
|
||||
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`;
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,8 @@ import { globalScene } from "#app/global-scene";
|
||||
import { allMoves } from "#app/data/data-lists";
|
||||
import { MoveFlags } from "#enums/MoveFlags";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import {
|
||||
type nil,
|
||||
getFrameMs,
|
||||
getEnumKeys,
|
||||
getEnumValues,
|
||||
animationFileName,
|
||||
coerceArray,
|
||||
isNullOrUndefined,
|
||||
} from "#app/utils/common";
|
||||
import { type nil, getFrameMs, animationFileName, coerceArray, isNullOrUndefined } from "#app/utils/common";
|
||||
import { getEnumKeys, getEnumValues } from "#app/utils/enums";
|
||||
import type { BattlerIndex } from "#enums/battler-index";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import Phaser from "phaser";
|
||||
@ -1402,10 +1395,10 @@ export class EncounterBattleAnim extends BattleAnim {
|
||||
export async function populateAnims() {
|
||||
const commonAnimNames = getEnumKeys(CommonAnim).map(k => k.toLowerCase());
|
||||
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 chargeAnimMatchNames = chargeAnimNames.map(k => k.replace(/_/g, " "));
|
||||
const chargeAnimIds = getEnumValues(ChargeAnim) as ChargeAnim[];
|
||||
const chargeAnimIds = getEnumValues(ChargeAnim);
|
||||
const commonNamePattern = /name: (?:Common:)?(Opp )?(.*)/;
|
||||
const moveNameToId = {};
|
||||
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 { PlayerPokemon } from "#app/field/pokemon";
|
||||
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 PokemonSpecies, { getPokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
||||
|
@ -1744,6 +1744,7 @@ export function getCharVariantFromDialogue(message: string): string {
|
||||
}
|
||||
|
||||
export function initTrainerTypeDialogue(): void {
|
||||
// TODO: this should not be using `Object.Keys`
|
||||
const trainerTypes = Object.keys(trainerTypeDialogue).map(t => Number.parseInt(t) as TrainerType);
|
||||
for (const trainerType of trainerTypes) {
|
||||
const messages = trainerTypeDialogue[trainerType];
|
||||
|
@ -27,7 +27,8 @@ import {
|
||||
} from "../status-effect";
|
||||
import { getTypeDamageMultiplier } from "../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 type { ArenaTrapTag } from "../arena-tag";
|
||||
import { WeakenMoveTypeTag } from "../arena-tag";
|
||||
|
@ -25,7 +25,6 @@ import {
|
||||
BooleanHolder,
|
||||
randSeedItem,
|
||||
isNullOrUndefined,
|
||||
getEnumValues,
|
||||
toDmgValue,
|
||||
fixedInt,
|
||||
rgbaToInt,
|
||||
@ -38,6 +37,7 @@ import {
|
||||
randSeedIntRange,
|
||||
coerceArray,
|
||||
} from "#app/utils/common";
|
||||
import { getEnumValues } from "#app/utils/enums";
|
||||
import type { TypeDamageMultiplier } from "#app/data/type";
|
||||
import { getTypeDamageMultiplier, getTypeRgb } from "#app/data/type";
|
||||
import { PokemonType } from "#enums/pokemon-type";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import Phaser from "phaser";
|
||||
import { getEnumValues } from "#app/utils/common";
|
||||
import { getEnumValues } from "./utils/enums";
|
||||
import { deepCopy } from "#app/utils/data";
|
||||
import pad_generic from "./configs/inputs/pad_generic";
|
||||
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 { WindowVariant, getWindowVariantSuffix } from "#app/ui/ui-theme";
|
||||
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 { initBiomes } from "#app/data/balance/biomes";
|
||||
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 PartyUiHandler from "#app/ui/party-ui-handler";
|
||||
import { getModifierTierTextTint } from "#app/ui/text";
|
||||
import {
|
||||
formatMoney,
|
||||
getEnumKeys,
|
||||
getEnumValues,
|
||||
isNullOrUndefined,
|
||||
NumberHolder,
|
||||
padInt,
|
||||
randSeedInt,
|
||||
} from "#app/utils/common";
|
||||
import { formatMoney, isNullOrUndefined, NumberHolder, padInt, randSeedInt } from "#app/utils/common";
|
||||
import { getEnumKeys, getEnumValues } from "#app/utils/enums";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { BerryType } from "#enums/berry-type";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
|
@ -19,7 +19,8 @@ import { MoveResult } from "#enums/move-result";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import Overrides from "#app/overrides";
|
||||
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 { ArenaTagType } from "#enums/arena-tag-type";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
|
@ -9,7 +9,8 @@ import type PokemonSpecies from "#app/data/pokemon-species";
|
||||
import { getPokemonSpecies } from "#app/utils/pokemon-utils";
|
||||
import { allSpecies } from "#app/data/data-lists";
|
||||
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 PokemonData from "#app/system/pokemon-data";
|
||||
import PersistentModifierData from "#app/system/modifier-data";
|
||||
|
@ -1,6 +1,7 @@
|
||||
import i18next from "i18next";
|
||||
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 { WindowVariant, addWindow } from "./ui-theme";
|
||||
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { UiMode } from "#enums/ui-mode";
|
||||
import { TextStyle, addTextObject, getEggTierTextTint, getTextStyleOptions } from "./text";
|
||||
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 { Egg, getLegendaryGachaSpeciesForTimestamp } from "../data/egg";
|
||||
import { VoucherType, getVoucherTypeIcon } from "../system/voucher";
|
||||
@ -299,7 +300,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
|
||||
|
||||
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 bg = addWindow(0, 0, 56, 22);
|
||||
@ -312,7 +313,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
|
||||
|
||||
this.voucherCountLabels.push(countLabel);
|
||||
|
||||
const iconImage = getVoucherTypeIcon(i as VoucherType);
|
||||
const iconImage = getVoucherTypeIcon(voucher);
|
||||
|
||||
const icon = globalScene.add.sprite(-19, 2, "items", iconImage);
|
||||
icon.setOrigin(0, 0);
|
||||
|
@ -2,7 +2,8 @@ import { bypassLogin } from "#app/global-vars/bypass-login";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { TextStyle, addTextObject, getTextStyleOptions } from "./text";
|
||||
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 { getCookie } from "#app/utils/cookies";
|
||||
import { addWindow, WindowVariant } from "./ui-theme";
|
||||
@ -76,11 +77,9 @@ export default class MenuUiHandler extends MessageUiHandler {
|
||||
{ condition: bypassLogin, options: [MenuOptions.LOG_OUT] },
|
||||
];
|
||||
|
||||
this.menuOptions = getEnumKeys(MenuOptions)
|
||||
.map(m => Number.parseInt(MenuOptions[m]) as MenuOptions)
|
||||
.filter(m => {
|
||||
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
|
||||
});
|
||||
this.menuOptions = getEnumValues(MenuOptions).filter(m => {
|
||||
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
|
||||
});
|
||||
}
|
||||
|
||||
setup(): void {
|
||||
@ -131,11 +130,9 @@ export default class MenuUiHandler extends MessageUiHandler {
|
||||
{ condition: bypassLogin, options: [MenuOptions.LOG_OUT] },
|
||||
];
|
||||
|
||||
this.menuOptions = getEnumKeys(MenuOptions)
|
||||
.map(m => Number.parseInt(MenuOptions[m]) as MenuOptions)
|
||||
.filter(m => {
|
||||
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
|
||||
});
|
||||
this.menuOptions = getEnumValues(MenuOptions).filter(m => {
|
||||
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
|
||||
});
|
||||
|
||||
this.optionSelectText = addTextObject(
|
||||
0,
|
||||
@ -511,11 +508,9 @@ export default class MenuUiHandler extends MessageUiHandler {
|
||||
this.render();
|
||||
super.show(args);
|
||||
|
||||
this.menuOptions = getEnumKeys(MenuOptions)
|
||||
.map(m => Number.parseInt(MenuOptions[m]) as MenuOptions)
|
||||
.filter(m => {
|
||||
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
|
||||
});
|
||||
this.menuOptions = getEnumValues(MenuOptions).filter(m => {
|
||||
return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m));
|
||||
});
|
||||
|
||||
this.menuContainer.setVisible(true);
|
||||
this.setCursor(0);
|
||||
|
@ -58,7 +58,7 @@ import {
|
||||
toReadableString,
|
||||
} from "#app/utils/common";
|
||||
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 type { BiomeTierTod } 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.menuOptions = getEnumKeys(MenuOptions).map(m => Number.parseInt(MenuOptions[m]) as MenuOptions);
|
||||
this.menuOptions = getEnumValues(MenuOptions);
|
||||
|
||||
this.optionSelectText = addBBCodeTextObject(
|
||||
0,
|
||||
@ -707,7 +707,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
||||
|
||||
this.starterAttributes = this.initStarterPrefs();
|
||||
|
||||
this.menuOptions = getEnumKeys(MenuOptions).map(m => Number.parseInt(MenuOptions[m]) as MenuOptions);
|
||||
this.menuOptions = getEnumValues(MenuOptions);
|
||||
|
||||
this.menuContainer.setVisible(true);
|
||||
|
||||
|
@ -6,13 +6,13 @@ import {
|
||||
getLocalizedSpriteKey,
|
||||
rgbHexToRgba,
|
||||
padInt,
|
||||
getEnumValues,
|
||||
fixedInt,
|
||||
isNullOrUndefined,
|
||||
toReadableString,
|
||||
formatStat,
|
||||
getShinyDescriptor,
|
||||
} from "#app/utils/common";
|
||||
import { getEnumValues } from "#app/utils/enums";
|
||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import type { PokemonMove } from "#app/data/moves/pokemon-move";
|
||||
import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters";
|
||||
|
@ -8,11 +8,18 @@ export type nil = null | undefined;
|
||||
|
||||
export const MissingTextureKey = "__MISSING";
|
||||
|
||||
// TODO: Draft tests for these utility functions
|
||||
/**
|
||||
* 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 {
|
||||
return str
|
||||
.replace(/_/g, " ")
|
||||
.split(" ")
|
||||
.map(s => `${s.slice(0, 1)}${s.slice(1).toLowerCase()}`)
|
||||
.map(s => capitalizeFirstLetter(s.toLowerCase()))
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
@ -257,18 +264,6 @@ export function formatStat(stat: number, forHp = false): string {
|
||||
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> {
|
||||
return condition ? promiseFunc() : new Promise<T | null>(resolve => resolve(null));
|
||||
}
|
||||
@ -620,25 +615,3 @@ export function coerceArray<T>(input: T): T extends any[] ? T : [T];
|
||||
export function coerceArray<T>(input: T): T | [T] {
|
||||
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}`);
|
||||
}
|
||||
|
51
src/utils/enums.ts
Normal file
51
src/utils/enums.ts
Normal file
@ -0,0 +1,51 @@
|
||||
// biome-ignore lint/correctness/noUnusedImports: Used for a JSDoc comment
|
||||
import type { EnumOrObject, EnumValues, TSNumericEnum, NormalEnum } from "#app/@types/enum-types";
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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 or reverse mapped, so we can retrieve the keys by filtering out all strings.
|
||||
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.
|
||||
* @remarks
|
||||
* To retrieve the keys of a {@linkcode NormalEnum}, use {@linkcode Object.values} instead.
|
||||
*/
|
||||
// NB: This does not use `EnumValues<E>` due to 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 EnumOrObject} 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 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.
|
||||
*/
|
||||
export function enumValueToKey<T extends EnumOrObject>(object: T, val: T[keyof T]): keyof T {
|
||||
for (const [key, value] of Object.entries(object)) {
|
||||
if (val === value) {
|
||||
return key as keyof T;
|
||||
}
|
||||
}
|
||||
throw new Error(`Invalid value passed to \`enumValueToKey\`! Value: ${val}`);
|
||||
}
|
Loading…
Reference in New Issue
Block a user