UNPKG

isaacscript-common

Version:

Helper functions and features for IsaacScript mods.

244 lines (219 loc) • 9.23 kB
import type { ItemConfigPillEffectClass, ItemConfigPillEffectType, PillEffect, } from "isaac-typescript-definitions"; import { PillColor } from "isaac-typescript-definitions"; import { PILL_COLOR_VALUES } from "../cachedEnumValues"; import { game, itemConfig } from "../core/cachedClasses"; import { FIRST_HORSE_PILL_COLOR, FIRST_PILL_COLOR, LAST_HORSE_PILL_COLOR, LAST_NORMAL_PILL_COLOR, LAST_VANILLA_PILL_EFFECT, } from "../core/constantsFirstLast"; import { PHD_PILL_CONVERSIONS_MAP } from "../maps/PHDPillConversionsMap"; import { FALSE_PHD_PILL_CONVERSIONS_MAP } from "../maps/falsePHDPillConversionsMap"; import { DEFAULT_PILL_EFFECT_CLASS, PILL_EFFECT_CLASSES, } from "../objects/pillEffectClasses"; import { DEFAULT_PILL_EFFECT_NAME, PILL_EFFECT_NAMES, } from "../objects/pillEffectNames"; import { PILL_EFFECT_TYPE_TO_PILL_EFFECTS } from "../objects/pillEffectTypeToPillEffects"; import { DEFAULT_PILL_EFFECT_TYPE, PILL_EFFECT_TYPES, } from "../objects/pillEffectTypes"; import { asNumber, asPillColor, asPillEffect } from "./types"; import { iRange } from "./utils"; /** * Add this to a `PillColor` to get the corresponding giant pill color. * * Corresponds to the vanilla `PillColor.GIANT_FLAG` value. * * 1 << 11 */ const HORSE_PILL_COLOR_ADJUSTMENT = 2048; /** * Helper function to get an array with every non-null pill color. This includes all gold colors and * all horse colors. */ export function getAllPillColors(): readonly PillColor[] { return PILL_COLOR_VALUES.slice(1); // Remove `PillColor.NULL` } /** * Helper function to get the associated pill effect after False PHD is acquired. If a pill effect * is not altered by False PHD, then the same pill effect will be returned. */ export function getFalsePHDPillEffect(pillEffect: PillEffect): PillEffect { const convertedPillEffect = FALSE_PHD_PILL_CONVERSIONS_MAP.get(pillEffect); return convertedPillEffect ?? pillEffect; } /** * Helper function to get the corresponding horse pill color from a normal pill color. * * For example, passing `PillColor.BLUE_BLUE` would result in 2049, which is the value that * corresponds to the horse pill color for blue/blue. * * If passed a horse pill color, this function will return the unmodified pill color. */ export function getHorsePillColor(pillColor: PillColor): PillColor { return isHorsePill(pillColor) ? pillColor : pillColor + HORSE_PILL_COLOR_ADJUSTMENT; } /** Helper function to get an array with every non-gold horse pill color. */ export function getHorsePillColors(): readonly PillColor[] { return iRange(FIRST_HORSE_PILL_COLOR, LAST_HORSE_PILL_COLOR); } /** * Helper function to get the corresponding normal pill color from a horse pill color. * * For example, passing 2049 would result in `PillColor.BLUE_BLUE`. * * If called with a non-horse pill color, this function will return back the same color. */ export function getNormalPillColorFromHorse(pillColor: PillColor): PillColor { return isHorsePill(pillColor) ? asPillColor(pillColor - HORSE_PILL_COLOR_ADJUSTMENT) : pillColor; } /** Helper function to get an array with every non-gold and non-horse pill color. */ export function getNormalPillColors(): readonly PillColor[] { return iRange(FIRST_PILL_COLOR, LAST_NORMAL_PILL_COLOR); } /** * Helper function to get the associated pill effect after PHD is acquired. If a pill effect is not * altered by PHD, then the same pill effect will be returned. */ export function getPHDPillEffect(pillEffect: PillEffect): PillEffect { const convertedPillEffect = PHD_PILL_CONVERSIONS_MAP.get(pillEffect); return convertedPillEffect ?? pillEffect; } /** * Helper function to get the corresponding pill color from an effect by repeatedly using the * `ItemPool.GetPillEffect` method. * * Note that this will return the corresponding effect even if the passed pill color is not yet * identified by the player. * * Returns `PillColor.NULL` if there is the corresponding pill color cannot be found. * * This function is especially useful in the `POST_USE_PILL` callback, since at that point, the used * pill is already consumed, and the callback only passes the effect. In this specific circumstance, * consider using the `POST_USE_PILL_FILTER` callback instead of the `POST_USE_PILL` callback, since * it correctly passes the color and handles the case of horse pills. */ export function getPillColorFromEffect(pillEffect: PillEffect): PillColor { const itemPool = game.GetItemPool(); const normalPillColors = getNormalPillColors(); for (const normalPillColor of normalPillColors) { const normalPillEffect = itemPool.GetPillEffect(normalPillColor); if (normalPillEffect === pillEffect) { return normalPillColor; } } return PillColor.NULL; } /** * Helper function to get a pill effect class from a PillEffect enum value. In this context, the * class is equal to the numerical prefix in the "class" tag in the "pocketitems.xml" file. Use the * `getPillEffectType` helper function to determine whether the pill effect is positive, negative, * or neutral. * * Due to limitations in the API, this function will not work properly for modded pill effects, and * will always return `DEFAULT_PILL_EFFECT_CLASS` in those cases. */ export function getPillEffectClass( pillEffect: PillEffect, ): ItemConfigPillEffectClass { // `ItemConfigPillEffect` does not contain the "class" tag, so we must manually compile a map of // pill effect classes. Modded pill effects are not included in the map. const pillEffectClass = PILL_EFFECT_CLASSES[pillEffect]; // Handle modded pill effects. // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition return pillEffectClass ?? DEFAULT_PILL_EFFECT_CLASS; } /** * Helper function to get a pill effect name from a `PillEffect`. Returns "Unknown" if the provided * pill effect is not valid. * * This function works for both vanilla and modded pill effects. * * For example, `getPillEffectName(PillEffect.BAD_GAS)` would return "Bad Gas". */ export function getPillEffectName(pillEffect: PillEffect): string { // `ItemConfigPillEffect.Name` is bugged with vanilla pill effects on patch v1.7.6, so we use a // hard-coded map as a workaround. const pillEffectName = PILL_EFFECT_NAMES[pillEffect]; // Handle modded pill effects. // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (pillEffectName !== undefined) { return pillEffectName; } const itemConfigPillEffect = itemConfig.GetPillEffect(pillEffect); if (itemConfigPillEffect !== undefined) { return itemConfigPillEffect.Name; } return DEFAULT_PILL_EFFECT_NAME; } /** * Helper function to get a pill effect type from a `PillEffect` enum value. In this context, the * type is equal to positive, negative, or neutral. This is derived from the suffix of the "class" * tag in the "pocketitems.xml" file. Use the `getPillEffectClass` helper function to determine the * "power" of the pill. * * Due to limitations in the API, this function will not work properly for modded pill effects, and * will always return `DEFAULT_PILL_EFFECT_TYPE` in those cases. */ export function getPillEffectType( pillEffect: PillEffect, ): ItemConfigPillEffectType { // `ItemConfigPillEffect` does not contain the "class" tag, so we must manually compile a map of // pill effect classes. Modded pill effects are not included in the map. const pillEffectType = PILL_EFFECT_TYPES[pillEffect]; // Handle modded pill effects. // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition return pillEffectType ?? DEFAULT_PILL_EFFECT_TYPE; } export function getVanillaPillEffectsOfType( pillEffectType: ItemConfigPillEffectType, ): readonly PillEffect[] { return PILL_EFFECT_TYPE_TO_PILL_EFFECTS[pillEffectType]; } /** Helper function to see if the given pill color is either a gold pill or a horse gold pill. */ export function isGoldPill(pillColor: PillColor): boolean { return pillColor === PillColor.GOLD || pillColor === PillColor.HORSE_GOLD; } /** * Helper function to see if the given pill color is a horse pill. * * Under the hood, this checks for `pillColor > 2048`. */ export function isHorsePill(pillColor: PillColor): boolean { return asNumber(pillColor) > HORSE_PILL_COLOR_ADJUSTMENT; } export function isModdedPillEffect(pillEffect: PillEffect): boolean { return !isVanillaPillEffect(pillEffect); } /** * Helper function to see if the given pill color is not a gold pill and not a horse pill and not * the null value. * * Under the hood, this checks using the `FIRST_PILL_COLOR` and `LAST_NORMAL_PILL_COLOR` constants. */ export function isNormalPillColor(pillColor: PillColor): boolean { return pillColor >= FIRST_PILL_COLOR && pillColor <= LAST_NORMAL_PILL_COLOR; } export function isValidPillEffect(pillEffect: int): pillEffect is PillEffect { const potentialPillEffect = asPillEffect(pillEffect); const itemConfigPillEffect = itemConfig.GetPillEffect(potentialPillEffect); return itemConfigPillEffect !== undefined; } export function isVanillaPillEffect(pillEffect: PillEffect): boolean { return pillEffect <= LAST_VANILLA_PILL_EFFECT; }