UNPKG

isaacscript-common

Version:

Helper functions and features for IsaacScript mods.

243 lines (242 loc) • 11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getAliveBosses = getAliveBosses; exports.getAllBosses = getAllBosses; exports.getAllNonStoryBosses = getAllNonStoryBosses; exports.getBossID = getBossID; exports.getBossIDFromEntityTypeVariant = getBossIDFromEntityTypeVariant; exports.getBossIDsForStage = getBossIDsForStage; exports.getBossIDsForStageID = getBossIDsForStageID; exports.getBossName = getBossName; exports.getBossStageIDs = getBossStageIDs; exports.getBosses = getBosses; exports.getEntityTypeVariantFromBossID = getEntityTypeVariantFromBossID; exports.isRepentanceBoss = isRepentanceBoss; exports.isSin = isSin; exports.spawnBoss = spawnBoss; exports.spawnBossWithSeed = spawnBossWithSeed; const isaac_typescript_definitions_1 = require("isaac-typescript-definitions"); const cachedClasses_1 = require("../core/cachedClasses"); const constants_1 = require("../core/constants"); const entityTypeVariantToBossIDMap_1 = require("../maps/entityTypeVariantToBossIDMap"); const bossIDToEntityTypeVariant_1 = require("../objects/bossIDToEntityTypeVariant"); const bossNames_1 = require("../objects/bossNames"); const bossSets_1 = require("../sets/bossSets"); const repentanceBossIDsSet_1 = require("../sets/repentanceBossIDsSet"); const sinEntityTypesSet_1 = require("../sets/sinEntityTypesSet"); const ReadonlySet_1 = require("../types/ReadonlySet"); const entities_1 = require("./entities"); const entitiesSpecific_1 = require("./entitiesSpecific"); const npcs_1 = require("./npcs"); const rng_1 = require("./rng"); const rooms_1 = require("./rooms"); const utils_1 = require("./utils"); const BOSSES_THAT_REQUIRE_MULTIPLE_SPAWNS = new ReadonlySet_1.ReadonlySet([ isaac_typescript_definitions_1.EntityType.LARRY_JR, // 19 (and The Hollow / Tuff Twins / The Shell) isaac_typescript_definitions_1.EntityType.CHUB, // 28 (and C.H.A.D. / The Carrion Queen) isaac_typescript_definitions_1.EntityType.LOKI, // 69 (only for Lokii) isaac_typescript_definitions_1.EntityType.GURGLING, // 237 (and Turdling) isaac_typescript_definitions_1.EntityType.TURDLET, // 918 ]); const DEFAULT_BOSS_MULTI_SEGMENTS = 4; /** * Helper function to get all of the non-dead bosses in the room. * * This function will not include bosses on an internal blacklist, such as Death's scythes or Big * Horn holes. * * @param entityType Optional. If specified, will only get the bosses that match the type. Default * is -1, which matches every type. * @param variant Optional. If specified, will only get the bosses that match the variant. Default * is -1, which matches every variant. * @param subType Optional. If specified, will only get the bosses that match the sub-type. Default * is -1, which matches every sub-type. * @param ignoreFriendly Optional. Default is false. */ function getAliveBosses(entityType = -1, variant = -1, subType = -1, ignoreFriendly = false) { const aliveNPCs = (0, npcs_1.getAliveNPCs)(entityType, variant, subType, ignoreFriendly); return aliveNPCs.filter((aliveNPC) => aliveNPC.IsBoss()); } /** * Helper function to get an array with every boss in the game. This is derived from the `BossID` * enum. * * This includes: * - Ultra Greed * - Ultra Greedier * * This does not include: * - mini-bosses (e.g. Ultra Pride, Krampus) * - bosses that do not appear in Boss Rooms (e.g. Uriel, Gabriel) * - the second phase of multi-phase bosses (e.g. Mega Satan 2) * - sub-bosses of The Beast fight (e.g. Ultra Famine, Ultra Pestilence, Ultra War, Ultra Death) * - bosses that do not have any Boss Rooms defined due to being unfinished (e.g. Raglich) * * Also see the `getAllNonStoryBosses` function. */ function getAllBosses() { return bossSets_1.ALL_BOSSES; } /** * Helper function to get an array with every boss in the game. This is derived from the `BossID` * enum. This is the same thing as the `getAllBosses` helper function, but with story bosses * filtered out. */ function getAllNonStoryBosses() { return bossSets_1.NON_STORY_BOSSES; } /** * Helper function to get the boss ID corresponding to the current room. Returns undefined if the * current room is not a Boss Room. * * Use this instead of the vanilla `Room.GetBossID` method since it has a saner return type and it * correctly handles Dogma, The Beast, and Ultra Greedier. */ function getBossID() { if ((0, rooms_1.inDogmaRoom)()) { return isaac_typescript_definitions_1.BossID.DOGMA; } if ((0, rooms_1.inBeastRoom)()) { return isaac_typescript_definitions_1.BossID.BEAST; } const room = cachedClasses_1.game.GetRoom(); // eslint-disable-next-line @typescript-eslint/no-deprecated const bossID = room.GetBossID(); if (bossID === 0) { return undefined; } // The Ultra Greed room holds both Ultra Greed and Ultra Greedier. if (bossID === isaac_typescript_definitions_1.BossID.ULTRA_GREED && (0, entities_1.doesEntityExist)(isaac_typescript_definitions_1.EntityType.ULTRA_GREED, isaac_typescript_definitions_1.UltraGreedVariant.ULTRA_GREEDIER)) { return isaac_typescript_definitions_1.BossID.ULTRA_GREEDIER; } return bossID; } function getBossIDFromEntityTypeVariant(entityType, variant) { // First, handle some special cases. if (entityType === isaac_typescript_definitions_1.EntityType.HORSEMAN_HEAD) { return isaac_typescript_definitions_1.BossID.HEADLESS_HORSEMAN; } const entityTypeVariant = `${entityType}.${variant}`; return entityTypeVariantToBossIDMap_1.ENTITY_TYPE_VARIANT_TO_BOSS_ID_MAP.get(entityTypeVariant); } /** * Helper function to get the set of vanilla bosses for a particular stage across all of the stage * types. For example, specifying `LevelStage.BASEMENT_2` will return a set with all of the bosses * for Basement, Cellar, Burning Basement, Downpour, and Dross. * * Also see the `getAllBossesSet` and `getBossIDsForStageID` functions. */ function getBossIDsForStage(stage) { return bossSets_1.STAGE_TO_COMBINED_BOSS_SET_MAP.get(stage); } /** * Helper function to get the set of vanilla bosses that can randomly appear on a particular stage * ID. * * Also see the `getAllBossesSet` and `getBossIDsForStage` functions. */ function getBossIDsForStageID(stageID) { return bossSets_1.STAGE_ID_TO_BOSS_IDS.get(stageID); } /** * Helper function to get the proper English name for a boss. For example, the name for * `BossID.WRETCHED` (36) is "The Wretched". */ function getBossName(bossID) { // Handle modded boss IDs. // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition return bossNames_1.BOSS_NAMES[bossID] ?? bossNames_1.DEFAULT_BOSS_NAME; } /** Helper function to get the set of stage IDs that a particular boss naturally appears in. */ function getBossStageIDs(bossID) { return bossSets_1.BOSS_ID_TO_STAGE_IDS[bossID]; } /** * Helper function to get all of the bosses in the room. * * @param entityType Optional. If specified, will only get the bosses that match the type. Default * is -1, which matches every type. * @param variant Optional. If specified, will only get the bosses that match the variant. Default * is -1, which matches every variant. * @param subType Optional. If specified, will only get the bosses that match the sub-type. Default * is -1, which matches every sub-type. * @param ignoreFriendly Optional. Default is false. */ function getBosses(entityType, variant, subType, ignoreFriendly = false) { const npcs = (0, entitiesSpecific_1.getNPCs)(entityType, variant, subType, ignoreFriendly); return npcs.filter((npc) => npc.IsBoss()); } function getEntityTypeVariantFromBossID(bossID) { return bossIDToEntityTypeVariant_1.BOSS_ID_TO_ENTITY_TYPE_VARIANT[bossID]; } /** * Helper function to check if a boss is only found on a Repentance floor such as Dross, Mines, and * so on. * * For example, The Pile is a boss that was added in Repentance, but since it can appear in * Necropolis, it is not considered a Repentance boss for the purposes of this function. */ function isRepentanceBoss(bossID) { return repentanceBossIDsSet_1.REPENTANCE_ONLY_BOSS_IDS_SET.has(bossID); } /** Helper function to check if the provided NPC is a Sin miniboss, such as Sloth or Lust. */ function isSin(npc) { return sinEntityTypesSet_1.SIN_ENTITY_TYPES_SET.has(npc.Type); } function getNumBossSegments(entityType, variant, numSegments) { if (numSegments !== undefined) { return numSegments; } switch (entityType) { // 28 case isaac_typescript_definitions_1.EntityType.CHUB: { // Chub is always composed of 3 segments. return 3; } // 69 case isaac_typescript_definitions_1.EntityType.LOKI: { // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison return variant === isaac_typescript_definitions_1.LokiVariant.LOKII ? 2 : 1; } // 237 case isaac_typescript_definitions_1.EntityType.GURGLING: { // Gurglings & Turdlings are always encountered in groups of 2. return 2; } default: { return DEFAULT_BOSS_MULTI_SEGMENTS; } } } /** * Helper function to spawn a boss. * * Use this function instead of `spawnNPC` since it handles automatically spawning multiple segments * for multi-segment bosses. * * By default, this will spawn Chub (and his variants) with 3 segments, Lokii with 2 copies, * Gurglings/Turdlings with 2 copies, and other multi-segment bosses with 4 segments. You can * customize this via the "numSegments" argument. */ function spawnBoss(entityType, variant, subType, positionOrGridIndex, velocity = constants_1.VectorZero, spawner, seedOrRNG, numSegments) { const seed = (0, rng_1.isRNG)(seedOrRNG) ? seedOrRNG.Next() : seedOrRNG; const npc = (0, entitiesSpecific_1.spawnNPC)(entityType, variant, subType, positionOrGridIndex, velocity, spawner, seed); if (BOSSES_THAT_REQUIRE_MULTIPLE_SPAWNS.has(entityType)) { const numBossSegments = getNumBossSegments(entityType, variant, numSegments); const remainingSegmentsToSpawn = numBossSegments - 1; (0, utils_1.repeat)(remainingSegmentsToSpawn, () => { (0, entitiesSpecific_1.spawnNPC)(entityType, variant, subType, positionOrGridIndex, velocity, spawner, seed); }); } return npc; } /** * Helper function to spawn a boss with a specific seed. * * For more information, see the documentation for the `spawnBoss` function. */ function spawnBossWithSeed(entityType, variant, subType, positionOrGridIndex, seedOrRNG, velocity = constants_1.VectorZero, spawner, numSegments) { const seed = (0, rng_1.isRNG)(seedOrRNG) ? seedOrRNG.Next() : seedOrRNG; return spawnBoss(entityType, variant, subType, positionOrGridIndex, velocity, spawner, seed, numSegments); }