UNPKG

isaacscript-common

Version:

Helper functions and features for IsaacScript mods.

120 lines (119 loc) 5.52 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PostItemDischarge = void 0; const isaac_typescript_definitions_1 = require("isaac-typescript-definitions"); const cachedEnumValues_1 = require("../../cachedEnumValues"); const cachedClasses_1 = require("../../core/cachedClasses"); const ModCallbackCustom_1 = require("../../enums/ModCallbackCustom"); const charge_1 = require("../../functions/charge"); const playerDataStructures_1 = require("../../functions/playerDataStructures"); const DefaultMap_1 = require("../DefaultMap"); const CustomCallback_1 = require("../private/CustomCallback"); const v = { run: { playersActiveItemMap: new DefaultMap_1.DefaultMap(() => new Map()), playersActiveChargeMap: new DefaultMap_1.DefaultMap(() => new Map()), }, room: { playersBulbLastCollisionFrame: new Map(), }, }; class PostItemDischarge extends CustomCallback_1.CustomCallback { v = v; constructor() { super(); this.callbacksUsed = [ // 30 [ isaac_typescript_definitions_1.ModCallback.PRE_NPC_COLLISION, this.preNPCCollisionSucker, [isaac_typescript_definitions_1.EntityType.SUCKER], ], ]; this.customCallbacksUsed = [ [ ModCallbackCustom_1.ModCallbackCustom.POST_PEFFECT_UPDATE_REORDERED, this.postPEffectUpdateReordered, ], ]; } shouldFire = (fireArgs, optionalArgs) => { const [_player, collectibleType] = fireArgs; const [callbackCollectibleType] = optionalArgs; return (callbackCollectibleType === undefined || callbackCollectibleType === collectibleType); }; // ModCallback.PRE_NPC_COLLISION (30) // EntityType.SUCKER (61) preNPCCollisionSucker = (npc, collider) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison if (npc.Variant === isaac_typescript_definitions_1.SuckerVariant.BULB) { return this.preNPCCollisionBulb(npc, collider); } return undefined; }; // ModCallback.PRE_NPC_COLLISION (30) // EntityType.SUCKER (61) preNPCCollisionBulb(_npc, collider) { this.checkPlayerCollidedWithBulb(collider); return undefined; } /** * The algorithm for detecting a discharge is checking if the current charge is less than the * charge on the previous frame. Thus, when a Bulb zaps a player and drains their charge, this * will be a false position, so Bulbs have to be handled. * * When Bulbs zap a player, they go to `NPCState.STATE_JUMP` for a frame. However, this only * happens on the frame after the player is discharged, which is too late to be of any use. * * Instead, we track the frames that Bulbs collide with players and assume that a collision means * a zap has occurred. */ checkPlayerCollidedWithBulb(collider) { const player = collider.ToPlayer(); if (player === undefined) { return; } const gameFrameCount = cachedClasses_1.game.GetFrameCount(); (0, playerDataStructures_1.mapSetPlayer)(v.room.playersBulbLastCollisionFrame, player, gameFrameCount); } // ModCallbackCustom.POST_PEFFECT_UPDATE_REORDERED postPEffectUpdateReordered = (player) => { const activeItemMap = (0, playerDataStructures_1.defaultMapGetPlayer)(v.run.playersActiveItemMap, player); const chargeMap = (0, playerDataStructures_1.defaultMapGetPlayer)(v.run.playersActiveChargeMap, player); for (const activeSlot of cachedEnumValues_1.ACTIVE_SLOT_VALUES) { const currentActiveItem = player.GetActiveItem(); let previousActiveItem = activeItemMap.get(activeSlot); previousActiveItem ??= currentActiveItem; activeItemMap.set(activeSlot, currentActiveItem); if (currentActiveItem !== previousActiveItem) { // The player swapped out their active item for something else, so it should be impossible // for the discharge callback to fire on this frame. continue; } const currentCharge = (0, charge_1.getTotalCharge)(player, activeSlot); let previousCharge = chargeMap.get(activeSlot); previousCharge ??= currentCharge; chargeMap.set(activeSlot, currentCharge); if (this.playerRecentlyCollidedWithBulb(player)) { continue; } if (currentCharge < previousCharge) { const collectibleType = player.GetActiveItem(activeSlot); this.fire(player, collectibleType, activeSlot); } } }; /** * If the player collided with a Bulb on either this frame or the last frame, then assume a zap * has occurred. (We do not want to fire the discharge callback if this is the case.) */ playerRecentlyCollidedWithBulb(player) { const gameFrameCount = cachedClasses_1.game.GetFrameCount(); const bulbLastCollisionFrame = (0, playerDataStructures_1.mapGetPlayer)(v.room.playersBulbLastCollisionFrame, player); const collidedOnThisFrame = gameFrameCount === bulbLastCollisionFrame; const collidedOnLastFrame = gameFrameCount - 1 === bulbLastCollisionFrame; return collidedOnThisFrame || collidedOnLastFrame; } } exports.PostItemDischarge = PostItemDischarge;