UNPKG

isaacscript-common

Version:

Helper functions and features for IsaacScript mods.

298 lines (297 loc) • 14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.addCollectible = addCollectible; exports.addCollectibleCostume = addCollectibleCostume; exports.anyPlayerHasCollectible = anyPlayerHasCollectible; exports.getActiveItemSlots = getActiveItemSlots; exports.getAdjustedPrice = getAdjustedPrice; exports.getPlayerCollectibleCount = getPlayerCollectibleCount; exports.getPlayersWithCollectible = getPlayersWithCollectible; exports.getTotalPlayerCollectibles = getTotalPlayerCollectibles; exports.hasCollectible = hasCollectible; exports.hasCollectibleInActiveSlot = hasCollectibleInActiveSlot; exports.hasOpenActiveItemSlot = hasOpenActiveItemSlot; exports.isActiveSlotEmpty = isActiveSlotEmpty; exports.removeAllActiveItems = removeAllActiveItems; exports.removeCollectible = removeCollectible; exports.removeCollectibleCostume = removeCollectibleCostume; exports.removeCollectibleFromAllPlayers = removeCollectibleFromAllPlayers; exports.setActiveItem = setActiveItem; exports.useActiveItemTemp = useActiveItemTemp; const isaac_typescript_definitions_1 = require("isaac-typescript-definitions"); const cachedEnumValues_1 = require("../cachedEnumValues"); const cachedClasses_1 = require("../core/cachedClasses"); const ReadonlySet_1 = require("../types/ReadonlySet"); const array_1 = require("./array"); const collectibles_1 = require("./collectibles"); const playerIndex_1 = require("./playerIndex"); const players_1 = require("./players"); /** * Helper function to add one or more collectibles to a player. * * This function is variadic, meaning that you can supply as many collectible types as you want to * add. */ function addCollectible(player, ...collectibleTypes) { for (const collectibleType of collectibleTypes) { player.AddCollectible(collectibleType); } } function addCollectibleCostume(player, collectibleType) { const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); if (itemConfigItem === undefined) { return; } player.AddCostume(itemConfigItem, false); } /** * Helper function to check to see if any player has a particular collectible. * * @param collectibleType The collectible type to check for. * @param ignoreModifiers If set to true, only counts collectibles the player actually owns and * ignores effects granted by items like Zodiac, 3 Dollar Bill and Lemegeton. * Default is false. */ function anyPlayerHasCollectible(collectibleType, ignoreModifiers) { const players = (0, playerIndex_1.getAllPlayers)(); return players.some((player) => player.HasCollectible(collectibleType, ignoreModifiers)); } /** * Helper function to find the active slots that the player has the corresponding collectible type * in. Returns an empty array if the player does not have the collectible in any active slot. */ function getActiveItemSlots(player, collectibleType) { return cachedEnumValues_1.ACTIVE_SLOT_VALUES.filter((activeSlot) => { const activeItem = player.GetActiveItem(activeSlot); return activeItem === collectibleType; }); } /** * Helper function to get the adjusted price for a pickup, depending on how many Steam Sales all * players currently have. (For example, if Jacob has one Steam Sale and Esau has one Steam Sale, * the prices for items in the shop would be the same as if Isaac had two Steam Sales.) */ function getAdjustedPrice(basePrice) { const numSteamSales = getTotalPlayerCollectibles(isaac_typescript_definitions_1.CollectibleType.STEAM_SALE); return numSteamSales > 0 ? Math.floor(basePrice / (numSteamSales + 1)) : basePrice; } /** * Helper function to return the total amount of collectibles that a player has that match the * collectible type(s) provided. * * This function is variadic, meaning that you can specify N collectible types. * * Note that this will filter out non-real collectibles like Lilith's Incubus. */ function getPlayerCollectibleCount(player, ...collectibleTypes) { let numCollectibles = 0; for (const collectibleType of collectibleTypes) { // We specify "true" as the second argument to filter out things like Lilith's Incubus. numCollectibles += player.GetCollectibleNum(collectibleType, true); } return numCollectibles; } /** * Helper function to get only the players that have a certain collectible. * * This function is variadic, meaning that you can supply as many collectible types as you want to * check for. It only returns the players that have all of the collectibles. */ function getPlayersWithCollectible(...collectibleTypes) { const players = (0, playerIndex_1.getPlayers)(); return players.filter((player) => collectibleTypes.every((collectibleType) => player.HasCollectible(collectibleType))); } /** * Returns the total number of collectibles amongst all players. For example, if player 1 has 1 Sad * Onion and player 2 has 2 Sad Onions, then this function would return 3. * * Note that this will filter out non-real collectibles like Lilith's Incubus. */ function getTotalPlayerCollectibles(collectibleType) { const players = (0, playerIndex_1.getPlayers)(); const numCollectiblesArray = players.map((player) => // We specify "true" as the second argument to filter out things like Lilith's Incubus. player.GetCollectibleNum(collectibleType, true)); return (0, array_1.sumArray)(numCollectiblesArray); } /** * Helper function to check to see if a player has one or more collectibles. * * This function is variadic, meaning that you can supply as many collectible types as you want to * check for. Returns true if the player has any of the supplied collectible types. * * This function always passes `false` to the `ignoreModifiers` argument. */ function hasCollectible(player, ...collectibleTypes) { return collectibleTypes.some((collectibleType) => player.HasCollectible(collectibleType)); } /** * Helper function to check to see if a player has a specific collectible in one or more active * slots. * * This function is variadic, meaning that you can specify as many active slots as you want to check * for. This function will return true if the collectible type is located in any of the active slots * provided. */ function hasCollectibleInActiveSlot(player, collectibleType, ...activeSlots) { const matchingActiveSlotsSet = new ReadonlySet_1.ReadonlySet(activeSlots); const activeItemSlots = getActiveItemSlots(player, collectibleType); return activeItemSlots.some((activeSlot) => matchingActiveSlotsSet.has(activeSlot)); } /** * Returns whether the player can hold an additional active item, beyond what they are currently * carrying. This takes the Schoolbag into account. * * If the player is the Tainted Soul, this always returns false, since that character cannot pick up * items. (Only Tainted Forgotten can pick up items.) */ function hasOpenActiveItemSlot(player) { if ((0, players_1.isCharacter)(player, isaac_typescript_definitions_1.PlayerType.SOUL_B)) { return false; } const activeItemPrimary = player.GetActiveItem(isaac_typescript_definitions_1.ActiveSlot.PRIMARY); const activeItemSecondary = player.GetActiveItem(isaac_typescript_definitions_1.ActiveSlot.SECONDARY); const hasSchoolbag = player.HasCollectible(isaac_typescript_definitions_1.CollectibleType.SCHOOLBAG); if (hasSchoolbag) { return (activeItemPrimary === isaac_typescript_definitions_1.CollectibleType.NULL || activeItemSecondary === isaac_typescript_definitions_1.CollectibleType.NULL); } return activeItemPrimary === isaac_typescript_definitions_1.CollectibleType.NULL; } /** * Helper function to check if the active slot of a particular player is empty. * * @param player The player to check. * @param activeSlot Optional. The active slot to check. Default is `ActiveSlot.PRIMARY`. */ function isActiveSlotEmpty(player, activeSlot = isaac_typescript_definitions_1.ActiveSlot.PRIMARY) { const activeCollectibleType = player.GetActiveItem(activeSlot); return activeCollectibleType === isaac_typescript_definitions_1.CollectibleType.NULL; } /** * Helper function to remove all of the active items from a player. This includes the Schoolbag item * and any pocket actives. */ function removeAllActiveItems(player) { for (const activeSlot of cachedEnumValues_1.ACTIVE_SLOT_VALUES) { const collectibleType = player.GetActiveItem(activeSlot); if (collectibleType === isaac_typescript_definitions_1.CollectibleType.NULL) { continue; } let stillHasCollectible; do { player.RemoveCollectible(collectibleType); stillHasCollectible = player.HasCollectible(collectibleType); } while (stillHasCollectible); } } /** * Helper function to remove one or more collectibles to a player. * * This function is variadic, meaning that you can supply as many collectible types as you want to * remove. */ function removeCollectible(player, ...collectibleTypes) { for (const collectibleType of collectibleTypes) { player.RemoveCollectible(collectibleType); } } /** * Helper function to remove a collectible costume from a player. Use this helper function to avoid * having to request the collectible from the item config. */ function removeCollectibleCostume(player, collectibleType) { const itemConfigItem = cachedClasses_1.itemConfig.GetCollectible(collectibleType); if (itemConfigItem === undefined) { return; } player.RemoveCostume(itemConfigItem); } /** * Helper function to remove one or more collectibles from all players. If any player has more than * one copy of the item, then all copies of it will be removed. * * This function is variadic, meaning that you can specify as many collectibles as you want to * remove. */ function removeCollectibleFromAllPlayers(...collectibleTypes) { for (const player of (0, playerIndex_1.getAllPlayers)()) { for (const collectibleType of collectibleTypes) { while (player.HasCollectible(collectibleType, true)) { player.RemoveCollectible(collectibleType); } } } } /** * Helper function to set an active collectible to a particular slot. This has different behavior * than calling the `player.AddCollectible` method with the `activeSlot` argument, because this * function will not shift existing items into the Schoolbag and it handles * `ActiveSlot.SLOT_POCKET2`. * * Note that if an item is set to `ActiveSlot.SLOT_POCKET2`, it will disappear after being used and * will be automatically removed upon entering a new room. * * @param player The player to give the item to. * @param collectibleType The collectible type of the item to give. * @param activeSlot Optional. The slot to set. Default is `ActiveSlot.PRIMARY`. * @param charge Optional. The argument of charges to set. If not specified, the item will be set * with maximum charges. * @param keepInPools Optional. Whether to remove the item from pools. Default is false. */ function setActiveItem(player, collectibleType, activeSlot = isaac_typescript_definitions_1.ActiveSlot.PRIMARY, charge, keepInPools = false) { const itemPool = cachedClasses_1.game.GetItemPool(); const primaryCollectibleType = player.GetActiveItem(isaac_typescript_definitions_1.ActiveSlot.PRIMARY); const primaryCharge = player.GetActiveCharge(isaac_typescript_definitions_1.ActiveSlot.PRIMARY); const secondaryCollectibleType = player.GetActiveItem(isaac_typescript_definitions_1.ActiveSlot.SECONDARY); charge ??= (0, collectibles_1.getCollectibleMaxCharges)(collectibleType); if (!keepInPools) { itemPool.RemoveCollectible(collectibleType); } switch (activeSlot) { case isaac_typescript_definitions_1.ActiveSlot.PRIMARY: { // If there is a Schoolbag item, removing the primary item will shift the Schoolbag item to // the primary slot. if (primaryCollectibleType !== isaac_typescript_definitions_1.CollectibleType.NULL) { player.RemoveCollectible(primaryCollectibleType); } // If there was a Schoolbag item, adding a new primary item will shift it back into the // secondary slot. player.AddCollectible(collectibleType, charge, false); break; } case isaac_typescript_definitions_1.ActiveSlot.SECONDARY: { if (primaryCollectibleType !== isaac_typescript_definitions_1.CollectibleType.NULL) { player.RemoveCollectible(primaryCollectibleType); } if (secondaryCollectibleType !== isaac_typescript_definitions_1.CollectibleType.NULL) { player.RemoveCollectible(secondaryCollectibleType); } // Add the new item, which will go to the primary slot. player.AddCollectible(secondaryCollectibleType, charge, false); // Add back the original primary item, if any. if (primaryCollectibleType !== isaac_typescript_definitions_1.CollectibleType.NULL) { player.AddCollectible(primaryCollectibleType, primaryCharge, false); } break; } case isaac_typescript_definitions_1.ActiveSlot.POCKET: { player.SetPocketActiveItem(collectibleType, activeSlot, keepInPools); player.SetActiveCharge(charge, activeSlot); break; } case isaac_typescript_definitions_1.ActiveSlot.POCKET_SINGLE_USE: { player.SetPocketActiveItem(collectibleType, activeSlot, keepInPools); break; } } } /** * Helper function to use an active item without showing an animation, keeping the item, or adding * any costumes. */ function useActiveItemTemp(player, collectibleType) { player.UseActiveItem(collectibleType, false, false, true, false, -1); }