UNPKG

isaacscript-common

Version:

Helper functions and features for IsaacScript mods.

184 lines (183 loc) • 8.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getJSONRoomDoorSlotFlags = getJSONRoomDoorSlotFlags; exports.getJSONRoomOfVariant = getJSONRoomOfVariant; exports.getJSONRoomsOfSubType = getJSONRoomsOfSubType; exports.getRandomJSONEntity = getRandomJSONEntity; exports.getRandomJSONRoom = getRandomJSONRoom; const isaac_typescript_definitions_1 = require("isaac-typescript-definitions"); const array_1 = require("./array"); const doors_1 = require("./doors"); const enums_1 = require("./enums"); const flag_1 = require("./flag"); const log_1 = require("./log"); const random_1 = require("./random"); const types_1 = require("./types"); const utils_1 = require("./utils"); /** * Helper function to calculate what the resulting `BitFlags<DoorSlotFlag>` value would be for a * given JSON room. * * (A JSON room is an XML file converted to JSON so that it can be directly imported into your mod.) */ function getJSONRoomDoorSlotFlags(jsonRoom) { const roomShapeString = jsonRoom.$.shape; const roomShape = (0, types_1.parseIntSafe)(roomShapeString); (0, utils_1.assertDefined)(roomShape, `Failed to parse the "shape" field of a JSON room: ${roomShapeString}`); if (!(0, enums_1.isEnumValue)(roomShape, isaac_typescript_definitions_1.RoomShape)) { error(`Failed to parse the "shape" field of a JSON room since it was an invalid number: ${roomShape}`); } let doorSlotFlags = isaac_typescript_definitions_1.DoorSlotFlagZero; for (const door of jsonRoom.door) { const existsString = door.$.exists; if (existsString !== "True" && existsString !== "False") { error(`Failed to parse the "exists" field of a JSON room door: ${existsString}`); } if (existsString === "False") { continue; } const xString = door.$.x; const x = (0, types_1.parseIntSafe)(xString); (0, utils_1.assertDefined)(x, `Failed to parse the "x" field of a JSON room door: ${xString}`); const yString = door.$.y; const y = (0, types_1.parseIntSafe)(yString); (0, utils_1.assertDefined)(y, `Failed to parse the "y" field of a JSON room door: ${yString}`); const doorSlot = (0, doors_1.getRoomShapeDoorSlot)(roomShape, x, y); (0, utils_1.assertDefined)(doorSlot, `Failed to retrieve the door slot for a JSON room door at coordinates: [${x}, ${y}]`); const doorSlotFlag = (0, doors_1.doorSlotToDoorSlotFlag)(doorSlot); doorSlotFlags = (0, flag_1.addFlag)(doorSlotFlags, doorSlotFlag); } return doorSlotFlags; } /** * Helper function to find a specific room from an array of JSON rooms. * * (A JSON room is an XML file converted to JSON so that it can be directly imported into your mod.) * * @param jsonRooms The array of rooms to search through. * @param variant The room variant to select. (The room variant can be thought of as the ID of the * room.) */ function getJSONRoomOfVariant(jsonRooms, variant) { const jsonRoomsOfVariant = jsonRooms.filter((jsonRoom) => { const roomVariantString = jsonRoom.$.variant; const roomVariant = (0, types_1.parseIntSafe)(roomVariantString); if (roomVariant === undefined) { error(`Failed to convert a JSON room variant to an integer: ${roomVariantString}`); } return roomVariant === variant; }); // The room variant acts as an ID for the room. We assume that there should only be a single room // per variant. if (jsonRoomsOfVariant.length === 0) { return undefined; } if (jsonRoomsOfVariant.length === 1) { return jsonRoomsOfVariant[0]; } error(`Found ${jsonRoomsOfVariant.length} JSON rooms with a variant of ${variant}, when there should only be 1.`); } /** * Helper function to find all of the JSON rooms that match the sub-type provided. * * (A JSON room is an XML file converted to JSON so that it can be directly imported into your mod.) * * @param jsonRooms The array of rooms to search through. * @param subType The sub-type to match. */ function getJSONRoomsOfSubType(jsonRooms, subType) { return jsonRooms.filter((jsonRoom) => { const roomSubTypeString = jsonRoom.$.subtype; const roomSubType = (0, types_1.parseIntSafe)(roomSubTypeString); if (roomSubType === undefined) { error(`Failed to convert a JSON room sub-type to an integer: ${roomSubTypeString}`); } return roomSubType === subType; }); } /** * Helper function to get a random JSON entity from an array of JSON entities. * * (A JSON entity is an entity inside of a JSON room. A JSON room is an XML file converted to JSON * so that it can be directly imported into your mod.) * * Note that this function does not simply choose a random element in the provided array; it will * properly account for each room weight using the algorithm from: * https://stackoverflow.com/questions/1761626/weighted-random-numbers * * If you want an unseeded entity, you must explicitly pass `undefined` to the `seedOrRNG` * parameter. * * @param jsonEntities The array of entities to randomly choose between. * @param seedOrRNG The `Seed` or `RNG` object to use. If an `RNG` object is provided, the * `RNG.Next` method will be called. If `undefined` is provided, it will default to * a random seed. * @param verbose Optional. If specified, will write entries to the "log.txt" file that describe * what the function is doing. Default is false. */ function getRandomJSONEntity(jsonEntities, seedOrRNG, verbose = false) { const totalWeight = getTotalWeightOfJSONObject(jsonEntities); if (verbose) { (0, log_1.log)(`Total weight of the JSON entities provided: ${totalWeight}`); } const chosenWeight = (0, random_1.getRandomFloat)(0, totalWeight, seedOrRNG); if (verbose) { (0, log_1.log)(`Randomly chose weight for JSON entity: ${chosenWeight}`); } const randomJSONEntity = getJSONObjectWithChosenWeight(jsonEntities, chosenWeight); (0, utils_1.assertDefined)(randomJSONEntity, `Failed to get a JSON entity with chosen weight: ${chosenWeight}`); return randomJSONEntity; } /** * Helper function to get a random JSON room from an array of JSON rooms. * * (A JSON room is an XML file converted to JSON so that it can be directly imported into your mod.) * * Note that this function does not simply choose a random element in the provided array; it will * properly account for each room weight using the algorithm from: * https://stackoverflow.com/questions/1761626/weighted-random-numbers * * If you want an unseeded room, you must explicitly pass `undefined` to the `seedOrRNG` parameter. * * @param jsonRooms The array of rooms to randomly choose between. * @param seedOrRNG The `Seed` or `RNG` object to use. If an `RNG` object is provided, the * `RNG.Next` method will be called. If `undefined` is provided, it will default to * a random seed. * @param verbose Optional. If specified, will write entries to the "log.txt" file that describe * what the function is doing. Default is false. */ function getRandomJSONRoom(jsonRooms, seedOrRNG, verbose = false) { const totalWeight = getTotalWeightOfJSONObject(jsonRooms); if (verbose) { (0, log_1.log)(`Total weight of the JSON rooms provided: ${totalWeight}`); } const chosenWeight = (0, random_1.getRandomFloat)(0, totalWeight, seedOrRNG); if (verbose) { (0, log_1.log)(`Randomly chose weight for JSON room: ${chosenWeight}`); } const randomJSONRoom = getJSONObjectWithChosenWeight(jsonRooms, chosenWeight); (0, utils_1.assertDefined)(randomJSONRoom, `Failed to get a JSON room with chosen weight: ${chosenWeight}`); return randomJSONRoom; } function getTotalWeightOfJSONObject(jsonOjectArray) { const weights = jsonOjectArray.map((jsonObject) => { const weightString = jsonObject.$.weight; const weight = tonumber(weightString); (0, utils_1.assertDefined)(weight, `Failed to parse the weight of a JSON object: ${weightString}.`); return weight; }); return (0, array_1.sumArray)(weights); } function getJSONObjectWithChosenWeight(jsonOjectArray, chosenWeight) { let weightAccumulator = 0; for (const jsonObject of jsonOjectArray) { const weightString = jsonObject.$.weight; const weight = tonumber(weightString); (0, utils_1.assertDefined)(weight, `Failed to parse the weight of a JSON object: ${weightString}`); weightAccumulator += weight; if (weightAccumulator >= chosenWeight) { return jsonObject; } } return undefined; }