UNPKG

isaacscript-common

Version:

Helper functions and features for IsaacScript mods.

400 lines (340 loc) • 12 kB
import { BombVariant, EffectVariant, EntityType, FamiliarVariant, GridEntityType, KnifeVariant, LaserVariant, PickupVariant, PlayerVariant, ProjectileVariant, TearVariant, } from "isaac-typescript-definitions"; import { ReadonlySet } from "../types/ReadonlySet"; import { getEntities, getEntityFromPtrHash, getEntityID } from "./entities"; import { getGridEntities, getGridEntityID } from "./gridEntities"; import { log } from "./log"; const IGNORE_EFFECT_VARIANTS = new ReadonlySet<EffectVariant>([ EffectVariant.BLOOD_EXPLOSION, // 2 EffectVariant.BLOOD_PARTICLE, // 5 EffectVariant.TINY_BUG, // 21 EffectVariant.TINY_FLY, // 33 EffectVariant.WATER_DROPLET, // 41 EffectVariant.WORM, // 63 EffectVariant.WALL_BUG, // 68 EffectVariant.FALLING_EMBER, // 87 EffectVariant.LIGHT, // 121 EffectVariant.MIST, // 138 EffectVariant.BACKDROP_DECORATION, // 140 EffectVariant.TADPOLE, // 158 ]); /** Helper function for printing out every entity (or filtered entity) in the current room. */ export function logAllEntities( this: void, includeBackgroundEffects: boolean, entityTypeFilter?: EntityType, ): void { let msg = "Entities in the room"; if (entityTypeFilter !== undefined) { msg += ` (filtered to entity type ${entityTypeFilter})`; } else if (!includeBackgroundEffects) { msg += " (not including background effects)"; } msg += ":\n"; const entities = getEntities(); let numMatchedEntities = 0; for (const [i, entity] of entities.entries()) { // If a filter was specified, exclude all entities outside of the filter. if (entityTypeFilter !== undefined && entity.Type !== entityTypeFilter) { continue; } const effect = entity.ToEffect(); if ( !includeBackgroundEffects && effect !== undefined && IGNORE_EFFECT_VARIANTS.has(effect.Variant) ) { continue; } msg += getEntityLogLine(entity, i + 1); numMatchedEntities++; } const zeroText = "(no entities matched)"; const oneOrMoreText = `(${numMatchedEntities} total ${ numMatchedEntities === 1 ? "entity" : "entities" })`; const text = numMatchedEntities === 0 ? zeroText : oneOrMoreText; msg += `${text}\n`; // We must log each line because otherwise the message can get truncated. for (const line of msg.trim().split("\n")) { log(line); } } /** * Helper function for printing out every grid entity (or filtered grid entity) in the current room. * * @param includeWalls Optional. Whether oto log the walls. Default is false. * @param gridEntityTypeFilter Optional. If specified, will only log the given `GridEntityType`. * Default is undefined. */ export function logAllGridEntities( this: void, includeWalls = false, gridEntityTypeFilter?: GridEntityType, ): void { let msg = "Grid entities in the room"; if (gridEntityTypeFilter !== undefined) { msg += ` (filtered to grid entity type ${gridEntityTypeFilter})`; } else if (!includeWalls) { msg += " (not including walls)"; } msg += ":\n"; const gridEntities = getGridEntities(); let numMatchedEntities = 0; for (const gridEntity of gridEntities) { const gridEntityIndex = gridEntity.GetGridIndex(); const gridEntityType = gridEntity.GetType(); // If a filter was specified, exclude all entities outside of the filter. if ( gridEntityTypeFilter !== undefined && gridEntityType !== gridEntityTypeFilter ) { continue; } if ( !includeWalls && gridEntityType === GridEntityType.WALL && gridEntityTypeFilter !== GridEntityType.WALL ) { continue; } msg += getGridEntityLogLine(gridEntity, gridEntityIndex); numMatchedEntities++; } msg += numMatchedEntities === 0 ? "(no grid entities matched)\n" : `(${numMatchedEntities} total grid ${ numMatchedEntities === 1 ? "entity" : "entities" })\n`; // We must log each line because otherwise the message can get truncated. for (const line of msg.trim().split("\n")) { log(line); } } /** Helper function for logging an array of specific entities. */ export function logEntities(this: void, entities: readonly Entity[]): void { for (const entity of entities) { logEntity(entity); } } /** Helper function to log information about a specific entity. */ export function logEntity(this: void, entity: Entity): void { const msg = getEntityLogLine(entity); log(msg); } function getEntityLogLine(this: void, entity: Entity, num?: int): string { let msg = num === undefined ? "" : `${num}) `; msg += getEntityID(entity); const bomb = entity.ToBomb(); if (bomb !== undefined) { msg += ` (bomb - ${getBombVariantName(bomb)})`; } const effect = entity.ToEffect(); if (effect !== undefined) { msg += ` (effect - ${getEffectVariantName(effect)}) (State: ${ effect.State })`; } const familiar = entity.ToFamiliar(); if (familiar !== undefined) { msg += ` (familiar - ${getFamiliarVariantName(familiar)}) (State: ${ familiar.State })`; } const knife = entity.ToKnife(); if (knife !== undefined) { msg += ` (knife - ${getKnifeVariantName(knife)})`; } const laser = entity.ToLaser(); if (laser !== undefined) { msg += ` (laser - ${getLaserVariantName(laser)})`; } const npc = entity.ToNPC(); if (npc !== undefined) { msg += ` (NPC - ${getEntityTypeName(npc)}) (State: ${npc.State})`; } const pickup = entity.ToPickup(); if (pickup !== undefined) { msg += ` (pickup - ${getPickupVariantName(pickup)}) (State: ${ pickup.State })`; } const player = entity.ToPlayer(); if (player !== undefined) { msg += ` (player - ${getPlayerVariantName(player)})`; } const projectile = entity.ToProjectile(); if (projectile !== undefined) { msg += ` (projectile - ${getProjectileVariantName(projectile)})`; } const tear = entity.ToTear(); if (tear !== undefined) { msg += ` (tear - ${getTearVariantName(tear)})`; } msg += "\n"; msg += ` - Index: ${entity.Index}\n`; msg += ` - InitSeed: ${entity.InitSeed}\n`; msg += ` - DropSeed: ${entity.DropSeed}\n`; msg += ` - Position: (${entity.Position.X}, ${entity.Position.Y})\n`; msg += ` - Velocity: (${entity.Velocity.X}, ${entity.Velocity.Y})\n`; msg += ` - HP: ${entity.HitPoints} / ${entity.MaxHitPoints}\n`; // eslint-disable-next-line @typescript-eslint/no-base-to-string msg += ` - Parent: ${entity.Parent}\n`; // eslint-disable-next-line @typescript-eslint/no-base-to-string msg += ` - Child: ${entity.Child}\n`; // eslint-disable-next-line @typescript-eslint/no-base-to-string msg += ` - SpawnerEntity: ${entity.SpawnerEntity}\n`; msg += ` - SpawnerType / SpawnerVariant: ${entity.SpawnerType}.${entity.SpawnerVariant}\n`; msg += ` - FrameCount: ${entity.FrameCount}\n`; if (npc !== undefined) { msg += ` - CanShutDoors: ${npc.CanShutDoors}\n`; } return msg; } function getBombVariantName(bomb: EntityBomb) { // Handle modded entities. const enumName = BombVariant[bomb.Variant] as string | undefined; return enumName === undefined ? "unknown" : `BombVariant.${enumName}`; } function getEffectVariantName(effect: EntityEffect) { // Handle modded entities. const enumName = EffectVariant[effect.Variant] as string | undefined; return enumName === undefined ? "unknown" : `EffectVariant.${enumName}`; } function getFamiliarVariantName(familiar: EntityFamiliar) { // Handle modded entities. const enumName = FamiliarVariant[familiar.Variant] as string | undefined; return enumName === undefined ? "unknown" : `FamiliarVariant.${enumName}`; } function getKnifeVariantName(knife: EntityKnife) { // Handle modded entities. const enumName = KnifeVariant[knife.Variant] as string | undefined; return enumName === undefined ? "unknown" : `KnifeVariant.${enumName}`; } function getLaserVariantName(laser: EntityLaser) { // Handle modded entities. const enumName = LaserVariant[laser.Variant] as string | undefined; return enumName === undefined ? "unknown" : `LaserVariant.${enumName}`; } function getEntityTypeName(npc: EntityNPC) { // Handle modded entities. const enumName = EntityType[npc.Type] as string | undefined; return enumName === undefined ? "unknown" : `EntityType.${enumName}`; } function getPickupVariantName(pickup: EntityPickup) { // Handle modded entities. const enumName = PickupVariant[pickup.Variant] as string | undefined; return enumName === undefined ? "unknown" : `PickupVariant.${enumName}`; } function getPlayerVariantName(player: EntityPlayer) { // Handle modded entities. const enumName = PlayerVariant[player.Variant] as string | undefined; return enumName === undefined ? "unknown" : `PlayerVariant.${enumName}`; } function getProjectileVariantName(projectile: EntityProjectile) { // Handle modded entities. const enumName = ProjectileVariant[projectile.Variant] as string | undefined; return enumName === undefined ? "unknown" : `ProjectileVariant.${enumName}`; } function getTearVariantName(tear: EntityTear) { // Handle modded entities. const enumName = TearVariant[tear.Variant] as string | undefined; return enumName === undefined ? "unknown" : `TearVariant.${enumName}`; } /** Helper function for logging an array of specific grid entities. */ export function logGridEntities( this: void, gridEntities: readonly GridEntity[], ): void { for (const gridEntity of gridEntities) { logGridEntity(gridEntity); } } /** Helper function for log information about a specific grid entity. */ export function logGridEntity(this: void, gridEntity: GridEntity): void { const msg = getGridEntityLogLine(gridEntity); log(msg); } function getGridEntityLogLine( this: void, gridEntity: GridEntity, num?: int, ): string { const gridEntityDesc = gridEntity.GetSaveState(); let msg = num === undefined ? "" : `${num}) `; msg += getGridEntityID(gridEntity); const door = gridEntity.ToDoor(); if (door !== undefined) { msg += " (door)"; } const pit = gridEntity.ToPit(); if (pit !== undefined) { msg += " (pit)"; } const poop = gridEntity.ToPoop(); if (poop !== undefined) { msg += " (poop)"; } const pressurePlate = gridEntity.ToPressurePlate(); if (pressurePlate !== undefined) { msg += " (pressurePlate)"; } const rock = gridEntity.ToRock(); if (rock !== undefined) { msg += " (rock)"; } const spikes = gridEntity.ToSpikes(); if (spikes !== undefined) { msg += " (spikes)"; } const tnt = gridEntity.ToTNT(); if (tnt !== undefined) { msg += " (TNT)"; } msg += ` - State: ${gridEntity.State}\n`; msg += ` - VarData: ${gridEntity.VarData}\n`; msg += ` - Position: (${gridEntity.Position.X}, ${gridEntity.Position.Y})\n`; msg += ` - SpawnSeed: ${gridEntityDesc.SpawnSeed}\n`; msg += ` - VariableSeed: ${gridEntityDesc.VariableSeed})\n`; if (door !== undefined) { msg += ` - Slot: ${door.Slot}\n`; msg += ` - Direction: ${door.Direction}\n`; msg += ` - TargetRoomIndex: ${door.TargetRoomIndex}\n`; msg += ` - TargetRoomType: ${door.TargetRoomType}\n`; } return msg; } /** * Helper function to log information about the entity that corresponding to a pointer hash. (Only * use this when debugging, since retrieving the corresponding entity is expensive.) */ export function logPtrHash(this: void, ptrHash: PtrHash): void { log(`PtrHash: ${ptrHash}`); const entity = getEntityFromPtrHash(ptrHash); if (entity === undefined) { log("No corresponding entity found."); } else { logEntity(entity); } } /** * Helper function to log information about the entity that corresponding to one or more pointer * hashes. (Only use this when debugging, since retrieving the corresponding entity is expensive.) */ export function logPtrHashes(this: void, ptrHashes: readonly PtrHash[]): void { for (const ptrHash of ptrHashes) { logPtrHash(ptrHash); } }