UNPKG

isaacscript-common

Version:

Helper functions and features for IsaacScript mods.

581 lines (580 loc) • 29.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.clearCollectibleSprite = clearCollectibleSprite; exports.collectibleHasCacheFlag = collectibleHasCacheFlag; exports.collectibleSpriteEquals = collectibleSpriteEquals; exports.getCollectibleChargeType = getCollectibleChargeType; exports.getCollectibleDescription = getCollectibleDescription; exports.getCollectibleDevilCoinPrice = getCollectibleDevilCoinPrice; exports.getCollectibleDevilHeartPrice = getCollectibleDevilHeartPrice; exports.getCollectibleGfxFilename = getCollectibleGfxFilename; exports.getCollectibleInitCharge = getCollectibleInitCharge; exports.getCollectibleItemType = getCollectibleItemType; exports.getCollectibleMaxCharges = getCollectibleMaxCharges; exports.getCollectibleName = getCollectibleName; exports.getCollectiblePedestalType = getCollectiblePedestalType; exports.getCollectibleQuality = getCollectibleQuality; exports.getCollectibleTags = getCollectibleTags; exports.getVanillaCollectibleTypesOfQuality = getVanillaCollectibleTypesOfQuality; exports.isActiveCollectible = isActiveCollectible; exports.isBlindCollectible = isBlindCollectible; exports.isFamiliarCollectible = isFamiliarCollectible; exports.isGlitchedCollectible = isGlitchedCollectible; exports.isHiddenCollectible = isHiddenCollectible; exports.isModdedCollectibleType = isModdedCollectibleType; exports.isPassiveOrFamiliarCollectible = isPassiveOrFamiliarCollectible; exports.isQuality = isQuality; exports.isSingleUseCollectible = isSingleUseCollectible; exports.isValidCollectibleType = isValidCollectibleType; exports.isVanillaCollectibleType = isVanillaCollectibleType; exports.newCollectibleSprite = newCollectibleSprite; exports.preventCollectibleRotation = preventCollectibleRotation; exports.removeCollectiblePickupDelay = removeCollectiblePickupDelay; exports.setCollectibleBlind = setCollectibleBlind; exports.setCollectibleEmpty = setCollectibleEmpty; exports.setCollectibleGlitched = setCollectibleGlitched; exports.setCollectiblePedestalType = setCollectiblePedestalType; exports.setCollectibleSprite = setCollectibleSprite; exports.setCollectibleSubType = setCollectibleSubType; exports.setCollectiblesRerolledForItemTracker = setCollectiblesRerolledForItemTracker; const isaac_typescript_definitions_1 = require("isaac-typescript-definitions"); const cachedClasses_1 = require("../core/cachedClasses"); const constants_1 = require("../core/constants"); const constantsFirstLast_1 = require("../core/constantsFirstLast"); const constantsVanilla_1 = require("../core/constantsVanilla"); const collectibleDescriptions_1 = require("../objects/collectibleDescriptions"); const collectibleNames_1 = require("../objects/collectibleNames"); const singleUseActiveCollectibleTypesSet_1 = require("../sets/singleUseActiveCollectibleTypesSet"); const entities_1 = require("./entities"); const flag_1 = require("./flag"); const pickupVariants_1 = require("./pickupVariants"); const sprites_1 = require("./sprites"); const types_1 = require("./types"); const utils_1 = require("./utils"); const COLLECTIBLE_ANM2_PATH = "gfx/005.100_collectible.anm2"; const DEFAULT_COLLECTIBLE_PRICE = 15; /** Glitched items start at id 4294967295 (the final 32-bit integer) and increment backwards. */ const GLITCHED_ITEM_THRESHOLD = 4_000_000_000; const QUALITY_TO_VANILLA_COLLECTIBLE_TYPES_MAP = (() => { const qualityToCollectibleTypesMap = new Map(); for (const quality of constants_1.QUALITIES) { const collectibleTypes = []; for (const collectibleType of constantsVanilla_1.VANILLA_COLLECTIBLE_TYPES) { const collectibleTypeQuality = getCollectibleQuality(collectibleType); if (collectibleTypeQuality === quality) { collectibleTypes.push(collectibleType); } } qualityToCollectibleTypesMap.set(quality, collectibleTypes); } return qualityToCollectibleTypesMap; })(); /** The `isBlindCollectible` function needs a reference sprite to work properly. */ const questionMarkSprite = (() => { const sprite = Sprite(); sprite.Load("gfx/005.100_collectible.anm2", false); sprite.ReplaceSpritesheet(1, "gfx/items/collectibles/questionmark.png"); sprite.LoadGraphics(); return sprite; })(); function clearCollectibleSprite(collectible) { if (!(0, pickupVariants_1.isCollectible)(collectible)) { const entityID = (0, entities_1.getEntityID)(collectible); error(`The "clearCollectibleSprite" function was given a non-collectible: ${entityID}`); } setCollectibleSprite(collectible, undefined); } /** Helper function to check in the item config if a given collectible has a given cache flag. */ function collectibleHasCacheFlag(collectibleOrCollectibleType, cacheFlag) { const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "collectibleHasCacheFlag"); const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); if (itemConfigItem === undefined) { return false; } return (0, flag_1.hasFlag)(itemConfigItem.CacheFlags, cacheFlag); } /** Helper function to check if two collectible sprites have the same sprite sheet loaded. */ function collectibleSpriteEquals(sprite1, sprite2) { // We start at negative 40 texels upwards, as by default we assume a collectible that is sitting // on a pedestal. We finish at positive 10 texels downwards, in order to make comparing shop items // more accurate. const xStart = -1; const xFinish = 1; const xIncrement = 1; const yStart = -40; const yFinish = 10; const yIncrement = 3; return (0, sprites_1.spriteEquals)(sprite1, sprite2, isaac_typescript_definitions_1.CollectibleSpriteLayer.HEAD, xStart, xFinish, xIncrement, yStart, yFinish, yIncrement); } /** * Helper function to get the charge type that a collectible has. Returns * `ItemConfigChargeType.NORMAL` if the provided collectible type was not valid. */ function getCollectibleChargeType(collectibleOrCollectibleType) { const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "getCollectibleChargeType"); const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); if (itemConfigItem === undefined) { return isaac_typescript_definitions_1.ItemConfigChargeType.NORMAL; } return itemConfigItem.ChargeType; } /** * Helper function to get the in-game description for a collectible. Returns "Unknown" if the * provided collectible type was not valid. * * This function works for both vanilla and modded collectibles. */ function getCollectibleDescription(collectibleOrCollectibleType) { const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "getCollectibleDescription"); // "ItemConfigItem.Description" is bugged with vanilla items on patch v1.7.6, so we use a // hard-coded map as a workaround. const collectibleDescription = collectibleDescriptions_1.COLLECTIBLE_DESCRIPTIONS[collectibleType]; if (collectibleDescription !== undefined) { return collectibleDescription; } const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); if (itemConfigItem !== undefined) { return itemConfigItem.Description; } return collectibleDescriptions_1.DEFAULT_COLLECTIBLE_DESCRIPTION; } /** * Helper function to get the coin cost that a collectible item would be if it were being offered in * a Devil Room deal. Returns 0 if passed `CollectibleType.NULL`. */ function getCollectibleDevilCoinPrice(collectibleOrCollectibleType) { const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "getCollectibleDescription"); if (collectibleType === isaac_typescript_definitions_1.CollectibleType.NULL) { return 0; } const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); if (itemConfigItem === undefined) { return DEFAULT_COLLECTIBLE_PRICE; } return itemConfigItem.DevilPrice * DEFAULT_COLLECTIBLE_PRICE; } /** * Helper function to get the heart cost that a collectible item would be if it were being offered * in a Devil Room deal. Returns 0 if passed `CollectibleType.NULL`. */ function getCollectibleDevilHeartPrice(collectibleOrCollectibleType, player) { const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "getCollectibleDevilHeartPrice"); const maxHearts = player.GetMaxHearts(); if (collectibleType === isaac_typescript_definitions_1.CollectibleType.NULL) { return 0; } if (maxHearts === 0) { return isaac_typescript_definitions_1.PickupPrice.THREE_SOUL_HEARTS; } const defaultCollectiblePrice = isaac_typescript_definitions_1.PickupPrice.ONE_HEART; const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); if (itemConfigItem === undefined) { return defaultCollectiblePrice; } const twoHeartPrice = maxHearts === 2 ? isaac_typescript_definitions_1.PickupPrice.ONE_HEART_AND_TWO_SOUL_HEARTS : isaac_typescript_definitions_1.PickupPrice.TWO_HEARTS; return itemConfigItem.DevilPrice === 2 ? twoHeartPrice : isaac_typescript_definitions_1.PickupPrice.ONE_HEART; } /** * Helper function to get the path to a collectible PNG file. Returns the path to the question mark * sprite (i.e. from Curse of the Blind) if the provided collectible type was not valid. * * If you intentionally want the path to the question mark sprite, pass -1 as the collectible type. * * Note that this does not return the file name, but the full path to the collectible's PNG file. * The function is named "GfxFilename" to correspond to the associated `ItemConfigItem.GfxFileName` * field. */ function getCollectibleGfxFilename(collectibleOrCollectibleType) { if (collectibleOrCollectibleType === -1) { return constants_1.BLIND_ITEM_PNG_PATH; } const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "getCollectibleGfxFilename"); const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); if (itemConfigItem === undefined) { return constants_1.BLIND_ITEM_PNG_PATH; } return itemConfigItem.GfxFileName; } /** * Helper function to get the initial amount of charges that a collectible has. In most cases, when * picking up an active collectible for the first time, it will be fully charged, which corresponds * to an `InitCharge` value of -1. However, in some cases, this may be different. For example, * Eden's Soul starts without any charges, so it has an `InitCharge` value of 0. * * This function returns 0 if the provided collectible type was not valid. This function returns -1 * if the provided collectible type was not an active collectible. */ function getCollectibleInitCharge(collectibleOrCollectibleType) { const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "getCollectibleInitCharge"); const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); if (itemConfigItem === undefined) { return 0; } return itemConfigItem.InitCharge; } /** * Helper function to get the `ItemType` of a collectible. Returns `ItemType.ITEM_NULL` if the * provided collectible type was not valid. */ function getCollectibleItemType(collectibleOrCollectibleType) { const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "getCollectibleItemType"); const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); if (itemConfigItem === undefined) { return isaac_typescript_definitions_1.ItemType.NULL; } return itemConfigItem.Type; } /** * Helper function to get the maximum amount of charges that a collectible has. Returns 0 if the * provided collectible type was not valid. */ function getCollectibleMaxCharges(collectibleOrCollectibleType) { const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "getCollectibleMaxCharges"); const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); if (itemConfigItem === undefined) { return 0; } return itemConfigItem.MaxCharges; } /** * Helper function to get the name of a collectible. Returns "Unknown" if the provided collectible * type is not valid. * * This function works for both vanilla and modded collectibles. * * For example, `getCollectibleName(CollectibleType.SAD_ONION)` would return "Sad Onion". */ function getCollectibleName(collectibleOrCollectibleType) { const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "getCollectibleName"); // "ItemConfigItem.Name" is bugged with vanilla items on patch v1.7.6, so we use a hard-coded map // as a workaround. const collectibleName = collectibleNames_1.COLLECTIBLE_NAMES[collectibleType]; if (collectibleName !== undefined) { return collectibleName; } const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); if (itemConfigItem !== undefined) { return itemConfigItem.Name; } return collectibleNames_1.DEFAULT_COLLECTIBLE_NAME; } /** * Helper function to get the "pedestal type" of a collectible. For example, it might be sitting on * top of a broken Blood Donation Machine, or it might be sitting on top of an opened Spiked Chest. */ function getCollectiblePedestalType(collectible) { if (!(0, pickupVariants_1.isCollectible)(collectible)) { const entityID = (0, entities_1.getEntityID)(collectible); error(`The "getCollectiblePedestalType" function was given a non-collectible: ${entityID}`); } const sprite = collectible.GetSprite(); return sprite.GetOverlayFrame(); } /** * Helper function to get a collectible's quality, which ranges from 0 to 4 (inclusive). For * example, Mom's Knife has a quality of 4. Returns 0 if the provided collectible type was not * valid. */ function getCollectibleQuality(collectibleOrCollectibleType) { const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "getCollectibleQuality"); const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); if (itemConfigItem === undefined) { return 0; } return itemConfigItem.Quality; } /** * Helper function to get the tags of a collectible (which is the composition of zero or more * `ItemConfigTag`). Returns 0 if the provided collectible type is not valid. * * For example: * * ```ts * const collectibleType = CollectibleType.SAD_ONION; * const itemConfigTags = getCollectibleTags(collectibleType); // itemConfigTags is "18350080" * ``` */ function getCollectibleTags(collectibleOrCollectibleType) { const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "getCollectibleTags"); const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); return itemConfigItem === undefined ? isaac_typescript_definitions_1.ItemConfigTagZero : itemConfigItem.Tags; } /** * Returns an array containing every vanilla collectible type with the given quality. * * Note that this function will only return vanilla collectible types. To handle modded collectible * types, use the `getCollectibleTypesOfQuality` helper function instead. */ function getVanillaCollectibleTypesOfQuality(quality) { const collectibleTypes = QUALITY_TO_VANILLA_COLLECTIBLE_TYPES_MAP.get(quality); (0, utils_1.assertDefined)(collectibleTypes, `Failed to find the vanilla collectible types corresponding to quality: ${quality}`); return collectibleTypes; } /** Returns true if the item type in the item config is equal to `ItemType.ACTIVE`. */ function isActiveCollectible(collectibleType) { const itemType = getCollectibleItemType(collectibleType); return itemType === isaac_typescript_definitions_1.ItemType.ACTIVE; } /** * Returns true if the collectible has a red question mark sprite. * * Note that this function will not work properly in a render callback with the `RenderMode` set to * `RenderMode.WATER_REFLECT`. If this is detected, this function will throw a run-time error. */ function isBlindCollectible(collectible) { if (!(0, pickupVariants_1.isCollectible)(collectible)) { const entityID = (0, entities_1.getEntityID)(collectible); error(`The "isBlindCollectible" function was given a non-collectible: ${entityID}`); } const room = cachedClasses_1.game.GetRoom(); const renderMode = room.GetRenderMode(); if (renderMode === isaac_typescript_definitions_1.RenderMode.WATER_REFLECT) { error('The "isBlindCollectible" function will not work properly in a render callback with the render mode equal to "RenderMode.WATER_REFLECT". Make sure that you properly account for this case if you are calling this function in a render callback.'); } const sprite = collectible.GetSprite(); const animation = sprite.GetAnimation(); const frame = sprite.GetFrame(); questionMarkSprite.SetFrame(animation, frame); return collectibleSpriteEquals(sprite, questionMarkSprite); } /** Returns true if the item type in the item config is equal to `ItemType.FAMILIAR`. */ function isFamiliarCollectible(collectibleType) { const itemType = getCollectibleItemType(collectibleType); return itemType === isaac_typescript_definitions_1.ItemType.FAMILIAR; } /** * Returns whether the given collectible is a "glitched" item. All items are replaced by glitched * items once a player has TMTRAINER. However, glitched items can also "naturally" appear in secret * rooms and I AM ERROR rooms if the "Corrupted Data" achievement is unlocked. * * Under the hood, this checks if the sub-type of the collectible is greater than 4,000,000,000. */ function isGlitchedCollectible(collectible) { return (collectible.Variant === isaac_typescript_definitions_1.PickupVariant.COLLECTIBLE && collectible.SubType > GLITCHED_ITEM_THRESHOLD); } /** * Returns true if the collectible has the "Hidden" attribute in the item config. * * Hidden collectibles will not show up in any pools and Eden will not start with them. */ function isHiddenCollectible(collectibleOrCollectibleType) { const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "isHiddenCollectible"); const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); return itemConfigItem !== undefined && itemConfigItem.Hidden; } function isModdedCollectibleType(collectibleType) { return !isVanillaCollectibleType(collectibleType); } /** * Returns true if the item type in the item config is equal to `ItemType.ITEM_PASSIVE` or * `ItemType.ITEM_FAMILIAR`. */ function isPassiveOrFamiliarCollectible(collectibleOrCollectibleType) { const collectibleType = getCollectibleTypeFromArg(collectibleOrCollectibleType, "isPassiveCollectible"); const itemType = getCollectibleItemType(collectibleType); return itemType === isaac_typescript_definitions_1.ItemType.PASSIVE || itemType === isaac_typescript_definitions_1.ItemType.FAMILIAR; } /** Helper function to check if a collectible type is a particular quality. */ function isQuality(collectibleOrCollectibleType, quality) { const actualQuality = getCollectibleQuality(collectibleOrCollectibleType); return quality === actualQuality; } /** * Helper function to determine if a particular collectible will disappear from the player's * inventory upon use. Note that this will not work will modded collectibles, as there is no way to * dynamically know if a modded collectible will disappear. */ function isSingleUseCollectible(collectibleType) { return singleUseActiveCollectibleTypesSet_1.SINGLE_USE_ACTIVE_COLLECTIBLE_TYPES_SET.has(collectibleType); } function isValidCollectibleType(collectibleType) { const potentialCollectibleType = (0, types_1.asCollectibleType)(collectibleType); const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(potentialCollectibleType); return itemConfigItem !== undefined; } function isVanillaCollectibleType(collectibleType) { return collectibleType <= constantsFirstLast_1.LAST_VANILLA_COLLECTIBLE_TYPE; } /** * Helper function to generate a new sprite based on a collectible. If the provided collectible type * is invalid, a sprite with a Curse of the Blind question mark will be returned. * * If you intentionally want a question mark sprite, pass -1 as the collectible type. */ function newCollectibleSprite(collectibleType) { const sprite = Sprite(); sprite.Load(COLLECTIBLE_ANM2_PATH, false); // We want to clear the pedestal layers so that the returned sprite only has the collectible // image. We can't use the `Sprite.Reset` method for this purpose because that would unload the // anm2 file. (0, sprites_1.clearSprite)(sprite); const gfxFileName = getCollectibleGfxFilename(collectibleType); sprite.ReplaceSpritesheet(isaac_typescript_definitions_1.CollectibleSpriteLayer.HEAD, gfxFileName); sprite.LoadGraphics(); const defaultAnimation = sprite.GetDefaultAnimation(); sprite.Play(defaultAnimation, true); return sprite; } /** * Helper function to remove the rotation behavior from a collectible. This will happen by default * when collectibles are spawned when playing as Tainted Isaac or when having Binge Eater. * * Under the hood, this is accomplished by morphing the collectible with the `ignoreModifiers` * argument set to true. */ function preventCollectibleRotation(collectible) { if (!(0, pickupVariants_1.isCollectible)(collectible)) { const entityID = (0, entities_1.getEntityID)(collectible); error(`The "preventCollectibleRotation" function was given a non-collectible: ${entityID}`); } collectible.Morph(collectible.Type, collectible.Variant, collectible.SubType, true, true, true); } /** * Helper function to remove all pickup delay on a collectible. By default, collectibles have a 20 * frame delay before they can be picked up by a player. */ function removeCollectiblePickupDelay(collectible) { if (!(0, pickupVariants_1.isCollectible)(collectible)) { const entityID = (0, entities_1.getEntityID)(collectible); error(`The "removeCollectiblePickupDelay" function was given a non-collectible: ${entityID}`); } collectible.Wait = 0; } /** * Helper function to set a collectible sprite to a question mark (i.e. how collectibles look when * the player has Curse of the Blind). */ function setCollectibleBlind(collectible) { if (!(0, pickupVariants_1.isCollectible)(collectible)) { const entityID = (0, entities_1.getEntityID)(collectible); error(`The "setCollectibleBlind" function was given a non-collectible: ${entityID}`); } setCollectibleSprite(collectible, constants_1.BLIND_ITEM_PNG_PATH); } /** * Helper function to remove the collectible from a collectible pedestal and make it appear as if a * player has already taken the item. This is accomplished by changing the sub-type to * `CollectibleType.NULL` and then setting the sprite to an empty/missing PNG file. * * For more information, see the documentation for the "clearSprite" helper function. */ function setCollectibleEmpty(collectible) { if (!(0, pickupVariants_1.isCollectible)(collectible)) { const entityID = (0, entities_1.getEntityID)(collectible); error(`The "setCollectibleEmpty" function was given a non-collectible: ${entityID}`); } collectible.SubType = isaac_typescript_definitions_1.CollectibleType.NULL; clearCollectibleSprite(collectible); } /** * Helper function to change a collectible into a "glitched" item (like the ones that appear when * the player has TMTRAINER). */ function setCollectibleGlitched(collectible) { if (!(0, pickupVariants_1.isCollectible)(collectible)) { const entityID = (0, entities_1.getEntityID)(collectible); error(`The "setCollectibleGlitched" function was given a non-collectible: ${entityID}`); } // We need to generate a new glitched item. Thus, we temporarily give the player TMTRAINER, if // necessary. const player = Isaac.GetPlayer(); const hasTMTRAINER = player.HasCollectible(isaac_typescript_definitions_1.CollectibleType.TMTRAINER); if (!hasTMTRAINER) { player.AddCollectible(isaac_typescript_definitions_1.CollectibleType.TMTRAINER, 0, false); } const itemPool = cachedClasses_1.game.GetItemPool(); const collectibleType = itemPool.GetCollectible(constants_1.DEFAULT_ITEM_POOL_TYPE); setCollectibleSubType(collectible, collectibleType); if (!hasTMTRAINER) { player.RemoveCollectible(isaac_typescript_definitions_1.CollectibleType.TMTRAINER); } } /** * Helper function to set the "pedestal type" of a collectible. For example, it might be sitting on * top of a broken Blood Donation Machine and you want to change it to be sitting on top of an * opened Spiked Chest. */ function setCollectiblePedestalType(collectible, collectiblePedestalType) { if (!(0, pickupVariants_1.isCollectible)(collectible)) { const entityID = (0, entities_1.getEntityID)(collectible); error(`The "setCollectiblePedestalType" function was given a non-collectible: ${entityID}`); } const sprite = collectible.GetSprite(); const overlayAnimation = sprite.GetOverlayAnimation(); sprite.SetOverlayFrame(overlayAnimation, collectiblePedestalType); } /** * Helper function to change the sprite of a collectible pedestal entity. * * For more information about removing the collectible sprite, see the documentation for the * "clearSprite" helper function. * * @param collectible The collectible whose sprite you want to modify. * @param pngPath Equal to either the spritesheet path to load (e.g. * "gfx/items/collectibles/collectibles_001_thesadonion.png") or undefined. If * undefined, the sprite will be removed, making it appear like the collectible has * already been taken by the player. */ function setCollectibleSprite(collectible, pngPath) { if (!(0, pickupVariants_1.isCollectible)(collectible)) { const entityID = (0, entities_1.getEntityID)(collectible); error(`The "setCollectibleSprite" function was given a non-collectible: ${entityID}`); } const sprite = collectible.GetSprite(); if (pngPath === undefined) { // We want to remove the little circle that appears on top of the pedestal, which is why we also // clear `CollectibleSpriteLayer.ITEM_SHADOW`. (0, sprites_1.clearSprite)(sprite, isaac_typescript_definitions_1.CollectibleSpriteLayer.HEAD, isaac_typescript_definitions_1.CollectibleSpriteLayer.ITEM_SHADOW); } else { sprite.ReplaceSpritesheet(isaac_typescript_definitions_1.CollectibleSpriteLayer.HEAD, pngPath); sprite.LoadGraphics(); } } /** * Helper function to change the collectible on a pedestal. Simply updating the `SubType` field is * not sufficient because the sprite will not change. */ function setCollectibleSubType(collectible, newCollectibleType) { if (!(0, pickupVariants_1.isCollectible)(collectible)) { const entityID = (0, entities_1.getEntityID)(collectible); error(`The "setCollectibleSubType" function was given a non-collectible: ${entityID}`); } // You cannot morph a pedestal to "CollectibleType.NULL"; it would instead create a new random // collectible item. if (newCollectibleType === isaac_typescript_definitions_1.CollectibleType.NULL) { setCollectibleEmpty(collectible); return; } // The naive way to change a collectible's sub-type is to set it directly. However, doing this // will not update the sprite. Manually updating the sprite works in most situations, but does not // work when the pedestal is empty. Instead, we can simply morph the collectible, which seems to // work in all situations. collectible.Morph(isaac_typescript_definitions_1.EntityType.PICKUP, isaac_typescript_definitions_1.PickupVariant.COLLECTIBLE, newCollectibleType, true, true, true); } /** * Helper function to put a message in the log.txt file to let the Rebirth Item Tracker know that * the build has been rerolled. */ function setCollectiblesRerolledForItemTracker() { // This cannot use the "log" function since the prefix will prevent the Rebirth Item Tracker from // recognizing the message. The number here does not matter since the tracker does not check for a // specific number. Isaac.DebugString("Added 3 Collectibles"); } function getCollectibleTypeFromArg(collectibleOrCollectibleType, functionName) { if ((0, types_1.isInteger)(collectibleOrCollectibleType)) { return collectibleOrCollectibleType; } const collectible = collectibleOrCollectibleType; if (!(0, pickupVariants_1.isCollectible)(collectible)) { const entityID = (0, entities_1.getEntityID)(collectible); error(`The "${functionName}" function was given a non-collectible: ${entityID}`); } return collectible.SubType; }