isaacscript-common
Version:
Helper functions and features for IsaacScript mods.
243 lines (242 loc) • 11 kB
JavaScript
;
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);
}